diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-06-27 09:28:46 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-06-27 09:28:46 +0200 |
commit | 6668b07fcd51f86be243b9e08e667224e30c0cf8 (patch) | |
tree | 64f466e09b68a77ae1156c0d35cd5b95e18a34ca /Source/JavaScriptCore/dfg | |
parent | e7923d9de38974f0c6fb7646c898a6ea618261e8 (diff) | |
download | qtwebkit-6668b07fcd51f86be243b9e08e667224e30c0cf8.tar.gz |
Imported WebKit commit 26cd9bd8ab0471ffe987c9b60368f63dc0f1f31b (http://svn.webkit.org/repository/webkit/trunk@121325)
New snapshot with more Windows build fixes
Diffstat (limited to 'Source/JavaScriptCore/dfg')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGAbstractState.cpp | 12 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp | 12 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGCCallHelpers.h | 25 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGCSEPhase.cpp | 11 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGGraph.h | 31 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGNodeType.h | 5 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGOperations.cpp | 18 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGOperations.h | 7 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp | 6 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp | 28 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h | 30 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp | 95 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp | 79 |
13 files changed, 280 insertions, 79 deletions
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); |