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