Reduce JSC's binary size
authortzagallo@apple.com <tzagallo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 10 Dec 2019 19:41:40 +0000 (19:41 +0000)
committertzagallo@apple.com <tzagallo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 10 Dec 2019 19:41:40 +0000 (19:41 +0000)
https://bugs.webkit.org/show_bug.cgi?id=204549

Reviewed by Saam Barati.

The Wasm interpreter landed in r251886 and significantly increased JSC's binary size. To try and
offset that, here and some easy fixes that get us ~200kb back:
- We were generating 2 instances of dumpBytecode, at 30kb each. I changed the generator to emit a cpp
  file instead, avoiding the duplication.
- We had 3 instances of computeUsesForBytecodeIndex at 11kb each. I kept the work that depended on the
 template type in the template function and moved the massive switch into computeUsesForBytecodeIndexImpl.
 I also did the same for computeDefsForBytecodeIndex.
- We had 8 instances of emit_compareAndJump(Slow) at 8kb (7kb for Slow) each. I kept the code
  that extracts the data from the bytecode in the template, but moved the bulk of the function
  into emit_compareAndJump(Slow)Impl.

* CMakeLists.txt:
* DerivedSources-output.xcfilelist:
* DerivedSources.make:
* Sources.txt:
* bytecode/BytecodeDumper.cpp:
(JSC::BytecodeDumperBase::printLocationAndOp):
(JSC::BytecodeDumperBase::dumpValue):
* bytecode/BytecodeDumper.h:
(JSC::BytecodeDumperBase::~BytecodeDumperBase):
(JSC::BytecodeDumperBase::dumpValue):
(JSC::BytecodeDumperBase::BytecodeDumperBase):
(JSC::BytecodeDumper::BytecodeDumper):
* bytecode/BytecodeUseDef.cpp: Copied from Source/JavaScriptCore/bytecode/BytecodeUseDef.h.
(JSC::computeUsesForBytecodeIndexImpl):
(JSC::computeDefsForBytecodeIndexImpl):
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeIndex):
(JSC::computeDefsForBytecodeIndex):
* generator/DSL.rb:
* generator/Opcode.rb:
* generator/Options.rb:
* jit/JIT.h:
* jit/JITArithmetic.cpp:
(JSC::JIT::emit_compareAndJump):
(JSC::JIT::emit_compareAndJumpImpl):
(JSC::JIT::emit_compareUnsignedAndJump):
(JSC::JIT::emit_compareUnsignedAndJumpImpl):
(JSC::JIT::emit_compareUnsigned):
(JSC::JIT::emit_compareUnsignedImpl):
(JSC::JIT::emit_compareAndJumpSlow):
(JSC::JIT::emit_compareAndJumpSlowImpl):

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

14 files changed:
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/DerivedSources-output.xcfilelist
Source/JavaScriptCore/DerivedSources.make
Source/JavaScriptCore/Sources.txt
Source/JavaScriptCore/bytecode/BytecodeDumper.cpp
Source/JavaScriptCore/bytecode/BytecodeDumper.h
Source/JavaScriptCore/bytecode/BytecodeUseDef.cpp [new file with mode: 0644]
Source/JavaScriptCore/bytecode/BytecodeUseDef.h
Source/JavaScriptCore/generator/DSL.rb
Source/JavaScriptCore/generator/Opcode.rb
Source/JavaScriptCore/generator/Options.rb
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITArithmetic.cpp

index c9a82a7..3dcce0f 100644 (file)
@@ -214,10 +214,10 @@ set(GENERATOR
 )
 
 add_custom_command(
-    OUTPUT ${JavaScriptCore_DERIVED_SOURCES_DIR}/Bytecodes.h ${JavaScriptCore_DERIVED_SOURCES_DIR}/InitBytecodes.asm ${JavaScriptCore_DERIVED_SOURCES_DIR}/BytecodeStructs.h ${JavaScriptCore_DERIVED_SOURCES_DIR}/BytecodeIndices.h ${JavaScriptCore_DERIVED_SOURCES_DIR}/WasmLLIntGeneratorInlines.h ${JavaScriptCore_DERIVED_SOURCES_DIR}/InitWasm.asm
+    OUTPUT ${JavaScriptCore_DERIVED_SOURCES_DIR}/Bytecodes.h ${JavaScriptCore_DERIVED_SOURCES_DIR}/InitBytecodes.asm ${JavaScriptCore_DERIVED_SOURCES_DIR}/BytecodeStructs.h ${JavaScriptCore_DERIVED_SOURCES_DIR}/BytecodeIndices.h ${JavaScriptCore_DERIVED_SOURCES_DIR}/WasmLLIntGeneratorInlines.h ${JavaScriptCore_DERIVED_SOURCES_DIR}/InitWasm.asm ${JavaScriptCore_DERIVED_SOURCES_DIR}/BytecodeDumperGenerated.cpp
     MAIN_DEPENDENCY ${JAVASCRIPTCORE_DIR}/generator/main.rb
     DEPENDS ${GENERATOR} bytecode/BytecodeList.rb
-    COMMAND ${RUBY_EXECUTABLE} ${JAVASCRIPTCORE_DIR}/generator/main.rb --bytecodes_h ${JavaScriptCore_DERIVED_SOURCES_DIR}/Bytecodes.h --init_bytecodes_asm ${JavaScriptCore_DERIVED_SOURCES_DIR}/InitBytecodes.asm --bytecode_structs_h ${JavaScriptCore_DERIVED_SOURCES_DIR}/BytecodeStructs.h --bytecode_indices_h ${JavaScriptCore_DERIVED_SOURCES_DIR}/BytecodeIndices.h ${JAVASCRIPTCORE_DIR}/bytecode/BytecodeList.rb --wasm_json ${JAVASCRIPTCORE_DIR}/wasm/wasm.json --wasm_llint_generator_h ${JavaScriptCore_DERIVED_SOURCES_DIR}/WasmLLIntGeneratorInlines.h --init_wasm_llint ${JavaScriptCore_DERIVED_SOURCES_DIR}/InitWasm.asm
+    COMMAND ${RUBY_EXECUTABLE} ${JAVASCRIPTCORE_DIR}/generator/main.rb --bytecodes_h ${JavaScriptCore_DERIVED_SOURCES_DIR}/Bytecodes.h --init_bytecodes_asm ${JavaScriptCore_DERIVED_SOURCES_DIR}/InitBytecodes.asm --bytecode_structs_h ${JavaScriptCore_DERIVED_SOURCES_DIR}/BytecodeStructs.h --bytecode_indices_h ${JavaScriptCore_DERIVED_SOURCES_DIR}/BytecodeIndices.h ${JAVASCRIPTCORE_DIR}/bytecode/BytecodeList.rb --wasm_json ${JAVASCRIPTCORE_DIR}/wasm/wasm.json --wasm_llint_generator_h ${JavaScriptCore_DERIVED_SOURCES_DIR}/WasmLLIntGeneratorInlines.h --init_wasm_llint ${JavaScriptCore_DERIVED_SOURCES_DIR}/InitWasm.asm --bytecode_dumper ${JavaScriptCore_DERIVED_SOURCES_DIR}/BytecodeDumperGenerated.cpp
     VERBATIM)
 
 
index a9538d9..057d750 100644 (file)
@@ -1,3 +1,53 @@
+2019-12-10  Tadeu Zagallo  <tzagallo@apple.com>
+
+        Reduce JSC's binary size
+        https://bugs.webkit.org/show_bug.cgi?id=204549
+
+        Reviewed by Saam Barati.
+
+        The Wasm interpreter landed in r251886 and significantly increased JSC's binary size. To try and
+        offset that, here and some easy fixes that get us ~200kb back:
+        - We were generating 2 instances of dumpBytecode, at 30kb each. I changed the generator to emit a cpp
+          file instead, avoiding the duplication.
+        - We had 3 instances of computeUsesForBytecodeIndex at 11kb each. I kept the work that depended on the
+         template type in the template function and moved the massive switch into computeUsesForBytecodeIndexImpl.
+         I also did the same for computeDefsForBytecodeIndex.
+        - We had 8 instances of emit_compareAndJump(Slow) at 8kb (7kb for Slow) each. I kept the code
+          that extracts the data from the bytecode in the template, but moved the bulk of the function
+          into emit_compareAndJump(Slow)Impl.
+
+        * CMakeLists.txt:
+        * DerivedSources-output.xcfilelist:
+        * DerivedSources.make:
+        * Sources.txt:
+        * bytecode/BytecodeDumper.cpp:
+        (JSC::BytecodeDumperBase::printLocationAndOp):
+        (JSC::BytecodeDumperBase::dumpValue):
+        * bytecode/BytecodeDumper.h:
+        (JSC::BytecodeDumperBase::~BytecodeDumperBase):
+        (JSC::BytecodeDumperBase::dumpValue):
+        (JSC::BytecodeDumperBase::BytecodeDumperBase):
+        (JSC::BytecodeDumper::BytecodeDumper):
+        * bytecode/BytecodeUseDef.cpp: Copied from Source/JavaScriptCore/bytecode/BytecodeUseDef.h.
+        (JSC::computeUsesForBytecodeIndexImpl):
+        (JSC::computeDefsForBytecodeIndexImpl):
+        * bytecode/BytecodeUseDef.h:
+        (JSC::computeUsesForBytecodeIndex):
+        (JSC::computeDefsForBytecodeIndex):
+        * generator/DSL.rb:
+        * generator/Opcode.rb:
+        * generator/Options.rb:
+        * jit/JIT.h:
+        * jit/JITArithmetic.cpp:
+        (JSC::JIT::emit_compareAndJump):
+        (JSC::JIT::emit_compareAndJumpImpl):
+        (JSC::JIT::emit_compareUnsignedAndJump):
+        (JSC::JIT::emit_compareUnsignedAndJumpImpl):
+        (JSC::JIT::emit_compareUnsigned):
+        (JSC::JIT::emit_compareUnsignedImpl):
+        (JSC::JIT::emit_compareAndJumpSlow):
+        (JSC::JIT::emit_compareAndJumpSlowImpl):
+
 2019-12-10  Yusuke Suzuki  <ysuzuki@apple.com>
 
         [JSC] Put JSArray in IsoSubspace
index 3d2e7dd..a74450c 100644 (file)
@@ -8,6 +8,7 @@ $(BUILT_PRODUCTS_DIR)/DerivedSources/JavaScriptCore/AsyncGeneratorPrototype.lut.
 $(BUILT_PRODUCTS_DIR)/DerivedSources/JavaScriptCore/BigIntConstructor.lut.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/JavaScriptCore/BigIntPrototype.lut.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/JavaScriptCore/BooleanPrototype.lut.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/JavaScriptCore/BytecodeDumperGenerated.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/JavaScriptCore/BytecodeIndices.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/JavaScriptCore/BytecodeStructs.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/JavaScriptCore/Bytecodes.h
index 3866e2b..e2a36fa 100644 (file)
@@ -218,6 +218,7 @@ BYTECODE_FILES = \
     InitBytecodes.asm \
     WasmLLIntGeneratorInlines.h \
     InitWasm.asm \
+    BytecodeDumperGenerated.cpp \
 #
 BYTECODE_FILES_PATTERNS = $(subst .,%,$(BYTECODE_FILES))
 
@@ -232,6 +233,7 @@ $(BYTECODE_FILES_PATTERNS): $(wildcard $(JavaScriptCore)/generator/*.rb) $(JavaS
     --wasm_json $(JavaScriptCore)/wasm/wasm.json \
     --wasm_llint_generator_h WasmLLIntGeneratorInlines.h \
     --init_wasm_llint InitWasm.asm \
+    --bytecode_dumper BytecodeDumperGenerated.cpp \
 
 # Inspector interfaces
 
index be9a2a8..e118377 100644 (file)
@@ -201,6 +201,7 @@ bytecode/BytecodeIndex.cpp
 bytecode/BytecodeIntrinsicRegistry.cpp
 bytecode/BytecodeLivenessAnalysis.cpp
 bytecode/BytecodeRewriter.cpp
+bytecode/BytecodeUseDef.cpp
 bytecode/CallEdge.cpp
 bytecode/CallLinkInfo.cpp
 bytecode/CallLinkStatus.cpp
@@ -284,6 +285,9 @@ bytecode/VariableWriteFireDetail.cpp
 bytecode/VirtualRegister.cpp
 bytecode/Watchpoint.cpp
 
+// Derived Sources
+BytecodeDumperGenerated.cpp
+
 bytecompiler/BytecodeGenerator.cpp
 bytecompiler/NodesCodegen.cpp
 bytecompiler/ProfileTypeBytecodeFlag.cpp
index 7b41549..bbb7943 100644 (file)
@@ -55,6 +55,30 @@ static ALWAYS_INLINE bool isConstantRegisterIndex(int index)
     return index >= FirstConstantRegisterIndex;
 }
 
+void BytecodeDumperBase::printLocationAndOp(InstructionStream::Offset location, const char* op)
+{
+    m_currentLocation = location;
+    m_out.printf("[%4u] %-18s ", location, op);
+}
+
+void BytecodeDumperBase::dumpValue(VirtualRegister reg)
+{
+    m_out.printf("%s", registerName(reg.offset()).data());
+}
+
+template<typename Traits>
+void BytecodeDumperBase::dumpValue(GenericBoundLabel<Traits> label)
+{
+    InstructionStream::Offset targetOffset = label.target() + m_currentLocation;
+    m_out.print(label.target(), "(->", targetOffset, ")");
+}
+
+template void BytecodeDumperBase::dumpValue(GenericBoundLabel<JSGeneratorTraits>);
+
+#if ENABLE(WEBASSEMBLY)
+template void BytecodeDumperBase::dumpValue(GenericBoundLabel<Wasm::GeneratorTraits>);
+#endif // ENABLE(WEBASSEMBLY)
+
 template<class Block>
 CString BytecodeDumper<Block>::registerName(int r) const
 {
@@ -72,19 +96,6 @@ CString BytecodeDumper<Block>::constantName(int index) const
 }
 
 template<class Block>
-void BytecodeDumper<Block>::printLocationAndOp(InstructionStream::Offset location, const char* op)
-{
-    m_currentLocation = location;
-    m_out.printf("[%4u] %-18s ", location, op);
-}
-
-template<class Block>
-void BytecodeDumper<Block>::dumpValue(VirtualRegister reg)
-{
-    m_out.printf("%s", registerName(reg.offset()).data());
-}
-
-template<class Block>
 void BytecodeDumper<Block>::dumpBytecode(const InstructionStream::Ref& it, const ICStatusMap&)
 {
     ::JSC::dumpBytecode(this, it.offset(), it.ptr());
index 689e022..5be9412 100644 (file)
 
 #pragma once
 
+#include "BytecodeGeneratorBase.h"
 #include "CallLinkInfo.h"
 #include "ICStatusMap.h"
 #include "InstructionStream.h"
-#include "Label.h"
 #include "StructureStubInfo.h"
 
 namespace JSC {
 
 struct Instruction;
 
-template<class Block>
-class BytecodeDumper {
+class BytecodeDumperBase {
 public:
-    static void dumpBytecode(Block*, PrintStream& out, const InstructionStream::Ref& it, const ICStatusMap& = ICStatusMap());
+    virtual ~BytecodeDumperBase()
+    {
+    }
 
     void printLocationAndOp(InstructionStream::Offset location, const char* op);
 
@@ -54,18 +55,30 @@ public:
     void dumpValue(VirtualRegister);
 
     template<typename Traits>
-    void dumpValue(GenericBoundLabel<Traits> label)
+    void dumpValue(GenericBoundLabel<Traits>);
+
+    template<typename T>
+    void dumpValue(T v) { m_out.print(v); }
+
+protected:
+    virtual CString registerName(int) const = 0;
+
+    BytecodeDumperBase(PrintStream& out)
+        : m_out(out)
     {
-        InstructionStream::Offset targetOffset = label.target() + m_currentLocation;
-        m_out.print(label.target(), "(->", targetOffset, ")");
     }
 
+    PrintStream& m_out;
+    InstructionStream::Offset m_currentLocation { 0 };
+};
 
-    template<typename T>
-    void dumpValue(T v) { m_out.print(v); }
+template<class Block>
+class BytecodeDumper : public BytecodeDumperBase {
+public:
+    static void dumpBytecode(Block*, PrintStream& out, const InstructionStream::Ref& it, const ICStatusMap& = ICStatusMap());
 
     BytecodeDumper(Block* block, PrintStream& out)
-        : m_out(out)
+        : BytecodeDumperBase(out)
         , m_block(block)
     {
     }
@@ -77,14 +90,12 @@ protected:
 
     void dumpBytecode(const InstructionStream::Ref& it, const ICStatusMap&);
 
-    PrintStream& m_out;
+    CString registerName(int r) const override;
 
 private:
-    CString registerName(int r) const;
     virtual CString constantName(int index) const;
 
     Block* m_block;
-    InstructionStream::Offset m_currentLocation { 0 };
 };
 
 template<class Block>
diff --git a/Source/JavaScriptCore/bytecode/BytecodeUseDef.cpp b/Source/JavaScriptCore/bytecode/BytecodeUseDef.cpp
new file mode 100644 (file)
index 0000000..eb63293
--- /dev/null
@@ -0,0 +1,497 @@
+/*
+ * Copyright (C) 2013-2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "BytecodeUseDef.h"
+
+namespace JSC {
+
+#define CALL_FUNCTOR(__arg) \
+    functor(__bytecode.m_##__arg);
+
+#define USES_OR_DEFS(__opcode, ...) \
+    case __opcode::opcodeID: { \
+        auto __bytecode = instruction->as<__opcode>(); \
+        WTF_LAZY_FOR_EACH_TERM(CALL_FUNCTOR, __VA_ARGS__) \
+        return; \
+    }
+
+#define USES USES_OR_DEFS
+#define DEFS USES_OR_DEFS
+
+void computeUsesForBytecodeIndexImpl(VirtualRegister scopeRegister, const Instruction* instruction, const Function<void(VirtualRegister)>& functor)
+{
+    OpcodeID opcodeID = instruction->opcodeID();
+
+    auto handleNewArrayLike = [&](auto op) {
+        int base = op.m_argv.offset();
+        for (int i = 0; i < static_cast<int>(op.m_argc); i++)
+            functor(VirtualRegister { base - i });
+    };
+
+    auto handleOpCallLike = [&](auto op) {
+        functor(op.m_callee);
+        int lastArg = -static_cast<int>(op.m_argv) + CallFrame::thisArgumentOffset();
+        for (int i = 0; i < static_cast<int>(op.m_argc); i++)
+            functor(VirtualRegister { lastArg + i });
+        if (opcodeID == op_call_eval)
+            functor(scopeRegister);
+        return;
+    };
+
+    switch (opcodeID) {
+    case op_wide16:
+    case op_wide32:
+        RELEASE_ASSERT_NOT_REACHED();
+
+    // No uses.
+    case op_new_regexp:
+    case op_debug:
+    case op_jneq_ptr:
+    case op_loop_hint:
+    case op_jmp:
+    case op_new_object:
+    case op_new_promise:
+    case op_new_generator:
+    case op_enter:
+    case op_argument_count:
+    case op_catch:
+    case op_profile_control_flow:
+    case op_create_direct_arguments:
+    case op_create_cloned_arguments:
+    case op_get_rest_length:
+    case op_check_traps:
+    case op_get_argument:
+    case op_nop:
+    case op_unreachable:
+    case op_super_sampler_begin:
+    case op_super_sampler_end:
+        return;
+
+    USES(OpGetScope, dst)
+    USES(OpToThis, srcDst)
+    USES(OpCheckTdz, targetVirtualRegister)
+    USES(OpIdentityWithProfile, srcDst)
+    USES(OpProfileType, targetVirtualRegister);
+    USES(OpThrow, value)
+    USES(OpThrowStaticError, message)
+    USES(OpEnd, value)
+    USES(OpRet, value)
+    USES(OpJtrue, condition)
+    USES(OpJfalse, condition)
+    USES(OpJeqNull, value)
+    USES(OpJneqNull, value)
+    USES(OpJundefinedOrNull, value)
+    USES(OpJnundefinedOrNull, value)
+    USES(OpDec, srcDst)
+    USES(OpInc, srcDst)
+    USES(OpLogShadowChickenPrologue, scope)
+
+    USES(OpJless, lhs, rhs)
+    USES(OpJlesseq, lhs, rhs)
+    USES(OpJgreater, lhs, rhs)
+    USES(OpJgreatereq, lhs, rhs)
+    USES(OpJnless, lhs, rhs)
+    USES(OpJnlesseq, lhs, rhs)
+    USES(OpJngreater, lhs, rhs)
+    USES(OpJngreatereq, lhs, rhs)
+    USES(OpJeq, lhs, rhs)
+    USES(OpJneq, lhs, rhs)
+    USES(OpJstricteq, lhs, rhs)
+    USES(OpJnstricteq, lhs, rhs)
+    USES(OpJbelow, lhs, rhs)
+    USES(OpJbeloweq, lhs, rhs)
+    USES(OpSetFunctionName, function, name)
+    USES(OpLogShadowChickenTail, thisValue, scope)
+
+    USES(OpPutByVal, base, property, value)
+    USES(OpPutByValDirect, base, property, value)
+
+    USES(OpPutById, base, value)
+    USES(OpPutToScope, scope, value)
+    USES(OpPutToArguments, arguments, value)
+
+    USES(OpPutByIdWithThis, base, thisValue, value)
+
+    USES(OpPutByValWithThis, base, thisValue, property, value)
+
+    USES(OpPutGetterById, base, accessor)
+    USES(OpPutSetterById, base, accessor)
+
+    USES(OpPutGetterSetterById, base, getter, setter)
+
+    USES(OpPutGetterByVal, base, property, accessor)
+    USES(OpPutSetterByVal, base, property, accessor)
+
+    USES(OpDefineDataProperty, base, property, value, attributes)
+
+    USES(OpDefineAccessorProperty, base, property, getter, setter, attributes)
+
+    USES(OpSpread, argument)
+    USES(OpGetPropertyEnumerator, base)
+    USES(OpGetEnumerableLength, base)
+    USES(OpNewFuncExp, scope)
+    USES(OpNewGeneratorFuncExp, scope)
+    USES(OpNewAsyncFuncExp, scope)
+    USES(OpToIndexString, index)
+    USES(OpCreateLexicalEnvironment, scope, symbolTable, initialValue)
+    USES(OpCreateGeneratorFrameEnvironment, scope, symbolTable, initialValue)
+    USES(OpResolveScope, scope)
+    USES(OpResolveScopeForHoistingFuncDeclInEval, scope)
+    USES(OpGetFromScope, scope)
+    USES(OpToPrimitive, src)
+    USES(OpTryGetById, base)
+    USES(OpGetById, base)
+    USES(OpGetByIdDirect, base)
+    USES(OpInById, base)
+    USES(OpTypeof, value)
+    USES(OpIsEmpty, operand)
+    USES(OpIsUndefined, operand)
+    USES(OpIsUndefinedOrNull, operand)
+    USES(OpIsBoolean, operand)
+    USES(OpIsNumber, operand)
+    USES(OpIsObject, operand)
+    USES(OpIsObjectOrNull, operand)
+    USES(OpIsCellWithType, operand)
+    USES(OpIsFunction, operand)
+    USES(OpToNumber, operand)
+    USES(OpToNumeric, operand)
+    USES(OpToString, operand)
+    USES(OpToObject, operand)
+    USES(OpNegate, operand)
+    USES(OpBitnot, operand)
+    USES(OpEqNull, operand)
+    USES(OpNeqNull, operand)
+    USES(OpNot, operand)
+    USES(OpUnsigned, operand)
+    USES(OpMov, src)
+    USES(OpNewArrayWithSize, length)
+    USES(OpCreateThis, callee)
+    USES(OpCreatePromise, callee)
+    USES(OpCreateGenerator, callee)
+    USES(OpCreateAsyncGenerator, callee)
+    USES(OpDelById, base)
+    USES(OpNewFunc, scope)
+    USES(OpNewAsyncGeneratorFunc, scope)
+    USES(OpNewAsyncGeneratorFuncExp, scope)
+    USES(OpNewGeneratorFunc, scope)
+    USES(OpNewAsyncFunc, scope)
+    USES(OpGetParentScope, scope)
+    USES(OpCreateScopedArguments, scope)
+    USES(OpCreateRest, arraySize)
+    USES(OpGetFromArguments, arguments)
+    USES(OpNewArrayBuffer, immutableButterfly)
+
+    USES(OpHasGenericProperty, base, property)
+    USES(OpHasIndexedProperty, base, property)
+    USES(OpEnumeratorStructurePname, enumerator, index)
+    USES(OpEnumeratorGenericPname, enumerator, index)
+    USES(OpGetByVal, base, property)
+    USES(OpInByVal, base, property)
+    USES(OpOverridesHasInstance, constructor, hasInstanceValue)
+    USES(OpInstanceof, value, prototype)
+    USES(OpAdd, lhs, rhs)
+    USES(OpMul, lhs, rhs)
+    USES(OpDiv, lhs, rhs)
+    USES(OpMod, lhs, rhs)
+    USES(OpSub, lhs, rhs)
+    USES(OpPow, lhs, rhs)
+    USES(OpLshift, lhs, rhs)
+    USES(OpRshift, lhs, rhs)
+    USES(OpUrshift, lhs, rhs)
+    USES(OpBitand, lhs, rhs)
+    USES(OpBitxor, lhs, rhs)
+    USES(OpBitor, lhs, rhs)
+    USES(OpLess, lhs, rhs)
+    USES(OpLesseq, lhs, rhs)
+    USES(OpGreater, lhs, rhs)
+    USES(OpGreatereq, lhs, rhs)
+    USES(OpBelow, lhs, rhs)
+    USES(OpBeloweq, lhs, rhs)
+    USES(OpNstricteq, lhs, rhs)
+    USES(OpStricteq, lhs, rhs)
+    USES(OpNeq, lhs, rhs)
+    USES(OpEq, lhs, rhs)
+    USES(OpPushWithScope, currentScope, newScope)
+    USES(OpGetByIdWithThis, base, thisValue)
+    USES(OpDelByVal, base, property)
+    USES(OpTailCallForwardArguments, callee, thisValue)
+
+    USES(OpGetByValWithThis, base, thisValue, property)
+    USES(OpInstanceofCustom, value, constructor, hasInstanceValue)
+    USES(OpHasStructureProperty, base, property, enumerator)
+    USES(OpConstructVarargs, callee, thisValue, arguments)
+    USES(OpCallVarargs, callee, thisValue, arguments)
+    USES(OpTailCallVarargs, callee, thisValue, arguments)
+
+    USES(OpGetDirectPname, base, property, index, enumerator)
+
+    USES(OpSwitchString, scrutinee)
+    USES(OpSwitchChar, scrutinee)
+    USES(OpSwitchImm, scrutinee)
+
+    USES(OpGetInternalField, base)
+    USES(OpPutInternalField, base, value)
+
+    USES(OpYield, generator, argument)
+
+    case op_new_array_with_spread:
+        handleNewArrayLike(instruction->as<OpNewArrayWithSpread>());
+        return;
+    case op_new_array:
+        handleNewArrayLike(instruction->as<OpNewArray>());
+        return;
+
+    case op_strcat: {
+        auto bytecode = instruction->as<OpStrcat>();
+        int base = bytecode.m_src.offset();
+        for (int i = 0; i < bytecode.m_count; i++)
+            functor(VirtualRegister { base - i });
+        return;
+    }
+
+    case op_construct:
+        handleOpCallLike(instruction->as<OpConstruct>());
+        return;
+    case op_call_eval:
+        handleOpCallLike(instruction->as<OpCallEval>());
+        return;
+    case op_call:
+        handleOpCallLike(instruction->as<OpCall>());
+        return;
+    case op_tail_call:
+        handleOpCallLike(instruction->as<OpTailCall>());
+        return;
+
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+        break;
+    }
+}
+
+void computeDefsForBytecodeIndexImpl(unsigned numVars, const Instruction* instruction, const Function<void(VirtualRegister)>& functor)
+{
+    switch (instruction->opcodeID()) {
+    case op_wide16:
+    case op_wide32:
+        RELEASE_ASSERT_NOT_REACHED();
+
+    // These don't define anything.
+    case op_put_to_scope:
+    case op_end:
+    case op_throw:
+    case op_throw_static_error:
+    case op_check_tdz:
+    case op_debug:
+    case op_ret:
+    case op_jmp:
+    case op_jtrue:
+    case op_jfalse:
+    case op_jeq_null:
+    case op_jneq_null:
+    case op_jundefined_or_null:
+    case op_jnundefined_or_null:
+    case op_jneq_ptr:
+    case op_jless:
+    case op_jlesseq:
+    case op_jgreater:
+    case op_jgreatereq:
+    case op_jnless:
+    case op_jnlesseq:
+    case op_jngreater:
+    case op_jngreatereq:
+    case op_jeq:
+    case op_jneq:
+    case op_jstricteq:
+    case op_jnstricteq:
+    case op_jbelow:
+    case op_jbeloweq:
+    case op_loop_hint:
+    case op_switch_imm:
+    case op_switch_char:
+    case op_switch_string:
+    case op_put_by_id:
+    case op_put_by_id_with_this:
+    case op_put_by_val_with_this:
+    case op_put_getter_by_id:
+    case op_put_setter_by_id:
+    case op_put_getter_setter_by_id:
+    case op_put_getter_by_val:
+    case op_put_setter_by_val:
+    case op_put_by_val:
+    case op_put_by_val_direct:
+    case op_put_internal_field:
+    case op_define_data_property:
+    case op_define_accessor_property:
+    case op_profile_type:
+    case op_profile_control_flow:
+    case op_put_to_arguments:
+    case op_set_function_name:
+    case op_check_traps:
+    case op_log_shadow_chicken_prologue:
+    case op_log_shadow_chicken_tail:
+    case op_yield:
+    case op_nop:
+    case op_unreachable:
+    case op_super_sampler_begin:
+    case op_super_sampler_end:
+#define LLINT_HELPER_OPCODES(opcode, length) case opcode:
+        FOR_EACH_LLINT_OPCODE_EXTENSION(LLINT_HELPER_OPCODES);
+#undef LLINT_HELPER_OPCODES
+        return;
+    // These all have a single destination for the first argument.
+    DEFS(OpArgumentCount, dst)
+    DEFS(OpToIndexString, dst)
+    DEFS(OpGetEnumerableLength, dst)
+    DEFS(OpHasIndexedProperty, dst)
+    DEFS(OpHasStructureProperty, dst)
+    DEFS(OpHasGenericProperty, dst)
+    DEFS(OpGetDirectPname, dst)
+    DEFS(OpGetPropertyEnumerator, dst)
+    DEFS(OpEnumeratorStructurePname, dst)
+    DEFS(OpEnumeratorGenericPname, dst)
+    DEFS(OpGetParentScope, dst)
+    DEFS(OpPushWithScope, dst)
+    DEFS(OpCreateLexicalEnvironment, dst)
+    DEFS(OpCreateGeneratorFrameEnvironment, dst)
+    DEFS(OpResolveScope, dst)
+    DEFS(OpResolveScopeForHoistingFuncDeclInEval, dst)
+    DEFS(OpStrcat, dst)
+    DEFS(OpToPrimitive, dst)
+    DEFS(OpCreateThis, dst)
+    DEFS(OpCreatePromise, dst)
+    DEFS(OpCreateGenerator, dst)
+    DEFS(OpCreateAsyncGenerator, dst)
+    DEFS(OpNewArray, dst)
+    DEFS(OpNewArrayWithSpread, dst)
+    DEFS(OpSpread, dst)
+    DEFS(OpNewArrayBuffer, dst)
+    DEFS(OpNewArrayWithSize, dst)
+    DEFS(OpNewRegexp, dst)
+    DEFS(OpNewFunc, dst)
+    DEFS(OpNewFuncExp, dst)
+    DEFS(OpNewGeneratorFunc, dst)
+    DEFS(OpNewGeneratorFuncExp, dst)
+    DEFS(OpNewAsyncGeneratorFunc, dst)
+    DEFS(OpNewAsyncGeneratorFuncExp, dst)
+    DEFS(OpNewAsyncFunc, dst)
+    DEFS(OpNewAsyncFuncExp, dst)
+    DEFS(OpCallVarargs, dst)
+    DEFS(OpTailCallVarargs, dst)
+    DEFS(OpTailCallForwardArguments, dst)
+    DEFS(OpConstructVarargs, dst)
+    DEFS(OpGetFromScope, dst)
+    DEFS(OpCall, dst)
+    DEFS(OpTailCall, dst)
+    DEFS(OpCallEval, dst)
+    DEFS(OpConstruct, dst)
+    DEFS(OpTryGetById, dst)
+    DEFS(OpGetById, dst)
+    DEFS(OpGetByIdDirect, dst)
+    DEFS(OpGetByIdWithThis, dst)
+    DEFS(OpGetByValWithThis, dst)
+    DEFS(OpOverridesHasInstance, dst)
+    DEFS(OpInstanceof, dst)
+    DEFS(OpInstanceofCustom, dst)
+    DEFS(OpGetByVal, dst)
+    DEFS(OpTypeof, dst)
+    DEFS(OpIdentityWithProfile, srcDst)
+    DEFS(OpIsEmpty, dst)
+    DEFS(OpIsUndefined, dst)
+    USES(OpIsUndefinedOrNull, dst)
+    DEFS(OpIsBoolean, dst)
+    DEFS(OpIsNumber, dst)
+    DEFS(OpIsObject, dst)
+    DEFS(OpIsObjectOrNull, dst)
+    DEFS(OpIsCellWithType, dst)
+    DEFS(OpIsFunction, dst)
+    DEFS(OpInById, dst)
+    DEFS(OpInByVal, dst)
+    DEFS(OpToNumber, dst)
+    DEFS(OpToNumeric, dst)
+    DEFS(OpToString, dst)
+    DEFS(OpToObject, dst)
+    DEFS(OpNegate, dst)
+    DEFS(OpAdd, dst)
+    DEFS(OpMul, dst)
+    DEFS(OpDiv, dst)
+    DEFS(OpMod, dst)
+    DEFS(OpSub, dst)
+    DEFS(OpPow, dst)
+    DEFS(OpLshift, dst)
+    DEFS(OpRshift, dst)
+    DEFS(OpUrshift, dst)
+    DEFS(OpBitand, dst)
+    DEFS(OpBitxor, dst)
+    DEFS(OpBitor, dst)
+    DEFS(OpBitnot, dst)
+    DEFS(OpInc, srcDst)
+    DEFS(OpDec, srcDst)
+    DEFS(OpEq, dst)
+    DEFS(OpNeq, dst)
+    DEFS(OpStricteq, dst)
+    DEFS(OpNstricteq, dst)
+    DEFS(OpLess, dst)
+    DEFS(OpLesseq, dst)
+    DEFS(OpGreater, dst)
+    DEFS(OpGreatereq, dst)
+    DEFS(OpBelow, dst)
+    DEFS(OpBeloweq, dst)
+    DEFS(OpNeqNull, dst)
+    DEFS(OpEqNull, dst)
+    DEFS(OpNot, dst)
+    DEFS(OpMov, dst)
+    DEFS(OpNewObject, dst)
+    DEFS(OpNewPromise, dst)
+    DEFS(OpNewGenerator, dst)
+    DEFS(OpToThis, srcDst)
+    DEFS(OpGetScope, dst)
+    DEFS(OpCreateDirectArguments, dst)
+    DEFS(OpCreateScopedArguments, dst)
+    DEFS(OpCreateClonedArguments, dst)
+    DEFS(OpDelById, dst)
+    DEFS(OpDelByVal, dst)
+    DEFS(OpUnsigned, dst)
+    DEFS(OpGetFromArguments, dst)
+    DEFS(OpGetArgument, dst)
+    DEFS(OpCreateRest, dst)
+    DEFS(OpGetRestLength, dst)
+    DEFS(OpGetInternalField, dst)
+
+    DEFS(OpCatch, exception, thrownValue)
+
+    case op_enter: {
+        for (unsigned i = numVars; i--;)
+            functor(virtualRegisterForLocal(i));
+        return;
+    }
+    }
+}
+
+#undef CALL_FUNCTOR
+#undef USES_OR_DEFS
+#undef USES
+#undef DEFS
+} // namespace JSC
index 28fdb38..b3b00a9 100644 (file)
 
 namespace JSC {
 
-#define CALL_FUNCTOR(__arg) \
-    functor(__bytecode.m_##__arg);
+void computeUsesForBytecodeIndexImpl(VirtualRegister, const Instruction*, const Function<void(VirtualRegister)>&);
+void computeDefsForBytecodeIndexImpl(unsigned, const Instruction*, const Function<void(VirtualRegister)>&);
 
-#define USES_OR_DEFS(__opcode, ...) \
-    case __opcode::opcodeID: { \
-        auto __bytecode = instruction->as<__opcode>(); \
-        WTF_LAZY_FOR_EACH_TERM(CALL_FUNCTOR, __VA_ARGS__) \
-        return; \
-    }
-
-#define USES USES_OR_DEFS
-#define DEFS USES_OR_DEFS
-
-template<typename Block, typename Functor>
-void computeUsesForBytecodeIndex(Block* codeBlock, const Instruction* instruction, const Functor& functor)
+template<typename Block>
+void computeUsesForBytecodeIndex(Block* codeBlock, const Instruction* instruction, const Function<void(VirtualRegister)>& functor)
 {
     OpcodeID opcodeID = instruction->opcodeID();
     if (opcodeID != op_enter && (codeBlock->wasCompiledWithDebuggingOpcodes() || codeBlock->usesEval()) && codeBlock->scopeRegister().isValid())
         functor(codeBlock->scopeRegister());
 
-    auto handleNewArrayLike = [&](auto op) {
-        int base = op.m_argv.offset();
-        for (int i = 0; i < static_cast<int>(op.m_argc); i++)
-            functor(VirtualRegister { base - i });
-    };
-
-    auto handleOpCallLike = [&](auto op) {
-        functor(op.m_callee);
-        int lastArg = -static_cast<int>(op.m_argv) + CallFrame::thisArgumentOffset();
-        for (int i = 0; i < static_cast<int>(op.m_argc); i++)
-            functor(VirtualRegister { lastArg + i });
-        if (opcodeID == op_call_eval)
-            functor(codeBlock->scopeRegister());
-        return;
-    };
-
-    switch (opcodeID) {
-    case op_wide16:
-    case op_wide32:
-        RELEASE_ASSERT_NOT_REACHED();
-
-    // No uses.
-    case op_new_regexp:
-    case op_debug:
-    case op_jneq_ptr:
-    case op_loop_hint:
-    case op_jmp:
-    case op_new_object:
-    case op_new_promise:
-    case op_new_generator:
-    case op_enter:
-    case op_argument_count:
-    case op_catch:
-    case op_profile_control_flow:
-    case op_create_direct_arguments:
-    case op_create_cloned_arguments:
-    case op_get_rest_length:
-    case op_check_traps:
-    case op_get_argument:
-    case op_nop:
-    case op_unreachable:
-    case op_super_sampler_begin:
-    case op_super_sampler_end:
-        return;
-
-    USES(OpGetScope, dst)
-    USES(OpToThis, srcDst)
-    USES(OpCheckTdz, targetVirtualRegister)
-    USES(OpIdentityWithProfile, srcDst)
-    USES(OpProfileType, targetVirtualRegister);
-    USES(OpThrow, value)
-    USES(OpThrowStaticError, message)
-    USES(OpEnd, value)
-    USES(OpRet, value)
-    USES(OpJtrue, condition)
-    USES(OpJfalse, condition)
-    USES(OpJeqNull, value)
-    USES(OpJneqNull, value)
-    USES(OpJundefinedOrNull, value)
-    USES(OpJnundefinedOrNull, value)
-    USES(OpDec, srcDst)
-    USES(OpInc, srcDst)
-    USES(OpLogShadowChickenPrologue, scope)
-
-    USES(OpJless, lhs, rhs)
-    USES(OpJlesseq, lhs, rhs)
-    USES(OpJgreater, lhs, rhs)
-    USES(OpJgreatereq, lhs, rhs)
-    USES(OpJnless, lhs, rhs)
-    USES(OpJnlesseq, lhs, rhs)
-    USES(OpJngreater, lhs, rhs)
-    USES(OpJngreatereq, lhs, rhs)
-    USES(OpJeq, lhs, rhs)
-    USES(OpJneq, lhs, rhs)
-    USES(OpJstricteq, lhs, rhs)
-    USES(OpJnstricteq, lhs, rhs)
-    USES(OpJbelow, lhs, rhs)
-    USES(OpJbeloweq, lhs, rhs)
-    USES(OpSetFunctionName, function, name)
-    USES(OpLogShadowChickenTail, thisValue, scope)
-
-    USES(OpPutByVal, base, property, value)
-    USES(OpPutByValDirect, base, property, value)
-
-    USES(OpPutById, base, value)
-    USES(OpPutToScope, scope, value)
-    USES(OpPutToArguments, arguments, value)
-
-    USES(OpPutByIdWithThis, base, thisValue, value)
-
-    USES(OpPutByValWithThis, base, thisValue, property, value)
-
-    USES(OpPutGetterById, base, accessor)
-    USES(OpPutSetterById, base, accessor)
-
-    USES(OpPutGetterSetterById, base, getter, setter)
-
-    USES(OpPutGetterByVal, base, property, accessor)
-    USES(OpPutSetterByVal, base, property, accessor)
-
-    USES(OpDefineDataProperty, base, property, value, attributes)
-
-    USES(OpDefineAccessorProperty, base, property, getter, setter, attributes)
-
-    USES(OpSpread, argument)
-    USES(OpGetPropertyEnumerator, base)
-    USES(OpGetEnumerableLength, base)
-    USES(OpNewFuncExp, scope)
-    USES(OpNewGeneratorFuncExp, scope)
-    USES(OpNewAsyncFuncExp, scope)
-    USES(OpToIndexString, index)
-    USES(OpCreateLexicalEnvironment, scope, symbolTable, initialValue)
-    USES(OpCreateGeneratorFrameEnvironment, scope, symbolTable, initialValue)
-    USES(OpResolveScope, scope)
-    USES(OpResolveScopeForHoistingFuncDeclInEval, scope)
-    USES(OpGetFromScope, scope)
-    USES(OpToPrimitive, src)
-    USES(OpTryGetById, base)
-    USES(OpGetById, base)
-    USES(OpGetByIdDirect, base)
-    USES(OpInById, base)
-    USES(OpTypeof, value)
-    USES(OpIsEmpty, operand)
-    USES(OpIsUndefined, operand)
-    USES(OpIsUndefinedOrNull, operand)
-    USES(OpIsBoolean, operand)
-    USES(OpIsNumber, operand)
-    USES(OpIsObject, operand)
-    USES(OpIsObjectOrNull, operand)
-    USES(OpIsCellWithType, operand)
-    USES(OpIsFunction, operand)
-    USES(OpToNumber, operand)
-    USES(OpToNumeric, operand)
-    USES(OpToString, operand)
-    USES(OpToObject, operand)
-    USES(OpNegate, operand)
-    USES(OpBitnot, operand)
-    USES(OpEqNull, operand)
-    USES(OpNeqNull, operand)
-    USES(OpNot, operand)
-    USES(OpUnsigned, operand)
-    USES(OpMov, src)
-    USES(OpNewArrayWithSize, length)
-    USES(OpCreateThis, callee)
-    USES(OpCreatePromise, callee)
-    USES(OpCreateGenerator, callee)
-    USES(OpCreateAsyncGenerator, callee)
-    USES(OpDelById, base)
-    USES(OpNewFunc, scope)
-    USES(OpNewAsyncGeneratorFunc, scope)
-    USES(OpNewAsyncGeneratorFuncExp, scope)
-    USES(OpNewGeneratorFunc, scope)
-    USES(OpNewAsyncFunc, scope)
-    USES(OpGetParentScope, scope)
-    USES(OpCreateScopedArguments, scope)
-    USES(OpCreateRest, arraySize)
-    USES(OpGetFromArguments, arguments)
-    USES(OpNewArrayBuffer, immutableButterfly)
-
-    USES(OpHasGenericProperty, base, property)
-    USES(OpHasIndexedProperty, base, property)
-    USES(OpEnumeratorStructurePname, enumerator, index)
-    USES(OpEnumeratorGenericPname, enumerator, index)
-    USES(OpGetByVal, base, property)
-    USES(OpInByVal, base, property)
-    USES(OpOverridesHasInstance, constructor, hasInstanceValue)
-    USES(OpInstanceof, value, prototype)
-    USES(OpAdd, lhs, rhs)
-    USES(OpMul, lhs, rhs)
-    USES(OpDiv, lhs, rhs)
-    USES(OpMod, lhs, rhs)
-    USES(OpSub, lhs, rhs)
-    USES(OpPow, lhs, rhs)
-    USES(OpLshift, lhs, rhs)
-    USES(OpRshift, lhs, rhs)
-    USES(OpUrshift, lhs, rhs)
-    USES(OpBitand, lhs, rhs)
-    USES(OpBitxor, lhs, rhs)
-    USES(OpBitor, lhs, rhs)
-    USES(OpLess, lhs, rhs)
-    USES(OpLesseq, lhs, rhs)
-    USES(OpGreater, lhs, rhs)
-    USES(OpGreatereq, lhs, rhs)
-    USES(OpBelow, lhs, rhs)
-    USES(OpBeloweq, lhs, rhs)
-    USES(OpNstricteq, lhs, rhs)
-    USES(OpStricteq, lhs, rhs)
-    USES(OpNeq, lhs, rhs)
-    USES(OpEq, lhs, rhs)
-    USES(OpPushWithScope, currentScope, newScope)
-    USES(OpGetByIdWithThis, base, thisValue)
-    USES(OpDelByVal, base, property)
-    USES(OpTailCallForwardArguments, callee, thisValue)
-
-    USES(OpGetByValWithThis, base, thisValue, property)
-    USES(OpInstanceofCustom, value, constructor, hasInstanceValue)
-    USES(OpHasStructureProperty, base, property, enumerator)
-    USES(OpConstructVarargs, callee, thisValue, arguments)
-    USES(OpCallVarargs, callee, thisValue, arguments)
-    USES(OpTailCallVarargs, callee, thisValue, arguments)
-
-    USES(OpGetDirectPname, base, property, index, enumerator)
-
-    USES(OpSwitchString, scrutinee)
-    USES(OpSwitchChar, scrutinee)
-    USES(OpSwitchImm, scrutinee)
-
-    USES(OpGetInternalField, base)
-    USES(OpPutInternalField, base, value)
-
-    USES(OpYield, generator, argument)
-
-    case op_new_array_with_spread:
-        handleNewArrayLike(instruction->as<OpNewArrayWithSpread>());
-        return;
-    case op_new_array:
-        handleNewArrayLike(instruction->as<OpNewArray>());
-        return;
-
-    case op_strcat: {
-        auto bytecode = instruction->as<OpStrcat>();
-        int base = bytecode.m_src.offset();
-        for (int i = 0; i < bytecode.m_count; i++)
-            functor(VirtualRegister { base - i });
-        return;
-    }
-
-    case op_construct:
-        handleOpCallLike(instruction->as<OpConstruct>());
-        return;
-    case op_call_eval:
-        handleOpCallLike(instruction->as<OpCallEval>());
-        return;
-    case op_call:
-        handleOpCallLike(instruction->as<OpCall>());
-        return;
-    case op_tail_call:
-        handleOpCallLike(instruction->as<OpTailCall>());
-        return;
-
-    default:
-        RELEASE_ASSERT_NOT_REACHED();
-        break;
-    }
+    computeUsesForBytecodeIndexImpl(codeBlock->scopeRegister(), instruction, functor);
 }
 
-template<typename Block, typename Functor>
-void computeDefsForBytecodeIndex(Block* codeBlock, const Instruction* instruction, const Functor& functor)
+template<typename Block>
+void computeDefsForBytecodeIndex(Block* codeBlock, const Instruction* instruction, const Function<void(VirtualRegister)>& functor)
 {
-    switch (instruction->opcodeID()) {
-    case op_wide16:
-    case op_wide32:
-        RELEASE_ASSERT_NOT_REACHED();
-
-    // These don't define anything.
-    case op_put_to_scope:
-    case op_end:
-    case op_throw:
-    case op_throw_static_error:
-    case op_check_tdz:
-    case op_debug:
-    case op_ret:
-    case op_jmp:
-    case op_jtrue:
-    case op_jfalse:
-    case op_jeq_null:
-    case op_jneq_null:
-    case op_jundefined_or_null:
-    case op_jnundefined_or_null:
-    case op_jneq_ptr:
-    case op_jless:
-    case op_jlesseq:
-    case op_jgreater:
-    case op_jgreatereq:
-    case op_jnless:
-    case op_jnlesseq:
-    case op_jngreater:
-    case op_jngreatereq:
-    case op_jeq:
-    case op_jneq:
-    case op_jstricteq:
-    case op_jnstricteq:
-    case op_jbelow:
-    case op_jbeloweq:
-    case op_loop_hint:
-    case op_switch_imm:
-    case op_switch_char:
-    case op_switch_string:
-    case op_put_by_id:
-    case op_put_by_id_with_this:
-    case op_put_by_val_with_this:
-    case op_put_getter_by_id:
-    case op_put_setter_by_id:
-    case op_put_getter_setter_by_id:
-    case op_put_getter_by_val:
-    case op_put_setter_by_val:
-    case op_put_by_val:
-    case op_put_by_val_direct:
-    case op_put_internal_field:
-    case op_define_data_property:
-    case op_define_accessor_property:
-    case op_profile_type:
-    case op_profile_control_flow:
-    case op_put_to_arguments:
-    case op_set_function_name:
-    case op_check_traps:
-    case op_log_shadow_chicken_prologue:
-    case op_log_shadow_chicken_tail:
-    case op_yield:
-    case op_nop:
-    case op_unreachable:
-    case op_super_sampler_begin:
-    case op_super_sampler_end:
-#define LLINT_HELPER_OPCODES(opcode, length) case opcode:
-        FOR_EACH_LLINT_OPCODE_EXTENSION(LLINT_HELPER_OPCODES);
-#undef LLINT_HELPER_OPCODES
-        return;
-    // These all have a single destination for the first argument.
-    DEFS(OpArgumentCount, dst)
-    DEFS(OpToIndexString, dst)
-    DEFS(OpGetEnumerableLength, dst)
-    DEFS(OpHasIndexedProperty, dst)
-    DEFS(OpHasStructureProperty, dst)
-    DEFS(OpHasGenericProperty, dst)
-    DEFS(OpGetDirectPname, dst)
-    DEFS(OpGetPropertyEnumerator, dst)
-    DEFS(OpEnumeratorStructurePname, dst)
-    DEFS(OpEnumeratorGenericPname, dst)
-    DEFS(OpGetParentScope, dst)
-    DEFS(OpPushWithScope, dst)
-    DEFS(OpCreateLexicalEnvironment, dst)
-    DEFS(OpCreateGeneratorFrameEnvironment, dst)
-    DEFS(OpResolveScope, dst)
-    DEFS(OpResolveScopeForHoistingFuncDeclInEval, dst)
-    DEFS(OpStrcat, dst)
-    DEFS(OpToPrimitive, dst)
-    DEFS(OpCreateThis, dst)
-    DEFS(OpCreatePromise, dst)
-    DEFS(OpCreateGenerator, dst)
-    DEFS(OpCreateAsyncGenerator, dst)
-    DEFS(OpNewArray, dst)
-    DEFS(OpNewArrayWithSpread, dst)
-    DEFS(OpSpread, dst)
-    DEFS(OpNewArrayBuffer, dst)
-    DEFS(OpNewArrayWithSize, dst)
-    DEFS(OpNewRegexp, dst)
-    DEFS(OpNewFunc, dst)
-    DEFS(OpNewFuncExp, dst)
-    DEFS(OpNewGeneratorFunc, dst)
-    DEFS(OpNewGeneratorFuncExp, dst)
-    DEFS(OpNewAsyncGeneratorFunc, dst)
-    DEFS(OpNewAsyncGeneratorFuncExp, dst)
-    DEFS(OpNewAsyncFunc, dst)
-    DEFS(OpNewAsyncFuncExp, dst)
-    DEFS(OpCallVarargs, dst)
-    DEFS(OpTailCallVarargs, dst)
-    DEFS(OpTailCallForwardArguments, dst)
-    DEFS(OpConstructVarargs, dst)
-    DEFS(OpGetFromScope, dst)
-    DEFS(OpCall, dst)
-    DEFS(OpTailCall, dst)
-    DEFS(OpCallEval, dst)
-    DEFS(OpConstruct, dst)
-    DEFS(OpTryGetById, dst)
-    DEFS(OpGetById, dst)
-    DEFS(OpGetByIdDirect, dst)
-    DEFS(OpGetByIdWithThis, dst)
-    DEFS(OpGetByValWithThis, dst)
-    DEFS(OpOverridesHasInstance, dst)
-    DEFS(OpInstanceof, dst)
-    DEFS(OpInstanceofCustom, dst)
-    DEFS(OpGetByVal, dst)
-    DEFS(OpTypeof, dst)
-    DEFS(OpIdentityWithProfile, srcDst)
-    DEFS(OpIsEmpty, dst)
-    DEFS(OpIsUndefined, dst)
-    USES(OpIsUndefinedOrNull, dst)
-    DEFS(OpIsBoolean, dst)
-    DEFS(OpIsNumber, dst)
-    DEFS(OpIsObject, dst)
-    DEFS(OpIsObjectOrNull, dst)
-    DEFS(OpIsCellWithType, dst)
-    DEFS(OpIsFunction, dst)
-    DEFS(OpInById, dst)
-    DEFS(OpInByVal, dst)
-    DEFS(OpToNumber, dst)
-    DEFS(OpToNumeric, dst)
-    DEFS(OpToString, dst)
-    DEFS(OpToObject, dst)
-    DEFS(OpNegate, dst)
-    DEFS(OpAdd, dst)
-    DEFS(OpMul, dst)
-    DEFS(OpDiv, dst)
-    DEFS(OpMod, dst)
-    DEFS(OpSub, dst)
-    DEFS(OpPow, dst)
-    DEFS(OpLshift, dst)
-    DEFS(OpRshift, dst)
-    DEFS(OpUrshift, dst)
-    DEFS(OpBitand, dst)
-    DEFS(OpBitxor, dst)
-    DEFS(OpBitor, dst)
-    DEFS(OpBitnot, dst)
-    DEFS(OpInc, srcDst)
-    DEFS(OpDec, srcDst)
-    DEFS(OpEq, dst)
-    DEFS(OpNeq, dst)
-    DEFS(OpStricteq, dst)
-    DEFS(OpNstricteq, dst)
-    DEFS(OpLess, dst)
-    DEFS(OpLesseq, dst)
-    DEFS(OpGreater, dst)
-    DEFS(OpGreatereq, dst)
-    DEFS(OpBelow, dst)
-    DEFS(OpBeloweq, dst)
-    DEFS(OpNeqNull, dst)
-    DEFS(OpEqNull, dst)
-    DEFS(OpNot, dst)
-    DEFS(OpMov, dst)
-    DEFS(OpNewObject, dst)
-    DEFS(OpNewPromise, dst)
-    DEFS(OpNewGenerator, dst)
-    DEFS(OpToThis, srcDst)
-    DEFS(OpGetScope, dst)
-    DEFS(OpCreateDirectArguments, dst)
-    DEFS(OpCreateScopedArguments, dst)
-    DEFS(OpCreateClonedArguments, dst)
-    DEFS(OpDelById, dst)
-    DEFS(OpDelByVal, dst)
-    DEFS(OpUnsigned, dst)
-    DEFS(OpGetFromArguments, dst)
-    DEFS(OpGetArgument, dst)
-    DEFS(OpCreateRest, dst)
-    DEFS(OpGetRestLength, dst)
-    DEFS(OpGetInternalField, dst)
-
-    DEFS(OpCatch, exception, thrownValue)
-
-    case op_enter: {
-        for (unsigned i = codeBlock->numVars(); i--;)
-            functor(virtualRegisterForLocal(i));
-        return;
-    }
-    }
+    computeDefsForBytecodeIndexImpl(codeBlock->numVars(), instruction, functor);
 }
 
 #undef CALL_FUNCTOR
index a78b19d..4a8b1e5 100644 (file)
@@ -108,6 +108,7 @@ module DSL
 
         write_bytecodes(bytecode_list, options[:bytecodes_filename])
         write_bytecode_structs(bytecode_list, options[:bytecode_structs_filename])
+        write_bytecode_dumper(bytecode_list, options[:bytecode_dumper_filename])
         write_bytecodes_init(options[:init_asm_filename], bytecode_list)
         write_indices(bytecode_list, options[:bytecode_indices_filename])
         write_llint_generator(options[:wasm_llint_generator_filename], bytecode_list, @wasm_json)
@@ -127,8 +128,6 @@ module DSL
 
     def self.write_bytecode_structs(bytecode_list, bytecode_structs_filename)
         GeneratedFile::create(bytecode_structs_filename, bytecode_list) do |template|
-            opcodes = opcodes_for(:emit_in_structs_file)
-
             template.prefix = <<-EOF
 #pragma once
 
@@ -144,12 +143,43 @@ module DSL
 #include "ToThisStatus.h"
 
 namespace JSC {
+
+void dumpBytecode(BytecodeDumperBase* dumper, InstructionStream::Offset, const Instruction*);
+
+#if ENABLE(WEBASSEMBLY)
+void dumpWasm(BytecodeDumperBase* dumper, InstructionStream::Offset, const Instruction*);
+#endif // ENABLE(WEBASSEMBLY)
+
+EOF
+
+            template.body = <<-EOF
+#{opcodes_filter { |s| s.config[:emit_in_structs_file] && !s.is_wasm? }.map(&:struct).join("\n")}
+
+#if ENABLE(WEBASSEMBLY)
+#{opcodes_filter { |s| s.config[:emit_in_structs_file] && s.is_wasm? }.map(&:struct).join("\n")}
+#endif // ENABLE(WEBASSEMBLY)
+EOF
+            template.suffix = "} // namespace JSC"
+        end
+    end
+
+    def self.write_bytecode_dumper(bytecode_list, bytecode_dumper_filename)
+        GeneratedFile::create(bytecode_dumper_filename, bytecode_list) do |template|
+            template.prefix = <<-EOF
+#include "config.h"
+#include "BytecodeDumper.h"
+
+#include "BytecodeStructs.h"
+
+namespace JSC {
 EOF
 
             template.body = <<-EOF
-#{opcodes.map(&:struct).join("\n")}
 #{Opcode.dump_bytecode(:Bytecode, :JSOpcodeTraits, opcodes_filter { |s| s.config[:emit_in_structs_file] && !s.is_wasm? })}
+
+#if ENABLE(WEBASSEMBLY)
 #{Opcode.dump_bytecode(:Wasm, :WasmOpcodeTraits, opcodes_filter { |s| s.is_wasm? })}
+#endif // ENABLE(WEBASSEMBLY)
 EOF
             template.suffix = "} // namespace JSC"
         end
index 434c4fa..dab8686 100644 (file)
@@ -223,8 +223,7 @@ EOF
 
     def dumper
         <<-EOF
-    template<typename Block>
-    void dump(BytecodeDumper<Block>* dumper, InstructionStream::Offset __location, int __sizeShiftAmount)
+    void dump(BytecodeDumperBase* dumper, InstructionStream::Offset __location, int __sizeShiftAmount)
     {
         dumper->printLocationAndOp(__location, &"**#{@name}"[2 - __sizeShiftAmount]);
 #{print_args { |arg|
@@ -326,8 +325,7 @@ EOF
 
     def self.dump_bytecode(name, opcode_traits, opcodes)
         <<-EOF.chomp
-template<typename BytecodeDumper>
-static void dump#{name}(BytecodeDumper* dumper, InstructionStream::Offset __location, const Instruction* __instruction)
+void dump#{name}(BytecodeDumperBase* dumper, InstructionStream::Offset __location, const Instruction* __instruction)
 {
     switch (__instruction->opcodeID<#{opcode_traits}>()) {
 #{opcodes.map { |op|
index a829220..ff82217 100644 (file)
@@ -56,6 +56,10 @@ $config = {
         long: "--init_wasm_llint FILE",
         desc: "generate Wasm bytecodes init FILE",
     },
+    bytecode_dumper_filename: {
+        long: "--bytecode_dumper FILE",
+        desc: "generate bytecode dumper FILE",
+    },
 };
 
 module Options
index 017bc59..28032a2 100644 (file)
@@ -469,12 +469,16 @@ namespace JSC {
 
         template<typename Op>
         void emit_compareAndJump(const Instruction*, RelationalCondition);
+        void emit_compareAndJumpImpl(int op1, int op2, unsigned target, RelationalCondition);
         template<typename Op>
         void emit_compareUnsigned(const Instruction*, RelationalCondition);
+        void emit_compareUnsignedImpl(int dst, int op1, int op2, RelationalCondition);
         template<typename Op>
         void emit_compareUnsignedAndJump(const Instruction*, RelationalCondition);
+        void emit_compareUnsignedAndJumpImpl(int op1, int op2, unsigned target, RelationalCondition);
         template<typename Op>
         void emit_compareAndJumpSlow(const Instruction*, DoubleCondition, size_t (JIT_OPERATION *operation)(JSGlobalObject*, EncodedJSValue, EncodedJSValue), bool invert, Vector<SlowCaseEntry>::iterator&);
+        void emit_compareAndJumpSlowImpl(int op1, int op2, unsigned target, size_t instructionSize, DoubleCondition, size_t (JIT_OPERATION *operation)(JSGlobalObject*, EncodedJSValue, EncodedJSValue), bool invert, Vector<SlowCaseEntry>::iterator&);
         
         void assertStackPointerOffset();
 
index bb635f8..3458744 100644 (file)
@@ -171,15 +171,20 @@ void JIT::emit_op_unsigned(const Instruction* currentInstruction)
 template<typename Op>
 void JIT::emit_compareAndJump(const Instruction* instruction, RelationalCondition condition)
 {
+    auto bytecode = instruction->as<Op>();
+    int op1 = bytecode.m_lhs.offset();
+    int op2 = bytecode.m_rhs.offset();
+    unsigned target = jumpTarget(instruction, bytecode.m_targetLabel);
+    emit_compareAndJumpImpl(op1, op2, target, condition);
+}
+
+void JIT::emit_compareAndJumpImpl(int op1, int op2, unsigned target, RelationalCondition condition)
+{
     // We generate inline code for the following cases in the fast path:
     // - int immediate to constant int immediate
     // - constant int immediate to int immediate
     // - int immediate to int immediate
 
-    auto bytecode = instruction->as<Op>();
-    int op1 = bytecode.m_lhs.offset();
-    int op2 = bytecode.m_rhs.offset();
-    unsigned target = jumpTarget(instruction, bytecode.m_targetLabel);
     bool disallowAllocation = false;
     if (isOperandConstantChar(op1)) {
         emitGetVirtualRegister(op2, regT0);
@@ -228,6 +233,11 @@ void JIT::emit_compareUnsignedAndJump(const Instruction* instruction, Relational
     int op1 = bytecode.m_lhs.offset();
     int op2 = bytecode.m_rhs.offset();
     unsigned target = jumpTarget(instruction, bytecode.m_targetLabel);
+    emit_compareUnsignedAndJumpImpl(op1, op2, target, condition);
+}
+
+void JIT::emit_compareUnsignedAndJumpImpl(int op1, int op2, unsigned target, RelationalCondition condition)
+{
     if (isOperandConstantInt(op2)) {
         emitGetVirtualRegister(op1, regT0);
         int32_t op2imm = getOperandConstantInt(op2);
@@ -249,6 +259,11 @@ void JIT::emit_compareUnsigned(const Instruction* instruction, RelationalConditi
     int dst = bytecode.m_dst.offset();
     int op1 = bytecode.m_lhs.offset();
     int op2 = bytecode.m_rhs.offset();
+    emit_compareUnsignedImpl(dst, op1, op2, condition);
+}
+
+void JIT::emit_compareUnsignedImpl(int dst, int op1, int op2, RelationalCondition condition)
+{
     if (isOperandConstantInt(op2)) {
         emitGetVirtualRegister(op1, regT0);
         int32_t op2imm = getOperandConstantInt(op2);
@@ -272,6 +287,11 @@ void JIT::emit_compareAndJumpSlow(const Instruction* instruction, DoubleConditio
     int op1 = bytecode.m_lhs.offset();
     int op2 = bytecode.m_rhs.offset();
     unsigned target = jumpTarget(instruction, bytecode.m_targetLabel);
+    emit_compareAndJumpSlowImpl(op1, op2, target, instruction->size(), condition, operation, invert, iter);
+}
+
+void JIT::emit_compareAndJumpSlowImpl(int op1, int op2, unsigned target, size_t instructionSize, DoubleCondition condition, size_t (JIT_OPERATION *operation)(JSGlobalObject*, EncodedJSValue, EncodedJSValue), bool invert, Vector<SlowCaseEntry>::iterator& iter)
+{
 
     // We generate inline code for the following cases in the slow path:
     // - floating-point number to constant int immediate
@@ -302,7 +322,7 @@ void JIT::emit_compareAndJumpSlow(const Instruction* instruction, DoubleConditio
 
             emitJumpSlowToHot(branchDouble(condition, fpRegT0, fpRegT1), target);
 
-            emitJumpSlowToHot(jump(), instruction->size());
+            emitJumpSlowToHot(jump(), instructionSize);
 
             fail1.link(this);
         }
@@ -328,7 +348,7 @@ void JIT::emit_compareAndJumpSlow(const Instruction* instruction, DoubleConditio
 
             emitJumpSlowToHot(branchDouble(condition, fpRegT0, fpRegT1), target);
 
-            emitJumpSlowToHot(jump(), instruction->size());
+            emitJumpSlowToHot(jump(), instructionSize);
 
             fail1.link(this);
         }
@@ -352,7 +372,7 @@ void JIT::emit_compareAndJumpSlow(const Instruction* instruction, DoubleConditio
 
         emitJumpSlowToHot(branchDouble(condition, fpRegT0, fpRegT1), target);
 
-        emitJumpSlowToHot(jump(), instruction->size());
+        emitJumpSlowToHot(jump(), instructionSize);
 
         fail1.link(this);
         fail2.link(this);