DFG should inline Array.push and Array.pop
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 4 Oct 2011 02:55:54 +0000 (02:55 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 4 Oct 2011 02:55:54 +0000 (02:55 +0000)
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: https://svn.webkit.org/repository/webkit/trunk@96567 268f45cc-cd09-0410-ab3c-d52691b4dbfc

12 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h
Source/JavaScriptCore/create_hash_table
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGGraph.cpp
Source/JavaScriptCore/dfg/DFGIntrinsic.h
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGOperations.h
Source/JavaScriptCore/dfg/DFGPropagator.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

index 8792e11..2fd9624 100644 (file)
@@ -1,5 +1,36 @@
 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
         https://bugs.webkit.org/show_bug.cgi?id=69293
 
index 03af472..12a1869 100644 (file)
@@ -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);
index ab8e8a0..2e5a9fd 100755 (executable)
@@ -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++;
     }
index d36bf5d..7124e43 100644 (file)
@@ -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);
                 }
index 4be2f24..2b3f7c3 100644 (file)
@@ -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);
         }
     }
     
index fefff46..a401197 100644 (file)
@@ -33,7 +33,9 @@ enum Intrinsic {
     AbsIntrinsic,
     MinIntrinsic,
     MaxIntrinsic,
-    SqrtIntrinsic
+    SqrtIntrinsic,
+    ArrayPushIntrinsic,
+    ArrayPopIntrinsic
 };
 
 } } // namespace JSC::DFG
index 5bafa1a..db89703 100644 (file)
@@ -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;
index 05fe23e..19ac6cc 100644 (file)
@@ -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);
index 08a26d7..85ab12b 100644 (file)
@@ -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*);
index 61140f5..308860c 100644 (file)
@@ -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;
index bd66eb5..79b4072 100644 (file)
@@ -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))
index 1ddafcd..14cd2a0 100644 (file)
@@ -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());