diff options
Diffstat (limited to 'Source/JavaScriptCore')
38 files changed, 663 insertions, 199 deletions
diff --git a/Source/JavaScriptCore/API/JSBase.h b/Source/JavaScriptCore/API/JSBase.h index f46a41755..fed54fe23 100644 --- a/Source/JavaScriptCore/API/JSBase.h +++ b/Source/JavaScriptCore/API/JSBase.h @@ -71,7 +71,7 @@ typedef struct OpaqueJSValue* JSObjectRef; #elif defined(__GNUC__) && !defined(__CC_ARM) && !defined(__ARMCC__) #define JS_EXPORT __attribute__((visibility("default"))) #elif defined(WIN32) || defined(_WIN32) || defined(_WIN32_WCE) || defined(__CC_ARM) || defined(__ARMCC__) -#if defined(BUILDING_JavaScriptCore) || defined(STATICALLY_LINKED_WITH_JavaScriptCore) +#if defined(BUILDING_JavaScriptCore) || defined(BUILDING_WTF) #define JS_EXPORT __declspec(dllexport) #else #define JS_EXPORT __declspec(dllimport) diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog index 9304ce075..686fac171 100644 --- a/Source/JavaScriptCore/ChangeLog +++ b/Source/JavaScriptCore/ChangeLog @@ -1,33 +1,223 @@ -2012-06-19 Joel Dillon <joel.dillon@codethink.co.uk> Jocelyn Turcotte <jocelyn.turcotte@nokia.com> +2012-06-26 Geoffrey Garen <ggaren@apple.com> - [Qt][Win] Fix broken QtWebKit5.lib linking - https://bugs.webkit.org/show_bug.cgi?id=88321 + Reduced (but did not eliminate) use of "berzerker GC" + https://bugs.webkit.org/show_bug.cgi?id=89237 + + Reviewed by Gavin Barraclough. + + (PART 2) + + This part turns off "berzerker GC" and turns on incremental shrinking. + + * heap/IncrementalSweeper.cpp: + (JSC::IncrementalSweeper::doSweep): Free or shrink after sweeping to + maintain the behavior we used to get from the occasional berzerker GC, + which would run all finalizers and then free or shrink all blocks + synchronously. + + * heap/MarkedBlock.h: + (JSC::MarkedBlock::needsSweeping): Sweep zapped blocks, too. It's always + safe to sweep a zapped block (that's the point of zapping), and it's + sometimes profitable. For example, consider this case: Block A does some + allocation (transitioning Block A from Marked to FreeListed), then GC + happens (transitioning Block A to Zapped), then all objects in Block A + are free, then the incremental sweeper visits Block A. If we skipped + Zapped blocks, we'd skip Block A, even though it would be profitable to + run its destructors and free its memory. + + * runtime/GCActivityCallback.cpp: + (JSC::DefaultGCActivityCallback::doWork): Don't sweep eagerly; we'll do + this incrementally. + +2012-06-26 Filip Pizlo <fpizlo@apple.com> + + DFG PutByValAlias is too aggressive + https://bugs.webkit.org/show_bug.cgi?id=90026 + <rdar://problem/11751830> + + Reviewed by Gavin Barraclough. + + For CSE on normal arrays, we now treat PutByVal as impure. This does not appear to affect + performance by much. + + For CSE on typed arrays, we fix PutByValAlias by making GetByVal speculate that the access + is within bounds. This also has the effect of making our out-of-bounds handling consistent + with WebCore. + + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::performNodeCSE): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::byValIsPure): + (JSC::DFG::Graph::clobbersWorld): + * dfg/DFGNodeType.h: + (DFG): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileGetByValOnIntTypedArray): + (JSC::DFG::SpeculativeJIT::compileGetByValOnFloatTypedArray): + +2012-06-26 Yong Li <yoli@rim.com> + + [BlackBerry] Add JSC statistics into about:memory + https://bugs.webkit.org/show_bug.cgi?id=89779 + + Reviewed by Rob Buis. + + Fix non-JIT build on BlackBerry broken by r121196. + + * runtime/MemoryStatistics.cpp: + (JSC::globalMemoryStatistics): + +2012-06-25 Filip Pizlo <fpizlo@apple.com> + + DFG::operationNewArray is unnecessarily slow, and may use the wrong array + prototype when inlined + https://bugs.webkit.org/show_bug.cgi?id=89821 + + Reviewed by Geoffrey Garen. + + Fixes all array allocations to use the right structure, and hence the right prototype. Adds + inlining of new Array(...) with a non-zero number of arguments. Optimizes allocations of + empty arrays. + + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::execute): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleConstantInternalFunction): + * dfg/DFGCCallHelpers.h: + (JSC::DFG::CCallHelpers::setupArgumentsWithExecState): + (CCallHelpers): + * dfg/DFGNodeType.h: + (DFG): + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::callOperation): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * runtime/JSArray.h: + (JSC): + (JSC::constructArray): + * runtime/JSGlobalObject.h: + (JSC): + (JSC::constructArray): - Reviewed by NOBODY (OOPS!). +2012-06-26 Filip Pizlo <fpizlo@apple.com> - Also update the Wx build to use the new define. + New fast/js/dfg-store-unexpected-value-into-argument-and-osr-exit.html fails on 32 bit + https://bugs.webkit.org/show_bug.cgi?id=89953 - * API/JSBase.h: - * runtime/JSExportMacros.h: - * wscript: + Reviewed by Zoltan Herczeg. + + DFG 32-bit JIT was confused about the difference between a predicted type and a + proven type. This is easy to get confused about, since a local that is predicted int32 + almost always means that the local must be an int32 since speculations are hoisted to + stores to locals. But that is less likely to be the case for arguments, where there is + an additional least-upper-bounding step: any store to an argument with a weird type + may force the argument to be any type. + + This patch basically duplicates the functionality in DFGSpeculativeJIT64.cpp for + GetLocal: the decision of whether to load a local as an int32 (or as an array, or as + a boolean) is made based on the AbstractValue::m_type, which is a type proof, rather + than the VariableAccessData::prediction(), which is a predicted type. -2012-06-13 Patrick Gansterer <paroga@webkit.org> + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): - [WIN] Remove dependency on pthread from MachineStackMarker - https://bugs.webkit.org/show_bug.cgi?id=68429 +2012-06-25 Filip Pizlo <fpizlo@apple.com> - Reviewed by NOBODY (OOPS!). + JSC should try to make profiling deterministic because otherwise reproducing failures is + nearly impossible + https://bugs.webkit.org/show_bug.cgi?id=89940 - Implement pthread TLS functionality with native windows functions. + Rubber stamped by Gavin Barraclough. + + This rolls out the part of http://trac.webkit.org/changeset/121215 that introduced randomness + into the system. Now, instead of randomizing the tier-up threshold, we always set it to an + artificially low (and statically predetermined!) value. This gives most of the benefit of + threshold randomization without actually making the system behave completely differently on + each invocation. - * heap/MachineStackMarker.cpp: Use the new functions instead of pthread directly. - * heap/MachineStackMarker.h: - * wtf/ThreadSpecific.h: - (WTF::ThreadSpecificKeyCreate): Added wrapper around pthread_key_create. - (WTF::ThreadSpecificKeyDelete): Added wrapper around pthread_key_delete. - (WTF::ThreadSpecificSet): Added wrapper around pthread_setspecific. - (WTF::ThreadSpecificGet): Added wrapper around pthread_getspecific. - * wtf/ThreadSpecificWin.cpp: + * bytecode/ExecutionCounter.cpp: + (JSC::ExecutionCounter::setThreshold): + * runtime/Options.cpp: + (Options): + (JSC::Options::initializeOptions): + * runtime/Options.h: + (Options): + +2012-06-22 Filip Pizlo <fpizlo@apple.com> + + Value profiling should use tier-up threshold randomization to get more coverage + https://bugs.webkit.org/show_bug.cgi?id=89802 + + Reviewed by Gavin Barraclough. + + This patch causes both LLInt and Baseline JIT code to take the OSR slow path several + times before actually doing OSR. If we take the OSR slow path before the execution + count threshold is reached, then we just call CodeBlock::updateAllPredictions() to + compute the current latest least-upper-bound SpecType of all values seen in each + ValueProfile. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::stronglyVisitStrongReferences): + (JSC::CodeBlock::updateAllPredictionsAndCountLiveness): + (JSC): + (JSC::CodeBlock::updateAllPredictions): + (JSC::CodeBlock::shouldOptimizeNow): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::llintExecuteCounter): + (JSC::CodeBlock::jitExecuteCounter): + (CodeBlock): + (JSC::CodeBlock::updateAllPredictions): + * bytecode/ExecutionCounter.cpp: + (JSC::ExecutionCounter::setThreshold): + (JSC::ExecutionCounter::status): + (JSC): + * bytecode/ExecutionCounter.h: + (JSC::ExecutionCounter::count): + (ExecutionCounter): + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::execute): + * dfg/DFGOperations.cpp: + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::jitCompileAndSetHeuristics): + (JSC::LLInt::entryOSR): + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::JSGlobalObject): + (JSC): + * runtime/JSGlobalObject.h: + (JSGlobalObject): + (JSC::JSGlobalObject::weakRandomInteger): + * runtime/Options.cpp: + (Options): + (JSC::Options::initializeOptions): + * runtime/Options.h: + (Options): + * runtime/WeakRandom.h: + (WeakRandom): + (JSC::WeakRandom::seedUnsafe): + +2012-06-25 Yong Li <yoli@rim.com> + + [BlackBerry] Add JSC statistics into about:memory + https://bugs.webkit.org/show_bug.cgi?id=89779 + + Reviewed by Rob Buis. + + Add MemoryStatistics.cpp into build, and fill JITBytes for BlackBerry port. + + * PlatformBlackBerry.cmake: + * runtime/MemoryStatistics.cpp: + (JSC::globalMemoryStatistics): 2012-06-23 Sheriff Bot <webkit.review.bot@gmail.com> diff --git a/Source/JavaScriptCore/JavaScriptCore.pri b/Source/JavaScriptCore/JavaScriptCore.pri index f6580c51f..380bbaf1b 100644 --- a/Source/JavaScriptCore/JavaScriptCore.pri +++ b/Source/JavaScriptCore/JavaScriptCore.pri @@ -34,6 +34,12 @@ INCLUDEPATH += \ win32-* { LIBS += -lwinmm + + win32-g++* { + LIBS += -lpthreadGC2 + } else:win32-msvc* { + LIBS += -lpthreadVC2 + } } wince* { diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def index c48ef49c6..6a8a89372 100755 --- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def +++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def @@ -9,6 +9,7 @@ EXPORTS ??0DropAllLocks@JSLock@JSC@@QAE@W4JSLockBehavior@2@@Z ??0DynamicGlobalObjectScope@JSC@@QAE@AAVJSGlobalData@1@PAVJSGlobalObject@1@@Z ??0InternalFunction@JSC@@IAE@PAVJSGlobalObject@1@PAVStructure@1@@Z + ??0JSGlobalObject@JSC@@IAE@AAVJSGlobalData@1@PAVStructure@1@PBUGlobalObjectMethodTable@1@@Z ??0JSLock@JSC@@QAE@PAVExecState@1@@Z ??0MD5@WTF@@QAE@XZ ??0Mutex@WTF@@QAE@XZ diff --git a/Source/JavaScriptCore/PlatformBlackBerry.cmake b/Source/JavaScriptCore/PlatformBlackBerry.cmake index cc3cfead3..f9352cd4f 100644 --- a/Source/JavaScriptCore/PlatformBlackBerry.cmake +++ b/Source/JavaScriptCore/PlatformBlackBerry.cmake @@ -8,6 +8,7 @@ LIST(REMOVE_ITEM JavaScriptCore_SOURCES LIST(APPEND JavaScriptCore_SOURCES runtime/GCActivityCallbackBlackBerry.cpp + runtime/MemoryStatistics.cpp ) INSTALL(FILES "wtf/Forward.h" DESTINATION usr/include/browser/webkit/wtf) diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp index bcbb51f63..e0a4da71d 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp @@ -2104,26 +2104,7 @@ void CodeBlock::stronglyVisitStrongReferences(SlotVisitor& visitor) } #endif -#if ENABLE(DFG_JIT) - if (hasCodeOrigins()) { - // Make sure that executables that we have inlined don't die. - // FIXME: If they would have otherwise died, we should probably trigger recompilation. - for (size_t i = 0; i < inlineCallFrames().size(); ++i) { - InlineCallFrame& inlineCallFrame = inlineCallFrames()[i]; - visitor.append(&inlineCallFrame.executable); - visitor.append(&inlineCallFrame.callee); - } - } - - m_lazyOperandValueProfiles.computeUpdatedPredictions(Collection); -#endif - -#if ENABLE(VALUE_PROFILER) - for (unsigned profileIndex = 0; profileIndex < numberOfArgumentValueProfiles(); ++profileIndex) - valueProfileForArgument(profileIndex)->computeUpdatedPrediction(Collection); - for (unsigned profileIndex = 0; profileIndex < numberOfValueProfiles(); ++profileIndex) - valueProfile(profileIndex)->computeUpdatedPrediction(Collection); -#endif + updateAllPredictions(Collection); } void CodeBlock::stronglyVisitWeakReferences(SlotVisitor& visitor) @@ -2574,21 +2555,11 @@ bool FunctionCodeBlock::jitCompileImpl(ExecState* exec) #endif #if ENABLE(VALUE_PROFILER) -bool CodeBlock::shouldOptimizeNow() +void CodeBlock::updateAllPredictionsAndCountLiveness( + OperationInProgress operation, unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles) { -#if ENABLE(JIT_VERBOSE_OSR) - dataLog("Considering optimizing %p...\n", this); -#endif - -#if ENABLE(VERBOSE_VALUE_PROFILE) - dumpValueProfiles(); -#endif - - if (m_optimizationDelayCounter >= Options::maximumOptimizationDelay) - return true; - - unsigned numberOfLiveNonArgumentValueProfiles = 0; - unsigned numberOfSamplesInProfiles = 0; // If this divided by ValueProfile::numberOfBuckets equals numberOfValueProfiles() then value profiles are full. + numberOfLiveNonArgumentValueProfiles = 0; + numberOfSamplesInProfiles = 0; // If this divided by ValueProfile::numberOfBuckets equals numberOfValueProfiles() then value profiles are full. for (unsigned i = 0; i < totalNumberOfValueProfiles(); ++i) { ValueProfile* profile = getFromAllValueProfiles(i); unsigned numSamples = profile->totalNumberOfSamples(); @@ -2596,13 +2567,41 @@ bool CodeBlock::shouldOptimizeNow() numSamples = ValueProfile::numberOfBuckets; // We don't want profiles that are extremely hot to be given more weight. numberOfSamplesInProfiles += numSamples; if (profile->m_bytecodeOffset < 0) { - profile->computeUpdatedPrediction(); + profile->computeUpdatedPrediction(operation); continue; } if (profile->numberOfSamples() || profile->m_prediction != SpecNone) numberOfLiveNonArgumentValueProfiles++; - profile->computeUpdatedPrediction(); + profile->computeUpdatedPrediction(operation); } + +#if ENABLE(DFG_JIT) + m_lazyOperandValueProfiles.computeUpdatedPredictions(operation); +#endif +} + +void CodeBlock::updateAllPredictions(OperationInProgress operation) +{ + unsigned ignoredValue1, ignoredValue2; + updateAllPredictionsAndCountLiveness(operation, ignoredValue1, ignoredValue2); +} + +bool CodeBlock::shouldOptimizeNow() +{ +#if ENABLE(JIT_VERBOSE_OSR) + dataLog("Considering optimizing %p...\n", this); +#endif + +#if ENABLE(VERBOSE_VALUE_PROFILE) + dumpValueProfiles(); +#endif + + if (m_optimizationDelayCounter >= Options::maximumOptimizationDelay) + return true; + + unsigned numberOfLiveNonArgumentValueProfiles; + unsigned numberOfSamplesInProfiles; + updateAllPredictionsAndCountLiveness(NoOperation, numberOfLiveNonArgumentValueProfiles, numberOfSamplesInProfiles); #if ENABLE(JIT_VERBOSE_OSR) dataLog("Profile hotness: %lf, %lf\n", (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles(), (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / numberOfValueProfiles()); diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h index b73dcb2b6..4e4fee2b7 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.h +++ b/Source/JavaScriptCore/bytecode/CodeBlock.h @@ -913,9 +913,9 @@ namespace JSC { m_llintExecuteCounter.setNewThreshold(Options::thresholdForJITSoon, this); } - int32_t llintExecuteCounter() const + const ExecutionCounter& llintExecuteCounter() const { - return m_llintExecuteCounter.m_counter; + return m_llintExecuteCounter; } // Functions for controlling when tiered compilation kicks in. This @@ -971,7 +971,7 @@ namespace JSC { static ptrdiff_t offsetOfJITExecutionActiveThreshold() { return OBJECT_OFFSETOF(CodeBlock, m_jitExecuteCounter) + OBJECT_OFFSETOF(ExecutionCounter, m_activeThreshold); } static ptrdiff_t offsetOfJITExecutionTotalCount() { return OBJECT_OFFSETOF(CodeBlock, m_jitExecuteCounter) + OBJECT_OFFSETOF(ExecutionCounter, m_totalCount); } - int32_t jitExecuteCounter() const { return m_jitExecuteCounter.m_counter; } + const ExecutionCounter& jitExecuteCounter() const { return m_jitExecuteCounter; } unsigned optimizationDelayCounter() const { return m_optimizationDelayCounter; } @@ -1100,8 +1100,10 @@ namespace JSC { #if ENABLE(VALUE_PROFILER) bool shouldOptimizeNow(); + void updateAllPredictions(OperationInProgress = NoOperation); #else bool shouldOptimizeNow() { return false; } + void updateAllPredictions(OperationInProgress = NoOperation) { } #endif #if ENABLE(JIT) @@ -1134,6 +1136,9 @@ namespace JSC { #else void tallyFrequentExitSites() { } #endif +#if ENABLE(VALUE_PROFILER) + void updateAllPredictionsAndCountLiveness(OperationInProgress, unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles); +#endif void dump(ExecState*, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator&); diff --git a/Source/JavaScriptCore/bytecode/ExecutionCounter.cpp b/Source/JavaScriptCore/bytecode/ExecutionCounter.cpp index ea335005e..1f2e8260a 100644 --- a/Source/JavaScriptCore/bytecode/ExecutionCounter.cpp +++ b/Source/JavaScriptCore/bytecode/ExecutionCounter.cpp @@ -28,6 +28,7 @@ #include "CodeBlock.h" #include "ExecutableAllocator.h" +#include <wtf/StringExtras.h> namespace JSC { @@ -125,7 +126,7 @@ bool ExecutionCounter::setThreshold(CodeBlock* codeBlock) ASSERT(!hasCrossedThreshold(codeBlock)); // Compute the true total count. - double trueTotalCount = static_cast<double>(m_totalCount) + m_counter; + double trueTotalCount = count(); // Correct the threshold for current memory usage. double threshold = applyMemoryUsageHeuristics(m_activeThreshold, codeBlock); @@ -143,9 +144,14 @@ bool ExecutionCounter::setThreshold(CodeBlock* codeBlock) return true; } - if (threshold > std::numeric_limits<int32_t>::max()) - threshold = std::numeric_limits<int32_t>::max(); - + int32_t maxThreshold; + if (Options::randomizeExecutionCountsBetweenCheckpoints) + maxThreshold = codeBlock->globalObject()->weakRandomInteger() % Options::maximumExecutionCountsBetweenCheckpoints; + else + maxThreshold = Options::maximumExecutionCountsBetweenCheckpoints; + if (threshold > maxThreshold) + threshold = maxThreshold; + m_counter = static_cast<int32_t>(-threshold); m_totalCount = trueTotalCount + threshold; @@ -160,5 +166,12 @@ void ExecutionCounter::reset() m_activeThreshold = 0; } +const char* ExecutionCounter::status() const +{ + static char result[80]; + snprintf(result, sizeof(result), "%lf/%lf, %d", count(), static_cast<double>(m_activeThreshold), m_counter); + return result; +} + } // namespace JSC diff --git a/Source/JavaScriptCore/bytecode/ExecutionCounter.h b/Source/JavaScriptCore/bytecode/ExecutionCounter.h index d2ffbb649..1c0d23f0f 100644 --- a/Source/JavaScriptCore/bytecode/ExecutionCounter.h +++ b/Source/JavaScriptCore/bytecode/ExecutionCounter.h @@ -38,6 +38,8 @@ public: bool checkIfThresholdCrossedAndSet(CodeBlock*); void setNewThreshold(int32_t threshold, CodeBlock*); void deferIndefinitely(); + double count() const { return static_cast<double>(m_totalCount) + m_counter; } + const char* status() const; static double applyMemoryUsageHeuristics(int32_t value, CodeBlock*); static int32_t applyMemoryUsageHeuristicsAndConvertToInt(int32_t value, CodeBlock*); diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp index 94e96853d..c2d49f7ee 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp +++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp @@ -1141,13 +1141,19 @@ bool AbstractState::execute(unsigned indexInBlock) case NewArray: case NewArrayBuffer: node.setCanExit(false); - forNode(nodeIndex).set(m_codeBlock->globalObject()->arrayStructure()); + forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructure()); + m_haveStructures = true; + break; + + case NewArrayWithSize: + speculateInt32Unary(node); + forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructure()); m_haveStructures = true; break; case NewRegexp: node.setCanExit(false); - forNode(nodeIndex).set(m_codeBlock->globalObject()->regExpStructure()); + forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->regExpStructure()); m_haveStructures = true; break; @@ -1392,7 +1398,7 @@ bool AbstractState::execute(unsigned indexInBlock) case StructureTransitionWatchpoint: { // FIXME: Turn CheckStructure into StructureTransitionWatchpoint when possible! AbstractValue& value = forNode(node.child1()); - ASSERT(isCellSpeculation(value.m_type)); + ASSERT(value.isClear() || isCellSpeculation(value.m_type)); // Value could be clear if we've proven must-exit due to a speculation statically known to be bad. value.filter(node.structure()); node.setCanExit(true); break; diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp index 75611972e..cdb0b639a 100644 --- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp +++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp @@ -1606,15 +1606,19 @@ bool ByteCodeParser::handleConstantInternalFunction( // we know about is small enough, that having just a linear cascade of if statements // is good enough. - UNUSED_PARAM(registerOffset); // Remove this once we do more things to the arguments. UNUSED_PARAM(prediction); // Remove this once we do more things. UNUSED_PARAM(kind); // Remove this once we do more things. if (function->classInfo() == &ArrayConstructor::s_info) { - // We could handle this but don't for now. - if (argumentCountIncludingThis != 1) - return false; + if (argumentCountIncludingThis == 2) { + setIntrinsicResult( + usesResult, resultOperand, + addToGraph(NewArrayWithSize, get(registerOffset + argumentToOperand(1)))); + return true; + } + for (int i = 1; i < argumentCountIncludingThis; ++i) + addVarArgChild(get(registerOffset + argumentToOperand(i))); setIntrinsicResult( usesResult, resultOperand, addToGraph(Node::VarArg, NewArray, OpInfo(0), OpInfo(0))); diff --git a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h index 4cacd45c1..b60290870 100644 --- a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h +++ b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h @@ -160,6 +160,14 @@ public: addCallArgument(arg2); } + ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, GPRReg arg2) + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + addCallArgument(arg1); + addCallArgument(arg2); + } + ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImm32 arg2) { resetCallArguments(); @@ -203,6 +211,15 @@ public: addCallArgument(arg3); } + ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, TrustedImmPtr arg2, TrustedImmPtr arg3) + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + addCallArgument(arg1); + addCallArgument(arg2); + addCallArgument(arg3); + } + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2, TrustedImmPtr arg3) { resetCallArguments(); @@ -597,6 +614,14 @@ public: move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); } + ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, TrustedImmPtr arg2, TrustedImmPtr arg3) + { + move(arg1, GPRInfo::argumentGPR1); + move(arg2, GPRInfo::argumentGPR2); + move(arg3, GPRInfo::argumentGPR3); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + } + ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImm32 arg2, TrustedImm32 arg3) { move(arg1, GPRInfo::argumentGPR1); diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp index a362e6e97..be0012f56 100644 --- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp @@ -1080,10 +1080,15 @@ private: break; case PutByVal: - if (m_graph.byValIsPure(node) - && !m_graph[node.child1()].shouldSpeculateArguments() - && getByValLoadElimination(node.child1().index(), node.child2().index()) != NoNode) + if (isActionableMutableArraySpeculation(m_graph[node.child1()].prediction()) + && m_graph[node.child2()].shouldSpeculateInteger() + && !m_graph[node.child1()].shouldSpeculateArguments()) { + NodeIndex nodeIndex = getByValLoadElimination( + node.child1().index(), node.child2().index()); + if (nodeIndex == NoNode) + break; node.setOp(PutByValAlias); + } break; case CheckStructure: diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h index 9e4a28fc3..a9080d117 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.h +++ b/Source/JavaScriptCore/dfg/DFGGraph.h @@ -463,10 +463,31 @@ public: bool byValIsPure(Node& node) { - return at(node.child2()).shouldSpeculateInteger() - && ((node.op() == PutByVal || node.op() == PutByValAlias) - ? isActionableMutableArraySpeculation(at(node.child1()).prediction()) - : isActionableArraySpeculation(at(node.child1()).prediction())); + if (!at(node.child2()).shouldSpeculateInteger()) + return false; + SpeculatedType prediction = at(node.child1()).prediction(); + switch (node.op()) { + case PutByVal: + if (!isActionableMutableArraySpeculation(prediction)) + return false; + if (isArraySpeculation(prediction)) + return false; + return true; + + case PutByValAlias: + if (!isActionableMutableArraySpeculation(prediction)) + return false; + return true; + + case GetByVal: + if (!isActionableArraySpeculation(prediction)) + return false; + return true; + + default: + ASSERT_NOT_REACHED(); + return false; + } } bool clobbersWorld(Node& node) @@ -484,6 +505,8 @@ public: case CompareEq: return !isPredictedNumerical(node); case GetByVal: + case PutByVal: + case PutByValAlias: return !byValIsPure(node); default: ASSERT_NOT_REACHED(); diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h index 4671f6b6c..8c2f96222 100644 --- a/Source/JavaScriptCore/dfg/DFGNodeType.h +++ b/Source/JavaScriptCore/dfg/DFGNodeType.h @@ -111,8 +111,8 @@ namespace JSC { namespace DFG { /* Since a put to 'length' may invalidate optimizations here, */\ /* this must be the directly subsequent property put. */\ macro(GetByVal, NodeResultJS | NodeMustGenerate | NodeMightClobber) \ - macro(PutByVal, NodeMustGenerate | NodeClobbersWorld) \ - macro(PutByValAlias, NodeMustGenerate | NodeClobbersWorld) \ + macro(PutByVal, NodeMustGenerate | NodeMightClobber) \ + macro(PutByValAlias, NodeMustGenerate | NodeMightClobber) \ macro(GetById, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \ macro(GetByIdFlush, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \ macro(PutById, NodeMustGenerate | NodeClobbersWorld) \ @@ -184,6 +184,7 @@ namespace JSC { namespace DFG { /* Allocations. */\ macro(NewObject, NodeResultJS) \ macro(NewArray, NodeResultJS | NodeHasVarArgs) \ + macro(NewArrayWithSize, NodeResultJS) \ macro(NewArrayBuffer, NodeResultJS) \ macro(NewRegexp, NodeResultJS) \ \ diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp index b056a3c6d..11362f432 100644 --- a/Source/JavaScriptCore/dfg/DFGOperations.cpp +++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp @@ -1005,12 +1005,22 @@ EncodedJSValue DFG_OPERATION operationStrCat(ExecState* exec, void* buffer, size return JSValue::encode(jsString(exec, static_cast<Register*>(buffer), size)); } -EncodedJSValue DFG_OPERATION operationNewArray(ExecState* exec, void* buffer, size_t size) +EncodedJSValue DFG_OPERATION operationNewArray(ExecState* exec, Structure* arrayStructure, void* buffer, size_t size) { JSGlobalData* globalData = &exec->globalData(); NativeCallFrameTracer tracer(globalData, exec); - return JSValue::encode(constructArray(exec, static_cast<JSValue*>(buffer), size)); + return JSValue::encode(constructArray(exec, arrayStructure, static_cast<JSValue*>(buffer), size)); +} + +EncodedJSValue DFG_OPERATION operationNewEmptyArray(ExecState* exec, Structure* arrayStructure) +{ + return JSValue::encode(JSArray::create(exec->globalData(), arrayStructure)); +} + +EncodedJSValue DFG_OPERATION operationNewArrayWithSize(ExecState* exec, Structure* arrayStructure, int32_t size) +{ + return JSValue::encode(JSArray::create(exec->globalData(), arrayStructure, size)); } EncodedJSValue DFG_OPERATION operationNewArrayBuffer(ExecState* exec, size_t start, size_t size) @@ -1238,12 +1248,12 @@ void DFG_OPERATION debugOperationPrintSpeculationFailure(ExecState* exec, void* SpeculationFailureDebugInfo* debugInfo = static_cast<SpeculationFailureDebugInfo*>(debugInfoRaw); CodeBlock* codeBlock = debugInfo->codeBlock; CodeBlock* alternative = codeBlock->alternative(); - dataLog("Speculation failure in %p at @%u with executeCounter = %d, " + dataLog("Speculation failure in %p at @%u with executeCounter = %s, " "reoptimizationRetryCounter = %u, optimizationDelayCounter = %u, " "success/fail %u/(%u+%u)\n", codeBlock, debugInfo->nodeIndex, - alternative ? alternative->jitExecuteCounter() : 0, + alternative ? alternative->jitExecuteCounter().status() : 0, alternative ? alternative->reoptimizationRetryCounter() : 0, alternative ? alternative->optimizationDelayCounter() : 0, codeBlock->speculativeSuccessCounter(), diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h index 7477ab2fc..3c85ee761 100644 --- a/Source/JavaScriptCore/dfg/DFGOperations.h +++ b/Source/JavaScriptCore/dfg/DFGOperations.h @@ -76,6 +76,9 @@ typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EP)(ExecState*, void*); typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EPP)(ExecState*, void*, void*); typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EPS)(ExecState*, void*, size_t); typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ESS)(ExecState*, size_t, size_t); +typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ESt)(ExecState*, Structure*); +typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EStI)(ExecState*, Structure*, int32_t); +typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EStPS)(ExecState*, Structure*, void*, size_t); typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EZ)(ExecState*, int32_t); typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EZIcfZ)(ExecState*, int32_t, InlineCallFrame*, int32_t); typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EZZ)(ExecState*, int32_t, int32_t); @@ -124,8 +127,10 @@ EncodedJSValue DFG_OPERATION operationResolveBaseStrictPut(ExecState*, Identifie EncodedJSValue DFG_OPERATION operationResolveGlobal(ExecState*, GlobalResolveInfo*, JSGlobalObject*, Identifier*) WTF_INTERNAL; EncodedJSValue DFG_OPERATION operationToPrimitive(ExecState*, EncodedJSValue) WTF_INTERNAL; EncodedJSValue DFG_OPERATION operationStrCat(ExecState*, void*, size_t) WTF_INTERNAL; -EncodedJSValue DFG_OPERATION operationNewArray(ExecState*, void*, size_t) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationNewArray(ExecState*, Structure*, void*, size_t) WTF_INTERNAL; EncodedJSValue DFG_OPERATION operationNewArrayBuffer(ExecState*, size_t, size_t) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationNewEmptyArray(ExecState*, Structure*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationNewArrayWithSize(ExecState*, Structure*, int32_t) WTF_INTERNAL; EncodedJSValue DFG_OPERATION operationNewRegexp(ExecState*, void*) WTF_INTERNAL; void DFG_OPERATION operationPutByValStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL; void DFG_OPERATION operationPutByValNonStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL; diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp index bcb79a96a..0bd81ec44 100644 --- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp @@ -535,6 +535,12 @@ private: break; } + case NewArrayWithSize: { + changed |= setPrediction(SpecArray); + changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt); + break; + } + case NewArrayBuffer: { changed |= setPrediction(SpecArray); break; diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp index d9a79f13a..0c0f3260f 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp @@ -986,13 +986,8 @@ void SpeculativeJIT::compile(BasicBlock& block) m_jit.jitAssertHasValidCallFrame(); ASSERT(m_arguments.size() == block.variablesAtHead.numberOfArguments()); - for (size_t i = 0; i < m_arguments.size(); ++i) { - NodeIndex nodeIndex = block.variablesAtHead.argument(i); - if (nodeIndex == NoNode || m_jit.codeBlock()->argumentIsCaptured(i)) - m_arguments[i] = ValueSource(ValueInRegisterFile); - else - m_arguments[i] = ValueSource::forSpeculation(at(nodeIndex).variableAccessData()->prediction()); - } + for (size_t i = 0; i < m_arguments.size(); ++i) + m_arguments[i] = ValueSource(ValueInRegisterFile); m_state.reset(); m_state.beginBasicBlock(&block); @@ -2005,10 +2000,10 @@ void SpeculativeJIT::compileGetByValOnIntTypedArray(const TypedArrayDescriptor& return; } - MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(baseReg, descriptor.m_lengthOffset)); - m_jit.xorPtr(resultReg, resultReg); - MacroAssembler::Jump outOfBounds = m_jit.jump(); - inBounds.link(&m_jit); + speculationCheck( + Uncountable, JSValueRegs(), NoNode, + m_jit.branch32( + MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, descriptor.m_lengthOffset))); switch (elementSize) { case 1: if (signedness == SignedTypedArray) @@ -2028,7 +2023,6 @@ void SpeculativeJIT::compileGetByValOnIntTypedArray(const TypedArrayDescriptor& default: ASSERT_NOT_REACHED(); } - outOfBounds.link(&m_jit); if (elementSize < 4 || signedness == SignedTypedArray) { integerResult(resultReg, m_compileIndex); return; @@ -2167,11 +2161,10 @@ void SpeculativeJIT::compileGetByValOnFloatTypedArray(const TypedArrayDescriptor FPRTemporary result(this); FPRReg resultReg = result.fpr(); ASSERT(speculationRequirements != NoTypedArraySpecCheck); - MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(baseReg, descriptor.m_lengthOffset)); - static const double zero = 0; - m_jit.loadDouble(&zero, resultReg); - MacroAssembler::Jump outOfBounds = m_jit.jump(); - inBounds.link(&m_jit); + speculationCheck( + Uncountable, JSValueRegs(), NoNode, + m_jit.branch32( + MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, descriptor.m_lengthOffset))); switch (elementSize) { case 4: m_jit.loadFloat(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesFour), resultReg); @@ -2188,7 +2181,6 @@ void SpeculativeJIT::compileGetByValOnFloatTypedArray(const TypedArrayDescriptor default: ASSERT_NOT_REACHED(); } - outOfBounds.link(&m_jit); doubleResult(resultReg, m_compileIndex); } diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h index 6c6948b90..67a22b767 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h @@ -1244,6 +1244,21 @@ public: m_jit.setupArgumentsWithExecState(arg1); return appendCallWithExceptionCheckSetResult(operation, result); } + JITCompiler::Call callOperation(J_DFGOperation_ESt operation, GPRReg result, Structure* structure) + { + m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure)); + return appendCallWithExceptionCheckSetResult(operation, result); + } + JITCompiler::Call callOperation(J_DFGOperation_EStI operation, GPRReg result, Structure* structure, GPRReg arg2) + { + m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure), arg2); + return appendCallWithExceptionCheckSetResult(operation, result); + } + JITCompiler::Call callOperation(J_DFGOperation_EStPS operation, GPRReg result, Structure* structure, void* pointer, size_t size) + { + m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure), TrustedImmPtr(pointer), TrustedImmPtr(size)); + return appendCallWithExceptionCheckSetResult(operation, result); + } JITCompiler::Call callOperation(J_DFGOperation_EPS operation, GPRReg result, void* pointer, size_t size) { m_jit.setupArgumentsWithExecState(TrustedImmPtr(pointer), TrustedImmPtr(size)); @@ -1502,6 +1517,21 @@ public: m_jit.setupArgumentsWithExecState(arg1); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } + JITCompiler::Call callOperation(J_DFGOperation_ESt operation, GPRReg resultTag, GPRReg resultPayload, Structure* structure) + { + m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure)); + return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); + } + JITCompiler::Call callOperation(J_DFGOperation_EStI operation, GPRReg resultTag, GPRReg resultPayload, Structure* structure, GPRReg arg2) + { + m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure), arg2); + return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); + } + JITCompiler::Call callOperation(J_DFGOperation_EStPS operation, GPRReg resultTag, GPRReg resultPayload, Structure* structure, void* pointer, size_t size) + { + m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure), TrustedImmPtr(pointer), TrustedImmPtr(size)); + return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); + } JITCompiler::Call callOperation(J_DFGOperation_EPS operation, GPRReg resultTag, GPRReg resultPayload, void* pointer, size_t size) { m_jit.setupArgumentsWithExecState(TrustedImmPtr(pointer), TrustedImmPtr(size)); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp index 21d94e9e8..05609baa8 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp @@ -1891,7 +1891,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isInt32Speculation(prediction)) { + if (isInt32Speculation(value.m_type)) { GPRTemporary result(this); m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr()); @@ -1903,7 +1903,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isArraySpeculation(prediction)) { + if (isArraySpeculation(value.m_type)) { GPRTemporary result(this); m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr()); @@ -1915,7 +1915,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isBooleanSpeculation(prediction)) { + if (isBooleanSpeculation(value.m_type)) { GPRTemporary result(this); m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr()); @@ -2975,25 +2975,60 @@ void SpeculativeJIT::compile(Node& node) break; } - case StrCat: - case NewArray: { - // We really don't want to grow the register file just to do a StrCat or NewArray. - // Say we have 50 functions on the stack that all have a StrCat in them that has - // upwards of 10 operands. In the DFG this would mean that each one gets - // some random virtual register, and then to do the StrCat we'd need a second - // span of 10 operands just to have somewhere to copy the 10 operands to, where - // they'd be contiguous and we could easily tell the C code how to find them. - // Ugly! So instead we use the scratchBuffer infrastructure in JSGlobalData. That - // way, those 50 functions will share the same scratchBuffer for offloading their - // StrCat operands. It's about as good as we can do, unless we start doing - // virtual register coalescing to ensure that operands to StrCat get spilled - // in exactly the place where StrCat wants them, or else have the StrCat - // refer to those operands' SetLocal instructions to force them to spill in - // the right place. Basically, any way you cut it, the current approach - // probably has the best balance of performance and sensibility in the sense - // that it does not increase the complexity of the DFG JIT just to make StrCat - // fast and pretty. + case StrCat: { + size_t scratchSize = sizeof(EncodedJSValue) * node.numChildren(); + ScratchBuffer* scratchBuffer = m_jit.globalData()->scratchBufferForSize(scratchSize); + EncodedJSValue* buffer = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0; + + for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++operandIdx) { + JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]); + GPRReg opTagGPR = operand.tagGPR(); + GPRReg opPayloadGPR = operand.payloadGPR(); + operand.use(); + + m_jit.store32(opTagGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)); + m_jit.store32(opPayloadGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)); + } + + flushRegisters(); + if (scratchSize) { + GPRTemporary scratch(this); + + // Tell GC mark phase how much of the scratch buffer is active during call. + m_jit.move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratch.gpr()); + m_jit.storePtr(TrustedImmPtr(scratchSize), scratch.gpr()); + } + + GPRResult resultPayload(this); + GPRResult2 resultTag(this); + + callOperation(operationStrCat, resultTag.gpr(), resultPayload.gpr(), static_cast<void *>(buffer), node.numChildren()); + + if (scratchSize) { + GPRTemporary scratch(this); + + m_jit.move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratch.gpr()); + m_jit.storePtr(TrustedImmPtr(0), scratch.gpr()); + } + + // FIXME: make the callOperation above explicitly return a cell result, or jitAssert the tag is a cell tag. + cellResult(resultPayload.gpr(), m_compileIndex, UseChildrenCalledExplicitly); + break; + } + + case NewArray: { + if (!node.numChildren()) { + flushRegisters(); + GPRResult result(this); + GPRResult2 resultTagIgnored(this); + callOperation( + operationNewEmptyArray, resultTagIgnored.gpr(), result.gpr(), + m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure()); + cellResult(result.gpr(), m_compileIndex); + break; + } + size_t scratchSize = sizeof(EncodedJSValue) * node.numChildren(); ScratchBuffer* scratchBuffer = m_jit.globalData()->scratchBufferForSize(scratchSize); EncodedJSValue* buffer = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0; @@ -3021,7 +3056,10 @@ void SpeculativeJIT::compile(Node& node) GPRResult resultPayload(this); GPRResult2 resultTag(this); - callOperation(op == StrCat ? operationStrCat : operationNewArray, resultTag.gpr(), resultPayload.gpr(), static_cast<void *>(buffer), node.numChildren()); + callOperation( + operationNewArray, resultTag.gpr(), resultPayload.gpr(), + m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure(), + static_cast<void *>(buffer), node.numChildren()); if (scratchSize) { GPRTemporary scratch(this); @@ -3035,6 +3073,19 @@ void SpeculativeJIT::compile(Node& node) break; } + case NewArrayWithSize: { + SpeculateStrictInt32Operand size(this, node.child1()); + GPRReg sizeGPR = size.gpr(); + flushRegisters(); + GPRResult result(this); + GPRResult2 resultTagIgnored(this); + callOperation( + operationNewArrayWithSize, resultTagIgnored.gpr(), result.gpr(), + m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure(), sizeGPR); + cellResult(result.gpr(), m_compileIndex); + break; + } + case NewArrayBuffer: { flushRegisters(); GPRResult resultPayload(this); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp index a6c283584..215f8013d 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp @@ -3035,25 +3035,68 @@ void SpeculativeJIT::compile(Node& node) break; } - case StrCat: case NewArray: { - // We really don't want to grow the register file just to do a StrCat or NewArray. - // Say we have 50 functions on the stack that all have a StrCat in them that has - // upwards of 10 operands. In the DFG this would mean that each one gets - // some random virtual register, and then to do the StrCat we'd need a second - // span of 10 operands just to have somewhere to copy the 10 operands to, where - // they'd be contiguous and we could easily tell the C code how to find them. - // Ugly! So instead we use the scratchBuffer infrastructure in JSGlobalData. That - // way, those 50 functions will share the same scratchBuffer for offloading their - // StrCat operands. It's about as good as we can do, unless we start doing - // virtual register coalescing to ensure that operands to StrCat get spilled - // in exactly the place where StrCat wants them, or else have the StrCat - // refer to those operands' SetLocal instructions to force them to spill in - // the right place. Basically, any way you cut it, the current approach - // probably has the best balance of performance and sensibility in the sense - // that it does not increase the complexity of the DFG JIT just to make StrCat - // fast and pretty. + if (!node.numChildren()) { + flushRegisters(); + GPRResult result(this); + callOperation( + operationNewEmptyArray, result.gpr(), + m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure()); + cellResult(result.gpr(), m_compileIndex); + break; + } + + size_t scratchSize = sizeof(EncodedJSValue) * node.numChildren(); + ScratchBuffer* scratchBuffer = m_jit.globalData()->scratchBufferForSize(scratchSize); + EncodedJSValue* buffer = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0; + + for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++operandIdx) { + JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]); + GPRReg opGPR = operand.gpr(); + operand.use(); + + m_jit.storePtr(opGPR, buffer + operandIdx); + } + + flushRegisters(); + + if (scratchSize) { + GPRTemporary scratch(this); + // Tell GC mark phase how much of the scratch buffer is active during call. + m_jit.move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratch.gpr()); + m_jit.storePtr(TrustedImmPtr(scratchSize), scratch.gpr()); + } + + GPRResult result(this); + + callOperation( + operationNewArray, result.gpr(), + m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure(), + static_cast<void*>(buffer), node.numChildren()); + + if (scratchSize) { + GPRTemporary scratch(this); + + m_jit.move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratch.gpr()); + m_jit.storePtr(TrustedImmPtr(0), scratch.gpr()); + } + + cellResult(result.gpr(), m_compileIndex, UseChildrenCalledExplicitly); + break; + } + + case NewArrayWithSize: { + SpeculateStrictInt32Operand size(this, node.child1()); + GPRReg sizeGPR = size.gpr(); + flushRegisters(); + GPRResult result(this); + callOperation(operationNewArrayWithSize, result.gpr(), m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure(), sizeGPR); + cellResult(result.gpr(), m_compileIndex); + break; + } + + case StrCat: { size_t scratchSize = sizeof(EncodedJSValue) * node.numChildren(); ScratchBuffer* scratchBuffer = m_jit.globalData()->scratchBufferForSize(scratchSize); EncodedJSValue* buffer = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0; @@ -3078,7 +3121,7 @@ void SpeculativeJIT::compile(Node& node) GPRResult result(this); - callOperation(op == StrCat ? operationStrCat : operationNewArray, result.gpr(), static_cast<void *>(buffer), node.numChildren()); + callOperation(operationStrCat, result.gpr(), static_cast<void *>(buffer), node.numChildren()); if (scratchSize) { GPRTemporary scratch(this); diff --git a/Source/JavaScriptCore/heap/IncrementalSweeper.cpp b/Source/JavaScriptCore/heap/IncrementalSweeper.cpp index 165bfeaff..848377346 100644 --- a/Source/JavaScriptCore/heap/IncrementalSweeper.cpp +++ b/Source/JavaScriptCore/heap/IncrementalSweeper.cpp @@ -78,6 +78,7 @@ void IncrementalSweeper::doSweep(double sweepBeginTime) continue; block->sweep(); + m_globalData->heap.objectSpace().freeOrShrinkBlock(block); CFTimeInterval elapsedTime = WTF::monotonicallyIncreasingTime() - sweepBeginTime; if (elapsedTime < sweepTimeSlice) diff --git a/Source/JavaScriptCore/heap/MachineStackMarker.cpp b/Source/JavaScriptCore/heap/MachineStackMarker.cpp index 8e0c57b6a..7eb57479b 100644 --- a/Source/JavaScriptCore/heap/MachineStackMarker.cpp +++ b/Source/JavaScriptCore/heap/MachineStackMarker.cpp @@ -141,8 +141,10 @@ MachineThreads::MachineThreads(Heap* heap) MachineThreads::~MachineThreads() { - if (m_threadSpecific) - ThreadSpecificKeyDelete(m_threadSpecific); + if (m_threadSpecific) { + int error = pthread_key_delete(m_threadSpecific); + ASSERT_UNUSED(error, !error); + } MutexLocker registeredThreadsLock(m_registeredThreadsMutex); for (Thread* t = m_registeredThreads; t;) { @@ -179,17 +181,19 @@ void MachineThreads::makeUsableFromMultipleThreads() if (m_threadSpecific) return; - ThreadSpecificKeyCreate(&m_threadSpecific, removeThread); + int error = pthread_key_create(&m_threadSpecific, removeThread); + if (error) + CRASH(); } void MachineThreads::addCurrentThread() { ASSERT(!m_heap->globalData()->exclusiveThread || m_heap->globalData()->exclusiveThread == currentThread()); - if (!m_threadSpecific || ThreadSpecificGet(m_threadSpecific)) + if (!m_threadSpecific || pthread_getspecific(m_threadSpecific)) return; - ThreadSpecificSet(m_threadSpecific, this); + pthread_setspecific(m_threadSpecific, this); Thread* thread = new Thread(getCurrentPlatformThread(), wtfThreadData().stack().origin()); MutexLocker lock(m_registeredThreadsMutex); diff --git a/Source/JavaScriptCore/heap/MachineStackMarker.h b/Source/JavaScriptCore/heap/MachineStackMarker.h index 2209f97e9..0f5a4c3aa 100644 --- a/Source/JavaScriptCore/heap/MachineStackMarker.h +++ b/Source/JavaScriptCore/heap/MachineStackMarker.h @@ -22,8 +22,8 @@ #ifndef MachineThreads_h #define MachineThreads_h +#include <pthread.h> #include <wtf/Noncopyable.h> -#include <wtf/ThreadSpecific.h> #include <wtf/ThreadingPrimitives.h> namespace JSC { @@ -55,7 +55,7 @@ namespace JSC { Heap* m_heap; Mutex m_registeredThreadsMutex; Thread* m_registeredThreads; - WTF::ThreadSpecificKey m_threadSpecific; + pthread_key_t m_threadSpecific; }; } // namespace JSC diff --git a/Source/JavaScriptCore/heap/MarkedBlock.h b/Source/JavaScriptCore/heap/MarkedBlock.h index eb1cb681b..c3c43752b 100644 --- a/Source/JavaScriptCore/heap/MarkedBlock.h +++ b/Source/JavaScriptCore/heap/MarkedBlock.h @@ -408,7 +408,7 @@ namespace JSC { inline bool MarkedBlock::needsSweeping() { - return m_state == Marked; + return m_state == Marked || m_state == Zapped; } #if ENABLE(GGC) diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp index b0ff4a0c7..6b8082886 100644 --- a/Source/JavaScriptCore/jit/JITStubs.cpp +++ b/Source/JavaScriptCore/jit/JITStubs.cpp @@ -1928,11 +1928,13 @@ DEFINE_STUB_FUNCTION(void, optimize) unsigned bytecodeIndex = stackFrame.args[0].int32(); #if ENABLE(JIT_VERBOSE_OSR) - dataLog("%p: Entered optimize with bytecodeIndex = %u, executeCounter = %d, reoptimizationRetryCounter = %u, optimizationDelayCounter = %u\n", codeBlock, bytecodeIndex, codeBlock->jitExecuteCounter(), codeBlock->reoptimizationRetryCounter(), codeBlock->optimizationDelayCounter()); + dataLog("%p: Entered optimize with bytecodeIndex = %u, executeCounter = %s, reoptimizationRetryCounter = %u, optimizationDelayCounter = %u\n", codeBlock, bytecodeIndex, codeBlock->jitExecuteCounter().status(), codeBlock->reoptimizationRetryCounter(), codeBlock->optimizationDelayCounter()); #endif - if (!codeBlock->checkIfOptimizationThresholdReached()) + if (!codeBlock->checkIfOptimizationThresholdReached()) { + codeBlock->updateAllPredictions(); return; + } if (codeBlock->hasOptimizedReplacement()) { #if ENABLE(JIT_VERBOSE_OSR) diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp index ca3eb1eb0..a7698be37 100644 --- a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp +++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp @@ -264,6 +264,8 @@ inline bool shouldJIT(ExecState* exec) // Returns true if we should try to OSR. inline bool jitCompileAndSetHeuristics(CodeBlock* codeBlock, ExecState* exec) { + codeBlock->updateAllPredictions(); + if (!codeBlock->checkIfJITThresholdReached()) { #if ENABLE(JIT_VERBOSE_OSR) dataLog(" JIT threshold should be lifted.\n"); @@ -300,7 +302,8 @@ enum EntryKind { Prologue, ArityCheck }; static SlowPathReturnType entryOSR(ExecState* exec, Instruction* pc, CodeBlock* codeBlock, const char *name, EntryKind kind) { #if ENABLE(JIT_VERBOSE_OSR) - dataLog("%p: Entered %s with executeCounter = %d\n", codeBlock, name, codeBlock->llintExecuteCounter()); + dataLog("%p: Entered %s with executeCounter = %s\n", codeBlock, name, + codeBlock->llintExecuteCounter().status()); #endif if (!shouldJIT(exec)) { @@ -346,7 +349,8 @@ LLINT_SLOW_PATH_DECL(loop_osr) CodeBlock* codeBlock = exec->codeBlock(); #if ENABLE(JIT_VERBOSE_OSR) - dataLog("%p: Entered loop_osr with executeCounter = %d\n", codeBlock, codeBlock->llintExecuteCounter()); + dataLog("%p: Entered loop_osr with executeCounter = %s\n", codeBlock, + codeBlock->llintExecuteCounter().status()); #endif if (!shouldJIT(exec)) { @@ -376,7 +380,8 @@ LLINT_SLOW_PATH_DECL(replace) CodeBlock* codeBlock = exec->codeBlock(); #if ENABLE(JIT_VERBOSE_OSR) - dataLog("%p: Entered replace with executeCounter = %d\n", codeBlock, codeBlock->llintExecuteCounter()); + dataLog("%p: Entered replace with executeCounter = %s\n", codeBlock, + codeBlock->llintExecuteCounter().status()); #endif if (shouldJIT(exec)) diff --git a/Source/JavaScriptCore/runtime/GCActivityCallback.cpp b/Source/JavaScriptCore/runtime/GCActivityCallback.cpp index 794d1545e..c2fca8c01 100644 --- a/Source/JavaScriptCore/runtime/GCActivityCallback.cpp +++ b/Source/JavaScriptCore/runtime/GCActivityCallback.cpp @@ -75,7 +75,7 @@ void DefaultGCActivityCallback::doWork() return; } #endif - heap->collectAllGarbage(); + heap->collect(Heap::DoNotSweep); } void DefaultGCActivityCallback::scheduleTimer(double newDelay) diff --git a/Source/JavaScriptCore/runtime/JSArray.h b/Source/JavaScriptCore/runtime/JSArray.h index c1a3a632b..52c591324 100644 --- a/Source/JavaScriptCore/runtime/JSArray.h +++ b/Source/JavaScriptCore/runtime/JSArray.h @@ -380,7 +380,42 @@ namespace JSC { return size; } + + inline JSArray* constructArray(ExecState* exec, Structure* arrayStructure, const ArgList& values) + { + JSGlobalData& globalData = exec->globalData(); + unsigned length = values.size(); + JSArray* array = JSArray::tryCreateUninitialized(globalData, arrayStructure, length); + + // FIXME: we should probably throw an out of memory error here, but + // when making this change we should check that all clients of this + // function will correctly handle an exception being thrown from here. + if (!array) + CRASH(); + + for (unsigned i = 0; i < length; ++i) + array->initializeIndex(globalData, i, values.at(i)); + array->completeInitialization(length); + return array; + } - } // namespace JSC + inline JSArray* constructArray(ExecState* exec, Structure* arrayStructure, const JSValue* values, unsigned length) + { + JSGlobalData& globalData = exec->globalData(); + JSArray* array = JSArray::tryCreateUninitialized(globalData, arrayStructure, length); + + // FIXME: we should probably throw an out of memory error here, but + // when making this change we should check that all clients of this + // function will correctly handle an exception being thrown from here. + if (!array) + CRASH(); + + for (unsigned i = 0; i < length; ++i) + array->initializeIndex(globalData, i, values[i]); + array->completeInitialization(length); + return array; + } + +} // namespace JSC #endif // JSArray_h diff --git a/Source/JavaScriptCore/runtime/JSExportMacros.h b/Source/JavaScriptCore/runtime/JSExportMacros.h index 19e2c286f..884805f86 100644 --- a/Source/JavaScriptCore/runtime/JSExportMacros.h +++ b/Source/JavaScriptCore/runtime/JSExportMacros.h @@ -36,7 +36,7 @@ // See note in wtf/Platform.h for more info on EXPORT_MACROS. #if USE(EXPORT_MACROS) -#if defined(BUILDING_JavaScriptCore) || defined(STATICALLY_LINKED_WITH_JavaScriptCore) +#if defined(BUILDING_JavaScriptCore) #define JS_EXPORT_PRIVATE WTF_EXPORT #else #define JS_EXPORT_PRIVATE WTF_IMPORT @@ -50,7 +50,7 @@ #if !PLATFORM(CHROMIUM) && OS(WINDOWS) && !defined(BUILDING_WX__) && !COMPILER(GCC) -#if defined(BUILDING_JavaScriptCore) || defined(STATICALLY_LINKED_WITH_JavaScriptCore) +#if defined(BUILDING_JavaScriptCore) #define JS_EXPORTDATA __declspec(dllexport) #else #define JS_EXPORTDATA __declspec(dllimport) diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp index d38570dfb..d19db4fd8 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -112,6 +112,15 @@ template <typename T> static inline void visitIfNeeded(SlotVisitor& visitor, Wri visitor.append(v); } +JSGlobalObject::JSGlobalObject(JSGlobalData& globalData, Structure* structure, const GlobalObjectMethodTable* globalObjectMethodTable) + : JSSegmentedVariableObject(globalData, structure, &m_symbolTable) + , m_globalScopeChain() + , m_weakRandom(Options::forceWeakRandomSeed ? Options::forcedWeakRandomSeed : static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0))) + , m_evalEnabled(true) + , m_globalObjectMethodTable(globalObjectMethodTable ? globalObjectMethodTable : &s_globalObjectMethodTable) +{ +} + JSGlobalObject::~JSGlobalObject() { ASSERT(JSLock::currentThreadIsHoldingLock()); diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h index 2396142b1..1dcfc63cc 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.h +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h @@ -175,14 +175,7 @@ namespace JSC { static JS_EXPORTDATA const ClassInfo s_info; protected: - explicit JSGlobalObject(JSGlobalData& globalData, Structure* structure, const GlobalObjectMethodTable* globalObjectMethodTable = 0) - : JSSegmentedVariableObject(globalData, structure, &m_symbolTable) - , m_globalScopeChain() - , m_weakRandom(static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0))) - , m_evalEnabled(true) - , m_globalObjectMethodTable(globalObjectMethodTable ? globalObjectMethodTable : &s_globalObjectMethodTable) - { - } + JS_EXPORT_PRIVATE explicit JSGlobalObject(JSGlobalData&, Structure*, const GlobalObjectMethodTable* = 0); void finishCreation(JSGlobalData& globalData) { @@ -328,6 +321,7 @@ namespace JSC { } double weakRandomNumber() { return m_weakRandom.get(); } + unsigned weakRandomInteger() { return m_weakRandom.getUint32(); } protected: static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSSegmentedVariableObject::StructureFlags; @@ -451,23 +445,10 @@ namespace JSC { { return constructEmptyArray(exec, exec->lexicalGlobalObject(), initialLength); } - + inline JSArray* constructArray(ExecState* exec, JSGlobalObject* globalObject, const ArgList& values) { - JSGlobalData& globalData = exec->globalData(); - unsigned length = values.size(); - JSArray* array = JSArray::tryCreateUninitialized(globalData, globalObject->arrayStructure(), length); - - // FIXME: we should probably throw an out of memory error here, but - // when making this change we should check that all clients of this - // function will correctly handle an exception being thrown from here. - if (!array) - CRASH(); - - for (unsigned i = 0; i < length; ++i) - array->initializeIndex(globalData, i, values.at(i)); - array->completeInitialization(length); - return array; + return constructArray(exec, globalObject->arrayStructure(), values); } inline JSArray* constructArray(ExecState* exec, const ArgList& values) @@ -477,19 +458,7 @@ namespace JSC { inline JSArray* constructArray(ExecState* exec, JSGlobalObject* globalObject, const JSValue* values, unsigned length) { - JSGlobalData& globalData = exec->globalData(); - JSArray* array = JSArray::tryCreateUninitialized(globalData, globalObject->arrayStructure(), length); - - // FIXME: we should probably throw an out of memory error here, but - // when making this change we should check that all clients of this - // function will correctly handle an exception being thrown from here. - if (!array) - CRASH(); - - for (unsigned i = 0; i < length; ++i) - array->initializeIndex(globalData, i, values[i]); - array->completeInitialization(length); - return array; + return constructArray(exec, globalObject->arrayStructure(), values, length); } inline JSArray* constructArray(ExecState* exec, const JSValue* values, unsigned length) diff --git a/Source/JavaScriptCore/runtime/MemoryStatistics.cpp b/Source/JavaScriptCore/runtime/MemoryStatistics.cpp index 86101f559..14b1c7d06 100644 --- a/Source/JavaScriptCore/runtime/MemoryStatistics.cpp +++ b/Source/JavaScriptCore/runtime/MemoryStatistics.cpp @@ -37,7 +37,7 @@ GlobalMemoryStatistics globalMemoryStatistics() GlobalMemoryStatistics stats; stats.stackBytes = RegisterFile::committedByteCount(); -#if ENABLE(EXECUTABLE_ALLOCATOR_FIXED) +#if ENABLE(EXECUTABLE_ALLOCATOR_FIXED) || (PLATFORM(BLACKBERRY) && ENABLE(JIT)) stats.JITBytes = ExecutableAllocator::committedByteCount(); #else stats.JITBytes = 0; diff --git a/Source/JavaScriptCore/runtime/Options.cpp b/Source/JavaScriptCore/runtime/Options.cpp index 7b6da6536..894ca8cc0 100644 --- a/Source/JavaScriptCore/runtime/Options.cpp +++ b/Source/JavaScriptCore/runtime/Options.cpp @@ -67,6 +67,9 @@ int32_t thresholdForOptimizeSoon; int32_t executionCounterIncrementForLoop; int32_t executionCounterIncrementForReturn; +bool randomizeExecutionCountsBetweenCheckpoints; +int32_t maximumExecutionCountsBetweenCheckpoints; + unsigned desiredSpeculativeSuccessFailRatio; double likelyToTakeSlowCaseThreshold; @@ -95,6 +98,9 @@ unsigned gcMarkStackSegmentSize; unsigned numberOfGCMarkers; unsigned opaqueRootMergeThreshold; +bool forceWeakRandomSeed; +unsigned forcedWeakRandomSeed; + #if ENABLE(RUN_TIME_HEURISTICS) static bool parse(const char* string, bool& value) { @@ -184,6 +190,9 @@ void initializeOptions() SET(executionCounterIncrementForLoop, 1); SET(executionCounterIncrementForReturn, 15); + + SET(randomizeExecutionCountsBetweenCheckpoints, false); + SET(maximumExecutionCountsBetweenCheckpoints, 1000); SET(desiredSpeculativeSuccessFailRatio, 6); @@ -227,6 +236,9 @@ void initializeOptions() ASSERT((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp) << reoptimizationRetryCounterMax) > 0); ASSERT((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp) << reoptimizationRetryCounterMax) <= static_cast<int64_t>(std::numeric_limits<int32_t>::max())); + + SET(forceWeakRandomSeed, false); + SET(forcedWeakRandomSeed, 0); } } } // namespace JSC::Options diff --git a/Source/JavaScriptCore/runtime/Options.h b/Source/JavaScriptCore/runtime/Options.h index 0adb59e9b..1bce5b944 100644 --- a/Source/JavaScriptCore/runtime/Options.h +++ b/Source/JavaScriptCore/runtime/Options.h @@ -53,6 +53,9 @@ extern int32_t thresholdForOptimizeNextInvocation; extern int32_t executionCounterIncrementForLoop; extern int32_t executionCounterIncrementForReturn; +extern bool randomizeExecutionCountsBetweenCheckpoints; +extern int32_t maximumExecutionCountsBetweenCheckpoints; + extern unsigned desiredSpeculativeSuccessFailRatio; extern double likelyToTakeSlowCaseThreshold; @@ -81,6 +84,9 @@ extern unsigned gcMarkStackSegmentSize; JS_EXPORTDATA extern unsigned numberOfGCMarkers; JS_EXPORTDATA extern unsigned opaqueRootMergeThreshold; +extern bool forceWeakRandomSeed; +extern unsigned forcedWeakRandomSeed; + void initializeOptions(); } } // namespace JSC::Options diff --git a/Source/JavaScriptCore/runtime/WeakRandom.h b/Source/JavaScriptCore/runtime/WeakRandom.h index 6083980d2..3cd1016d3 100644 --- a/Source/JavaScriptCore/runtime/WeakRandom.h +++ b/Source/JavaScriptCore/runtime/WeakRandom.h @@ -62,6 +62,9 @@ public: , m_high(seed) { } + + // Returns the seed provided that you've never called get() or getUint32(). + unsigned seedUnsafe() const { return m_high; } double get() { diff --git a/Source/JavaScriptCore/wscript b/Source/JavaScriptCore/wscript index 58696d9c5..4afb4d26a 100644 --- a/Source/JavaScriptCore/wscript +++ b/Source/JavaScriptCore/wscript @@ -66,7 +66,7 @@ def build(bld): features = 'cc cxx cshlib', includes = '. .. assembler ../WTF ' + ' '.join(includes), source = sources, - defines = ['BUILDING_JavaScriptCore', 'STATICALLY_LINKED_WITH_WTF'], + defines = ['BUILDING_JavaScriptCore'], target = 'jscore', uselib = 'WX ICU ' + get_config(), uselib_local = '', |