Title: [217526] trunk/Source
Revision
217526
Author
[email protected]
Date
2017-05-28 01:12:09 -0700 (Sun, 28 May 2017)

Log Message

Implement a faster Interpreter::getOpcodeID().
https://bugs.webkit.org/show_bug.cgi?id=172669

Reviewed by Saam Barati.

Source/_javascript_Core:

We can implement Interpreter::getOpcodeID() without a hash table lookup by always
embedding the OpcodeID in the 32-bit word just before the start of the LLInt
handler code that executes each opcode.  getOpcodeID() can therefore just read
the 32-bits before the opcode address to get its OpcodeID.

This is currently only enabled for CPU(X86), CPU(X86_64), CPU(ARM64),
CPU(ARM_THUMB2), and only for OS(DARWIN).  It'll probably just work for linux as
well, but I'll let the Linux folks turn that on after they have verified that it
works on linux too.

I'll also take this opportunity to clean up how we initialize the opcodeIDTable:
1. we only need to initialize it once per process, not once per VM / interpreter
   instance.
2. we can initialize it in the Interpreter constructor instead of requiring a
   separate call to an initialize() function.

On debug builds, the Interpreter constructor will also verify that getOpcodeID()
is working correctly for each opcode when USE(LLINT_EMBEDDED_OPCODE_ID).

* bytecode/BytecodeList.json:
* generate-bytecode-files:
* interpreter/Interpreter.cpp:
(JSC::Interpreter::Interpreter):
(JSC::Interpreter::opcodeIDTable):
(JSC::Interpreter::initialize): Deleted.
* interpreter/Interpreter.h:
(JSC::Interpreter::getOpcode):
(JSC::Interpreter::getOpcodeID):
* llint/LowLevelInterpreter.cpp:
* runtime/VM.cpp:
(JSC::VM::VM):

Source/WTF:

Added the USE(LLINT_EMBEDDED_OPCODE_ID) configuration.

* wtf/Platform.h:

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (217525 => 217526)


--- trunk/Source/_javascript_Core/ChangeLog	2017-05-27 23:21:53 UTC (rev 217525)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-05-28 08:12:09 UTC (rev 217526)
@@ -1,3 +1,42 @@
+2017-05-28  Mark Lam  <[email protected]>
+
+        Implement a faster Interpreter::getOpcodeID().
+        https://bugs.webkit.org/show_bug.cgi?id=172669
+
+        Reviewed by Saam Barati.
+
+        We can implement Interpreter::getOpcodeID() without a hash table lookup by always
+        embedding the OpcodeID in the 32-bit word just before the start of the LLInt
+        handler code that executes each opcode.  getOpcodeID() can therefore just read
+        the 32-bits before the opcode address to get its OpcodeID.
+
+        This is currently only enabled for CPU(X86), CPU(X86_64), CPU(ARM64),
+        CPU(ARM_THUMB2), and only for OS(DARWIN).  It'll probably just work for linux as
+        well, but I'll let the Linux folks turn that on after they have verified that it
+        works on linux too.
+
+        I'll also take this opportunity to clean up how we initialize the opcodeIDTable:
+        1. we only need to initialize it once per process, not once per VM / interpreter
+           instance.
+        2. we can initialize it in the Interpreter constructor instead of requiring a
+           separate call to an initialize() function.
+
+        On debug builds, the Interpreter constructor will also verify that getOpcodeID()
+        is working correctly for each opcode when USE(LLINT_EMBEDDED_OPCODE_ID).
+
+        * bytecode/BytecodeList.json:
+        * generate-bytecode-files:
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::Interpreter):
+        (JSC::Interpreter::opcodeIDTable):
+        (JSC::Interpreter::initialize): Deleted.
+        * interpreter/Interpreter.h:
+        (JSC::Interpreter::getOpcode):
+        (JSC::Interpreter::getOpcodeID):
+        * llint/LowLevelInterpreter.cpp:
+        * runtime/VM.cpp:
+        (JSC::VM::VM):
+
 2017-05-27  Yusuke Suzuki  <[email protected]>
 
         [JSC] Map and Set constructors should have fast path for cloning

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeList.json (217525 => 217526)


--- trunk/Source/_javascript_Core/bytecode/BytecodeList.json	2017-05-27 23:21:53 UTC (rev 217525)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeList.json	2017-05-28 08:12:09 UTC (rev 217526)
@@ -1,6 +1,6 @@
 [
     {
-        "section" : "Bytecodes", "emitInHFile" : true, "emitInASMFile" : true, 
+        "section" : "Bytecodes", "emitInHFile" : true, "emitInASMFile" : true, "emitOpcodeIDStringValuesInHFile" : true,
         "macroNameComponent" : "BYTECODE", "asmPrefix" : "llint_", 
         "bytecodes" : [
             { "name" : "op_enter", "length" : 1 },
@@ -158,7 +158,7 @@
         ]
     },
     {
-        "section" : "CLoopHelpers", "emitInHFile" : true, "emitInASMFile" : false, "defaultLength" : 1,
+        "section" : "CLoopHelpers", "emitInHFile" : true, "emitInASMFile" : false, "emitOpcodeIDStringValuesInHFile" : false, "defaultLength" : 1,
         "macroNameComponent" : "CLOOP_BYTECODE_HELPER",
         "bytecodes" : [
             { "name" : "llint_entry" },
@@ -181,7 +181,7 @@
         ]
     },
     {
-        "section" : "NativeHelpers", "emitInHFile" : true, "emitInASMFile" : true, "defaultLength" : 1,
+        "section" : "NativeHelpers", "emitInHFile" : true, "emitInASMFile" : true, "emitOpcodeIDStringValuesInHFile" : false, "defaultLength" : 1,
         "macroNameComponent" : "BYTECODE_HELPER",
         "bytecodes" : [
             { "name" : "llint_program_prologue" },

Modified: trunk/Source/_javascript_Core/generate-bytecode-files (217525 => 217526)


--- trunk/Source/_javascript_Core/generate-bytecode-files	2017-05-27 23:21:53 UTC (rev 217525)
+++ trunk/Source/_javascript_Core/generate-bytecode-files	2017-05-28 08:12:09 UTC (rev 217526)
@@ -1,6 +1,6 @@
 #! /usr/bin/python
 
-# Copyright (C) 2014 Apple Inc. All rights reserved.
+# Copyright (C) 2014-2017 Apple Inc. All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
@@ -201,6 +201,15 @@
             bytecodeHFile.write("\n\n")
             bytecodeHFile.write("#define NUMBER_OF_{0}_IDS {1}\n\n".format(section["macroNameComponent"], bytecodeNum))
 
+        if bytecodeHFilename and section['emitOpcodeIDStringValuesInHFile']:
+            bytecodeNum = 0
+            for bytecode in section["bytecodes"]:
+                bytecodeHFile.write("#define {0}_value_string \"{1}\"\n".format(bytecode["name"], bytecodeNum))
+                firstMacro = False
+                bytecodeNum = bytecodeNum + 1
+
+            bytecodeHFile.write("\n")            
+
         if initASMFileName and section['emitInASMFile']:
             prefix = ""
             if "asmPrefix" in section:

Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.cpp (217525 => 217526)


--- trunk/Source/_javascript_Core/interpreter/Interpreter.cpp	2017-05-27 23:21:53 UTC (rev 217525)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.cpp	2017-05-28 08:12:09 UTC (rev 217526)
@@ -31,6 +31,7 @@
 #include "Interpreter.h"
 
 #include "BatchedTransitionOptimizer.h"
+#include "Bytecodes.h"
 #include "CallFrameClosure.h"
 #include "CodeBlock.h"
 #include "DirectArguments.h"
@@ -75,6 +76,7 @@
 
 #include <limits.h>
 #include <stdio.h>
+#include <wtf/NeverDestroyed.h>
 #include <wtf/StackStats.h>
 #include <wtf/StdLibExtras.h>
 #include <wtf/StringPrintStream.h>
@@ -315,10 +317,20 @@
 #if !ENABLE(JIT)
     , m_cloopStack(vm)
 #endif
-#if !ASSERT_DISABLED
-    , m_initialized(false)
+#if ENABLE(COMPUTED_GOTO_OPCODES)
+    , m_opcodeTable { LLInt::opcodeMap() }
+#if !USE(LLINT_EMBEDDED_OPCODE_ID) || !ASSERT_DISABLED
+    , m_opcodeIDTable { opcodeIDTable() }
 #endif
+#endif
 {
+#if !ASSERT_DISABLED
+    static std::once_flag assertOnceKey;
+    std::call_once(assertOnceKey, [this] {
+        for (unsigned i = 0; i < NUMBER_OF_BYTECODE_IDS; ++i)
+            RELEASE_ASSERT(getOpcodeID(m_opcodeTable[i]) == static_cast<OpcodeID>(i));
+    });
+#endif // USE(LLINT_EMBEDDED_OPCODE_ID)
 }
 
 Interpreter::~Interpreter()
@@ -325,18 +337,23 @@
 {
 }
 
-void Interpreter::initialize()
+#if ENABLE(COMPUTED_GOTO_OPCODES)
+#if !USE(LLINT_EMBEDDED_OPCODE_ID) || !ASSERT_DISABLED
+HashMap<Opcode, OpcodeID>& Interpreter::opcodeIDTable()
 {
-#if ENABLE(COMPUTED_GOTO_OPCODES)
-    m_opcodeTable = LLInt::opcodeMap();
-    for (int i = 0; i < numOpcodeIDs; ++i)
-        m_opcodeIDTable.add(m_opcodeTable[i], static_cast<OpcodeID>(i));
-#endif
+    static NeverDestroyed<HashMap<Opcode, OpcodeID>> opcodeIDTable;
 
-#if !ASSERT_DISABLED
-    m_initialized = true;
-#endif
+    static std::once_flag initializeKey;
+    std::call_once(initializeKey, [&] {
+        const Opcode* opcodeTable = LLInt::opcodeMap();
+        for (unsigned i = 0; i < NUMBER_OF_BYTECODE_IDS; ++i)
+            opcodeIDTable.get().add(opcodeTable[i], static_cast<OpcodeID>(i));
+    });
+
+    return opcodeIDTable;
 }
+#endif // !USE(LLINT_EMBEDDED_OPCODE_ID) || !ASSERT_DISABLED
+#endif // ENABLE(COMPUTED_GOTO_OPCODES)
 
 #ifdef NDEBUG
 
@@ -449,6 +466,7 @@
 
 #endif
 
+#if !ASSERT_DISABLED
 bool Interpreter::isOpcode(Opcode opcode)
 {
 #if ENABLE(COMPUTED_GOTO_OPCODES)
@@ -459,6 +477,7 @@
     return opcode >= 0 && opcode <= op_end;
 #endif
 }
+#endif // !ASSERT_DISABLED
 
 class GetStackTraceFunctor {
 public:

Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.h (217525 => 217526)


--- trunk/Source/_javascript_Core/interpreter/Interpreter.h	2017-05-27 23:21:53 UTC (rev 217525)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.h	2017-05-28 08:12:09 UTC (rev 217526)
@@ -97,8 +97,6 @@
         Interpreter(VM &);
         ~Interpreter();
         
-        void initialize();
-
 #if !ENABLE(JIT)
         CLoopStack& cloopStack() { return m_cloopStack; }
 #endif
@@ -105,7 +103,6 @@
         
         Opcode getOpcode(OpcodeID id)
         {
-            ASSERT(m_initialized);
 #if ENABLE(COMPUTED_GOTO_OPCODES)
             return m_opcodeTable[id];
 #else
@@ -115,11 +112,22 @@
 
         OpcodeID getOpcodeID(Opcode opcode)
         {
-            ASSERT(m_initialized);
 #if ENABLE(COMPUTED_GOTO_OPCODES)
             ASSERT(isOpcode(opcode));
+#if USE(LLINT_EMBEDDED_OPCODE_ID)
+            // The OpcodeID is embedded in the int32_t word preceding the location of
+            // the LLInt code for the opcode (see the EMBED_OPCODE_ID_IF_NEEDED macro
+            // in LowLevelInterpreter.cpp).
+            MacroAssemblerCodePtr codePtr(reinterpret_cast<void*>(opcode));
+            int32_t* opcodeIDAddress = reinterpret_cast<int32_t*>(codePtr.dataLocation()) - 1;
+            OpcodeID opcodeID = static_cast<OpcodeID>(*opcodeIDAddress);
+            ASSERT(opcodeID < NUMBER_OF_BYTECODE_IDS);
+            return opcodeID;
+#else
             return m_opcodeIDTable.get(opcode);
-#else
+#endif // USE(LLINT_EMBEDDED_OPCODE_ID)
+
+#else // not ENABLE(COMPUTED_GOTO_OPCODES)
             return opcode;
 #endif
         }
@@ -127,7 +135,9 @@
         OpcodeID getOpcodeID(const Instruction&);
         OpcodeID getOpcodeID(const UnlinkedInstruction&);
 
+#if !ASSERT_DISABLED
         bool isOpcode(Opcode);
+#endif
 
         JSValue executeProgram(const SourceCode&, CallFrame*, JSObject* thisObj);
         JSValue executeModuleProgram(ModuleProgramExecutable*, CallFrame*, JSModuleEnvironment*);
@@ -170,13 +180,14 @@
 #endif
         
 #if ENABLE(COMPUTED_GOTO_OPCODES)
-        Opcode* m_opcodeTable; // Maps OpcodeID => Opcode for compiling
-        HashMap<Opcode, OpcodeID> m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling
-#endif
+        const Opcode* m_opcodeTable; // Maps OpcodeID => Opcode for compiling
 
-#if !ASSERT_DISABLED
-        bool m_initialized;
-#endif
+#if !USE(LLINT_EMBEDDED_OPCODE_ID) || !ASSERT_DISABLED
+        HashMap<Opcode, OpcodeID>& m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling
+
+        static HashMap<Opcode, OpcodeID>& opcodeIDTable();
+#endif // !USE(LLINT_EMBEDDED_OPCODE_ID) || !ASSERT_DISABLED
+#endif // ENABLE(COMPUTED_GOTO_OPCODES)
     };
 
     JSValue eval(CallFrame*);

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter.cpp (217525 => 217526)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter.cpp	2017-05-27 23:21:53 UTC (rev 217525)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter.cpp	2017-05-28 08:12:09 UTC (rev 217526)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012, 2014, 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -497,7 +497,16 @@
 #define OFFLINE_ASM_BEGIN   asm (
 #define OFFLINE_ASM_END     );
 
-#define OFFLINE_ASM_OPCODE_LABEL(__opcode) OFFLINE_ASM_LOCAL_LABEL(llint_##__opcode)
+#if USE(LLINT_EMBEDDED_OPCODE_ID)
+#define EMBED_OPCODE_ID_IF_NEEDED(__opcode) ".int " __opcode##_value_string "\n"
+#else
+#define EMBED_OPCODE_ID_IF_NEEDED(__opcode)
+#endif
+
+#define OFFLINE_ASM_OPCODE_LABEL(__opcode) \
+    EMBED_OPCODE_ID_IF_NEEDED(__opcode) \
+    OFFLINE_ASM_LOCAL_LABEL(llint_##__opcode)
+
 #define OFFLINE_ASM_GLUE_LABEL(__opcode)   OFFLINE_ASM_LOCAL_LABEL(__opcode)
 
 #if CPU(ARM_THUMB2)

Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (217525 => 217526)


--- trunk/Source/_javascript_Core/runtime/VM.cpp	2017-05-27 23:21:53 UTC (rev 217525)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp	2017-05-28 08:12:09 UTC (rev 217526)
@@ -288,8 +288,6 @@
     ftlThunks = std::make_unique<FTL::Thunks>();
 #endif // ENABLE(FTL_JIT)
     
-    interpreter->initialize();
-    
 #if ENABLE(JIT)
     initializeHostCallReturnValue(); // This is needed to convince the linker not to drop host call return support.
 #endif

Modified: trunk/Source/WTF/ChangeLog (217525 => 217526)


--- trunk/Source/WTF/ChangeLog	2017-05-27 23:21:53 UTC (rev 217525)
+++ trunk/Source/WTF/ChangeLog	2017-05-28 08:12:09 UTC (rev 217526)
@@ -1,3 +1,14 @@
+2017-05-28  Mark Lam  <[email protected]>
+
+        Implement a faster Interpreter::getOpcodeID().
+        https://bugs.webkit.org/show_bug.cgi?id=172669
+
+        Reviewed by Saam Barati.
+
+        Added the USE(LLINT_EMBEDDED_OPCODE_ID) configuration.
+
+        * wtf/Platform.h:
+
 2017-05-26  Brent Fulgham  <[email protected]>
 
         [WK2] Address thread safety issues with ResourceLoadStatistics

Modified: trunk/Source/WTF/wtf/Platform.h (217525 => 217526)


--- trunk/Source/WTF/wtf/Platform.h	2017-05-27 23:21:53 UTC (rev 217525)
+++ trunk/Source/WTF/wtf/Platform.h	2017-05-28 08:12:09 UTC (rev 217526)
@@ -916,6 +916,15 @@
 #define ENABLE_COMPUTED_GOTO_OPCODES 1
 #endif
 
+#if ENABLE(JIT) && !COMPILER(MSVC) && \
+    (CPU(X86) || CPU(X86_64) || CPU(ARM64) || CPU(ARM_THUMB2)) && OS(DARWIN)
+/* This feature works by embedding the OpcodeID in the 32 bit just before the generated LLint code
+   that executes each opcode. It cannot be supported by the CLoop since there's no way to embed the
+   OpcodeID word in the CLoop's switch statement cases. It is also currently not implemented for MSVC.
+*/
+#define USE_LLINT_EMBEDDED_OPCODE_ID 1
+#endif
+
 /* Regular _expression_ Tracing - Set to 1 to trace RegExp's in jsc.  Results dumped at exit */
 #define ENABLE_REGEXP_TRACING 0
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to