DFG::operationNewArray is unnecessarily slow, and may use the wrong array
prototype when inlined
https://bugs.webkit.org/show_bug.cgi?id=89821

Source/JavaScriptCore: 

Reviewed by Geoffrey Garen.
        
Fixes all array allocations to use the right structure, and hence the right prototype. Adds
inlining of new Array(...) with a non-zero number of arguments. Optimizes allocations of
empty arrays.

* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::execute):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleConstantInternalFunction):
* dfg/DFGCCallHelpers.h:
(JSC::DFG::CCallHelpers::setupArgumentsWithExecState):
(CCallHelpers):
* dfg/DFGNodeType.h:
(DFG):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* runtime/JSArray.h:
(JSC):
(JSC::constructArray):
* runtime/JSGlobalObject.h:
(JSC):
(JSC::constructArray):

LayoutTests: 

Rubber stamped by Geoffrey Garen.

* fast/js/dfg-cross-global-object-inline-new-array-expected.txt: Added.
* fast/js/dfg-cross-global-object-inline-new-array-literal-expected.txt: Added.
* fast/js/dfg-cross-global-object-inline-new-array-literal-with-variables-expected.txt: Added.
* fast/js/dfg-cross-global-object-inline-new-array-literal-with-variables.html: Added.
* fast/js/dfg-cross-global-object-inline-new-array-literal.html: Added.
* fast/js/dfg-cross-global-object-inline-new-array-with-elements-expected.txt: Added.
* fast/js/dfg-cross-global-object-inline-new-array-with-elements.html: Added.
* fast/js/dfg-cross-global-object-inline-new-array-with-size-expected.txt: Added.
* fast/js/dfg-cross-global-object-inline-new-array-with-size.html: Added.
* fast/js/dfg-cross-global-object-inline-new-array.html: Added.
* fast/js/script-tests/cross-global-object-inline-global-var.js:
(done):
* fast/js/script-tests/dfg-cross-global-object-inline-new-array-literal-with-variables.js: Added.
(foo):
(done):
(doit):
* fast/js/script-tests/dfg-cross-global-object-inline-new-array-literal.js: Added.
(foo):
(done):
(doit):
* fast/js/script-tests/dfg-cross-global-object-inline-new-array-with-elements.js: Added.
(foo):
(done):
(doit):
* fast/js/script-tests/dfg-cross-global-object-inline-new-array-with-size.js: Added.
(foo):
(done):
(doit):
* fast/js/script-tests/dfg-cross-global-object-inline-new-array.js: Added.
(foo):
(done):
(doit):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@121280 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 72aa427..4225402 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,41 @@
+2012-06-25  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG::operationNewArray is unnecessarily slow, and may use the wrong array
+        prototype when inlined
+        https://bugs.webkit.org/show_bug.cgi?id=89821
+
+        Reviewed by Geoffrey Garen.
+        
+        Fixes all array allocations to use the right structure, and hence the right prototype. Adds
+        inlining of new Array(...) with a non-zero number of arguments. Optimizes allocations of
+        empty arrays.
+
+        * dfg/DFGAbstractState.cpp:
+        (JSC::DFG::AbstractState::execute):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleConstantInternalFunction):
+        * dfg/DFGCCallHelpers.h:
+        (JSC::DFG::CCallHelpers::setupArgumentsWithExecState):
+        (CCallHelpers):
+        * dfg/DFGNodeType.h:
+        (DFG):
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::callOperation):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * runtime/JSArray.h:
+        (JSC):
+        (JSC::constructArray):
+        * runtime/JSGlobalObject.h:
+        (JSC):
+        (JSC::constructArray):
+
 2012-06-26  Filip Pizlo  <fpizlo@apple.com>
 
         New fast/js/dfg-store-unexpected-value-into-argument-and-osr-exit.html fails on 32 bit
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index b4205ef..c2d49f7 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -1141,13 +1141,19 @@
     case NewArray:
     case NewArrayBuffer:
         node.setCanExit(false);
-        forNode(nodeIndex).set(m_codeBlock->globalObject()->arrayStructure());
+        forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructure());
+        m_haveStructures = true;
+        break;
+        
+    case NewArrayWithSize:
+        speculateInt32Unary(node);
+        forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructure());
         m_haveStructures = true;
         break;
             
     case NewRegexp:
         node.setCanExit(false);
-        forNode(nodeIndex).set(m_codeBlock->globalObject()->regExpStructure());
+        forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->regExpStructure());
         m_haveStructures = true;
         break;
             
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 7561197..cdb0b63 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -1606,15 +1606,19 @@
     // we know about is small enough, that having just a linear cascade of if statements
     // is good enough.
     
-    UNUSED_PARAM(registerOffset); // Remove this once we do more things to the arguments.
     UNUSED_PARAM(prediction); // Remove this once we do more things.
     UNUSED_PARAM(kind); // Remove this once we do more things.
     
     if (function->classInfo() == &ArrayConstructor::s_info) {
-        // We could handle this but don't for now.
-        if (argumentCountIncludingThis != 1)
-            return false;
+        if (argumentCountIncludingThis == 2) {
+            setIntrinsicResult(
+                usesResult, resultOperand,
+                addToGraph(NewArrayWithSize, get(registerOffset + argumentToOperand(1))));
+            return true;
+        }
         
+        for (int i = 1; i < argumentCountIncludingThis; ++i)
+            addVarArgChild(get(registerOffset + argumentToOperand(i)));
         setIntrinsicResult(
             usesResult, resultOperand,
             addToGraph(Node::VarArg, NewArray, OpInfo(0), OpInfo(0)));
diff --git a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h
index 4cacd45..b602908 100644
--- a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h
+++ b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h
@@ -160,6 +160,14 @@
         addCallArgument(arg2);
     }
 
+    ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, GPRReg arg2)
+    {
+        resetCallArguments();
+        addCallArgument(GPRInfo::callFrameRegister);
+        addCallArgument(arg1);
+        addCallArgument(arg2);
+    }
+
     ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImm32 arg2)
     {
         resetCallArguments();
@@ -203,6 +211,15 @@
         addCallArgument(arg3);
     }
 
+    ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, TrustedImmPtr arg2, TrustedImmPtr arg3)
+    {
+        resetCallArguments();
+        addCallArgument(GPRInfo::callFrameRegister);
+        addCallArgument(arg1);
+        addCallArgument(arg2);
+        addCallArgument(arg3);
+    }
+
     ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2, TrustedImmPtr arg3)
     {
         resetCallArguments();
@@ -597,6 +614,14 @@
         move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
     }
 
+    ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, TrustedImmPtr arg2, TrustedImmPtr arg3)
+    {
+        move(arg1, GPRInfo::argumentGPR1);
+        move(arg2, GPRInfo::argumentGPR2);
+        move(arg3, GPRInfo::argumentGPR3);
+        move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+    }
+
     ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImm32 arg2, TrustedImm32 arg3)
     {
         move(arg1, GPRInfo::argumentGPR1);
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index 4671f6b..db798d0 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -184,6 +184,7 @@
     /* Allocations. */\
     macro(NewObject, NodeResultJS) \
     macro(NewArray, NodeResultJS | NodeHasVarArgs) \
+    macro(NewArrayWithSize, NodeResultJS) \
     macro(NewArrayBuffer, NodeResultJS) \
     macro(NewRegexp, NodeResultJS) \
     \
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index 3ece917..11362f4 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -1005,12 +1005,22 @@
     return JSValue::encode(jsString(exec, static_cast<Register*>(buffer), size));
 }
 
-EncodedJSValue DFG_OPERATION operationNewArray(ExecState* exec, void* buffer, size_t size)
+EncodedJSValue DFG_OPERATION operationNewArray(ExecState* exec, Structure* arrayStructure, void* buffer, size_t size)
 {
     JSGlobalData* globalData = &exec->globalData();
     NativeCallFrameTracer tracer(globalData, exec);
 
-    return JSValue::encode(constructArray(exec, static_cast<JSValue*>(buffer), size));
+    return JSValue::encode(constructArray(exec, arrayStructure, static_cast<JSValue*>(buffer), size));
+}
+
+EncodedJSValue DFG_OPERATION operationNewEmptyArray(ExecState* exec, Structure* arrayStructure)
+{
+    return JSValue::encode(JSArray::create(exec->globalData(), arrayStructure));
+}
+
+EncodedJSValue DFG_OPERATION operationNewArrayWithSize(ExecState* exec, Structure* arrayStructure, int32_t size)
+{
+    return JSValue::encode(JSArray::create(exec->globalData(), arrayStructure, size));
 }
 
 EncodedJSValue DFG_OPERATION operationNewArrayBuffer(ExecState* exec, size_t start, size_t size)
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h
index 7477ab2..3c85ee7 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.h
+++ b/Source/JavaScriptCore/dfg/DFGOperations.h
@@ -76,6 +76,9 @@
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EPP)(ExecState*, void*, void*);
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EPS)(ExecState*, void*, size_t);
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ESS)(ExecState*, size_t, size_t);
+typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ESt)(ExecState*, Structure*);
+typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EStI)(ExecState*, Structure*, int32_t);
+typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EStPS)(ExecState*, Structure*, void*, size_t);
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EZ)(ExecState*, int32_t);
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EZIcfZ)(ExecState*, int32_t, InlineCallFrame*, int32_t);
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EZZ)(ExecState*, int32_t, int32_t);
@@ -124,8 +127,10 @@
 EncodedJSValue DFG_OPERATION operationResolveGlobal(ExecState*, GlobalResolveInfo*, JSGlobalObject*, Identifier*) WTF_INTERNAL;
 EncodedJSValue DFG_OPERATION operationToPrimitive(ExecState*, EncodedJSValue) WTF_INTERNAL;
 EncodedJSValue DFG_OPERATION operationStrCat(ExecState*, void*, size_t) WTF_INTERNAL;
-EncodedJSValue DFG_OPERATION operationNewArray(ExecState*, void*, size_t) WTF_INTERNAL;
+EncodedJSValue DFG_OPERATION operationNewArray(ExecState*, Structure*, void*, size_t) WTF_INTERNAL;
 EncodedJSValue DFG_OPERATION operationNewArrayBuffer(ExecState*, size_t, size_t) WTF_INTERNAL;
+EncodedJSValue DFG_OPERATION operationNewEmptyArray(ExecState*, Structure*) WTF_INTERNAL;
+EncodedJSValue DFG_OPERATION operationNewArrayWithSize(ExecState*, Structure*, int32_t) WTF_INTERNAL;
 EncodedJSValue DFG_OPERATION operationNewRegexp(ExecState*, void*) WTF_INTERNAL;
 void DFG_OPERATION operationPutByValStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL;
 void DFG_OPERATION operationPutByValNonStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL;
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index bcb79a9..0bd81ec 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -535,6 +535,12 @@
             break;
         }
             
+        case NewArrayWithSize: {
+            changed |= setPrediction(SpecArray);
+            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+            break;
+        }
+            
         case NewArrayBuffer: {
             changed |= setPrediction(SpecArray);
             break;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 6c6948b..67a22b7 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -1244,6 +1244,21 @@
         m_jit.setupArgumentsWithExecState(arg1);
         return appendCallWithExceptionCheckSetResult(operation, result);
     }
+    JITCompiler::Call callOperation(J_DFGOperation_ESt operation, GPRReg result, Structure* structure)
+    {
+        m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure));
+        return appendCallWithExceptionCheckSetResult(operation, result);
+    }
+    JITCompiler::Call callOperation(J_DFGOperation_EStI operation, GPRReg result, Structure* structure, GPRReg arg2)
+    {
+        m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure), arg2);
+        return appendCallWithExceptionCheckSetResult(operation, result);
+    }
+    JITCompiler::Call callOperation(J_DFGOperation_EStPS operation, GPRReg result, Structure* structure, void* pointer, size_t size)
+    {
+        m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure), TrustedImmPtr(pointer), TrustedImmPtr(size));
+        return appendCallWithExceptionCheckSetResult(operation, result);
+    }
     JITCompiler::Call callOperation(J_DFGOperation_EPS operation, GPRReg result, void* pointer, size_t size)
     {
         m_jit.setupArgumentsWithExecState(TrustedImmPtr(pointer), TrustedImmPtr(size));
@@ -1502,6 +1517,21 @@
         m_jit.setupArgumentsWithExecState(arg1);
         return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
     }
+    JITCompiler::Call callOperation(J_DFGOperation_ESt operation, GPRReg resultTag, GPRReg resultPayload, Structure* structure)
+    {
+        m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure));
+        return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+    }
+    JITCompiler::Call callOperation(J_DFGOperation_EStI operation, GPRReg resultTag, GPRReg resultPayload, Structure* structure, GPRReg arg2)
+    {
+        m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure), arg2);
+        return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+    }
+    JITCompiler::Call callOperation(J_DFGOperation_EStPS operation, GPRReg resultTag, GPRReg resultPayload, Structure* structure, void* pointer, size_t size)
+    {
+        m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure), TrustedImmPtr(pointer), TrustedImmPtr(size));
+        return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+    }
     JITCompiler::Call callOperation(J_DFGOperation_EPS operation, GPRReg resultTag, GPRReg resultPayload, void* pointer, size_t size)
     {
         m_jit.setupArgumentsWithExecState(TrustedImmPtr(pointer), TrustedImmPtr(size));
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index e007a6e..05609ba 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -2975,25 +2975,7 @@
         break;
     }
         
-    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
-        // they'd be contiguous and we could easily tell the C code how to find them.
-        // Ugly! So instead we use the scratchBuffer infrastructure in JSGlobalData. That
-        // way, those 50 functions will share the same scratchBuffer for offloading their
-        // StrCat operands. It's about as good as we can do, unless we start doing
-        // virtual register coalescing to ensure that operands to StrCat get spilled
-        // in exactly the place where StrCat wants them, or else have the StrCat
-        // refer to those operands' SetLocal instructions to force them to spill in
-        // the right place. Basically, any way you cut it, the current approach
-        // probably has the best balance of performance and sensibility in the sense
-        // that it does not increase the complexity of the DFG JIT just to make StrCat
-        // fast and pretty.
-
+    case StrCat: {
         size_t scratchSize = sizeof(EncodedJSValue) * node.numChildren();
         ScratchBuffer* scratchBuffer = m_jit.globalData()->scratchBufferForSize(scratchSize);
         EncodedJSValue* buffer = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0;
@@ -3021,7 +3003,7 @@
         GPRResult resultPayload(this);
         GPRResult2 resultTag(this);
         
-        callOperation(op == StrCat ? operationStrCat : operationNewArray, resultTag.gpr(), resultPayload.gpr(), static_cast<void *>(buffer), node.numChildren());
+        callOperation(operationStrCat, resultTag.gpr(), resultPayload.gpr(), static_cast<void *>(buffer), node.numChildren());
 
         if (scratchSize) {
             GPRTemporary scratch(this);
@@ -3035,6 +3017,75 @@
         break;
     }
 
+    case NewArray: {
+        if (!node.numChildren()) {
+            flushRegisters();
+            GPRResult result(this);
+            GPRResult2 resultTagIgnored(this);
+            callOperation(
+                operationNewEmptyArray, resultTagIgnored.gpr(), result.gpr(),
+                m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure());
+            cellResult(result.gpr(), m_compileIndex);
+            break;
+        }
+        
+        size_t scratchSize = sizeof(EncodedJSValue) * node.numChildren();
+        ScratchBuffer* scratchBuffer = m_jit.globalData()->scratchBufferForSize(scratchSize);
+        EncodedJSValue* buffer = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0;
+        
+        for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++operandIdx) {
+            JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]);
+            GPRReg opTagGPR = operand.tagGPR();
+            GPRReg opPayloadGPR = operand.payloadGPR();
+            operand.use();
+            
+            m_jit.store32(opTagGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
+            m_jit.store32(opPayloadGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
+        }
+        
+        flushRegisters();
+
+        if (scratchSize) {
+            GPRTemporary scratch(this);
+
+            // Tell GC mark phase how much of the scratch buffer is active during call.
+            m_jit.move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratch.gpr());
+            m_jit.storePtr(TrustedImmPtr(scratchSize), scratch.gpr());
+        }
+
+        GPRResult resultPayload(this);
+        GPRResult2 resultTag(this);
+        
+        callOperation(
+            operationNewArray, resultTag.gpr(), resultPayload.gpr(),
+            m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure(),
+            static_cast<void *>(buffer), node.numChildren());
+
+        if (scratchSize) {
+            GPRTemporary scratch(this);
+
+            m_jit.move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratch.gpr());
+            m_jit.storePtr(TrustedImmPtr(0), scratch.gpr());
+        }
+
+        // FIXME: make the callOperation above explicitly return a cell result, or jitAssert the tag is a cell tag.
+        cellResult(resultPayload.gpr(), m_compileIndex, UseChildrenCalledExplicitly);
+        break;
+    }
+
+    case NewArrayWithSize: {
+        SpeculateStrictInt32Operand size(this, node.child1());
+        GPRReg sizeGPR = size.gpr();
+        flushRegisters();
+        GPRResult result(this);
+        GPRResult2 resultTagIgnored(this);
+        callOperation(
+            operationNewArrayWithSize, resultTagIgnored.gpr(), result.gpr(),
+            m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure(), sizeGPR);
+        cellResult(result.gpr(), m_compileIndex);
+        break;
+    }
+        
     case NewArrayBuffer: {
         flushRegisters();
         GPRResult resultPayload(this);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index a6c2835..215f801 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -3035,25 +3035,17 @@
         break;
     }
         
-    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
-        // they'd be contiguous and we could easily tell the C code how to find them.
-        // Ugly! So instead we use the scratchBuffer infrastructure in JSGlobalData. That
-        // way, those 50 functions will share the same scratchBuffer for offloading their
-        // StrCat operands. It's about as good as we can do, unless we start doing
-        // virtual register coalescing to ensure that operands to StrCat get spilled
-        // in exactly the place where StrCat wants them, or else have the StrCat
-        // refer to those operands' SetLocal instructions to force them to spill in
-        // the right place. Basically, any way you cut it, the current approach
-        // probably has the best balance of performance and sensibility in the sense
-        // that it does not increase the complexity of the DFG JIT just to make StrCat
-        // fast and pretty.
-
+        if (!node.numChildren()) {
+            flushRegisters();
+            GPRResult result(this);
+            callOperation(
+                operationNewEmptyArray, result.gpr(),
+                m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure());
+            cellResult(result.gpr(), m_compileIndex);
+            break;
+        }
+        
         size_t scratchSize = sizeof(EncodedJSValue) * node.numChildren();
         ScratchBuffer* scratchBuffer = m_jit.globalData()->scratchBufferForSize(scratchSize);
         EncodedJSValue* buffer = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0;
@@ -3078,7 +3070,58 @@
 
         GPRResult result(this);
         
-        callOperation(op == StrCat ? operationStrCat : operationNewArray, result.gpr(), static_cast<void *>(buffer), node.numChildren());
+        callOperation(
+            operationNewArray, result.gpr(),
+            m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure(),
+            static_cast<void*>(buffer), node.numChildren());
+
+        if (scratchSize) {
+            GPRTemporary scratch(this);
+
+            m_jit.move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratch.gpr());
+            m_jit.storePtr(TrustedImmPtr(0), scratch.gpr());
+        }
+
+        cellResult(result.gpr(), m_compileIndex, UseChildrenCalledExplicitly);
+        break;
+    }
+        
+    case NewArrayWithSize: {
+        SpeculateStrictInt32Operand size(this, node.child1());
+        GPRReg sizeGPR = size.gpr();
+        flushRegisters();
+        GPRResult result(this);
+        callOperation(operationNewArrayWithSize, result.gpr(), m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure(), sizeGPR);
+        cellResult(result.gpr(), m_compileIndex);
+        break;
+    }
+        
+    case StrCat: {
+        size_t scratchSize = sizeof(EncodedJSValue) * node.numChildren();
+        ScratchBuffer* scratchBuffer = m_jit.globalData()->scratchBufferForSize(scratchSize);
+        EncodedJSValue* buffer = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0;
+        
+        for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++operandIdx) {
+            JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]);
+            GPRReg opGPR = operand.gpr();
+            operand.use();
+            
+            m_jit.storePtr(opGPR, buffer + operandIdx);
+        }
+        
+        flushRegisters();
+
+        if (scratchSize) {
+            GPRTemporary scratch(this);
+
+            // Tell GC mark phase how much of the scratch buffer is active during call.
+            m_jit.move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratch.gpr());
+            m_jit.storePtr(TrustedImmPtr(scratchSize), scratch.gpr());
+        }
+
+        GPRResult result(this);
+        
+        callOperation(operationStrCat, result.gpr(), static_cast<void *>(buffer), node.numChildren());
 
         if (scratchSize) {
             GPRTemporary scratch(this);
diff --git a/Source/JavaScriptCore/runtime/JSArray.h b/Source/JavaScriptCore/runtime/JSArray.h
index c1a3a63..52c5913 100644
--- a/Source/JavaScriptCore/runtime/JSArray.h
+++ b/Source/JavaScriptCore/runtime/JSArray.h
@@ -380,7 +380,42 @@
     
         return size;
     }
+
+    inline JSArray* constructArray(ExecState* exec, Structure* arrayStructure, const ArgList& values)
+    {
+        JSGlobalData& globalData = exec->globalData();
+        unsigned length = values.size();
+        JSArray* array = JSArray::tryCreateUninitialized(globalData, arrayStructure, length);
+
+        // FIXME: we should probably throw an out of memory error here, but
+        // when making this change we should check that all clients of this
+        // function will correctly handle an exception being thrown from here.
+        if (!array)
+            CRASH();
+
+        for (unsigned i = 0; i < length; ++i)
+            array->initializeIndex(globalData, i, values.at(i));
+        array->completeInitialization(length);
+        return array;
+    }
     
-    } // namespace JSC
+    inline JSArray* constructArray(ExecState* exec, Structure* arrayStructure, const JSValue* values, unsigned length)
+    {
+        JSGlobalData& globalData = exec->globalData();
+        JSArray* array = JSArray::tryCreateUninitialized(globalData, arrayStructure, length);
+
+        // FIXME: we should probably throw an out of memory error here, but
+        // when making this change we should check that all clients of this
+        // function will correctly handle an exception being thrown from here.
+        if (!array)
+            CRASH();
+
+        for (unsigned i = 0; i < length; ++i)
+            array->initializeIndex(globalData, i, values[i]);
+        array->completeInitialization(length);
+        return array;
+    }
+
+} // namespace JSC
 
 #endif // JSArray_h
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h
index 8fec633..1dcfc63 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObject.h
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h
@@ -445,23 +445,10 @@
     {
         return constructEmptyArray(exec, exec->lexicalGlobalObject(), initialLength);
     }
-
+ 
     inline JSArray* constructArray(ExecState* exec, JSGlobalObject* globalObject, const ArgList& values)
     {
-        JSGlobalData& globalData = exec->globalData();
-        unsigned length = values.size();
-        JSArray* array = JSArray::tryCreateUninitialized(globalData, globalObject->arrayStructure(), length);
-
-        // FIXME: we should probably throw an out of memory error here, but
-        // when making this change we should check that all clients of this
-        // function will correctly handle an exception being thrown from here.
-        if (!array)
-            CRASH();
-
-        for (unsigned i = 0; i < length; ++i)
-            array->initializeIndex(globalData, i, values.at(i));
-        array->completeInitialization(length);
-        return array;
+        return constructArray(exec, globalObject->arrayStructure(), values);
     }
 
     inline JSArray* constructArray(ExecState* exec, const ArgList& values)
@@ -471,19 +458,7 @@
 
     inline JSArray* constructArray(ExecState* exec, JSGlobalObject* globalObject, const JSValue* values, unsigned length)
     {
-        JSGlobalData& globalData = exec->globalData();
-        JSArray* array = JSArray::tryCreateUninitialized(globalData, globalObject->arrayStructure(), length);
-
-        // FIXME: we should probably throw an out of memory error here, but
-        // when making this change we should check that all clients of this
-        // function will correctly handle an exception being thrown from here.
-        if (!array)
-            CRASH();
-
-        for (unsigned i = 0; i < length; ++i)
-            array->initializeIndex(globalData, i, values[i]);
-        array->completeInitialization(length);
-        return array;
+        return constructArray(exec, globalObject->arrayStructure(), values, length);
     }
 
     inline JSArray* constructArray(ExecState* exec, const JSValue* values, unsigned length)