diff options
Diffstat (limited to 'Source/JavaScriptCore/dfg')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGAbstractState.cpp | 10 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp | 43 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGCSEPhase.cpp | 13 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGDriver.cpp | 2 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGGraph.h | 9 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGJITCompiler.cpp | 1 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGNode.h | 10 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGNodeType.h | 2 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGOperations.cpp | 43 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGOperations.h | 13 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp | 4 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGRepatch.cpp | 17 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp | 72 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h | 23 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp | 20 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp | 18 | ||||
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGValueSource.h | 2 |
17 files changed, 246 insertions, 56 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp index e4561da06..01996f132 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp +++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp @@ -128,6 +128,8 @@ void AbstractState::initialize(Graph& graph) root->valuesAtHead.argument(i).set(SpecFloat32Array); else if (isFloat64ArraySpeculation(prediction)) root->valuesAtHead.argument(i).set(SpecFloat64Array); + else if (isCellSpeculation(prediction)) + root->valuesAtHead.argument(i).set(SpecCell); else root->valuesAtHead.argument(i).makeTop(); @@ -272,7 +274,8 @@ bool AbstractState::execute(unsigned indexInBlock) } case SetLocal: { - if (node.variableAccessData()->isCaptured()) { + if (node.variableAccessData()->isCaptured() + || m_graph.isCreatedThisArgument(node.local())) { m_variables.operand(node.local()) = forNode(node.child1()); node.setCanExit(false); break; @@ -290,6 +293,9 @@ bool AbstractState::execute(unsigned indexInBlock) else if (isArraySpeculation(predictedType)) { node.setCanExit(!isArraySpeculation(forNode(node.child1()).m_type)); forNode(node.child1()).filter(SpecArray); + } else if (isCellSpeculation(predictedType)) { + node.setCanExit(!isCellSpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecCell); } else if (isBooleanSpeculation(predictedType)) speculateBooleanUnary(node); else @@ -1437,6 +1443,8 @@ bool AbstractState::execute(unsigned indexInBlock) m_haveStructures = true; break; case GetPropertyStorage: + case AllocatePropertyStorage: + case ReallocatePropertyStorage: node.setCanExit(false); forNode(node.child1()).filter(SpecCell); forNode(nodeIndex).clear(); // The result is not a JS value. diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp index 1b1395934..e4e94e90b 100644 --- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp +++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp @@ -2271,7 +2271,6 @@ bool ByteCodeParser::parseBlock(unsigned limit) m_graph.m_storageAccessData.append(storageAccessData); } else if (!hasExitSite && putByIdStatus.isSimpleTransition() - && putByIdStatus.oldStructure()->outOfLineCapacity() == putByIdStatus.newStructure()->outOfLineCapacity() && structureChainIsStillValid( direct, putByIdStatus.oldStructure(), @@ -2293,20 +2292,38 @@ bool ByteCodeParser::parseBlock(unsigned limit) } } ASSERT(putByIdStatus.oldStructure()->transitionWatchpointSetHasBeenInvalidated()); - addToGraph( - PutStructure, - OpInfo( - m_graph.addStructureTransitionData( - StructureTransitionData( - putByIdStatus.oldStructure(), - putByIdStatus.newStructure()))), - base); NodeIndex propertyStorage; - if (isInlineOffset(putByIdStatus.offset())) - propertyStorage = base; - else - propertyStorage = addToGraph(GetPropertyStorage, base); + StructureTransitionData* transitionData = + m_graph.addStructureTransitionData( + StructureTransitionData( + putByIdStatus.oldStructure(), + putByIdStatus.newStructure())); + + if (putByIdStatus.oldStructure()->outOfLineCapacity() + != putByIdStatus.newStructure()->outOfLineCapacity()) { + + // If we're growing the property storage then it must be because we're + // storing into the out-of-line storage. + ASSERT(!isInlineOffset(putByIdStatus.offset())); + + if (!putByIdStatus.oldStructure()->outOfLineCapacity()) { + propertyStorage = addToGraph( + AllocatePropertyStorage, OpInfo(transitionData), base); + } else { + propertyStorage = addToGraph( + ReallocatePropertyStorage, OpInfo(transitionData), + base, addToGraph(GetPropertyStorage, base)); + } + } else { + if (isInlineOffset(putByIdStatus.offset())) + propertyStorage = base; + else + propertyStorage = addToGraph(GetPropertyStorage, base); + } + + addToGraph(PutStructure, OpInfo(transitionData), base); + addToGraph( PutByOffset, OpInfo(m_graph.m_storageAccessData.size()), diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp index 04c3ebc66..4532214ee 100644 --- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp @@ -465,6 +465,8 @@ private: case NewArray: case NewObject: case CreateThis: + case AllocatePropertyStorage: + case ReallocatePropertyStorage: return NoNode; default: @@ -581,6 +583,17 @@ private: if (node.child1() == child1) return index; break; + + case AllocatePropertyStorage: + case ReallocatePropertyStorage: + // If we can cheaply prove this is a change to our object's storage, we + // can optimize and use its result. + if (node.child1() == child1) + return index; + // Otherwise, we currently can't prove that this doesn't change our object's + // storage, so we conservatively assume that it may change the storage + // pointer of any object, including ours. + return NoNode; case PutByOffset: case PutStructure: diff --git a/Source/JavaScriptCore/dfg/DFGDriver.cpp b/Source/JavaScriptCore/dfg/DFGDriver.cpp index 64fc0c7e5..f160b6d35 100644 --- a/Source/JavaScriptCore/dfg/DFGDriver.cpp +++ b/Source/JavaScriptCore/dfg/DFGDriver.cpp @@ -64,7 +64,7 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo if (!Options::useDFGJIT()) return false; - + #if DFG_ENABLE(DEBUG_VERBOSE) dataLog("DFG compiling code block %p(%p) for executable %p, number of instructions = %u.\n", codeBlock, codeBlock->alternative(), codeBlock->ownerExecutable(), codeBlock->instructionCount()); #endif diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h index 4091c48f7..3e6539353 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.h +++ b/Source/JavaScriptCore/dfg/DFGGraph.h @@ -441,6 +441,15 @@ public: return m_codeBlock->usesArguments(); } + bool isCreatedThisArgument(int operand) + { + if (!operandIsArgument(operand)) + return false; + if (operandToArgument(operand)) + return false; + return m_codeBlock->specializationKind() == CodeForConstruct; + } + unsigned numSuccessors(BasicBlock* block) { return at(block->last()).numSuccessors(); diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp index 5a9f972b8..ae28fad3f 100644 --- a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp +++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp @@ -188,6 +188,7 @@ void JITCompiler::link(LinkBuffer& linkBuffer) CallLinkInfo& info = m_codeBlock->callLinkInfo(i); info.callType = m_jsCalls[i].m_callType; info.isDFG = true; + info.bytecodeIndex = m_jsCalls[i].m_codeOrigin.bytecodeIndex; linkBuffer.link(m_jsCalls[i].m_slowCall, FunctionPtr((m_globalData->getCTIStub(info.callType == CallLinkInfo::Construct ? linkConstructThunkGenerator : linkCallThunkGenerator)).code().executableAddress())); info.callReturnLocation = linkBuffer.locationOfNearCall(m_jsCalls[i].m_slowCall); info.hotPathBegin = linkBuffer.locationOf(m_jsCalls[i].m_targetToCheck); diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h index ae07d5512..e72bd5e36 100644 --- a/Source/JavaScriptCore/dfg/DFGNode.h +++ b/Source/JavaScriptCore/dfg/DFGNode.h @@ -632,7 +632,15 @@ struct Node { bool hasStructureTransitionData() { - return op() == PutStructure || op() == PhantomPutStructure; + switch (op()) { + case PutStructure: + case PhantomPutStructure: + case AllocatePropertyStorage: + case ReallocatePropertyStorage: + return true; + default: + return false; + } } StructureTransitionData& structureTransitionData() diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h index 7fcd2ec14..0ca0039b9 100644 --- a/Source/JavaScriptCore/dfg/DFGNodeType.h +++ b/Source/JavaScriptCore/dfg/DFGNodeType.h @@ -133,6 +133,8 @@ namespace JSC { namespace DFG { macro(StructureTransitionWatchpoint, NodeMustGenerate) \ macro(PutStructure, NodeMustGenerate) \ macro(PhantomPutStructure, NodeMustGenerate | NodeDoesNotExit) \ + macro(AllocatePropertyStorage, NodeMustGenerate | NodeDoesNotExit | NodeResultStorage) \ + macro(ReallocatePropertyStorage, NodeMustGenerate | NodeDoesNotExit | NodeResultStorage) \ macro(GetPropertyStorage, NodeResultStorage) \ macro(GetIndexedPropertyStorage, NodeMustGenerate | NodeResultStorage) \ macro(GetByOffset, NodeResultJS) \ diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp index 03c0666b7..9050d590e 100644 --- a/Source/JavaScriptCore/dfg/DFGOperations.cpp +++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp @@ -28,6 +28,7 @@ #include "Arguments.h" #include "CodeBlock.h" +#include "CopiedSpaceInlineMethods.h" #include "DFGOSRExit.h" #include "DFGRepatch.h" #include "DFGThunks.h" @@ -894,7 +895,7 @@ static void* handleHostCall(ExecState* execCallee, JSValue callee, CodeSpecializ return globalData->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); } -inline void* linkFor(ExecState* execCallee, CodeSpecializationKind kind) +inline char* linkFor(ExecState* execCallee, CodeSpecializationKind kind) { ExecState* exec = execCallee->callerFrame(); JSGlobalData* globalData = &exec->globalData(); @@ -903,7 +904,7 @@ inline void* linkFor(ExecState* execCallee, CodeSpecializationKind kind) JSValue calleeAsValue = execCallee->calleeAsValue(); JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue); if (!calleeAsFunctionCell) - return handleHostCall(execCallee, calleeAsValue, kind); + return reinterpret_cast<char*>(handleHostCall(execCallee, calleeAsValue, kind)); JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell); execCallee->setScopeChain(callee->scopeUnchecked()); @@ -918,7 +919,7 @@ inline void* linkFor(ExecState* execCallee, CodeSpecializationKind kind) JSObject* error = functionExecutable->compileFor(execCallee, callee->scope(), kind); if (error) { globalData->exception = createStackOverflowError(exec); - return globalData->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); + return reinterpret_cast<char*>(globalData->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress()); } codeBlock = &functionExecutable->generatedBytecodeFor(kind); if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters())) @@ -931,20 +932,20 @@ inline void* linkFor(ExecState* execCallee, CodeSpecializationKind kind) callLinkInfo.setSeen(); else dfgLinkFor(execCallee, callLinkInfo, codeBlock, callee, codePtr, kind); - return codePtr.executableAddress(); + return reinterpret_cast<char*>(codePtr.executableAddress()); } -void* DFG_OPERATION operationLinkCall(ExecState* execCallee) +char* DFG_OPERATION operationLinkCall(ExecState* execCallee) { return linkFor(execCallee, CodeForCall); } -void* DFG_OPERATION operationLinkConstruct(ExecState* execCallee) +char* DFG_OPERATION operationLinkConstruct(ExecState* execCallee) { return linkFor(execCallee, CodeForConstruct); } -inline void* virtualFor(ExecState* execCallee, CodeSpecializationKind kind) +inline char* virtualFor(ExecState* execCallee, CodeSpecializationKind kind) { ExecState* exec = execCallee->callerFrame(); JSGlobalData* globalData = &exec->globalData(); @@ -953,7 +954,7 @@ inline void* virtualFor(ExecState* execCallee, CodeSpecializationKind kind) JSValue calleeAsValue = execCallee->calleeAsValue(); JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue); if (UNLIKELY(!calleeAsFunctionCell)) - return handleHostCall(execCallee, calleeAsValue, kind); + return reinterpret_cast<char*>(handleHostCall(execCallee, calleeAsValue, kind)); JSFunction* function = jsCast<JSFunction*>(calleeAsFunctionCell); execCallee->setScopeChain(function->scopeUnchecked()); @@ -963,18 +964,18 @@ inline void* virtualFor(ExecState* execCallee, CodeSpecializationKind kind) JSObject* error = functionExecutable->compileFor(execCallee, function->scope(), kind); if (error) { exec->globalData().exception = error; - return globalData->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); + return reinterpret_cast<char*>(globalData->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress()); } } - return executable->generatedJITCodeWithArityCheckFor(kind).executableAddress(); + return reinterpret_cast<char*>(executable->generatedJITCodeWithArityCheckFor(kind).executableAddress()); } -void* DFG_OPERATION operationVirtualCall(ExecState* execCallee) +char* DFG_OPERATION operationVirtualCall(ExecState* execCallee) { return virtualFor(execCallee, CodeForCall); } -void* DFG_OPERATION operationVirtualConstruct(ExecState* execCallee) +char* DFG_OPERATION operationVirtualConstruct(ExecState* execCallee) { return virtualFor(execCallee, CodeForConstruct); } @@ -1241,6 +1242,24 @@ void DFG_OPERATION operationReallocateStorageAndFinishPut(ExecState* exec, JSObj base->putDirectOffset(globalData, offset, JSValue::decode(value)); } +char* DFG_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecState* exec) +{ + JSGlobalData& globalData = exec->globalData(); + void* result; + if (!globalData.heap.tryAllocateStorage(initialOutOfLineCapacity * sizeof(JSValue), &result)) + CRASH(); + return reinterpret_cast<char*>(result); +} + +char* DFG_OPERATION operationAllocatePropertyStorage(ExecState* exec, size_t newSize) +{ + JSGlobalData& globalData = exec->globalData(); + void* result; + if (!globalData.heap.tryAllocateStorage(newSize, &result)) + CRASH(); + return reinterpret_cast<char*>(result); +} + double DFG_OPERATION operationFModOnInts(int32_t a, int32_t b) { return fmod(a, b); diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h index 109dcb2eb..d0fbf7ed4 100644 --- a/Source/JavaScriptCore/dfg/DFGOperations.h +++ b/Source/JavaScriptCore/dfg/DFGOperations.h @@ -104,7 +104,8 @@ typedef void DFG_OPERATION (*V_DFGOperation_EJJJ)(ExecState*, EncodedJSValue, En typedef void DFG_OPERATION (*V_DFGOperation_EJPP)(ExecState*, EncodedJSValue, EncodedJSValue, void*); typedef void DFG_OPERATION (*V_DFGOperation_EPZJ)(ExecState*, void*, int32_t, EncodedJSValue); typedef void DFG_OPERATION (*V_DFGOperation_W)(WatchpointSet*); -typedef void* DFG_OPERATION (*P_DFGOperation_E)(ExecState*); +typedef char* DFG_OPERATION (*P_DFGOperation_E)(ExecState*); +typedef char* DFG_OPERATION (*P_DFGOperation_ES)(ExecState*, size_t); // These routines are provide callbacks out to C++ implementations of operations too complex to JIT. JSCell* DFG_OPERATION operationNewObject(ExecState*) WTF_INTERNAL; @@ -162,10 +163,10 @@ size_t DFG_OPERATION operationCompareGreaterEq(ExecState*, EncodedJSValue encode size_t DFG_OPERATION operationCompareEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; size_t DFG_OPERATION operationCompareStrictEqCell(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; size_t DFG_OPERATION operationCompareStrictEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; -void* DFG_OPERATION operationVirtualCall(ExecState*) WTF_INTERNAL; -void* DFG_OPERATION operationLinkCall(ExecState*) WTF_INTERNAL; -void* DFG_OPERATION operationVirtualConstruct(ExecState*) WTF_INTERNAL; -void* DFG_OPERATION operationLinkConstruct(ExecState*) WTF_INTERNAL; +char* DFG_OPERATION operationVirtualCall(ExecState*) WTF_INTERNAL; +char* DFG_OPERATION operationLinkCall(ExecState*) WTF_INTERNAL; +char* DFG_OPERATION operationVirtualConstruct(ExecState*) WTF_INTERNAL; +char* DFG_OPERATION operationLinkConstruct(ExecState*) WTF_INTERNAL; JSCell* DFG_OPERATION operationCreateActivation(ExecState*) WTF_INTERNAL; JSCell* DFG_OPERATION operationCreateArguments(ExecState*) WTF_INTERNAL; JSCell* DFG_OPERATION operationCreateInlinedArguments(ExecState*, InlineCallFrame*) WTF_INTERNAL; @@ -181,6 +182,8 @@ double DFG_OPERATION operationFModOnInts(int32_t, int32_t) WTF_INTERNAL; size_t DFG_OPERATION operationIsObject(EncodedJSValue) WTF_INTERNAL; size_t DFG_OPERATION operationIsFunction(EncodedJSValue) WTF_INTERNAL; void DFG_OPERATION operationReallocateStorageAndFinishPut(ExecState*, JSObject*, Structure*, PropertyOffset, EncodedJSValue) WTF_INTERNAL; +char* DFG_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecState*) WTF_INTERNAL; +char* DFG_OPERATION operationAllocatePropertyStorage(ExecState*, size_t newSize) WTF_INTERNAL; // This method is used to lookup an exception hander, keyed by faultLocation, which is // the return location from one of the calls out to one of the helper operations above. diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp index d23cd8265..2e4f8094c 100644 --- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp @@ -449,7 +449,9 @@ private: } case GetPropertyStorage: - case GetIndexedPropertyStorage: { + case GetIndexedPropertyStorage: + case AllocatePropertyStorage: + case ReallocatePropertyStorage: { changed |= setPrediction(SpecOther); changed |= mergeDefaultFlags(node); break; diff --git a/Source/JavaScriptCore/dfg/DFGRepatch.cpp b/Source/JavaScriptCore/dfg/DFGRepatch.cpp index cfc2cd664..19e064f2c 100644 --- a/Source/JavaScriptCore/dfg/DFGRepatch.cpp +++ b/Source/JavaScriptCore/dfg/DFGRepatch.cpp @@ -829,33 +829,18 @@ static void emitPutTransitionStub( size_t oldSize = oldStructure->outOfLineCapacity() * sizeof(JSValue); ASSERT(newSize > oldSize); - // Optimistically assume that the old storage was the very last thing - // allocated. stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), scratchGPR3); - stubJit.loadPtr(&copiedAllocator->m_currentPayloadEnd, scratchGPR2); stubJit.loadPtr(&copiedAllocator->m_currentRemaining, scratchGPR1); - stubJit.subPtr(scratchGPR1, scratchGPR2); - stubJit.subPtr(MacroAssembler::TrustedImm32(oldSize), scratchGPR2); - MacroAssembler::Jump needFullRealloc = - stubJit.branchPtr(MacroAssembler::NotEqual, scratchGPR2, scratchGPR3); - slowPath.append(stubJit.branchSubPtr(MacroAssembler::Signed, MacroAssembler::TrustedImm32(newSize - oldSize), scratchGPR1)); - stubJit.storePtr(scratchGPR1, &copiedAllocator->m_currentRemaining); - stubJit.move(scratchGPR2, scratchGPR1); - MacroAssembler::Jump doneRealloc = stubJit.jump(); - - needFullRealloc.link(&stubJit); slowPath.append(stubJit.branchSubPtr(MacroAssembler::Signed, MacroAssembler::TrustedImm32(newSize), scratchGPR1)); stubJit.storePtr(scratchGPR1, &copiedAllocator->m_currentRemaining); stubJit.negPtr(scratchGPR1); stubJit.addPtr(MacroAssembler::AbsoluteAddress(&copiedAllocator->m_currentPayloadEnd), scratchGPR1); stubJit.subPtr(MacroAssembler::TrustedImm32(newSize), scratchGPR1); // We have scratchGPR1 = new storage, scratchGPR3 = old storage, scratchGPR2 = available - for (size_t offset = 0; offset < oldSize; offset += sizeof(JSValue)) { + for (size_t offset = 0; offset < oldSize; offset += sizeof(void*)) { stubJit.loadPtr(MacroAssembler::Address(scratchGPR3, offset), scratchGPR2); stubJit.storePtr(scratchGPR2, MacroAssembler::Address(scratchGPR1, offset)); } - - doneRealloc.link(&stubJit); } stubJit.storePtr(scratchGPR1, MacroAssembler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage())); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp index e8824b832..f368cf298 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp @@ -1241,7 +1241,8 @@ void SpeculativeJIT::checkArgumentTypes() m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister)); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->float64ArrayDescriptor().m_classInfo))); - } + } else if (isCellSpeculation(predictedType)) + speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, JITCompiler::addressFor(virtualRegister), GPRInfo::tagMaskRegister)); #else if (isInt32Speculation(predictedType)) speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag))); @@ -1307,7 +1308,8 @@ void SpeculativeJIT::checkArgumentTypes() speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag))); m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->float64ArrayDescriptor().m_classInfo))); - } + } else if (isCellSpeculation(predictedType)) + speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::CellTag))); #endif } m_isCheckingArgumentTypes = false; @@ -3137,6 +3139,72 @@ bool SpeculativeJIT::compileRegExpExec(Node& node) return true; } +void SpeculativeJIT::compileAllocatePropertyStorage(Node& node) +{ + SpeculateCellOperand base(this, node.child1()); + GPRTemporary scratch(this); + + GPRReg baseGPR = base.gpr(); + GPRReg scratchGPR = scratch.gpr(); + + ASSERT(!node.structureTransitionData().previousStructure->outOfLineCapacity()); + ASSERT(initialOutOfLineCapacity == node.structureTransitionData().newStructure->outOfLineCapacity()); + size_t newSize = initialOutOfLineCapacity * sizeof(JSValue); + CopiedAllocator* copiedAllocator = &m_jit.globalData()->heap.storageAllocator(); + + m_jit.loadPtr(&copiedAllocator->m_currentRemaining, scratchGPR); + JITCompiler::Jump slowPath = m_jit.branchSubPtr(JITCompiler::Signed, JITCompiler::TrustedImm32(newSize), scratchGPR); + m_jit.storePtr(scratchGPR, &copiedAllocator->m_currentRemaining); + m_jit.negPtr(scratchGPR); + m_jit.addPtr(JITCompiler::AbsoluteAddress(&copiedAllocator->m_currentPayloadEnd), scratchGPR); + m_jit.subPtr(JITCompiler::TrustedImm32(newSize), scratchGPR); + + addSlowPathGenerator( + slowPathCall(slowPath, this, operationAllocatePropertyStorageWithInitialCapacity, scratchGPR)); + + m_jit.storePtr(scratchGPR, JITCompiler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage())); + + storageResult(scratchGPR, m_compileIndex); +} + +void SpeculativeJIT::compileReallocatePropertyStorage(Node& node) +{ + SpeculateCellOperand base(this, node.child1()); + StorageOperand oldStorage(this, node.child2()); + GPRTemporary scratch1(this); + GPRTemporary scratch2(this); + + GPRReg baseGPR = base.gpr(); + GPRReg oldStorageGPR = oldStorage.gpr(); + GPRReg scratchGPR1 = scratch1.gpr(); + GPRReg scratchGPR2 = scratch2.gpr(); + + JITCompiler::Jump slowPath; + + size_t oldSize = node.structureTransitionData().previousStructure->outOfLineCapacity() * sizeof(JSValue); + size_t newSize = oldSize * outOfLineGrowthFactor; + ASSERT(newSize == node.structureTransitionData().newStructure->outOfLineCapacity() * sizeof(JSValue)); + CopiedAllocator* copiedAllocator = &m_jit.globalData()->heap.storageAllocator(); + + m_jit.loadPtr(&copiedAllocator->m_currentRemaining, scratchGPR2); + slowPath = m_jit.branchSubPtr(JITCompiler::Signed, JITCompiler::TrustedImm32(newSize), scratchGPR2); + m_jit.storePtr(scratchGPR2, &copiedAllocator->m_currentRemaining); + m_jit.negPtr(scratchGPR2); + m_jit.addPtr(JITCompiler::AbsoluteAddress(&copiedAllocator->m_currentPayloadEnd), scratchGPR2); + m_jit.subPtr(JITCompiler::TrustedImm32(newSize), scratchGPR2); + + addSlowPathGenerator( + slowPathCall(slowPath, this, operationAllocatePropertyStorage, scratchGPR2, newSize)); + // We have scratchGPR2 = new storage, scratchGPR1 = scratch + for (size_t offset = 0; offset < oldSize; offset += sizeof(void*)) { + m_jit.loadPtr(JITCompiler::Address(oldStorageGPR, offset), scratchGPR1); + m_jit.storePtr(scratchGPR1, JITCompiler::Address(scratchGPR2, offset)); + } + m_jit.storePtr(scratchGPR2, JITCompiler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage())); + + storageResult(scratchGPR2, m_compileIndex); +} + } } // namespace JSC::DFG #endif diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h index 487addd7f..cb7d89106 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h @@ -1151,6 +1151,16 @@ public: // machine registers, and delegate the calling convention specific // decision as to how to fill the regsiters to setupArguments* methods. #if USE(JSVALUE64) + JITCompiler::Call callOperation(P_DFGOperation_E operation, GPRReg result) + { + m_jit.setupArgumentsExecState(); + return appendCallWithExceptionCheckSetResult(operation, result); + } + JITCompiler::Call callOperation(P_DFGOperation_ES operation, GPRReg result, size_t size) + { + m_jit.setupArgumentsWithExecState(TrustedImmPtr(size)); + return appendCallWithExceptionCheckSetResult(operation, result); + } JITCompiler::Call callOperation(J_DFGOperation_E operation, GPRReg result) { m_jit.setupArgumentsExecState(); @@ -1413,6 +1423,16 @@ public: #define EABI_32BIT_DUMMY_ARG #endif + JITCompiler::Call callOperation(P_DFGOperation_E operation, GPRReg result) + { + m_jit.setupArgumentsExecState(); + return appendCallWithExceptionCheckSetResult(operation, result); + } + JITCompiler::Call callOperation(P_DFGOperation_ES operation, GPRReg result, size_t size) + { + m_jit.setupArgumentsWithExecState(TrustedImmPtr(size)); + return appendCallWithExceptionCheckSetResult(operation, result); + } JITCompiler::Call callOperation(Z_DFGOperation_D operation, GPRReg result, FPRReg arg1) { prepareForExternalCall(); @@ -2048,6 +2068,9 @@ public: bool compileStrictEq(Node&); + void compileAllocatePropertyStorage(Node&); + void compileReallocatePropertyStorage(Node&); + void compileGetCharCodeAt(Node&); void compileGetByValOnString(Node&); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp index ed98e0800..c63ba8c21 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp @@ -1918,7 +1918,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isArraySpeculation(value.m_type)) { + if (isArraySpeculation(value.m_type) || isCellSpeculation(value.m_type)) { GPRTemporary result(this); m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr()); @@ -2010,7 +2010,7 @@ void SpeculativeJIT::compile(Node& node) // OSR exit, would not be visible to the old JIT in any way. m_codeOriginForOSR = nextNode->codeOrigin; - if (!node.variableAccessData()->isCaptured()) { + if (!node.variableAccessData()->isCaptured() && !m_jit.graph().isCreatedThisArgument(node.local())) { if (node.variableAccessData()->shouldUseDoubleFormat()) { SpeculateDoubleOperand value(this, node.child1()); m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node.local())); @@ -2046,6 +2046,14 @@ void SpeculativeJIT::compile(Node& node) recordSetLocal(node.local(), ValueSource(CellInRegisterFile)); break; } + if (isCellSpeculation(predictedType)) { + SpeculateCellOperand cell(this, node.child1()); + GPRReg cellGPR = cell.gpr(); + m_jit.storePtr(cellGPR, JITCompiler::payloadFor(node.local())); + noResult(m_compileIndex); + recordSetLocal(node.local(), ValueSource(CellInRegisterFile)); + break; + } if (isBooleanSpeculation(predictedType)) { SpeculateBooleanOperand value(this, node.child1()); m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local())); @@ -3542,6 +3550,14 @@ void SpeculativeJIT::compile(Node& node) break; } + case AllocatePropertyStorage: + compileAllocatePropertyStorage(node); + break; + + case ReallocatePropertyStorage: + compileReallocatePropertyStorage(node); + break; + case GetPropertyStorage: { SpeculateCellOperand base(this, node.child1()); GPRTemporary result(this, base); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp index 9e468e758..6dbb8a4b1 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp @@ -2052,7 +2052,7 @@ void SpeculativeJIT::compile(Node& node) // OSR exit, would not be visible to the old JIT in any way. m_codeOriginForOSR = nextNode->codeOrigin; - if (!node.variableAccessData()->isCaptured()) { + if (!node.variableAccessData()->isCaptured() && !m_jit.graph().isCreatedThisArgument(node.local())) { if (node.variableAccessData()->shouldUseDoubleFormat()) { SpeculateDoubleOperand value(this, node.child1()); m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node.local())); @@ -2082,6 +2082,14 @@ void SpeculativeJIT::compile(Node& node) recordSetLocal(node.local(), ValueSource(CellInRegisterFile)); break; } + if (isCellSpeculation(predictedType)) { + SpeculateCellOperand cell(this, node.child1()); + GPRReg cellGPR = cell.gpr(); + m_jit.storePtr(cellGPR, JITCompiler::addressFor(node.local())); + noResult(m_compileIndex); + recordSetLocal(node.local(), ValueSource(CellInRegisterFile)); + break; + } if (isBooleanSpeculation(predictedType)) { SpeculateBooleanOperand boolean(this, node.child1()); m_jit.storePtr(boolean.gpr(), JITCompiler::addressFor(node.local())); @@ -3557,6 +3565,14 @@ void SpeculativeJIT::compile(Node& node) break; } + case AllocatePropertyStorage: + compileAllocatePropertyStorage(node); + break; + + case ReallocatePropertyStorage: + compileReallocatePropertyStorage(node); + break; + case GetPropertyStorage: { SpeculateCellOperand base(this, node.child1()); GPRTemporary result(this, base); diff --git a/Source/JavaScriptCore/dfg/DFGValueSource.h b/Source/JavaScriptCore/dfg/DFGValueSource.h index be4a6e081..f776137d0 100644 --- a/Source/JavaScriptCore/dfg/DFGValueSource.h +++ b/Source/JavaScriptCore/dfg/DFGValueSource.h @@ -130,7 +130,7 @@ public: { if (isInt32Speculation(prediction)) return ValueSource(Int32InRegisterFile); - if (isArraySpeculation(prediction)) + if (isArraySpeculation(prediction) || isCellSpeculation(prediction)) return ValueSource(CellInRegisterFile); if (isBooleanSpeculation(prediction)) return ValueSource(BooleanInRegisterFile); |