summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/dfg')
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractState.cpp10
-rw-r--r--Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp43
-rw-r--r--Source/JavaScriptCore/dfg/DFGCSEPhase.cpp13
-rw-r--r--Source/JavaScriptCore/dfg/DFGDriver.cpp2
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.h9
-rw-r--r--Source/JavaScriptCore/dfg/DFGJITCompiler.cpp1
-rw-r--r--Source/JavaScriptCore/dfg/DFGNode.h10
-rw-r--r--Source/JavaScriptCore/dfg/DFGNodeType.h2
-rw-r--r--Source/JavaScriptCore/dfg/DFGOperations.cpp43
-rw-r--r--Source/JavaScriptCore/dfg/DFGOperations.h13
-rw-r--r--Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp4
-rw-r--r--Source/JavaScriptCore/dfg/DFGRepatch.cpp17
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp72
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h23
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp20
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp18
-rw-r--r--Source/JavaScriptCore/dfg/DFGValueSource.h2
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);