WebKit Bugzilla
Attachment 339690 Details for
Bug 185365
: InPlaceAbstractState::beginBasicBlock shouldn't have to clear any abstract values
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
the patch
blah.patch (text/plain), 23.28 KB, created by
Filip Pizlo
on 2018-05-06 13:47:01 PDT
(
hide
)
Description:
the patch
Filename:
MIME Type:
Creator:
Filip Pizlo
Created:
2018-05-06 13:47:01 PDT
Size:
23.28 KB
patch
obsolete
>Index: Source/JavaScriptCore/ChangeLog >=================================================================== >--- Source/JavaScriptCore/ChangeLog (revision 231400) >+++ Source/JavaScriptCore/ChangeLog (working copy) >@@ -1,3 +1,46 @@ >+2018-05-06 Filip Pizlo <fpizlo@apple.com> >+ >+ InPlaceAbstractState::beginBasicBlock shouldn't have to clear any abstract values >+ https://bugs.webkit.org/show_bug.cgi?id=185365 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ This patch does three things to improve compile times: >+ >+ - Fixes some inlining goofs. >+ >+ - Adds the ability to measure compile times with run-jsc-benchmarks. >+ >+ - Dramatically improves the performance of InPlaceAbstractState::beginBasicBlock by removing the >+ code that clears abstract values. It turns out that on constant folding "needed" this, in the >+ sense that this was the only thing protecting it from loading the abstract value of a no-result >+ node and then concluding that because it had a non-empty m_value, it could be constant-folded. >+ Any node that produces a result will explicitly set its abstract value, so this problem can >+ also be guarded by just having constant folding check if the node it wants to fold returns any >+ result. >+ >+ Solid 0.96% compile time speed-up across SunSpider-CompileTime and V8Spider-CompileTime. >+ >+ * dfg/DFGAbstractInterpreterInlines.h: >+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): >+ * dfg/DFGAbstractValue.cpp: >+ (JSC::DFG::AbstractValue::set): >+ * dfg/DFGAbstractValue.h: >+ (JSC::DFG::AbstractValue::merge): >+ * dfg/DFGConstantFoldingPhase.cpp: >+ (JSC::DFG::ConstantFoldingPhase::foldConstants): >+ * dfg/DFGGraph.h: >+ (JSC::DFG::Graph::doToChildrenWithNode): >+ (JSC::DFG::Graph::doToChildren): >+ * dfg/DFGInPlaceAbstractState.cpp: >+ (JSC::DFG::InPlaceAbstractState::beginBasicBlock): >+ * jit/JIT.cpp: >+ (JSC::JIT::totalCompileTime): >+ * jit/JIT.h: >+ * jsc.cpp: >+ (GlobalObject::finishCreation): >+ (functionTotalCompileTime): >+ > 2018-05-05 Filip Pizlo <fpizlo@apple.com> > > DFG CFA phase should only do clobber asserts in debug >Index: Source/JavaScriptCore/jsc.cpp >=================================================================== >--- Source/JavaScriptCore/jsc.cpp (revision 231399) >+++ Source/JavaScriptCore/jsc.cpp (working copy) >@@ -347,6 +347,7 @@ static EncodedJSValue JSC_HOST_CALL func > static EncodedJSValue JSC_HOST_CALL functionFlashHeapAccess(ExecState*); > static EncodedJSValue JSC_HOST_CALL functionDisableRichSourceInfo(ExecState*); > static EncodedJSValue JSC_HOST_CALL functionMallocInALoop(ExecState*); >+static EncodedJSValue JSC_HOST_CALL functionTotalCompileTime(ExecState*); > > struct Script { > enum class StrictMode { >@@ -606,6 +607,7 @@ protected: > > addFunction(vm, "disableRichSourceInfo", functionDisableRichSourceInfo, 0); > addFunction(vm, "mallocInALoop", functionMallocInALoop, 0); >+ addFunction(vm, "totalCompileTime", functionTotalCompileTime, 0); > } > > void addFunction(VM& vm, JSObject* object, const char* name, NativeFunction function, unsigned arguments) >@@ -1809,6 +1811,11 @@ EncodedJSValue JSC_HOST_CALL functionMal > return JSValue::encode(jsUndefined()); > } > >+EncodedJSValue JSC_HOST_CALL functionTotalCompileTime(ExecState*) >+{ >+ return JSValue::encode(jsNumber(JIT::totalCompileTime().milliseconds())); >+} >+ > template<typename ValueType> > typename std::enable_if<!std::is_fundamental<ValueType>::value>::type addOption(VM&, JSObject*, Identifier, ValueType) { } > >Index: Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (revision 231399) >+++ Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (working copy) >@@ -3410,8 +3410,6 @@ bool AbstractInterpreter<AbstractStateTy > case CheckTraps: > case LogShadowChickenPrologue: > case LogShadowChickenTail: >- break; >- > case ProfileType: > case ProfileControlFlow: > case Phantom: >@@ -3421,6 +3419,10 @@ bool AbstractInterpreter<AbstractStateTy > case CheckTypeInfoFlags: > case SuperSamplerBegin: > case SuperSamplerEnd: >+ case CheckTierUpAndOSREnter: >+ case LoopHint: >+ case ZombieHint: >+ case ExitOK: > break; > > case ParseInt: { >@@ -3483,10 +3485,6 @@ bool AbstractInterpreter<AbstractStateTy > break; > } > >- case CheckTierUpAndOSREnter: >- case LoopHint: >- case ZombieHint: >- case ExitOK: > break; > > case Unreachable: >Index: Source/JavaScriptCore/dfg/DFGAbstractValue.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAbstractValue.cpp (revision 231399) >+++ Source/JavaScriptCore/dfg/DFGAbstractValue.cpp (working copy) >@@ -53,9 +53,9 @@ void AbstractValue::set(Graph& graph, co > if (!!value && value.value().isCell()) { > Structure* structure = value.structure(); > StructureRegistrationResult result; >- RegisteredStructure RegisteredStructure = graph.registerStructure(structure, result); >+ RegisteredStructure registeredStructure = graph.registerStructure(structure, result); > if (result == StructureRegisteredAndWatched) { >- m_structure = RegisteredStructure; >+ m_structure = registeredStructure; > if (clobberState == StructuresAreClobbered) { > m_arrayModes = ALL_ARRAY_MODES; > m_structure.clobber(); >Index: Source/JavaScriptCore/dfg/DFGAbstractValue.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAbstractValue.h (revision 231399) >+++ Source/JavaScriptCore/dfg/DFGAbstractValue.h (working copy) >@@ -243,7 +243,7 @@ struct AbstractValue { > return !(*this == other); > } > >- bool merge(const AbstractValue& other) >+ ALWAYS_INLINE bool merge(const AbstractValue& other) > { > if (other.isClear()) > return false; >Index: Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp (revision 231399) >+++ Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp (working copy) >@@ -852,7 +852,7 @@ private: > // about such things. > break; > } >- if (!node->shouldGenerate() || m_state.didClobber() || node->hasConstant()) >+ if (!node->shouldGenerate() || m_state.didClobber() || node->hasConstant() || !node->result()) > continue; > > // Interesting fact: this freezing that we do right here may turn an fragile value into >Index: Source/JavaScriptCore/dfg/DFGGraph.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGGraph.h (revision 231399) >+++ Source/JavaScriptCore/dfg/DFGGraph.h (working copy) >@@ -84,23 +84,12 @@ using SSANaturalLoops = NaturalLoops<SSA > thingToDo(_node, (graph).m_varArgChildren[_childIdx]); \ > } \ > } else { \ >- if (!_node->child1()) { \ >- ASSERT( \ >- !_node->child2() \ >- && !_node->child3()); \ >- break; \ >+ for (unsigned _edgeIndex = 0; _edgeIndex < AdjacencyList::Size; _edgeIndex++) { \ >+ Edge& _edge = _node->children.child(_edgeIndex); \ >+ if (!_edge) \ >+ break; \ >+ thingToDo(_node, _edge); \ > } \ >- thingToDo(_node, _node->child1()); \ >- \ >- if (!_node->child2()) { \ >- ASSERT(!_node->child3()); \ >- break; \ >- } \ >- thingToDo(_node, _node->child2()); \ >- \ >- if (!_node->child3()) \ >- break; \ >- thingToDo(_node, _node->child3()); \ > } \ > } while (false) > >@@ -719,13 +708,13 @@ public: > } > > template<typename ChildFunctor> >- void doToChildrenWithNode(Node* node, const ChildFunctor& functor) >+ ALWAYS_INLINE void doToChildrenWithNode(Node* node, const ChildFunctor& functor) > { > DFG_NODE_DO_TO_CHILDREN(*this, node, functor); > } > > template<typename ChildFunctor> >- void doToChildren(Node* node, const ChildFunctor& functor) >+ ALWAYS_INLINE void doToChildren(Node* node, const ChildFunctor& functor) > { > doToChildrenWithNode( > node, >Index: Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp (revision 231399) >+++ Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp (working copy) >@@ -60,13 +60,6 @@ void InPlaceAbstractState::beginBasicBlo > ASSERT(basicBlock->variablesAtHead.numberOfLocals() == basicBlock->variablesAtTail.numberOfLocals()); > > m_abstractValues.resize(); >- >- for (size_t i = 0; i < basicBlock->size(); i++) { >- NodeFlowProjection::forEach( >- basicBlock->at(i), [&] (NodeFlowProjection nodeProjection) { >- forNode(nodeProjection).clear(); >- }); >- } > > m_variables = basicBlock->valuesAtHead; > >Index: Source/JavaScriptCore/jit/JIT.cpp >=================================================================== >--- Source/JavaScriptCore/jit/JIT.cpp (revision 231399) >+++ Source/JavaScriptCore/jit/JIT.cpp (working copy) >@@ -1013,6 +1013,11 @@ HashMap<CString, Seconds> JIT::compileTi > return result; > } > >+Seconds JIT::totalCompileTime() >+{ >+ return totalBaselineCompileTime + totalDFGCompileTime + totalFTLCompileTime; >+} >+ > } // namespace JSC > > #endif // ENABLE(JIT) >Index: Source/JavaScriptCore/jit/JIT.h >=================================================================== >--- Source/JavaScriptCore/jit/JIT.h (revision 231399) >+++ Source/JavaScriptCore/jit/JIT.h (working copy) >@@ -250,6 +250,7 @@ namespace JSC { > static int stackPointerOffsetFor(CodeBlock*); > > JS_EXPORT_PRIVATE static HashMap<CString, Seconds> compileTimeStats(); >+ JS_EXPORT_PRIVATE static Seconds totalCompileTime(); > > private: > void privateCompileMainPass(); >Index: Source/WTF/ChangeLog >=================================================================== >--- Source/WTF/ChangeLog (revision 231399) >+++ Source/WTF/ChangeLog (working copy) >@@ -1,3 +1,18 @@ >+2018-05-06 Filip Pizlo <fpizlo@apple.com> >+ >+ InPlaceAbstractState::beginBasicBlock shouldn't have to clear any abstract values >+ https://bugs.webkit.org/show_bug.cgi?id=185365 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Fix some inlining goof-ups. >+ >+ * wtf/TinyPtrSet.h: >+ (WTF::TinyPtrSet::add): >+ (WTF::TinyPtrSet::merge): >+ (WTF::TinyPtrSet::addOutOfLine): >+ (WTF::TinyPtrSet::mergeOtherOutOfLine): >+ > 2018-05-04 Tim Horton <timothy_horton@apple.com> > > Shift to a lower-level framework for simplifying URLs >Index: Source/WTF/wtf/TinyPtrSet.h >=================================================================== >--- Source/WTF/wtf/TinyPtrSet.h (revision 231399) >+++ Source/WTF/wtf/TinyPtrSet.h (working copy) >@@ -27,6 +27,7 @@ > #define TinyPtrSet_h > > #include <wtf/Assertions.h> >+#include <wtf/DataLog.h> > #include <wtf/FastMalloc.h> > > namespace JSC { namespace DFG { >@@ -103,7 +104,7 @@ public: > } > > // Returns true if the value was added, or false if the value was already there. >- bool add(T value) >+ ALWAYS_INLINE bool add(T value) > { > ASSERT(value); > if (isThin()) { >@@ -156,7 +157,7 @@ public: > return containsOutOfLine(value); > } > >- bool merge(const TinyPtrSet& other) >+ ALWAYS_INLINE bool merge(const TinyPtrSet& other) > { > if (other.isThin()) { > if (other.singleEntry()) >@@ -164,25 +165,7 @@ public: > return false; > } > >- OutOfLineList* list = other.list(); >- if (list->m_length >= 2) { >- if (isThin()) { >- OutOfLineList* myNewList = OutOfLineList::create( >- list->m_length + !!singleEntry()); >- if (singleEntry()) { >- myNewList->m_length = 1; >- myNewList->list()[0] = singleEntry(); >- } >- set(myNewList); >- } >- bool changed = false; >- for (unsigned i = 0; i < list->m_length; ++i) >- changed |= addOutOfLine(list->list()[i]); >- return changed; >- } >- >- ASSERT(list->m_length); >- return add(list->list()[0]); >+ return mergeOtherOutOfLine(other); > } > > template<typename Functor> >@@ -379,7 +362,7 @@ private: > > static const unsigned defaultStartingSize = 4; > >- bool addOutOfLine(T value) >+ NEVER_INLINE bool addOutOfLine(T value) > { > OutOfLineList* list = this->list(); > for (unsigned i = 0; i < list->m_length; ++i) { >@@ -402,6 +385,29 @@ private: > return true; > } > >+ NEVER_INLINE bool mergeOtherOutOfLine(const TinyPtrSet& other) >+ { >+ OutOfLineList* list = other.list(); >+ if (list->m_length >= 2) { >+ if (isThin()) { >+ OutOfLineList* myNewList = OutOfLineList::create( >+ list->m_length + !!singleEntry()); >+ if (singleEntry()) { >+ myNewList->m_length = 1; >+ myNewList->list()[0] = singleEntry(); >+ } >+ set(myNewList); >+ } >+ bool changed = false; >+ for (unsigned i = 0; i < list->m_length; ++i) >+ changed |= addOutOfLine(list->list()[i]); >+ return changed; >+ } >+ >+ ASSERT(list->m_length); >+ return add(list->list()[0]); >+ } >+ > bool containsOutOfLine(T value) const > { > OutOfLineList* list = this->list(); >Index: Tools/ChangeLog >=================================================================== >--- Tools/ChangeLog (revision 231400) >+++ Tools/ChangeLog (working copy) >@@ -1,3 +1,14 @@ >+2018-05-06 Filip Pizlo <fpizlo@apple.com> >+ >+ InPlaceAbstractState::beginBasicBlock shouldn't have to clear any abstract values >+ https://bugs.webkit.org/show_bug.cgi?id=185365 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Make it possible to measure compile times. >+ >+ * Scripts/run-jsc-benchmarks: >+ > 2018-05-04 Wenson Hsieh <wenson_hsieh@apple.com> > > [iOS] Multiple links in Mail are dropped in a single line, and are difficult to tell apart >Index: Tools/Scripts/run-jsc-benchmarks >=================================================================== >--- Tools/Scripts/run-jsc-benchmarks (revision 231399) >+++ Tools/Scripts/run-jsc-benchmarks (working copy) >@@ -1,6 +1,6 @@ > #!/usr/bin/env ruby > >-# Copyright (C) 2011-2015 Apple Inc. All rights reserved. >+# Copyright (C) 2011-2018 Apple Inc. All rights reserved. > # > # Redistribution and use in source and binary forms, with or without > # modification, are permitted provided that the following conditions >@@ -216,8 +216,10 @@ $warmup=1 > $outer=4 > $quantum=1000 > $includeSunSpider=true >+$includeSunSpiderCompileTime=true > $includeLongSpider=false > $includeV8=true >+$includeV8CompileTime=true > $includeKraken=true > $includeJSBench=true > $includeMicrobenchmarks=true >@@ -311,7 +313,11 @@ def usage > puts "--dont-copy-vms Don't copy VMs even when doing a remote benchmarking run;" > puts " instead assume that they are already there." > puts "--sunspider Only run SunSpider." >- puts "--v8-spider Only run V8." >+ puts "--sunspider-compile-time" >+ puts " Only run the SunSpider compile time benchmark." >+ puts "--v8-spider Only run SunSpider-style V8." >+ puts "--v8-spider-compile-time" >+ puts " Only run the SunSpider-style V8 compile time benchmark." > puts "--kraken Only run Kraken." > puts "--js-bench Only run JSBench." > puts "--microbenchmarks Only run microbenchmarks." >@@ -856,6 +862,20 @@ class SingleFileCustomTimedBenchmarkPara > end > end > >+# Benchmark that consists of a single file and must be loaded in its own global object each >+# time (i.e. run()), and returns the time spent compiling >+class SingleFileCompileTimeBenchmarkParameters >+ attr_reader :benchPath >+ >+ def initialize(benchPath) >+ @benchPath = benchPath >+ end >+ >+ def kind >+ :singleFileCompileTimeBenchmark >+ end >+end >+ > # Benchmark that consists of one or more data files that should be loaded globally, followed > # by a command to run the benchmark. > class MultiFileTimedBenchmarkParameters >@@ -999,6 +1019,23 @@ def emitBenchRunCodeFile(name, plan, ben > doublePuts($stderr,file,"print(\"#{name}: #{plan.vm}: #{plan.iteration}: #{innerIndex}: Time: \"+__bencher_run(#{benchParams.benchPath.inspect}));") > doublePuts($stderr,file,"gc();") unless plan.vm.shouldMeasureGC > } >+ elsif benchParams.kind == :singleFileCompileTimeBenchmark >+ doublePuts($stderr,file,"function __bencher_run(__bencher_what) {") >+ doublePuts($stderr,file," var __compileTimeBefore = totalCompileTime();") >+ $rerun.times { >+ doublePuts($stderr,file," run(__bencher_what);") >+ } >+ doublePuts($stderr,file," return totalCompileTime() - __compileTimeBefore;") >+ doublePuts($stderr,file,"}") >+ $warmup.times { >+ doublePuts($stderr,file,"__bencher_run(#{benchParams.benchPath.inspect})") >+ doublePuts($stderr,file,"gc();") unless plan.vm.shouldMeasureGC >+ } >+ $inner.times { >+ | innerIndex | >+ doublePuts($stderr,file,"print(\"#{name}: #{plan.vm}: #{plan.iteration}: #{innerIndex}: Time: \"+__bencher_run(#{benchParams.benchPath.inspect}));") >+ doublePuts($stderr,file,"gc();") unless plan.vm.shouldMeasureGC >+ } > else > raise unless benchParams.kind == :singleFileTimedBenchmark > doublePuts($stderr,file,"function __bencher_run(__bencher_what) {") >@@ -1539,6 +1576,10 @@ module Benchmark > "x#{weight} " > end > end >+ >+ def environment >+ {} >+ end > end > > class SunSpiderBenchmark >@@ -1641,6 +1682,23 @@ class CustomTimedBenchmark > end > end > >+class CompileTimeBenchmark >+ include Benchmark >+ >+ def initialize(name, fullPath) >+ @name = name >+ @fullPath = fullPath >+ end >+ >+ def emitRunCode(plan) >+ emitBenchRunCode(fullname, plan, SingleFileCompileTimeBenchmarkParameters.new(ensureFile("CompileTime-#{@name}", @fullPath))) >+ end >+ >+ def environment >+ {"JSC_useConcurrentJIT" => "false", "JSC_reportTotalCompileTimes" => "true"} >+ end >+end >+ > class KrakenBenchmark > include Benchmark > >@@ -2038,7 +2096,12 @@ class BenchRunPlan > end > > def environment >- @environment >+ result = @environment.clone >+ benchmark.environment.each_pair { >+ | key, value | >+ result[key] = value >+ } >+ result > end > > def prefix >@@ -2722,8 +2785,10 @@ begin > def resetBenchOptionsIfNecessary > unless $sawBenchOptions > $includeSunSpider = false >+ $includeSunSpiderCompileTime = false > $includeLongSpider = false > $includeV8 = false >+ $includeV8CompileTime = false > $includeKraken = false > $includeJSBench = false > $includeMicrobenchmarks = false >@@ -2748,8 +2813,10 @@ begin > ['--minimum', GetoptLong::REQUIRED_ARGUMENT], > ['--timing-mode', GetoptLong::REQUIRED_ARGUMENT], > ['--sunspider', GetoptLong::NO_ARGUMENT], >+ ['--sunspider-compile-time', GetoptLong::NO_ARGUMENT], > ['--longspider', GetoptLong::NO_ARGUMENT], > ['--v8-spider', GetoptLong::NO_ARGUMENT], >+ ['--v8-spider-compile-time', GetoptLong::NO_ARGUMENT], > ['--kraken', GetoptLong::NO_ARGUMENT], > ['--js-bench', GetoptLong::NO_ARGUMENT], > ['--microbenchmarks', GetoptLong::NO_ARGUMENT], >@@ -2828,12 +2895,18 @@ begin > when '--sunspider' > resetBenchOptionsIfNecessary > $includeSunSpider = true >+ when '--sunspider-compile-time' >+ resetBenchOptionsIfNecessary >+ $includeSunSpiderCompileTime = true > when '--longspider' > resetBenchOptionsIfNecessary > $includeLongSpider = true > when '--v8-spider' > resetBenchOptionsIfNecessary > $includeV8 = true >+ when '--v8-spider-compile-time' >+ resetBenchOptionsIfNecessary >+ $includeV8CompileTime = true > when '--kraken' > resetBenchOptionsIfNecessary > $includeKraken = true >@@ -3002,6 +3075,7 @@ begin > } > > SUNSPIDER = BenchmarkSuite.new("SunSpider", :arithmeticMean, 0) >+ SUNSPIDER_COMPILE_TIME = BenchmarkSuite.new("SunSpider-CompileTime", :arithmeticMean, 0) > WARMUP = BenchmarkSuite.new("WARMUP", :arithmeticMean, 0) > ["3d-cube", "3d-morph", "3d-raytrace", "access-binary-trees", > "access-fannkuch", "access-nbody", "access-nsieve", >@@ -3013,6 +3087,7 @@ begin > "string-unpack-code", "string-validate-input"].each { > | name | > SUNSPIDER.add SunSpiderBenchmark.new(name) >+ SUNSPIDER_COMPILE_TIME.add CompileTimeBenchmark.new(name, "#{SUNSPIDER_PATH}/#{name}.js") > WARMUP.addIgnoringPattern SunSpiderBenchmark.new(name) > } > >@@ -3029,10 +3104,12 @@ begin > } > > V8 = BenchmarkSuite.new("V8Spider", :geometricMean, 0) >+ V8_COMPILE_TIME = BenchmarkSuite.new("V8Spider-CompileTime", :geometricMean, 0) > ["crypto", "deltablue", "earley-boyer", "raytrace", > "regexp", "richards", "splay"].each { > | name | > V8.add V8Benchmark.new(name) >+ V8_COMPILE_TIME.add CompileTimeBenchmark.new(name, "#{V8_PATH}/v8-#{name}.js") > } > > OCTANE = BenchmarkSuite.new("Octane", :geometricMean, 1) >@@ -3193,6 +3270,10 @@ begin > $suites << SUNSPIDER > end > >+ if $includeSunSpiderCompileTime and not SUNSPIDER_COMPILE_TIME.empty? >+ $suites << SUNSPIDER_COMPILE_TIME >+ end >+ > if $includeLongSpider and not LONGSPIDER.empty? > $suites << LONGSPIDER > end >@@ -3201,6 +3282,10 @@ begin > $suites << V8 > end > >+ if $includeV8CompileTime and not V8_COMPILE_TIME.empty? >+ $suites << V8_COMPILE_TIME >+ end >+ > if $includeOctane and not OCTANE.empty? > if OCTANE_PATH > $suites << OCTANE
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
saam
:
review+
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 185365
: 339690