2011-06-14 Oliver Hunt <oliver@apple.com>
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 14 Jun 2011 23:39:25 +0000 (23:39 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 14 Jun 2011 23:39:25 +0000 (23:39 +0000)
        Reviewed by Gavin Barraclough.

        Constant array literals result in unnecessarily large amounts of code
        https://bugs.webkit.org/show_bug.cgi?id=62658

        Add a new version of op_new_array that simply copies values from a buffer
        we hang off of the CodeBlock, rather than generating code to place each
        entry into the registerfile, and then copying it from the registerfile into
        the array.  This is a slight improvement on some sunspider tests, but no
        measurable overall change.  That's okay though as our goal was to reduce
        code size without hurting performance.

        * bytecode/CodeBlock.cpp:
        (JSC::CodeBlock::dump):
        * bytecode/CodeBlock.h:
        (JSC::CodeBlock::addImmediateBuffer):
        (JSC::CodeBlock::immediateBuffer):
        * bytecode/Opcode.h:
        * bytecompiler/BytecodeGenerator.cpp:
        (JSC::BytecodeGenerator::addImmediateBuffer):
        (JSC::BytecodeGenerator::emitNewArray):
        * bytecompiler/BytecodeGenerator.h:
        * bytecompiler/NodesCodegen.cpp:
        (JSC::ArrayNode::emitBytecode):
        * interpreter/Interpreter.cpp:
        (JSC::Interpreter::privateExecute):
        * jit/JIT.cpp:
        (JSC::JIT::privateCompileMainPass):
        * jit/JIT.h:
        * jit/JITOpcodes.cpp:
        (JSC::JIT::emit_op_new_array):
        (JSC::JIT::emit_op_new_array_buffer):
        * jit/JITOpcodes32_64.cpp:
        * jit/JITStubs.cpp:
        (JSC::DEFINE_STUB_FUNCTION):
        * jit/JITStubs.h:

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

14 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/bytecode/Opcode.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/interpreter/Interpreter.cpp
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITOpcodes.cpp
Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
Source/JavaScriptCore/jit/JITStubs.cpp
Source/JavaScriptCore/jit/JITStubs.h

index a719a6e..0ce2f8c 100644 (file)
@@ -1,3 +1,42 @@
+2011-06-14  Oliver Hunt  <oliver@apple.com>
+
+        Reviewed by Gavin Barraclough.
+
+        Constant array literals result in unnecessarily large amounts of code
+        https://bugs.webkit.org/show_bug.cgi?id=62658
+
+        Add a new version of op_new_array that simply copies values from a buffer
+        we hang off of the CodeBlock, rather than generating code to place each
+        entry into the registerfile, and then copying it from the registerfile into
+        the array.  This is a slight improvement on some sunspider tests, but no
+        measurable overall change.  That's okay though as our goal was to reduce
+        code size without hurting performance.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dump):
+        * bytecode/CodeBlock.h:
+        (JSC::CodeBlock::addImmediateBuffer):
+        (JSC::CodeBlock::immediateBuffer):
+        * bytecode/Opcode.h:
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::addImmediateBuffer):
+        (JSC::BytecodeGenerator::emitNewArray):
+        * bytecompiler/BytecodeGenerator.h:
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::ArrayNode::emitBytecode):
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::privateExecute):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        * jit/JIT.h:
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_new_array):
+        (JSC::JIT::emit_op_new_array_buffer):
+        * jit/JITOpcodes32_64.cpp:
+        * jit/JITStubs.cpp:
+        (JSC::DEFINE_STUB_FUNCTION):
+        * jit/JITStubs.h:
+
 2011-06-14  Sheriff Bot  <webkit.review.bot@gmail.com>
 
         Unreviewed, rolling out r88841.
index 71fae6b..d9e2355 100644 (file)
@@ -530,6 +530,13 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
             printf("[%4d] new_array\t %s, %s, %d\n", location, registerName(exec, dst).data(), registerName(exec, argv).data(), argc);
             break;
         }
+        case op_new_array_buffer: {
+            int dst = (++it)->u.operand;
+            int argv = (++it)->u.operand;
+            int argc = (++it)->u.operand;
+            printf("[%4d] new_array_buffer %s, %d, %d\n", location, registerName(exec, dst).data(), argv, argc);
+            break;
+        }
         case op_new_regexp: {
             int r0 = (++it)->u.operand;
             int re0 = (++it)->u.operand;
index fe44f8f..c271415 100644 (file)
@@ -456,6 +456,20 @@ namespace JSC {
         }
         RegExp* regexp(int index) const { ASSERT(m_rareData); return m_rareData->m_regexps[index].get(); }
 
+        unsigned addImmediateBuffer(unsigned length)
+        {
+            createRareDataIfNecessary();
+            unsigned size = m_rareData->m_immediateBuffers.size();
+            m_rareData->m_immediateBuffers.append(Vector<JSValue>(length));
+            return size;
+        }
+
+        JSValue* immediateBuffer(unsigned index)
+        {
+            ASSERT(m_rareData);
+            return m_rareData->m_immediateBuffers[index].data();
+        }
+
         JSGlobalObject* globalObject() { return m_globalObject.get(); }
 
         // Jump Tables
@@ -559,6 +573,9 @@ namespace JSC {
             // Rare Constants
             Vector<WriteBarrier<RegExp> > m_regexps;
 
+            // Buffers used for large array literals
+            Vector<Vector<JSValue> > m_immediateBuffers;
+            
             // Jump Tables
             Vector<SimpleJumpTable> m_immediateSwitchJumpTables;
             Vector<SimpleJumpTable> m_characterSwitchJumpTables;
index 8082ae0..18902eb 100644 (file)
@@ -49,6 +49,7 @@ namespace JSC {
         \
         macro(op_new_object, 2) \
         macro(op_new_array, 4) \
+        macro(op_new_array_buffer, 4) \
         macro(op_new_regexp, 3) \
         macro(op_mov, 3) \
         \
index 235c3da..b53544c 100644 (file)
@@ -1541,8 +1541,44 @@ RegisterID* BytecodeGenerator::emitNewObject(RegisterID* dst)
     return dst;
 }
 
-RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elements)
+unsigned BytecodeGenerator::addImmediateBuffer(unsigned length)
 {
+    return m_codeBlock->addImmediateBuffer(length);
+}
+
+RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elements, unsigned length)
+{
+#if !ASSERT_DISABLED
+    unsigned checkLength = 0;
+#endif
+    bool hadNonNumber = false;
+    if (length) {
+        for (ElementNode* n = elements; n; n = n->next()) {
+            if (!n->value()->isNumber()) {
+                hadNonNumber = true;
+                break;
+            }
+            if (n->elision())
+                break;
+#if !ASSERT_DISABLED
+            checkLength++;
+#endif
+        }
+        if (!hadNonNumber) {
+            ASSERT(length == checkLength);
+            unsigned immediateBufferIndex = addImmediateBuffer(length);
+            JSValue* immediateBuffer = m_codeBlock->immediateBuffer(immediateBufferIndex);
+            unsigned index = 0;
+            for (ElementNode* n = elements; index < length; n = n->next())
+                immediateBuffer[index++] = jsNumber(static_cast<NumberNode*>(n->value())->value());
+            emitOpcode(op_new_array_buffer);
+            instructions().append(dst->index());
+            instructions().append(immediateBufferIndex);
+            instructions().append(length);
+            return dst;
+        }
+    }
+
     Vector<RefPtr<RegisterID>, 16> argv;
     for (ElementNode* n = elements; n; n = n->next()) {
         if (n->elision())
index b1230e6..608e854 100644 (file)
@@ -285,7 +285,7 @@ namespace JSC {
         RegisterID* emitUnaryNoDstOp(OpcodeID, RegisterID* src);
 
         RegisterID* emitNewObject(RegisterID* dst);
-        RegisterID* emitNewArray(RegisterID* dst, ElementNode*); // stops at first elision
+        RegisterID* emitNewArray(RegisterID* dst, ElementNode*, unsigned length); // stops at first elision
 
         RegisterID* emitNewFunction(RegisterID* dst, FunctionBodyNode* body);
         RegisterID* emitLazyNewFunction(RegisterID* dst, FunctionBodyNode* body);
@@ -477,6 +477,8 @@ namespace JSC {
         RegisterID* addConstantValue(JSValue);
         unsigned addRegExp(RegExp*);
 
+        unsigned addImmediateBuffer(unsigned length);
+        
         FunctionExecutable* makeFunction(ExecState* exec, FunctionBodyNode* body)
         {
             return FunctionExecutable::create(exec, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
index b9d1c0a..a7abadf 100644 (file)
@@ -171,9 +171,9 @@ RegisterID* ArrayNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds
     }
 
     if (!firstPutElement && !m_elision)
-        return generator.emitNewArray(generator.finalDestination(dst), m_element);
+        return generator.emitNewArray(generator.finalDestination(dst), m_element, length);
 
-    RefPtr<RegisterID> array = generator.emitNewArray(generator.tempDestination(dst), m_element);
+    RefPtr<RegisterID> array = generator.emitNewArray(generator.tempDestination(dst), m_element, length);
 
     for (ElementNode* n = firstPutElement; n; n = n->next()) {
         RegisterID* value = generator.emitNode(n->value());
index e5b71c1..89276d8 100644 (file)
@@ -1554,6 +1554,22 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
         vPC += OPCODE_LENGTH(op_new_array);
         NEXT_INSTRUCTION();
     }
+    DEFINE_OPCODE(op_new_array_buffer) {
+        /* new_array_buffer dst(r) index(n) argCount(n)
+         
+         Constructs a new Array instance using the original
+         constructor, and puts the result in register dst.
+         The array be initialized with the values from immediateBuffer[index]
+         */
+        int dst = vPC[1].u.operand;
+        int firstArg = vPC[2].u.operand;
+        int argCount = vPC[3].u.operand;
+        ArgList args(codeBlock->immediateBuffer(firstArg), argCount);
+        callFrame->uncheckedR(dst) = JSValue(constructArray(callFrame, args));
+        
+        vPC += OPCODE_LENGTH(op_new_array);
+        NEXT_INSTRUCTION();
+    }
     DEFINE_OPCODE(op_new_regexp) {
         /* new_regexp dst(r) regExp(re)
 
index 853de69..5d8aae1 100644 (file)
@@ -272,6 +272,7 @@ void JIT::privateCompileMainPass()
         DEFINE_OP(op_neq)
         DEFINE_OP(op_neq_null)
         DEFINE_OP(op_new_array)
+        DEFINE_OP(op_new_array_buffer)
         DEFINE_OP(op_new_func)
         DEFINE_OP(op_new_func_exp)
         DEFINE_OP(op_new_object)
index 0833251..a2a1751 100644 (file)
@@ -778,6 +778,7 @@ namespace JSC {
         void emit_op_neq(Instruction*);
         void emit_op_neq_null(Instruction*);
         void emit_op_new_array(Instruction*);
+        void emit_op_new_array_buffer(Instruction*);
         void emit_op_new_func(Instruction*);
         void emit_op_new_func_exp(Instruction*);
         void emit_op_new_object(Instruction*);
index bbb161e..9f0f552 100644 (file)
@@ -579,14 +579,6 @@ void JIT::emit_op_ret_object_or_this(Instruction* currentInstruction)
     ret();
 }
 
-void JIT::emit_op_new_array(Instruction* currentInstruction)
-{
-    JITStubCall stubCall(this, cti_op_new_array);
-    stubCall.addArgument(Imm32(currentInstruction[2].u.operand));
-    stubCall.addArgument(Imm32(currentInstruction[3].u.operand));
-    stubCall.call(currentInstruction[1].u.operand);
-}
-
 void JIT::emit_op_resolve(Instruction* currentInstruction)
 {
     JITStubCall stubCall(this, cti_op_resolve);
@@ -1734,6 +1726,22 @@ void JIT::emit_op_new_func(Instruction* currentInstruction)
         lazyJump.link(this);
 }
 
+void JIT::emit_op_new_array(Instruction* currentInstruction)
+{
+    JITStubCall stubCall(this, cti_op_new_array);
+    stubCall.addArgument(Imm32(currentInstruction[2].u.operand));
+    stubCall.addArgument(Imm32(currentInstruction[3].u.operand));
+    stubCall.call(currentInstruction[1].u.operand);
+}
+
+void JIT::emit_op_new_array_buffer(Instruction* currentInstruction)
+{
+    JITStubCall stubCall(this, cti_op_new_array_buffer);
+    stubCall.addArgument(Imm32(currentInstruction[2].u.operand));
+    stubCall.addArgument(Imm32(currentInstruction[3].u.operand));
+    stubCall.call(currentInstruction[1].u.operand);
+}
+
 } // namespace JSC
 
 #endif // ENABLE(JIT)
index 9a34660..e8fe100 100644 (file)
@@ -733,14 +733,6 @@ void JIT::emit_op_tear_off_arguments(Instruction* currentInstruction)
     argsNotCreated.link(this);
 }
 
-void JIT::emit_op_new_array(Instruction* currentInstruction)
-{
-    JITStubCall stubCall(this, cti_op_new_array);
-    stubCall.addArgument(Imm32(currentInstruction[2].u.operand));
-    stubCall.addArgument(Imm32(currentInstruction[3].u.operand));
-    stubCall.call(currentInstruction[1].u.operand);
-}
-
 void JIT::emit_op_resolve(Instruction* currentInstruction)
 {
     JITStubCall stubCall(this, cti_op_resolve);
index 2f5c666..95e4da7 100644 (file)
@@ -2260,6 +2260,14 @@ DEFINE_STUB_FUNCTION(JSObject*, op_new_array)
     return constructArray(stackFrame.callFrame, argList);
 }
 
+DEFINE_STUB_FUNCTION(JSObject*, op_new_array_buffer)
+{
+    STUB_INIT_STACK_FRAME(stackFrame);
+    
+    ArgList argList(stackFrame.callFrame->codeBlock()->immediateBuffer(stackFrame.args[0].int32()), stackFrame.args[1].int32());
+    return constructArray(stackFrame.callFrame, argList);
+}
+
 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve)
 {
     STUB_INIT_STACK_FRAME(stackFrame);
index 624b6be..75fbb08 100644 (file)
@@ -380,6 +380,7 @@ extern "C" {
     EncodedJSValue JIT_STUB cti_op_urshift(STUB_ARGS_DECLARATION);
     EncodedJSValue JIT_STUB cti_to_object(STUB_ARGS_DECLARATION);
     JSObject* JIT_STUB cti_op_new_array(STUB_ARGS_DECLARATION);
+    JSObject* JIT_STUB cti_op_new_array_buffer(STUB_ARGS_DECLARATION);
     JSObject* JIT_STUB cti_op_new_func(STUB_ARGS_DECLARATION);
     JSObject* JIT_STUB cti_op_new_func_exp(STUB_ARGS_DECLARATION);
     JSObject* JIT_STUB cti_op_new_object(STUB_ARGS_DECLARATION);