DFG JIT cannot compile op_new_object, op_new_array,
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 28 Sep 2011 05:33:21 +0000 (05:33 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 28 Sep 2011 05:33:21 +0000 (05:33 +0000)
op_new_array_buffer, or op_new_regexp
https://bugs.webkit.org/show_bug.cgi?id=68580

Reviewed by Oliver Hunt.

This implements all four opcodes, but has op_new_regexp turns off
by default because it unveils some bad speculation logic when
compiling string-validate-input.

With op_new_regexp turned off, this is a 5% win on Kraken and a
0.7% speed-up on V8. Neutral on SunSpider.

* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.h:
(JSC::DFG::canCompileOpcode):
* dfg/DFGJITCodeGenerator.h:
(JSC::DFG::callOperation):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasConstantBuffer):
(JSC::DFG::Node::startConstant):
(JSC::DFG::Node::numConstants):
(JSC::DFG::Node::hasRegexpIndex):
(JSC::DFG::Node::regexpIndex):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPropagator.cpp:
(JSC::DFG::Propagator::propagateNodePredictions):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::emitAllocateJSFinalObject):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::isKnownArray):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@96189 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCapabilities.h
Source/JavaScriptCore/dfg/DFGJITCodeGenerator.h
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGOperations.h
Source/JavaScriptCore/dfg/DFGPropagator.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

index a691225..159d5bd 100644 (file)
@@ -1,5 +1,42 @@
 2011-09-27  Filip Pizlo  <fpizlo@apple.com>
 
+        DFG JIT cannot compile op_new_object, op_new_array,
+        op_new_array_buffer, or op_new_regexp
+        https://bugs.webkit.org/show_bug.cgi?id=68580
+
+        Reviewed by Oliver Hunt.
+        
+        This implements all four opcodes, but has op_new_regexp turns off
+        by default because it unveils some bad speculation logic when
+        compiling string-validate-input.
+        
+        With op_new_regexp turned off, this is a 5% win on Kraken and a
+        0.7% speed-up on V8. Neutral on SunSpider.
+
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCapabilities.h:
+        (JSC::DFG::canCompileOpcode):
+        * dfg/DFGJITCodeGenerator.h:
+        (JSC::DFG::callOperation):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::hasConstantBuffer):
+        (JSC::DFG::Node::startConstant):
+        (JSC::DFG::Node::numConstants):
+        (JSC::DFG::Node::hasRegexpIndex):
+        (JSC::DFG::Node::regexpIndex):
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPropagator.cpp:
+        (JSC::DFG::Propagator::propagateNodePredictions):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::emitAllocateJSFinalObject):
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::isKnownArray):
+
+2011-09-27  Filip Pizlo  <fpizlo@apple.com>
+
         DFG JIT should speculate more aggressively on reads of array.length
         https://bugs.webkit.org/show_bug.cgi?id=68932
 
index e09f555..42c8fdf 100644 (file)
@@ -724,6 +724,32 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             NEXT_OPCODE(op_create_this);
         }
             
+        case op_new_object: {
+            set(currentInstruction[1].u.operand, addToGraph(NewObject));
+            NEXT_OPCODE(op_new_object);
+        }
+            
+        case op_new_array: {
+            int startOperand = currentInstruction[2].u.operand;
+            int numOperands = currentInstruction[3].u.operand;
+            for (int operandIdx = startOperand; operandIdx < startOperand + numOperands; ++operandIdx)
+                addVarArgChild(get(operandIdx));
+            set(currentInstruction[1].u.operand, addToGraph(Node::VarArg, NewArray, OpInfo(0), OpInfo(0)));
+            NEXT_OPCODE(op_new_array);
+        }
+            
+        case op_new_array_buffer: {
+            int startConstant = currentInstruction[2].u.operand;
+            int numConstants = currentInstruction[3].u.operand;
+            set(currentInstruction[1].u.operand, addToGraph(NewArrayBuffer, OpInfo(startConstant), OpInfo(numConstants)));
+            NEXT_OPCODE(op_new_array_buffer);
+        }
+            
+        case op_new_regexp: {
+            set(currentInstruction[1].u.operand, addToGraph(NewRegexp, OpInfo(currentInstruction[2].u.operand)));
+            NEXT_OPCODE(op_new_regexp);
+        }
+            
         case op_get_callee: {
             set(currentInstruction[1].u.operand, addToGraph(GetCallee));
             NEXT_OPCODE(op_get_callee);
@@ -1401,8 +1427,9 @@ bool ByteCodeParser::parseBlock(unsigned limit)
         }
 
         default:
-            // Parse failed!
-            ASSERT(!canCompileOpcode(opcodeID));
+            // Parse failed! This should not happen because the capabilities checker
+            // should have caught it.
+            ASSERT_NOT_REACHED();
             return false;
         }
         
index a318b3c..f7fdfdb 100644 (file)
@@ -31,6 +31,8 @@
 
 namespace JSC { namespace DFG {
 
+#define ENABLE_DFG_RESTRICTIONS 1
+
 #if ENABLE(DFG_JIT)
 // Fast check functions; if they return true it is still necessary to
 // check opcodes.
@@ -119,11 +121,28 @@ inline bool canCompileOpcode(OpcodeID opcodeID)
     case op_resolve:
     case op_resolve_base:
     case op_resolve_global:
+    case op_new_object:
+    case op_new_array:
+    case op_new_array_buffer:
     case op_strcat:
     case op_to_primitive:
     case op_throw:
     case op_throw_reference_error:
         return true;
+        
+    // Opcodes we support conditionally. Enabling these opcodes currently results in
+    // performance regressions. Each node that we disable under restrictions has a
+    // comment describing what we know about the regression so far.
+        
+    // Regresses string-validate-input, probably because it uses comparisons (< and >)
+    // on strings, which currently will cause speculation failures in some cases.
+    case op_new_regexp: 
+#if ENABLE(DFG_RESTRICTIONS)
+        return false;
+#else
+        return true;
+#endif
+        
     default:
         return false;
     }
index 612c0cf..b4dfe4d 100644 (file)
@@ -1068,6 +1068,17 @@ protected:
         appendCallWithExceptionCheck(operation);
         m_jit.move(GPRInfo::returnValueGPR, result);
     }
+    void callOperation(J_DFGOperation_ESS operation, GPRReg result, int startConstant, int numConstants)
+    {
+        ASSERT(isFlushed());
+
+        m_jit.move(JITCompiler::TrustedImm32(numConstants), GPRInfo::argumentGPR2);
+        m_jit.move(JITCompiler::TrustedImm32(startConstant), GPRInfo::argumentGPR1);
+        m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+
+        appendCallWithExceptionCheck(operation);
+        m_jit.move(GPRInfo::returnValueGPR, result);
+    }
     void callOperation(J_DFGOperation_EJP operation, GPRReg result, GPRReg arg1, void* pointer)
     {
         ASSERT(isFlushed());
index 9cd0750..7140896 100644 (file)
@@ -287,6 +287,12 @@ static inline const char* arithNodeFlagsAsString(ArithNodeFlags flags)
     macro(Call, NodeResultJS | NodeMustGenerate | NodeHasVarArgs | NodeClobbersWorld) \
     macro(Construct, NodeResultJS | NodeMustGenerate | NodeHasVarArgs | NodeClobbersWorld) \
     \
+    /* Allocations. */\
+    macro(NewObject, NodeResultJS) \
+    macro(NewArray, NodeResultJS | NodeHasVarArgs) \
+    macro(NewArrayBuffer, NodeResultJS) \
+    macro(NewRegexp, NodeResultJS) \
+    \
     /* Resolve nodes. */\
     macro(Resolve, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
     macro(ResolveBase, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
@@ -560,6 +566,34 @@ struct Node {
         return true;
     }
     
+    bool hasConstantBuffer()
+    {
+        return op == NewArrayBuffer;
+    }
+    
+    unsigned startConstant()
+    {
+        ASSERT(hasConstantBuffer());
+        return m_opInfo;
+    }
+    
+    unsigned numConstants()
+    {
+        ASSERT(hasConstantBuffer());
+        return m_opInfo2;
+    }
+    
+    bool hasRegexpIndex()
+    {
+        return op == NewRegexp;
+    }
+    
+    unsigned regexpIndex()
+    {
+        ASSERT(hasRegexpIndex());
+        return m_opInfo;
+    }
+    
     bool hasVarNumber()
     {
         return op == GetGlobalVar || op == PutGlobalVar || op == GetScopedVar || op == PutScopedVar;
index e05b010..84952b8 100644 (file)
@@ -157,6 +157,11 @@ EncodedJSValue operationCreateThis(ExecState* exec, EncodedJSValue encodedOp)
     return JSValue::encode(constructEmptyObject(exec, structure));
 }
 
+EncodedJSValue operationNewObject(ExecState* exec)
+{
+    return JSValue::encode(constructEmptyObject(exec));
+}
+
 EncodedJSValue operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
 {
     JSValue op1 = JSValue::decode(encodedOp1);
@@ -790,6 +795,29 @@ EncodedJSValue operationStrCat(ExecState* exec, void* start, size_t size)
     return JSValue::encode(jsString(exec, static_cast<Register*>(start), size));
 }
 
+EncodedJSValue operationNewArray(ExecState* exec, void* start, size_t size)
+{
+    ArgList argList(static_cast<Register*>(start), size);
+    return JSValue::encode(constructArray(exec, argList));
+}
+
+EncodedJSValue operationNewArrayBuffer(ExecState* exec, size_t start, size_t size)
+{
+    ArgList argList(exec->codeBlock()->constantBuffer(start), size);
+    return JSValue::encode(constructArray(exec, argList));
+}
+
+EncodedJSValue operationNewRegexp(ExecState* exec, void* regexpPtr)
+{
+    RegExp* regexp = static_cast<RegExp*>(regexpPtr);
+    if (!regexp->isValid()) {
+        throwError(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor."));
+        return JSValue::encode(jsUndefined());
+    }
+    
+    return RegExpObject::create(exec->globalData(), exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->regExpStructure(), regexp);
+}
+
 void operationThrowHasInstanceError(ExecState* exec, EncodedJSValue encodedBase)
 {
     JSValue base = JSValue::decode(encodedBase);
index aaf1fa3..6dbf7a1 100644 (file)
@@ -50,6 +50,7 @@ typedef EncodedJSValue (*J_DFGOperation_EJP)(ExecState*, EncodedJSValue, void*);
 typedef EncodedJSValue (*J_DFGOperation_EJI)(ExecState*, EncodedJSValue, Identifier*);
 typedef EncodedJSValue (*J_DFGOperation_EP)(ExecState*, void*);
 typedef EncodedJSValue (*J_DFGOperation_EPS)(ExecState*, void*, size_t);
+typedef EncodedJSValue (*J_DFGOperation_ESS)(ExecState*, size_t, size_t);
 typedef EncodedJSValue (*J_DFGOperation_EI)(ExecState*, Identifier*);
 typedef RegisterSizedBoolean (*Z_DFGOperation_EJ)(ExecState*, EncodedJSValue);
 typedef RegisterSizedBoolean (*Z_DFGOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
@@ -62,6 +63,7 @@ typedef void *(*P_DFGOperation_E)(ExecState*);
 // These routines are provide callbacks out to C++ implementations of operations too complex to JIT.
 EncodedJSValue operationConvertThis(ExecState*, EncodedJSValue encodedOp1);
 EncodedJSValue operationCreateThis(ExecState*, EncodedJSValue encodedOp1);
+EncodedJSValue operationNewObject(ExecState*);
 EncodedJSValue operationValueAdd(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
 EncodedJSValue operationValueAddNotNumber(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
 EncodedJSValue operationArithAdd(EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
@@ -82,6 +84,9 @@ EncodedJSValue operationResolveBaseStrictPut(ExecState*, Identifier*);
 EncodedJSValue operationResolveGlobal(ExecState*, GlobalResolveInfo*, Identifier*);
 EncodedJSValue operationToPrimitive(ExecState*, EncodedJSValue);
 EncodedJSValue operationStrCat(ExecState*, void* start, size_t);
+EncodedJSValue operationNewArray(ExecState*, void* start, size_t);
+EncodedJSValue operationNewArrayBuffer(ExecState*, size_t, size_t);
+EncodedJSValue operationNewRegexp(ExecState*, void*);
 void operationThrowHasInstanceError(ExecState*, EncodedJSValue base);
 void operationPutByValStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
 void operationPutByValNonStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
index 3a00cdc..9e47d7d 100644 (file)
@@ -509,11 +509,23 @@ private:
             break;
         }
             
-        case CreateThis: {
+        case CreateThis:
+        case NewObject: {
             changed |= setPrediction(PredictFinalObject);
             break;
         }
             
+        case NewArray:
+        case NewArrayBuffer: {
+            changed |= setPrediction(PredictArray);
+            break;
+        }
+            
+        case NewRegexp: {
+            changed |= setPrediction(PredictObjectOther);
+            break;
+        }
+            
         case StrCat: {
             changed |= setPrediction(PredictString);
             break;
@@ -538,7 +550,7 @@ private:
             }
             break;
         }
-
+            
         case ValueToDouble:
         case GetArrayLength: {
             // This node should never be visible at this stage of compilation. It is
index 23088a8..5409dd6 100644 (file)
@@ -685,6 +685,36 @@ bool SpeculativeJIT::compare(Node& node, MacroAssembler::RelationalCondition con
     return false;
 }
 
+template<typename T>
+void SpeculativeJIT::emitAllocateJSFinalObject(T structure, GPRReg resultGPR, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath)
+{
+    MarkedSpace::SizeClass* sizeClass = &m_jit.globalData()->heap.sizeClassForObject(sizeof(JSFinalObject));
+    
+    m_jit.loadPtr(&sizeClass->firstFreeCell, resultGPR);
+    slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR));
+    
+    // The object is half-allocated: we have what we know is a fresh object, but
+    // it's still on the GC's free list.
+    
+    // Ditch the structure by placing it into the structure slot, so that we can reuse
+    // scratchGPR.
+    m_jit.storePtr(structure, MacroAssembler::Address(resultGPR, JSObject::structureOffset()));
+    
+    // Now that we have scratchGPR back, remove the object from the free list
+    m_jit.loadPtr(MacroAssembler::Address(resultGPR), scratchGPR);
+    m_jit.storePtr(scratchGPR, &sizeClass->firstFreeCell);
+    
+    // Initialize the object's vtable
+    m_jit.storePtr(MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsFinalObjectVPtr), MacroAssembler::Address(resultGPR));
+    
+    // Initialize the object's inheritorID.
+    m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(resultGPR, JSObject::offsetOfInheritorID()));
+    
+    // Initialize the object's property storage pointer.
+    m_jit.addPtr(MacroAssembler::TrustedImm32(sizeof(JSObject)), resultGPR, scratchGPR);
+    m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, JSFinalObject::offsetOfPropertyStorage()));
+}
+
 void SpeculativeJIT::compile(Node& node)
 {
     NodeType op = node.op;
@@ -1386,8 +1416,7 @@ void SpeculativeJIT::compile(Node& node)
 
         // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
         // If we have predicted the base to be type array, we can skip the check.
-        Node& baseNode = m_jit.graph()[node.child1()];
-        if (baseNode.op != GetLocal || !isArrayPrediction(m_jit.graph().getPrediction(baseNode.local())))
+        if (!isKnownArray(node.child1()))
             speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
         speculationCheck(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())));
 
@@ -1421,8 +1450,7 @@ void SpeculativeJIT::compile(Node& node)
 
         // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
         // If we have predicted the base to be type array, we can skip the check.
-        Node& baseNode = m_jit.graph()[node.child1()];
-        if (baseNode.op != GetLocal || !isArrayPrediction(m_jit.graph().getPrediction(baseNode.local())))
+        if (!isKnownArray(node.child1()))
             speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
 
         base.use();
@@ -1637,9 +1665,10 @@ void SpeculativeJIT::compile(Node& node)
         break;
     }
         
-    case StrCat: {
-        // We really don't want to grow the register file just to do a StrCat. Say we
-        // have 50 functions on the stack that all have a StrCat in them that has
+    case StrCat:
+    case NewArray: {
+        // We really don't want to grow the register file just to do a StrCat or NewArray.
+        // Say we have 50 functions on the stack that all have a StrCat in them that has
         // upwards of 10 operands. In the DFG this would mean that each one gets
         // some random virtual register, and then to do the StrCat we'd need a second
         // span of 10 operands just to have somewhere to copy the 10 operands to, where
@@ -1669,12 +1698,32 @@ void SpeculativeJIT::compile(Node& node)
         
         GPRResult result(this);
         
-        callOperation(operationStrCat, result.gpr(), buffer, node.numChildren());
+        callOperation(op == StrCat ? operationStrCat : operationNewArray, result.gpr(), buffer, node.numChildren());
         
-        jsValueResult(result.gpr(), m_compileIndex, UseChildrenCalledExplicitly);
+        cellResult(result.gpr(), m_compileIndex, UseChildrenCalledExplicitly);
         break;
     }
-
+        
+    case NewArrayBuffer: {
+        flushRegisters();
+        GPRResult result(this);
+        
+        callOperation(operationNewArrayBuffer, result.gpr(), node.startConstant(), node.numConstants());
+        
+        cellResult(result.gpr(), m_compileIndex);
+        break;
+    }
+        
+    case NewRegexp: {
+        flushRegisters();
+        GPRResult result(this);
+        
+        callOperation(operationNewRegexp, result.gpr(), m_jit.codeBlock()->regexp(node.regexpIndex()));
+        
+        cellResult(result.gpr(), m_compileIndex);
+        break;
+    }
+        
     case ConvertThis: {
         SpeculateCellOperand thisValue(this, node.child1());
 
@@ -1718,46 +1767,49 @@ void SpeculativeJIT::compile(Node& node)
         m_jit.loadPtr(MacroAssembler::Address(protoGPR, JSObject::offsetOfInheritorID()), scratchGPR);
         slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, scratchGPR));
         
-        MarkedSpace::SizeClass* sizeClass = &m_jit.globalData()->heap.sizeClassForObject(sizeof(JSFinalObject));
+        emitAllocateJSFinalObject(scratchGPR, resultGPR, scratchGPR, slowPath);
         
-        m_jit.loadPtr(&sizeClass->firstFreeCell, resultGPR);
-        slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR));
+        MacroAssembler::Jump done = m_jit.jump();
         
-        // The object is half-allocated: we have what we know is a fresh object, but
-        // it's still on the GC's free list.
+        slowPath.link(&m_jit);
         
-        // Ditch the inheritorID by placing it into the structure, so that we can reuse
-        // scratchGPR.
-        m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, JSObject::structureOffset()));
+        silentSpillAllRegisters(resultGPR);
+        m_jit.move(protoGPR, GPRInfo::argumentGPR1);
+        m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+        appendCallWithExceptionCheck(operationCreateThis);
+        m_jit.move(GPRInfo::returnValueGPR, resultGPR);
+        silentFillAllRegisters(resultGPR);
         
-        // Now that we have scratchGPR back, remove the object from the free list
-        m_jit.loadPtr(MacroAssembler::Address(resultGPR), scratchGPR);
-        m_jit.storePtr(scratchGPR, &sizeClass->firstFreeCell);
+        done.link(&m_jit);
         
-        // Initialize the object's vtable
-        m_jit.storePtr(MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsFinalObjectVPtr), MacroAssembler::Address(resultGPR));
+        cellResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
+        break;
+    }
+        
+    case NewObject: {
+        GPRTemporary result(this);
+        GPRTemporary scratch(this);
+        
+        GPRReg resultGPR = result.gpr();
+        GPRReg scratchGPR = scratch.gpr();
         
-        // Initialize the object's inheritorID.
-        m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(resultGPR, JSObject::offsetOfInheritorID()));
+        MacroAssembler::JumpList slowPath;
         
-        // Initialize the object's property storage pointer.
-        m_jit.addPtr(MacroAssembler::TrustedImm32(sizeof(JSObject)), resultGPR, scratchGPR);
-        m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, JSFinalObject::offsetOfPropertyStorage()));
+        emitAllocateJSFinalObject(MacroAssembler::TrustedImmPtr(m_jit.codeBlock()->globalObject()->emptyObjectStructure()), resultGPR, scratchGPR, slowPath);
         
         MacroAssembler::Jump done = m_jit.jump();
         
         slowPath.link(&m_jit);
         
         silentSpillAllRegisters(resultGPR);
-        m_jit.move(protoGPR, GPRInfo::argumentGPR1);
         m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
-        appendCallWithExceptionCheck(operationCreateThis);
+        appendCallWithExceptionCheck(operationNewObject);
         m_jit.move(GPRInfo::returnValueGPR, resultGPR);
         silentFillAllRegisters(resultGPR);
         
         done.link(&m_jit);
         
-        cellResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
+        cellResult(resultGPR, m_compileIndex);
         break;
     }
         
@@ -1833,14 +1885,13 @@ void SpeculativeJIT::compile(Node& node)
     }
         
     case GetArrayLength: {
-        Node& baseNode = m_jit.graph()[node.child1()];
         SpeculateCellOperand base(this, node.child1());
         GPRTemporary result(this);
         
         GPRReg baseGPR = base.gpr();
         GPRReg resultGPR = result.gpr();
         
-        if (baseNode.op != GetLocal || !isArrayPrediction(m_jit.graph().getPrediction(baseNode.local())))
+        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()), resultGPR);
index 53ede6f..13243ed 100644 (file)
@@ -512,11 +512,32 @@ private:
             || (shouldSpeculateObject(op1) && shouldSpeculateArray(op2));
     }
     
+    bool isKnownArray(NodeIndex op1)
+    {
+        Node& node = m_jit.graph()[op1];
+        switch (node.op) {
+        case GetLocal:
+            return isArrayPrediction(m_jit.graph().getPrediction(node.local()));
+            
+        case NewArray:
+        case NewArrayBuffer:
+            return true;
+            
+        default:
+            return false;
+        }
+    }
+    
     bool compare(Node&, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, Z_DFGOperation_EJJ);
     void compilePeepHoleIntegerBranch(Node&, NodeIndex branchNodeIndex, JITCompiler::RelationalCondition);
     void compilePeepHoleDoubleBranch(Node&, NodeIndex branchNodeIndex, JITCompiler::DoubleCondition);
     void compilePeepHoleObjectEquality(Node&, NodeIndex branchNodeIndex, void* vptr);
     void compileObjectEquality(Node&, void* vptr);
+    
+    // It is acceptable to have structure be equal to scratch, so long as you're fine
+    // with the structure GPR being clobbered.
+    template<typename T>
+    void emitAllocateJSFinalObject(T structure, GPRReg resultGPR, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath);
    
 #if USE(JSVALUE64) 
     JITCompiler::Jump convertToDouble(GPRReg value, FPRReg result, GPRReg tmp);