Commit 24d24e5b authored by fpizlo@apple.com's avatar fpizlo@apple.com

DFG should inline Array.push and Array.pop

https://bugs.webkit.org/show_bug.cgi?id=69314

Reviewed by Oliver Hunt.
        
1% speed-up in V8 due to 6% speed-up in V8-deltablue.

* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::storePtr):
* create_hash_table:
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsic):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGIntrinsic.h:
* dfg/DFGNode.h:
(JSC::DFG::Node::hasHeapPrediction):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPropagator.cpp:
(JSC::DFG::Propagator::propagateNodePredictions):
(JSC::DFG::Propagator::getByValLoadElimination):
(JSC::DFG::Propagator::getMethodLoadElimination):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@96567 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 95130fcc
2011-10-03 Filip Pizlo <fpizlo@apple.com>
DFG should inline Array.push and Array.pop
https://bugs.webkit.org/show_bug.cgi?id=69314
Reviewed by Oliver Hunt.
1% speed-up in V8 due to 6% speed-up in V8-deltablue.
* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::storePtr):
* create_hash_table:
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsic):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGIntrinsic.h:
* dfg/DFGNode.h:
(JSC::DFG::Node::hasHeapPrediction):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPropagator.cpp:
(JSC::DFG::Propagator::propagateNodePredictions):
(JSC::DFG::Propagator::getByValLoadElimination):
(JSC::DFG::Propagator::getMethodLoadElimination):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
2011-10-03 Filip Pizlo <fpizlo@apple.com>
JSC ASSERT Opening the Web Inspector
......@@ -298,6 +298,12 @@ public:
storePtr(scratchRegister, address);
}
void storePtr(TrustedImmPtr imm, BaseIndex address)
{
move(imm, scratchRegister);
m_assembler.movq_rm(scratchRegister, address.offset, address.base, address.index, address.scale);
}
DataLabel32 storePtrWithAddressOffsetPatch(RegisterID src, Address address)
{
m_assembler.movq_rm_disp32(src, address.offset, address.base);
......
......@@ -321,6 +321,14 @@ sub output() {
$thunkGenerator = "logThunkGenerator";
}
}
if ($name eq "arrayPrototypeTable") {
if ($key eq "push") {
$intrinsic = "DFG::ArrayPushIntrinsic";
}
if ($key eq "pop") {
$intrinsic = "DFG::ArrayPopIntrinsic";
}
}
print " { \"$key\", $attrs[$i], (intptr_t)" . $castStr . "($firstValue), (intptr_t)$secondValue THUNK_GENERATOR($thunkGenerator) INTRINSIC($intrinsic) },\n";
$i++;
}
......
......@@ -70,7 +70,7 @@ private:
bool handleMinMax(bool usesResult, int resultOperand, NodeType op, int firstArg, int lastArg);
// Handle intrinsic functions.
bool handleIntrinsic(bool usesResult, int resultOperand, Intrinsic, int firstArg, int lastArg);
bool handleIntrinsic(bool usesResult, int resultOperand, Intrinsic, int firstArg, int lastArg, PredictedType prediction);
// Parse a single basic block of bytecode instructions.
bool parseBlock(unsigned limit);
// Setup predecessor links in the graph's BasicBlocks.
......@@ -681,7 +681,7 @@ bool ByteCodeParser::handleMinMax(bool usesResult, int resultOperand, NodeType o
return false;
}
bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrinsic intrinsic, int firstArg, int lastArg)
bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrinsic intrinsic, int firstArg, int lastArg, PredictedType prediction)
{
switch (intrinsic) {
case AbsIntrinsic: {
......@@ -720,6 +720,27 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins
return true;
}
case ArrayPushIntrinsic: {
if (firstArg + 1 != lastArg)
return false;
NodeIndex arrayPush = addToGraph(ArrayPush, OpInfo(0), OpInfo(prediction), get(firstArg), get(firstArg + 1));
if (usesResult)
set(resultOperand, arrayPush);
return true;
}
case ArrayPopIntrinsic: {
if (firstArg != lastArg)
return false;
NodeIndex arrayPop = addToGraph(ArrayPop, OpInfo(0), OpInfo(prediction), get(firstArg));
if (usesResult)
set(resultOperand, arrayPop);
return true;
}
default:
ASSERT(intrinsic == NoIntrinsic);
return false;
......@@ -1531,14 +1552,16 @@ bool ByteCodeParser::parseBlock(unsigned limit)
bool usesResult = false;
int resultOperand = 0; // make compiler happy
Instruction* putInstruction = currentInstruction + OPCODE_LENGTH(op_call);
PredictedType prediction = PredictNone;
if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) {
resultOperand = putInstruction[1].u.operand;
usesResult = true;
prediction = getPrediction(m_graph.size(), m_currentIndex + OPCODE_LENGTH(op_call));
}
DFG::Intrinsic intrinsic = m_graph.valueOfFunctionConstant(m_codeBlock, callTarget)->executable()->intrinsic();
if (handleIntrinsic(usesResult, resultOperand, intrinsic, firstArg, lastArg)) {
if (handleIntrinsic(usesResult, resultOperand, intrinsic, firstArg, lastArg, prediction)) {
// NEXT_OPCODE() has to be inside braces.
NEXT_OPCODE(op_call);
}
......
......@@ -208,7 +208,28 @@ void Graph::dump(NodeIndex nodeIndex, CodeBlock* codeBlock)
printf(" predicting %s", predictionToString(node.getHeapPrediction()));
else if (node.hasMethodCheckData()) {
MethodCheckData& methodCheckData = m_methodCheckData[node.methodCheckDataIndex()];
printf(" predicting function %p", methodCheckData.function);
JSCell* functionCell = getJSFunction(methodCheckData.function);
ExecutableBase* executable = 0;
CodeBlock* primaryForCall = 0;
CodeBlock* secondaryForCall = 0;
CodeBlock* primaryForConstruct = 0;
CodeBlock* secondaryForConstruct = 0;
if (functionCell) {
JSFunction* function = asFunction(functionCell);
executable = function->executable();
if (!executable->isHostFunction()) {
FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
if (functionExecutable->isGeneratedForCall()) {
primaryForCall = &functionExecutable->generatedBytecodeForCall();
secondaryForCall = primaryForCall->alternative();
}
if (functionExecutable->isGeneratedForConstruct()) {
primaryForConstruct = &functionExecutable->generatedBytecodeForConstruct();
secondaryForConstruct = primaryForConstruct->alternative();
}
}
}
printf(" predicting function %p(%p(%p(%p) %p(%p)))", methodCheckData.function, executable, primaryForCall, secondaryForCall, primaryForConstruct, secondaryForConstruct);
}
}
......
......@@ -33,7 +33,9 @@ enum Intrinsic {
AbsIntrinsic,
MinIntrinsic,
MaxIntrinsic,
SqrtIntrinsic
SqrtIntrinsic,
ArrayPushIntrinsic,
ArrayPopIntrinsic
};
} } // namespace JSC::DFG
......
......@@ -342,6 +342,10 @@ static inline const char* arithNodeFlagsAsString(ArithNodeFlags flags)
macro(GetGlobalVar, NodeResultJS | NodeMustGenerate) \
macro(PutGlobalVar, NodeMustGenerate | NodeClobbersWorld) \
\
/* Optimizations for array mutation. */\
macro(ArrayPush, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
macro(ArrayPop, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
\
/* Nodes for comparison operations. */\
macro(CompareLess, NodeResultBoolean | NodeMustGenerate | NodeMightClobber) \
macro(CompareLessEq, NodeResultBoolean | NodeMustGenerate | NodeMightClobber) \
......@@ -772,6 +776,8 @@ struct Node {
case ResolveBase:
case ResolveBaseStrictPut:
case ResolveGlobal:
case ArrayPop:
case ArrayPush:
return true;
default:
return false;
......
......@@ -375,6 +375,17 @@ void DFG_OPERATION operationPutByValBeyondArrayBounds(ExecState* exec, JSArray*
array->JSArray::put(exec, index, JSValue::decode(encodedValue));
}
EncodedJSValue DFG_OPERATION operationArrayPush(ExecState* exec, JSArray* array, EncodedJSValue encodedValue)
{
array->push(exec, JSValue::decode(encodedValue));
return JSValue::encode(jsNumber(array->length()));
}
EncodedJSValue DFG_OPERATION operationArrayPop(ExecState*, JSArray* array)
{
return JSValue::encode(array->pop());
}
void DFG_OPERATION operationPutByIdStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName)
{
PutPropertySlot slot(true);
......
......@@ -97,6 +97,8 @@ void DFG_OPERATION operationThrowHasInstanceError(ExecState*, EncodedJSValue bas
void DFG_OPERATION operationPutByValStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
void DFG_OPERATION operationPutByValNonStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
void DFG_OPERATION operationPutByValBeyondArrayBounds(ExecState*, JSArray*, int32_t index, EncodedJSValue encodedValue);
EncodedJSValue DFG_OPERATION operationArrayPush(ExecState*, JSArray*, EncodedJSValue encodedValue);
EncodedJSValue DFG_OPERATION operationArrayPop(ExecState*, JSArray*);
void DFG_OPERATION operationPutByIdStrict(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier*);
void DFG_OPERATION operationPutByIdNonStrict(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier*);
void DFG_OPERATION operationPutByIdDirectStrict(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier*);
......
......@@ -335,7 +335,14 @@ private:
changed |= setPrediction(PredictInt32);
break;
}
case ArrayPop:
case ArrayPush: {
if (node.getHeapPrediction())
changed |= mergePrediction(node.getHeapPrediction());
break;
}
case ArithMod: {
PredictedType left = m_graph[node.child1()].prediction();
PredictedType right = m_graph[node.child2()].prediction();
......@@ -966,6 +973,9 @@ private:
// for a structure change or a put to property storage to affect
// the GetByVal.
break;
case ArrayPush:
// A push cannot affect previously existing elements in the array.
break;
default:
if (clobbersWorld(index))
return NoNode;
......@@ -999,6 +1009,11 @@ private:
// change.
break;
case ArrayPush:
case ArrayPop:
// Pushing and popping cannot despecify a function.
break;
default:
if (clobbersWorld(index))
return NoNode;
......
......@@ -1260,6 +1260,122 @@ void SpeculativeJIT::compile(Node& node)
break;
}
case ArrayPush: {
SpeculateCellOperand base(this, node.child1());
JSValueOperand value(this, node.child2());
GPRTemporary storage(this);
GPRTemporary storageLength(this);
GPRReg baseGPR = base.gpr();
GPRReg valueTagGPR = value.tagGPR();
GPRReg valuePayloadGPR = value.payloadGPR();
GPRReg storageGPR = storage.gpr();
GPRReg storageLengthGPR = storageLength.gpr();
writeBarrier(baseGPR, valueTagGPR, node.child2(), WriteBarrierForPropertyAccess, storageGPR, storageLengthGPR);
if (!isKnownArray(node.child1()))
speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR);
m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
// Refuse to handle bizarre lengths.
speculationCheck(m_jit.branch32(MacroAssembler::Above, storageLengthGPR, TrustedImm32(0x7ffffffe)));
MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(baseGPR, JSArray::vectorLengthOffset()));
m_jit.store32(valueTagGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
m_jit.store32(valuePayloadGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
m_jit.add32(Imm32(1), storageLengthGPR);
m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)));
m_jit.add32(Imm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
m_jit.move(Imm32(JSValue::Int32Tag), storageGPR);
MacroAssembler::Jump done = m_jit.jump();
slowPath.link(&m_jit);
silentSpillAllRegisters(storageGPR, storageLengthGPR);
m_jit.push(valueTagGPR);
m_jit.push(valuePayloadGPR);
m_jit.push(baseGPR);
m_jit.push(GPRInfo::callFrameRegister);
appendCallWithExceptionCheck(operationArrayPush);
setupResults(storageGPR, storageLengthGPR);
silentFillAllRegisters(storageGPR, storageLengthGPR);
done.link(&m_jit);
jsValueResult(storageGPR, storageLengthGPR, m_compileIndex);
break;
}
case ArrayPop: {
SpeculateCellOperand base(this, node.child1());
GPRTemporary valueTag(this);
GPRTemporary valuePayload(this);
GPRTemporary storage(this);
GPRTemporary storageLength(this);
GPRReg baseGPR = base.gpr();
GPRReg valueTagGPR = valueTag.gpr();
GPRReg valuePayloadGPR = valuePayload.gpr();
GPRReg storageGPR = storage.gpr();
GPRReg storageLengthGPR = storageLength.gpr();
if (!isKnownArray(node.child1()))
speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR);
m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
MacroAssembler::Jump emptyArrayCase = m_jit.branchTest32(MacroAssembler::Zero, storageLengthGPR);
m_jit.sub32(Imm32(1), storageLengthGPR);
MacroAssembler::Jump slowCase = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(baseGPR, JSArray::vectorLengthOffset()));
m_jit.load32(MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), valueTagGPR);
m_jit.load32(MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), valuePayloadGPR);
m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)));
MacroAssembler::Jump notHole = m_jit.branchTestPtr(MacroAssembler::NonZero, valueTagGPR);
MacroAssembler::Jump holeCase = m_jit.branchTestPtr(MacroAssembler::Zero, valuePayloadGPR);
notHole.link(&m_jit);
m_jit.move(Imm32(0), storageLengthGPR);
m_jit.store32(storageLengthGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
m_jit.store32(storageLengthGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
m_jit.sub32(MacroAssembler::Imm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
MacroAssembler::JumpList done;
done.append(m_jit.jump());
holeCase.link(&m_jit);
emptyArrayCase.link(&m_jit);
m_jit.move(MacroAssembler::Imm32(jsUndefined().tag()), valueTagGPR);
m_jit.move(MacroAssembler::Imm32(jsUndefined().payload()), valuePayloadGPR);
done.append(m_jit.jump());
slowCase.link(&m_jit);
silentSpillAllRegisters(valueTagGPR, valuePayloadGPR);
m_jit.push(baseGPR);
m_jit.push(GPRInfo::callFrameRegister);
appendCallWithExceptionCheck(operationArrayPop);
setupResults(valueTagGPR, valuePayloadGPR);
silentFillAllRegisters(valueTagGPR, valuePayloadGPR);
done.link(&m_jit);
jsValueResult(valueTagGPR, valuePayloadGPR, m_compileIndex);
break;
}
case DFG::Jump: {
BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(node.takenBytecodeOffset());
if (taken != (m_block + 1))
......
......@@ -1353,6 +1353,110 @@ void SpeculativeJIT::compile(Node& node)
noResult(m_compileIndex);
break;
}
case ArrayPush: {
SpeculateCellOperand base(this, node.child1());
JSValueOperand value(this, node.child2());
GPRTemporary storage(this);
GPRTemporary storageLength(this);
GPRReg baseGPR = base.gpr();
GPRReg valueGPR = value.gpr();
GPRReg storageGPR = storage.gpr();
GPRReg storageLengthGPR = storageLength.gpr();
writeBarrier(baseGPR, valueGPR, node.child2(), WriteBarrierForPropertyAccess, storageGPR, storageLengthGPR);
if (!isKnownArray(node.child1()))
speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR);
m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
// Refuse to handle bizarre lengths.
speculationCheck(m_jit.branch32(MacroAssembler::Above, storageLengthGPR, TrustedImm32(0x7ffffffe)));
MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(baseGPR, JSArray::vectorLengthOffset()));
m_jit.storePtr(valueGPR, MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
m_jit.add32(Imm32(1), storageLengthGPR);
m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)));
m_jit.add32(Imm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
m_jit.orPtr(GPRInfo::tagTypeNumberRegister, storageLengthGPR);
MacroAssembler::Jump done = m_jit.jump();
slowPath.link(&m_jit);
silentSpillAllRegisters(storageLengthGPR);
setupStubArguments(baseGPR, valueGPR);
m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
appendCallWithExceptionCheck(operationArrayPush);
m_jit.move(GPRInfo::returnValueGPR, storageLengthGPR);
silentFillAllRegisters(storageLengthGPR);
done.link(&m_jit);
jsValueResult(storageLengthGPR, m_compileIndex);
break;
}
case ArrayPop: {
SpeculateCellOperand base(this, node.child1());
GPRTemporary value(this);
GPRTemporary storage(this);
GPRTemporary storageLength(this);
GPRReg baseGPR = base.gpr();
GPRReg valueGPR = value.gpr();
GPRReg storageGPR = storage.gpr();
GPRReg storageLengthGPR = storageLength.gpr();
if (!isKnownArray(node.child1()))
speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR);
m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
MacroAssembler::Jump emptyArrayCase = m_jit.branchTest32(MacroAssembler::Zero, storageLengthGPR);
m_jit.sub32(Imm32(1), storageLengthGPR);
MacroAssembler::Jump slowCase = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(baseGPR, JSArray::vectorLengthOffset()));
m_jit.loadPtr(MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), valueGPR);
m_jit.store32(storageLengthGPR, MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)));
MacroAssembler::Jump holeCase = m_jit.branchTestPtr(MacroAssembler::Zero, valueGPR);
m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::BaseIndex(storageGPR, storageLengthGPR, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
m_jit.sub32(MacroAssembler::Imm32(1), MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
MacroAssembler::JumpList done;
done.append(m_jit.jump());
holeCase.link(&m_jit);
emptyArrayCase.link(&m_jit);
m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsUndefined())), valueGPR);
done.append(m_jit.jump());
slowCase.link(&m_jit);
silentSpillAllRegisters(valueGPR);
m_jit.move(baseGPR, GPRInfo::argumentGPR1);
m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
appendCallWithExceptionCheck(operationArrayPop);
m_jit.move(GPRInfo::returnValueGPR, valueGPR);
silentFillAllRegisters(valueGPR);
done.link(&m_jit);
jsValueResult(valueGPR, m_compileIndex);
break;
}
case DFG::Jump: {
BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(node.takenBytecodeOffset());
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment