Baseline JIT should be concurrent
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 17 Jun 2016 04:48:47 +0000 (04:48 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 17 Jun 2016 04:48:47 +0000 (04:48 +0000)
https://bugs.webkit.org/show_bug.cgi?id=158755

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

This makes the baseline JIT concurrent. We want it to be concurrent because it takes up
about 1% of PLT3 and 10% of JSBench (though the JSBench number might be down from recent
optimizations).

The idea is really simple: I separated the compile and link phases of JIT::privateCompile(),
and arranged to call the compile phase from another thread. This doesn't reuse the old
DFG::Worklist code, because that code does things we don't need (like compilation plan
cancellation to allow GC to interleave with compilations) and is structured in a way that
would have required more changes to the baseline JIT. Also, I think that code uses the wrong
API, and as a result, clients of that API have a bad time. For example, it's never clear who
has the responsibility of setting the JIT thresholds and the DFG::Worklist goes to great
lengths to try to help its client set those things correctly, but since it doesn't set them
directly, the client then has to have additional complex logic to combine what it learned
from the Worklist and what it knows to set the thresholds. This patch takes a simpler
approach: the JITWorklist takes complete control over scheduling compilations. It's like a
combination of DFG::Worklist and operationOptimize().

Because the baseline JIT runs quickly, we can take some shortcuts. The JITWorklist requires
that all of its plans complete before a GC begins. This ensures that we don't have to worry
about interactions between the concurrent baseline JIT and the GC.

I needed to do a bunch of minor changes to the JIT to handle the races that emerged. For
example, I needed to do things to opcodes that read profiling both in the main path code
generator and the slow path one. One trick I used was to create a copy of the instruction
stream and provide that for anyone interested in the original value of the profiles. Most
code still uses the CodeBlock's instruction stream because it may emit JIT code that points
at the stream.

This also fixes a LLInt bug in prototype caching. This bug was revealed by this change
because more of our LayoutTests now run in LLInt.

This looks like it might be a ~1% Octane speed-up (on command line) and a ~0.7% PLT3
speed-up. This also looks like a ~2% JSBench speed-up.

* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* debugger/Debugger.cpp:
(JSC::Debugger::setSteppingMode):
(JSC::Debugger::toggleBreakpoint):
(JSC::Debugger::clearBreakpoints):
(JSC::Debugger::clearDebuggerRequests):
* dfg/DFGOSRExitPreparation.cpp:
(JSC::DFG::prepareCodeOriginForOSRExit):
* heap/Heap.cpp:
(JSC::Heap::didFinishIterating):
(JSC::Heap::completeAllJITPlans):
(JSC::Heap::deleteAllCodeBlocks):
(JSC::Heap::collectImpl):
(JSC::Heap::completeAllDFGPlans): Deleted.
* heap/Heap.h:
* heap/HeapInlines.h:
(JSC::Heap::forEachCodeBlock):
* jit/JIT.cpp:
(JSC::JIT::emitNotifyWrite):
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
(JSC::JIT::compileWithoutLinking):
(JSC::JIT::link):
(JSC::JIT::privateCompile):
(JSC::JIT::privateCompileExceptionHandlers):
* jit/JIT.h:
(JSC::JIT::compile):
(JSC::JIT::getSlowCase):
(JSC::JIT::linkSlowCase):
(JSC::JIT::linkDummySlowCase):
* jit/JITInlines.h:
(JSC::JIT::emitTagBool):
(JSC::JIT::originalInstruction):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emitSlow_op_put_to_scope):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emitSlow_op_put_by_val):
(JSC::JIT::emit_op_resolve_scope):
(JSC::JIT::emitSlow_op_resolve_scope):
(JSC::JIT::emit_op_get_from_scope):
(JSC::JIT::emitSlow_op_get_from_scope):
(JSC::JIT::emit_op_put_to_scope):
(JSC::JIT::emitSlow_op_put_to_scope):
* jit/JITWorklist.cpp: Added.
(JSC::JITWorklist::Plan::Plan):
(JSC::JITWorklist::Plan::compileInThread):
(JSC::JITWorklist::Plan::finalize):
(JSC::JITWorklist::Plan::codeBlock):
(JSC::JITWorklist::Plan::vm):
(JSC::JITWorklist::Plan::isFinishedCompiling):
(JSC::JITWorklist::Plan::isFinalized):
(JSC::JITWorklist::JITWorklist):
(JSC::JITWorklist::~JITWorklist):
(JSC::JITWorklist::completeAllForVM):
(JSC::JITWorklist::poll):
(JSC::JITWorklist::compileLater):
(JSC::JITWorklist::compileNow):
(JSC::JITWorklist::runThread):
(JSC::JITWorklist::finalizePlans):
(JSC::JITWorklist::instance):
* jit/JITWorklist.h: Added.
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::jitCompileAndSetHeuristics):
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/CommonSlowPaths.h:
(JSC::CommonSlowPaths::tryCachePutToScopeGlobal):
(JSC::CommonSlowPaths::tryCacheGetFromScopeGlobal):
* runtime/VM.cpp:
(JSC::VM::~VM):

Source/WTF:

The concurrent baseline JIT needs to be able to clone bytecode to get a consistent snapshot.
So, this adds such a method.

* wtf/RefCountedArray.h:
(WTF::RefCountedArray::RefCountedArray):
(WTF::RefCountedArray::clone):

Tools:

Need to disable concurrent JIT when running profiler tests. We should have been doing this
all along.

* Scripts/run-jsc-stress-tests:

LayoutTests:

This change revealed a latent bug in the LLInt.  The non-llint version of this new test
would usually fail because it was still in LLInt.  This new test always fails.

* js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-llint.html: Added.
* js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-llint-expected.txt: Added.
* js/dom/script-tests/prototype-chain-caching-with-impure-get-own-property-slot-traps-llint.js: Added.

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

30 files changed:
LayoutTests/ChangeLog
LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-llint-expected.txt [new file with mode: 0644]
LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-llint.html [new file with mode: 0644]
LayoutTests/js/dom/script-tests/prototype-chain-caching-with-impure-get-own-property-slot-traps-llint.js [new file with mode: 0644]
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/debugger/Debugger.cpp
Source/JavaScriptCore/dfg/DFGOSRExitPreparation.cpp
Source/JavaScriptCore/heap/Heap.cpp
Source/JavaScriptCore/heap/Heap.h
Source/JavaScriptCore/heap/HeapInlines.h
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITCall.cpp
Source/JavaScriptCore/jit/JITInlines.h
Source/JavaScriptCore/jit/JITPropertyAccess.cpp
Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
Source/JavaScriptCore/jit/JITWorklist.cpp [new file with mode: 0644]
Source/JavaScriptCore/jit/JITWorklist.h [new file with mode: 0644]
Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
Source/JavaScriptCore/runtime/CommonSlowPaths.h
Source/JavaScriptCore/runtime/VM.cpp
Source/WTF/ChangeLog
Source/WTF/wtf/RefCountedArray.h
Tools/ChangeLog
Tools/Scripts/run-jsc-stress-tests

index 6d27a8b..6125610 100644 (file)
@@ -1,3 +1,17 @@
+2016-06-15  Filip Pizlo  <fpizlo@apple.com>
+
+        Baseline JIT should be concurrent
+        https://bugs.webkit.org/show_bug.cgi?id=158755
+
+        Reviewed by Geoffrey Garen.
+        
+        This change revealed a latent bug in the LLInt.  The non-llint version of this new test
+        would usually fail because it was still in LLInt.  This new test always fails.
+
+        * js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-llint.html: Added.
+        * js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-llint-expected.txt: Added.
+        * js/dom/script-tests/prototype-chain-caching-with-impure-get-own-property-slot-traps-llint.js: Added.
+
 2016-06-16  Frederic Wang  <fwang@igalia.com>
 
         Add separate MathOperator for selection/measuring/drawing of stretchy operators
diff --git a/LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-llint-expected.txt b/LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-llint-expected.txt
new file mode 100644 (file)
index 0000000..e2e7de3
--- /dev/null
@@ -0,0 +1,49 @@
+Tests what happens when you make prototype chain accesses with impure GetOwnPropertySlot traps in the way.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "function"
+PASS typeof result is "object"
+PASS typeof result is "object"
+PASS typeof result is "object"
+PASS typeof result is "object"
+PASS typeof result is "object"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-llint.html b/LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-llint.html
new file mode 100644 (file)
index 0000000..670025b
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="script-tests/prototype-chain-caching-with-impure-get-own-property-slot-traps-llint.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/dom/script-tests/prototype-chain-caching-with-impure-get-own-property-slot-traps-llint.js b/LayoutTests/js/dom/script-tests/prototype-chain-caching-with-impure-get-own-property-slot-traps-llint.js
new file mode 100644 (file)
index 0000000..5456a45
--- /dev/null
@@ -0,0 +1,18 @@
+description(
+"Tests what happens when you make prototype chain accesses with impure GetOwnPropertySlot traps in the way."
+);
+
+var doc = document;
+
+var expected = "\"function\"";
+for (var i = 0; i < 40; ++i) {
+    if (i == 35) {
+        var img = new Image();
+        img.name = "getElementsByTagName";
+        document.body.appendChild(img);
+        expected = "\"object\"";
+    }
+    var result = doc.getElementsByTagName;
+    shouldBe("typeof result", expected);
+}
+
index 4a763ff..4d68a73 100644 (file)
@@ -555,6 +555,7 @@ set(JavaScriptCore_SOURCES
     jit/JITSubGenerator.cpp
     jit/JITThunks.cpp
     jit/JITToDFGDeferredCompilationCallback.cpp
+    jit/JITWorklist.cpp
     jit/PCToCodeOriginMap.cpp
     jit/PolymorphicCallStubRoutine.cpp
     jit/Reg.cpp
index 56782f2..450867c 100644 (file)
@@ -1,3 +1,116 @@
+2016-06-14  Filip Pizlo  <fpizlo@apple.com>
+
+        Baseline JIT should be concurrent
+        https://bugs.webkit.org/show_bug.cgi?id=158755
+
+        Reviewed by Geoffrey Garen.
+        
+        This makes the baseline JIT concurrent. We want it to be concurrent because it takes up
+        about 1% of PLT3 and 10% of JSBench (though the JSBench number might be down from recent
+        optimizations).
+        
+        The idea is really simple: I separated the compile and link phases of JIT::privateCompile(),
+        and arranged to call the compile phase from another thread. This doesn't reuse the old
+        DFG::Worklist code, because that code does things we don't need (like compilation plan
+        cancellation to allow GC to interleave with compilations) and is structured in a way that
+        would have required more changes to the baseline JIT. Also, I think that code uses the wrong
+        API, and as a result, clients of that API have a bad time. For example, it's never clear who
+        has the responsibility of setting the JIT thresholds and the DFG::Worklist goes to great
+        lengths to try to help its client set those things correctly, but since it doesn't set them
+        directly, the client then has to have additional complex logic to combine what it learned
+        from the Worklist and what it knows to set the thresholds. This patch takes a simpler
+        approach: the JITWorklist takes complete control over scheduling compilations. It's like a
+        combination of DFG::Worklist and operationOptimize().
+        
+        Because the baseline JIT runs quickly, we can take some shortcuts. The JITWorklist requires
+        that all of its plans complete before a GC begins. This ensures that we don't have to worry
+        about interactions between the concurrent baseline JIT and the GC.
+        
+        I needed to do a bunch of minor changes to the JIT to handle the races that emerged. For
+        example, I needed to do things to opcodes that read profiling both in the main path code
+        generator and the slow path one. One trick I used was to create a copy of the instruction
+        stream and provide that for anyone interested in the original value of the profiles. Most
+        code still uses the CodeBlock's instruction stream because it may emit JIT code that points
+        at the stream.
+        
+        This also fixes a LLInt bug in prototype caching. This bug was revealed by this change
+        because more of our LayoutTests now run in LLInt.
+        
+        This looks like it might be a ~1% Octane speed-up (on command line) and a ~0.7% PLT3
+        speed-up. This also looks like a ~2% JSBench speed-up.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * debugger/Debugger.cpp:
+        (JSC::Debugger::setSteppingMode):
+        (JSC::Debugger::toggleBreakpoint):
+        (JSC::Debugger::clearBreakpoints):
+        (JSC::Debugger::clearDebuggerRequests):
+        * dfg/DFGOSRExitPreparation.cpp:
+        (JSC::DFG::prepareCodeOriginForOSRExit):
+        * heap/Heap.cpp:
+        (JSC::Heap::didFinishIterating):
+        (JSC::Heap::completeAllJITPlans):
+        (JSC::Heap::deleteAllCodeBlocks):
+        (JSC::Heap::collectImpl):
+        (JSC::Heap::completeAllDFGPlans): Deleted.
+        * heap/Heap.h:
+        * heap/HeapInlines.h:
+        (JSC::Heap::forEachCodeBlock):
+        * jit/JIT.cpp:
+        (JSC::JIT::emitNotifyWrite):
+        (JSC::JIT::privateCompileMainPass):
+        (JSC::JIT::privateCompileSlowCases):
+        (JSC::JIT::compileWithoutLinking):
+        (JSC::JIT::link):
+        (JSC::JIT::privateCompile):
+        (JSC::JIT::privateCompileExceptionHandlers):
+        * jit/JIT.h:
+        (JSC::JIT::compile):
+        (JSC::JIT::getSlowCase):
+        (JSC::JIT::linkSlowCase):
+        (JSC::JIT::linkDummySlowCase):
+        * jit/JITInlines.h:
+        (JSC::JIT::emitTagBool):
+        (JSC::JIT::originalInstruction):
+        * jit/JITPropertyAccess32_64.cpp:
+        (JSC::JIT::emitSlow_op_put_to_scope):
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emitSlow_op_put_by_val):
+        (JSC::JIT::emit_op_resolve_scope):
+        (JSC::JIT::emitSlow_op_resolve_scope):
+        (JSC::JIT::emit_op_get_from_scope):
+        (JSC::JIT::emitSlow_op_get_from_scope):
+        (JSC::JIT::emit_op_put_to_scope):
+        (JSC::JIT::emitSlow_op_put_to_scope):
+        * jit/JITWorklist.cpp: Added.
+        (JSC::JITWorklist::Plan::Plan):
+        (JSC::JITWorklist::Plan::compileInThread):
+        (JSC::JITWorklist::Plan::finalize):
+        (JSC::JITWorklist::Plan::codeBlock):
+        (JSC::JITWorklist::Plan::vm):
+        (JSC::JITWorklist::Plan::isFinishedCompiling):
+        (JSC::JITWorklist::Plan::isFinalized):
+        (JSC::JITWorklist::JITWorklist):
+        (JSC::JITWorklist::~JITWorklist):
+        (JSC::JITWorklist::completeAllForVM):
+        (JSC::JITWorklist::poll):
+        (JSC::JITWorklist::compileLater):
+        (JSC::JITWorklist::compileNow):
+        (JSC::JITWorklist::runThread):
+        (JSC::JITWorklist::finalizePlans):
+        (JSC::JITWorklist::instance):
+        * jit/JITWorklist.h: Added.
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::jitCompileAndSetHeuristics):
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+        * runtime/CommonSlowPaths.h:
+        (JSC::CommonSlowPaths::tryCachePutToScopeGlobal):
+        (JSC::CommonSlowPaths::tryCacheGetFromScopeGlobal):
+        * runtime/VM.cpp:
+        (JSC::VM::~VM):
+
 2016-06-16  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: console.profile should use the new Sampling Profiler
index c13ae3a..4fa3b0b 100644 (file)
                C4F4B6F51A05C984005CAB76 /* generate_objc_protocol_types_implementation.py in Headers */ = {isa = PBXBuildFile; fileRef = C4F4B6D71A05C76F005CAB76 /* generate_objc_protocol_types_implementation.py */; settings = {ATTRIBUTES = (Private, ); }; };
                C4F4B6F61A05C984005CAB76 /* objc_generator_templates.py in Headers */ = {isa = PBXBuildFile; fileRef = C4F4B6D81A05C76F005CAB76 /* objc_generator_templates.py */; settings = {ATTRIBUTES = (Private, ); }; };
                DC00039319D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h in Headers */ = {isa = PBXBuildFile; fileRef = DC00039019D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h */; };
+               DC0184191D10C1890057B053 /* JITWorklist.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0184181D10C1870057B053 /* JITWorklist.h */; };
+               DC01841A1D10C18C0057B053 /* JITWorklist.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC0184171D10C1870057B053 /* JITWorklist.cpp */; };
                DC17E8171C9C91D6008A6AB3 /* ShadowChicken.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC17E8131C9C7FD4008A6AB3 /* ShadowChicken.cpp */; };
                DC17E8181C9C91D9008A6AB3 /* ShadowChicken.h in Headers */ = {isa = PBXBuildFile; fileRef = DC17E8141C9C7FD4008A6AB3 /* ShadowChicken.h */; settings = {ATTRIBUTES = (Private, ); }; };
                DC17E8191C9C91DB008A6AB3 /* ShadowChickenInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = DC17E8151C9C7FD4008A6AB3 /* ShadowChickenInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
                D21202280AD4310C00ED79B6 /* DateConversion.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DateConversion.cpp; sourceTree = "<group>"; };
                D21202290AD4310C00ED79B6 /* DateConversion.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DateConversion.h; sourceTree = "<group>"; };
                DC00039019D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPreciseLocalClobberize.h; path = dfg/DFGPreciseLocalClobberize.h; sourceTree = "<group>"; };
+               DC0184171D10C1870057B053 /* JITWorklist.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITWorklist.cpp; sourceTree = "<group>"; };
+               DC0184181D10C1870057B053 /* JITWorklist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITWorklist.h; sourceTree = "<group>"; };
                DC17E8131C9C7FD4008A6AB3 /* ShadowChicken.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ShadowChicken.cpp; sourceTree = "<group>"; };
                DC17E8141C9C7FD4008A6AB3 /* ShadowChicken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShadowChicken.h; sourceTree = "<group>"; };
                DC17E8151C9C7FD4008A6AB3 /* ShadowChickenInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShadowChickenInlines.h; sourceTree = "<group>"; };
                                0F5EF91C16878F78003E5C25 /* JITThunks.h */,
                                0FC712E017CD878F008CC93C /* JITToDFGDeferredCompilationCallback.cpp */,
                                0FC712E117CD878F008CC93C /* JITToDFGDeferredCompilationCallback.h */,
+                               DC0184171D10C1870057B053 /* JITWorklist.cpp */,
+                               DC0184181D10C1870057B053 /* JITWorklist.h */,
                                A76F54A213B28AAB00EF2BCE /* JITWriteBarrier.h */,
                                A76C51741182748D00715B05 /* JSInterfaceJIT.h */,
                                792CB3471C4EED5C00D13AF3 /* PCToCodeOriginMap.cpp */,
                                90213E3E123A40C200D422F3 /* MemoryStatistics.h in Headers */,
                                0FB5467B14F5C7E1002C2989 /* MethodOfGettingAValueProfile.h in Headers */,
                                7C008CE7187631B600955C24 /* Microtask.h in Headers */,
+                               DC0184191D10C1890057B053 /* JITWorklist.h in Headers */,
                                86C568E211A213EE0007F7F0 /* MIPSAssembler.h in Headers */,
                                C4703CD7192844CC0013FBEA /* models.py in Headers */,
                                E3794E761B77EB97005543AE /* ModuleAnalyzer.h in Headers */,
                                E3EF88741B66DF23003F26CB /* JSPropertyNameIterator.cpp in Sources */,
                                862553D116136DA9009F17D0 /* JSProxy.cpp in Sources */,
                                A552C37F1ADDB8FE00139726 /* JSRemoteInspector.cpp in Sources */,
+                               DC01841A1D10C18C0057B053 /* JITWorklist.cpp in Sources */,
                                9928FF3B18AC4AEC00B8CF12 /* JSReplayInputs.cpp in Sources */,
                                14874AE515EBDE4A002E3587 /* JSScope.cpp in Sources */,
                                A7C0C4AD1681067E0017011D /* JSScriptRef.cpp in Sources */,
index a74f86b..ec0007d 100644 (file)
@@ -238,6 +238,8 @@ void CodeBlock::dumpAssumingJITType(PrintStream& out, JITCode::JITType jitType)
         out.print(" (DidTryToEnterInLoop)");
     if (ownerScriptExecutable()->isStrictMode())
         out.print(" (StrictMode)");
+    if (m_didFailJITCompilation)
+        out.print(" (JITFail)");
     if (this->jitType() == JITCode::BaselineJIT && m_didFailFTLCompilation)
         out.print(" (FTLFail)");
     if (this->jitType() == JITCode::BaselineJIT && m_hasBeenCompiledWithFTL)
@@ -1836,6 +1838,7 @@ CodeBlock::CodeBlock(VM* vm, Structure* structure, CopyParsedBlockTag, CodeBlock
 #if ENABLE(JIT)
     , m_capabilityLevelState(DFG::CapabilityLevelNotSet)
 #endif
+    , m_didFailJITCompilation(false)
     , m_didFailFTLCompilation(false)
     , m_hasBeenCompiledWithFTL(false)
     , m_isConstructor(other.m_isConstructor)
@@ -1901,6 +1904,7 @@ CodeBlock::CodeBlock(VM* vm, Structure* structure, ScriptExecutable* ownerExecut
 #if ENABLE(JIT)
     , m_capabilityLevelState(DFG::CapabilityLevelNotSet)
 #endif
+    , m_didFailJITCompilation(false)
     , m_didFailFTLCompilation(false)
     , m_hasBeenCompiledWithFTL(false)
     , m_isConstructor(unlinkedCodeBlock->isConstructor())
@@ -2392,6 +2396,7 @@ CodeBlock::CodeBlock(VM* vm, Structure* structure, WebAssemblyExecutable* ownerE
 #if ENABLE(JIT)
     , m_capabilityLevelState(DFG::CannotCompile)
 #endif
+    , m_didFailJITCompilation(false)
     , m_didFailFTLCompilation(false)
     , m_hasBeenCompiledWithFTL(false)
     , m_isConstructor(false)
@@ -3885,7 +3890,7 @@ bool CodeBlock::shouldReoptimizeFromLoopNow()
 }
 #endif
 
-ArrayProfile* CodeBlock::getArrayProfile(unsigned bytecodeOffset)
+ArrayProfile* CodeBlock::getArrayProfile(const ConcurrentJITLocker&, unsigned bytecodeOffset)
 {
     for (unsigned i = 0; i < m_arrayProfiles.size(); ++i) {
         if (m_arrayProfiles[i].bytecodeOffset() == bytecodeOffset)
@@ -3894,12 +3899,36 @@ ArrayProfile* CodeBlock::getArrayProfile(unsigned bytecodeOffset)
     return 0;
 }
 
-ArrayProfile* CodeBlock::getOrAddArrayProfile(unsigned bytecodeOffset)
+ArrayProfile* CodeBlock::getArrayProfile(unsigned bytecodeOffset)
+{
+    ConcurrentJITLocker locker(m_lock);
+    return getArrayProfile(locker, bytecodeOffset);
+}
+
+ArrayProfile* CodeBlock::addArrayProfile(const ConcurrentJITLocker&, unsigned bytecodeOffset)
+{
+    m_arrayProfiles.append(ArrayProfile(bytecodeOffset));
+    return &m_arrayProfiles.last();
+}
+
+ArrayProfile* CodeBlock::addArrayProfile(unsigned bytecodeOffset)
 {
-    ArrayProfile* result = getArrayProfile(bytecodeOffset);
+    ConcurrentJITLocker locker(m_lock);
+    return addArrayProfile(locker, bytecodeOffset);
+}
+
+ArrayProfile* CodeBlock::getOrAddArrayProfile(const ConcurrentJITLocker& locker, unsigned bytecodeOffset)
+{
+    ArrayProfile* result = getArrayProfile(locker, bytecodeOffset);
     if (result)
         return result;
-    return addArrayProfile(bytecodeOffset);
+    return addArrayProfile(locker, bytecodeOffset);
+}
+
+ArrayProfile* CodeBlock::getOrAddArrayProfile(unsigned bytecodeOffset)
+{
+    ConcurrentJITLocker locker(m_lock);
+    return getOrAddArrayProfile(locker, bytecodeOffset);
 }
 
 #if ENABLE(DFG_JIT)
index 5bba339..621fabf 100644 (file)
@@ -461,12 +461,11 @@ public:
 
     unsigned numberOfArrayProfiles() const { return m_arrayProfiles.size(); }
     const ArrayProfileVector& arrayProfiles() { return m_arrayProfiles; }
-    ArrayProfile* addArrayProfile(unsigned bytecodeOffset)
-    {
-        m_arrayProfiles.append(ArrayProfile(bytecodeOffset));
-        return &m_arrayProfiles.last();
-    }
+    ArrayProfile* addArrayProfile(const ConcurrentJITLocker&, unsigned bytecodeOffset);
+    ArrayProfile* addArrayProfile(unsigned bytecodeOffset);
+    ArrayProfile* getArrayProfile(const ConcurrentJITLocker&, unsigned bytecodeOffset);
     ArrayProfile* getArrayProfile(unsigned bytecodeOffset);
+    ArrayProfile* getOrAddArrayProfile(const ConcurrentJITLocker&, unsigned bytecodeOffset);
     ArrayProfile* getOrAddArrayProfile(unsigned bytecodeOffset);
 
     // Exception handling support
@@ -868,6 +867,7 @@ public:
 
     bool m_allTransitionsHaveBeenMarked : 1; // Initialized and used on every GC.
 
+    bool m_didFailJITCompilation : 1;
     bool m_didFailFTLCompilation : 1;
     bool m_hasBeenCompiledWithFTL : 1;
     bool m_isConstructor : 1;
index f88933c..e870677 100644 (file)
@@ -212,7 +212,7 @@ void Debugger::setSteppingMode(SteppingMode mode)
     if (mode == m_steppingMode)
         return;
 
-    m_vm.heap.completeAllDFGPlans();
+    m_vm.heap.completeAllJITPlans();
 
     m_steppingMode = mode;
     SetSteppingModeFunctor functor(this, mode);
@@ -313,7 +313,7 @@ private:
 
 void Debugger::toggleBreakpoint(Breakpoint& breakpoint, Debugger::BreakpointState enabledOrNot)
 {
-    m_vm.heap.completeAllDFGPlans();
+    m_vm.heap.completeAllJITPlans();
 
     ToggleBreakpointFunctor functor(this, breakpoint, enabledOrNot);
     m_vm.heap.forEachCodeBlock(functor);
@@ -487,7 +487,7 @@ private:
 
 void Debugger::clearBreakpoints()
 {
-    m_vm.heap.completeAllDFGPlans();
+    m_vm.heap.completeAllJITPlans();
 
     m_topBreakpointID = noBreakpointID;
     m_breakpointIDToBreakpoint.clear();
@@ -517,7 +517,7 @@ private:
 
 void Debugger::clearDebuggerRequests(JSGlobalObject* globalObject)
 {
-    m_vm.heap.completeAllDFGPlans();
+    m_vm.heap.completeAllJITPlans();
 
     ClearDebuggerRequestsFunctor functor(globalObject);
     m_vm.heap.forEachCodeBlock(functor);
index ba2a0da..6e74a2a 100644 (file)
@@ -32,6 +32,7 @@
 #include "Executable.h"
 #include "JIT.h"
 #include "JITCode.h"
+#include "JITWorklist.h"
 #include "JSCInlines.h"
 
 namespace JSC { namespace DFG {
@@ -43,12 +44,7 @@ void prepareCodeOriginForOSRExit(ExecState* exec, CodeOrigin codeOrigin)
     
     for (; codeOrigin.inlineCallFrame; codeOrigin = codeOrigin.inlineCallFrame->directCaller) {
         CodeBlock* codeBlock = codeOrigin.inlineCallFrame->baselineCodeBlock.get();
-        if (codeBlock->jitType() == JSC::JITCode::BaselineJIT)
-            continue;
-
-        ASSERT(codeBlock->jitType() == JSC::JITCode::InterpreterThunk);
-        JIT::compile(&vm, codeBlock, JITCompilationMustSucceed);
-        codeBlock->ownerScriptExecutable()->installCode(codeBlock);
+        JITWorklist::instance()->compileNow(codeBlock);
     }
 }
 
index 6d8de76..0991de7 100644 (file)
@@ -40,6 +40,7 @@
 #include "HeapVerifier.h"
 #include "IncrementalSweeper.h"
 #include "Interpreter.h"
+#include "JITWorklist.h"
 #include "JSCInlines.h"
 #include "JSGlobalObject.h"
 #include "JSLock.h"
@@ -519,8 +520,11 @@ void Heap::didFinishIterating()
     m_objectSpace.didFinishIterating();
 }
 
-void Heap::completeAllDFGPlans()
+void Heap::completeAllJITPlans()
 {
+#if ENABLE(JIT)
+    JITWorklist::instance()->completeAllForVM(*m_vm);
+#endif // ENABLE(JIT)
 #if ENABLE(DFG_JIT)
     DFG::completeAllPlansForVM(*m_vm);
 #endif
@@ -1045,7 +1049,7 @@ void Heap::deleteAllCodeBlocks()
     RELEASE_ASSERT(!m_vm->entryScope);
     ASSERT(m_operationInProgress == NoOperation);
 
-    completeAllDFGPlans();
+    completeAllJITPlans();
 
     for (ExecutableBase* executable : m_executables)
         executable->clearCode();
@@ -1141,6 +1145,13 @@ NEVER_INLINE void Heap::collectImpl(HeapOperation collectionType, void* stackOri
         vm()->typeProfilerLog()->processLogEntries(ASCIILiteral("GC"));
     }
 
+#if ENABLE(JIT)
+    {
+        DeferGCForAWhile awhile(*this);
+        JITWorklist::instance()->completeAllForVM(*m_vm);
+    }
+#endif // ENABLE(JIT)
+
     vm()->shadowChicken().update(*vm(), vm()->topCallFrame);
 
     RELEASE_ASSERT(!m_deferralDepth);
index 795fdee..293cbbb 100644 (file)
@@ -171,7 +171,7 @@ public:
     JS_EXPORT_PRIVATE void collect(HeapOperation collectionType = AnyCollection);
     bool collectIfNecessaryOrDefer(); // Returns true if it did collect.
 
-    void completeAllDFGPlans();
+    void completeAllJITPlans();
     
     // Use this API to report non-GC memory referenced by GC objects. Be sure to
     // call both of these functions: Calling only one may trigger catastropic
index 091c9d7..7749580 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -150,7 +150,7 @@ inline void Heap::deprecatedReportExtraMemory(size_t size)
 template<typename Functor> inline void Heap::forEachCodeBlock(Functor& functor)
 {
     // We don't know the full set of CodeBlocks until compilation has terminated.
-    completeAllDFGPlans();
+    completeAllJITPlans();
 
     return m_codeBlocks.iterate<Functor>(functor);
 }
index 4549ecb..be64f1a 100644 (file)
@@ -45,6 +45,7 @@
 #include "ResultType.h"
 #include "SlowPathCall.h"
 #include "StackAlignment.h"
+#include "SuperSampler.h"
 #include "TypeProfilerLog.h"
 #include <wtf/CryptographicallyRandomNumber.h>
 
@@ -108,8 +109,10 @@ void JIT::emitEnterOptimizationCheck()
 
 void JIT::emitNotifyWrite(WatchpointSet* set)
 {
-    if (!set || set->state() == IsInvalidated)
+    if (!set || set->state() == IsInvalidated) {
+        addSlowCase(Jump());
         return;
+    }
     
     addSlowCase(branch8(NotEqual, AbsoluteAddress(set->addressOfState()), TrustedImm32(IsInvalidated)));
 }
@@ -155,11 +158,14 @@ void JIT::assertStackPointerOffset()
 
 void JIT::privateCompileMainPass()
 {
+    if (false)
+        dataLog("Compiling ", *m_codeBlock, "\n");
+    
     jitAssertTagsInPlace();
     jitAssertArgumentCountSane();
     
     Instruction* instructionsBegin = m_codeBlock->instructions().begin();
-    unsigned instructionCount = m_codeBlock->instructions().size();
+    unsigned instructionCount = m_instructions.size();
 
     m_callLinkInfoIndex = 0;
 
@@ -501,11 +507,16 @@ void JIT::privateCompileSlowCases()
 #endif
 }
 
-CompilationResult JIT::privateCompile(JITCompilationEffort effort)
+void JIT::compileWithoutLinking(JITCompilationEffort effort)
 {
     double before = 0;
     if (UNLIKELY(computeCompileTimes()))
         before = monotonicallyIncreasingTimeMS();
+    
+    {
+        ConcurrentJITLocker locker(m_codeBlock->m_lock);
+        m_instructions = m_codeBlock->instructions().clone();
+    }
 
     DFG::CapabilityLevel level = m_codeBlock->capabilityLevel();
     switch (level) {
@@ -538,8 +549,6 @@ CompilationResult JIT::privateCompile(JITCompilationEffort effort)
         break;
     }
 
-    m_codeBlock->setCalleeSaveRegisters(RegisterSet::llintBaselineCalleeSaveRegisters()); // Might be able to remove as this is probably already set to this value.
-
     // This ensures that we have the most up to date type information when performing typecheck optimizations for op_profile_type.
     if (m_vm->typeProfiler())
         m_vm->typeProfilerLog()->processLogEntries(ASCIILiteral("Preparing for JIT compilation."));
@@ -601,6 +610,8 @@ CompilationResult JIT::privateCompile(JITCompilationEffort effort)
 
     emitSaveCalleeSaves();
     emitMaterializeTagCheckRegisters();
+    
+    RELEASE_ASSERT(!JITCode::isJIT(m_codeBlock->jitType()));
 
     privateCompileMainPass();
     privateCompileLinkPass();
@@ -616,9 +627,8 @@ CompilationResult JIT::privateCompile(JITCompilationEffort effort)
         addPtr(TrustedImm32(-maxFrameExtentForSlowPathCall), stackPointerRegister);
     callOperationWithCallFrameRollbackOnException(operationThrowStackOverflowError, m_codeBlock);
 
-    Label arityCheck;
     if (m_codeBlock->codeType() == FunctionCode) {
-        arityCheck = label();
+        m_arityCheck = label();
         store8(TrustedImm32(0), &m_codeBlock->m_shouldAlwaysBeInlined);
         emitFunctionPrologue();
         emitPutToCallFrameHeader(m_codeBlock, JSStack::CodeBlock);
@@ -652,11 +662,31 @@ CompilationResult JIT::privateCompile(JITCompilationEffort effort)
         m_disassembler->setEndOfCode(label());
     m_pcToCodeOriginMapBuilder.appendItem(label(), PCToCodeOriginMapBuilder::defaultCodeOrigin());
 
+    m_linkBuffer = std::unique_ptr<LinkBuffer>(new LinkBuffer(*m_vm, *this, m_codeBlock, effort));
+
+    double after;
+    if (UNLIKELY(computeCompileTimes())) {
+        after = monotonicallyIncreasingTimeMS();
+
+        if (Options::reportTotalCompileTimes())
+            totalBaselineCompileTime += after - before;
+    }
+    if (UNLIKELY(reportCompileTimes())) {
+        CString codeBlockName = toCString(*m_codeBlock);
+        
+        dataLog("Optimized ", codeBlockName, " with Baseline JIT into ", m_linkBuffer->size(), " bytes in ", after - before, " ms.\n");
+    }
+}
 
-    LinkBuffer patchBuffer(*m_vm, *this, m_codeBlock, effort);
+CompilationResult JIT::link()
+{
+    LinkBuffer& patchBuffer = *m_linkBuffer;
+    
     if (patchBuffer.didFailToAllocate())
         return CompilationFailed;
 
+    m_codeBlock->setCalleeSaveRegisters(RegisterSet::llintBaselineCalleeSaveRegisters()); // Might be able to remove as this is probably already set to this value.
+
     // Translate vPC offsets into addresses in JIT generated code, for switch tables.
     for (unsigned i = 0; i < m_switches.size(); ++i) {
         SwitchRecord record = m_switches[i];
@@ -738,7 +768,7 @@ CompilationResult JIT::privateCompile(JITCompilationEffort effort)
 
     MacroAssemblerCodePtr withArityCheck;
     if (m_codeBlock->codeType() == FunctionCode)
-        withArityCheck = patchBuffer.locationOf(arityCheck);
+        withArityCheck = patchBuffer.locationOf(m_arityCheck);
 
     if (Options::dumpDisassembly()) {
         m_disassembler->dump(patchBuffer);
@@ -759,25 +789,12 @@ CompilationResult JIT::privateCompile(JITCompilationEffort effort)
     
     m_vm->machineCodeBytesPerBytecodeWordForBaselineJIT.add(
         static_cast<double>(result.size()) /
-        static_cast<double>(m_codeBlock->instructions().size()));
+        static_cast<double>(m_instructions.size()));
 
     m_codeBlock->shrinkToFit(CodeBlock::LateShrink);
     m_codeBlock->setJITCode(
         adoptRef(new DirectJITCode(result, withArityCheck, JITCode::BaselineJIT)));
 
-    double after;
-    if (UNLIKELY(computeCompileTimes())) {
-        after = monotonicallyIncreasingTimeMS();
-
-        if (Options::reportTotalCompileTimes())
-            totalBaselineCompileTime += after - before;
-    }
-    if (UNLIKELY(reportCompileTimes())) {
-        CString codeBlockName = toCString(*m_codeBlock);
-        
-        dataLog("Optimized ", codeBlockName, " with Baseline JIT into ", patchBuffer.size(), " bytes in ", after - before, " ms.\n");
-    }
-
 #if ENABLE(JIT_VERBOSE)
     dataLogF("JIT generated code for %p at [%p, %p).\n", m_codeBlock, result.executableMemory()->start(), result.executableMemory()->end());
 #endif
@@ -785,6 +802,12 @@ CompilationResult JIT::privateCompile(JITCompilationEffort effort)
     return CompilationSuccessful;
 }
 
+CompilationResult JIT::privateCompile(JITCompilationEffort effort)
+{
+    compileWithoutLinking(effort);
+    return link();
+}
+
 void JIT::privateCompileExceptionHandlers()
 {
     if (!m_exceptionChecksWithCallFrameRollback.empty()) {
index 53ddc65..ad4b66e 100644 (file)
@@ -194,6 +194,12 @@ namespace JSC {
         static const int patchPutByIdDefaultOffset = 256;
 
     public:
+        JIT(VM*, CodeBlock* = 0);
+        ~JIT();
+
+        void compileWithoutLinking(JITCompilationEffort);
+        CompilationResult link();
+        
         static CompilationResult compile(VM* vm, CodeBlock* codeBlock, JITCompilationEffort effort)
         {
             return JIT(vm, codeBlock).privateCompile(effort);
@@ -256,9 +262,6 @@ namespace JSC {
         JS_EXPORT_PRIVATE static HashMap<CString, double> compileTimeStats();
 
     private:
-        JIT(VM*, CodeBlock* = 0);
-        ~JIT();
-
         void privateCompileMainPass();
         void privateCompileLinkPass();
         void privateCompileSlowCases();
@@ -713,7 +716,8 @@ namespace JSC {
         }
         void linkSlowCase(Vector<SlowCaseEntry>::iterator& iter)
         {
-            iter->from.link(this);
+            if (iter->from.isSet())
+                iter->from.link(this);
             ++iter;
         }
         void linkDummySlowCase(Vector<SlowCaseEntry>::iterator& iter)
@@ -908,8 +912,15 @@ namespace JSC {
 
         static bool reportCompileTimes();
         static bool computeCompileTimes();
+        
+        // If you need to check the value of an instruction multiple times and the instruction is
+        // part of a LLInt inline cache, then you want to use this. It will give you the value of
+        // the instruction at the start of JITing.
+        Instruction* copiedInstruction(Instruction*);
 
         Interpreter* m_interpreter;
+        
+        RefCountedArray<Instruction> m_instructions;
 
         Vector<CallRecord> m_calls;
         Vector<Label> m_labels;
@@ -930,6 +941,9 @@ namespace JSC {
         unsigned m_putByIdIndex;
         unsigned m_byValInstructionIndex;
         unsigned m_callLinkInfoIndex;
+        
+        Label m_arityCheck;
+        std::unique_ptr<LinkBuffer> m_linkBuffer;
 
         std::unique_ptr<JITDisassembler> m_disassembler;
         RefPtr<Profiler::Compilation> m_compilation;
index 7edfcc0..0c34f2c 100644 (file)
@@ -125,9 +125,13 @@ void JIT::compileCallEvalSlowCase(Instruction* instruction, Vector<SlowCaseEntry
 
     load64(Address(stackPointerRegister, sizeof(Register) * JSStack::Callee - sizeof(CallerFrameAndPC)), regT0);
     move(TrustedImmPtr(info), regT2);
-    MacroAssemblerCodeRef virtualThunk = virtualThunkFor(m_vm, *info);
-    info->setSlowStub(createJITStubRoutine(virtualThunk, *m_vm, nullptr, true));
-    emitNakedCall(virtualThunk.code());
+    Call call = emitNakedCall();
+    addLinkTask(
+        [=] (LinkBuffer& linkBuffer) {
+            MacroAssemblerCodeRef virtualThunk = virtualThunkFor(m_vm, *info);
+            info->setSlowStub(createJITStubRoutine(virtualThunk, *m_vm, nullptr, true));
+            linkBuffer.link(call, CodeLocationLabel(virtualThunk.code()));
+        });
     addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock) * sizeof(Register)), callFrameRegister, stackPointerRegister);
     checkStackPointerAlignment();
 
index 32b41c6..b71d7c6 100644 (file)
@@ -1355,6 +1355,12 @@ ALWAYS_INLINE void JIT::emitTagBool(RegisterID reg)
     or32(TrustedImm32(static_cast<int32_t>(ValueFalse)), reg);
 }
 
+inline Instruction* JIT::copiedInstruction(Instruction* inst)
+{
+    ASSERT(inst >= m_codeBlock->instructions().begin() && inst < m_codeBlock->instructions().end());
+    return m_instructions.begin() + (inst - m_codeBlock->instructions().begin());
+}
+
 #endif // USE(JSVALUE32_64)
 
 } // namespace JSC
index 2afb6b1..786e118 100644 (file)
@@ -466,7 +466,7 @@ void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCas
     int base = currentInstruction[1].u.operand;
     int property = currentInstruction[2].u.operand;
     int value = currentInstruction[3].u.operand;
-    ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
+    JITArrayMode mode = m_byValCompilationInfo[m_byValInstructionIndex].arrayMode;
     ByValInfo* byValInfo = m_byValCompilationInfo[m_byValInstructionIndex].byValInfo;
 
     linkSlowCaseIfNotJSCell(iter, base); // base cell check
@@ -476,7 +476,6 @@ void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCas
     
     linkSlowCase(iter); // out of bounds
     
-    JITArrayMode mode = chooseArrayMode(profile);
     switch (mode) {
     case JITInt32:
     case JITDouble:
@@ -730,7 +729,7 @@ void JIT::emit_op_resolve_scope(Instruction* currentInstruction)
 {
     int dst = currentInstruction[1].u.operand;
     int scope = currentInstruction[2].u.operand;
-    ResolveType resolveType = static_cast<ResolveType>(currentInstruction[4].u.operand);
+    ResolveType resolveType = static_cast<ResolveType>(copiedInstruction(currentInstruction)[4].u.operand);
     unsigned depth = currentInstruction[5].u.operand;
 
     auto emitCode = [&] (ResolveType resolveType) {
@@ -805,7 +804,7 @@ void JIT::emit_op_resolve_scope(Instruction* currentInstruction)
 
 void JIT::emitSlow_op_resolve_scope(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
-    ResolveType resolveType = static_cast<ResolveType>(currentInstruction[4].u.operand);
+    ResolveType resolveType = static_cast<ResolveType>(copiedInstruction(currentInstruction)[4].u.operand);
     if (resolveType == GlobalProperty || resolveType == GlobalVar || resolveType == ClosureVar || resolveType == GlobalLexicalVar || resolveType == ModuleVar)
         return;
 
@@ -849,7 +848,7 @@ void JIT::emit_op_get_from_scope(Instruction* currentInstruction)
 {
     int dst = currentInstruction[1].u.operand;
     int scope = currentInstruction[2].u.operand;
-    ResolveType resolveType = GetPutInfo(currentInstruction[4].u.operand).resolveType();
+    ResolveType resolveType = GetPutInfo(copiedInstruction(currentInstruction)[4].u.operand).resolveType();
     Structure** structureSlot = currentInstruction[5].u.structure.slot();
     uintptr_t* operandSlot = reinterpret_cast<uintptr_t*>(&currentInstruction[6].u.pointer);
 
@@ -944,7 +943,7 @@ void JIT::emit_op_get_from_scope(Instruction* currentInstruction)
 void JIT::emitSlow_op_get_from_scope(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
     int dst = currentInstruction[1].u.operand;
-    ResolveType resolveType = GetPutInfo(currentInstruction[4].u.operand).resolveType();
+    ResolveType resolveType = GetPutInfo(copiedInstruction(currentInstruction)[4].u.operand).resolveType();
 
     if (resolveType == GlobalVar || resolveType == ClosureVar)
         return;
@@ -998,7 +997,7 @@ void JIT::emit_op_put_to_scope(Instruction* currentInstruction)
 {
     int scope = currentInstruction[1].u.operand;
     int value = currentInstruction[3].u.operand;
-    GetPutInfo getPutInfo = GetPutInfo(currentInstruction[4].u.operand);
+    GetPutInfo getPutInfo = GetPutInfo(copiedInstruction(currentInstruction)[4].u.operand);
     ResolveType resolveType = getPutInfo.resolveType();
     Structure** structureSlot = currentInstruction[5].u.structure.slot();
     uintptr_t* operandSlot = reinterpret_cast<uintptr_t*>(&currentInstruction[6].u.pointer);
@@ -1095,15 +1094,15 @@ void JIT::emit_op_put_to_scope(Instruction* currentInstruction)
 
 void JIT::emitSlow_op_put_to_scope(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
-    GetPutInfo getPutInfo = GetPutInfo(currentInstruction[4].u.operand);
+    GetPutInfo getPutInfo = GetPutInfo(copiedInstruction(currentInstruction)[4].u.operand);
     ResolveType resolveType = getPutInfo.resolveType();
     unsigned linkCount = 0;
     if (resolveType != GlobalVar && resolveType != ClosureVar && resolveType != LocalClosureVar && resolveType != GlobalLexicalVar)
         linkCount++;
-    if ((resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks 
-         || resolveType == GlobalLexicalVar || resolveType == GlobalLexicalVarWithVarInjectionChecks 
-         || resolveType == LocalClosureVar)
-        && currentInstruction[5].u.watchpointSet->state() != IsInvalidated)
+    if (resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks 
+        || resolveType == GlobalLexicalVar || resolveType == GlobalLexicalVarWithVarInjectionChecks 
+        || resolveType == ClosureVar || resolveType == ClosureVarWithVarInjectionChecks
+        || resolveType == LocalClosureVar)
         linkCount++;
     if (resolveType == GlobalProperty || resolveType == GlobalPropertyWithVarInjectionChecks)
         linkCount++; // bad structure
index 6a3c464..7a933ef 100644 (file)
@@ -1102,9 +1102,10 @@ void JIT::emitSlow_op_put_to_scope(Instruction* currentInstruction, Vector<SlowC
     unsigned linkCount = 0;
     if (resolveType != GlobalVar && resolveType != ClosureVar && resolveType != LocalClosureVar && resolveType != GlobalLexicalVar)
         linkCount++;
-    if ((resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks || resolveType == LocalClosureVar
-        || resolveType == GlobalLexicalVar || resolveType == GlobalLexicalVarWithVarInjectionChecks)
-        && currentInstruction[5].u.watchpointSet->state() != IsInvalidated)
+    if (resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks 
+        || resolveType == GlobalLexicalVar || resolveType == GlobalLexicalVarWithVarInjectionChecks 
+        || resolveType == ClosureVar || resolveType == ClosureVarWithVarInjectionChecks
+        || resolveType == LocalClosureVar)
         linkCount++;
     if (!isInitialization(getPutInfo.initializationMode()) && (resolveType == GlobalLexicalVar || resolveType == GlobalLexicalVarWithVarInjectionChecks)) // TDZ check.
         linkCount++;
diff --git a/Source/JavaScriptCore/jit/JITWorklist.cpp b/Source/JavaScriptCore/jit/JITWorklist.cpp
new file mode 100644 (file)
index 0000000..83e2074
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2016 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. ``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
+ * 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 "JITWorklist.h"
+
+#if ENABLE(JIT)
+
+#include "JIT.h"
+#include "JSCInlines.h"
+#include "VMInlines.h"
+
+namespace JSC {
+
+class JITWorklist::Plan : public ThreadSafeRefCounted<JITWorklist::Plan> {
+public:
+    Plan(CodeBlock* codeBlock)
+        : m_codeBlock(codeBlock)
+        , m_jit(codeBlock->vm(), codeBlock)
+    {
+    }
+    
+    void compileInThread()
+    {
+        m_jit.compileWithoutLinking(JITCompilationCanFail);
+        
+        LockHolder locker(m_lock);
+        m_isFinishedCompiling = true;
+    }
+    
+    void finalize()
+    {
+        CompilationResult result = m_jit.link();
+        switch (result) {
+        case CompilationFailed:
+            CODEBLOCK_LOG_EVENT(m_codeBlock, "delayJITCompile", ("compilation failed"));
+            if (Options::verboseOSR())
+                dataLogF("    JIT compilation failed.\n");
+            m_codeBlock->dontJITAnytimeSoon();
+            m_codeBlock->m_didFailJITCompilation = true;
+            return;
+        case CompilationSuccessful:
+            if (Options::verboseOSR())
+                dataLogF("    JIT compilation successful.\n");
+            m_codeBlock->ownerScriptExecutable()->installCode(m_codeBlock);
+            m_codeBlock->jitSoon();
+            return;
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            return;
+        }
+        
+        LockHolder locker(m_lock);
+        m_isFinalized = true;
+    }
+    
+    CodeBlock* codeBlock() { return m_codeBlock; }
+    VM* vm() { return m_codeBlock->vm(); }
+    
+    bool isFinishedCompiling()
+    {
+        LockHolder locker(m_lock);
+        return m_isFinishedCompiling;
+    }
+    bool isFinalized()
+    {
+        LockHolder locker(m_lock);
+        return m_isFinalized;
+    }
+    
+private:
+    CodeBlock* m_codeBlock;
+    JIT m_jit;
+    Lock m_lock;
+    bool m_isFinishedCompiling { false };
+    bool m_isFinalized { false };
+};
+
+JITWorklist::JITWorklist()
+{
+    createThread("JIT Worklist Worker Thread", [this] () { runThread(); });
+}
+
+JITWorklist::~JITWorklist()
+{
+    UNREACHABLE_FOR_PLATFORM();
+}
+
+void JITWorklist::completeAllForVM(VM& vm)
+{
+    DeferGC deferGC(vm.heap);
+    for (;;) {
+        Vector<RefPtr<Plan>, 32> myPlans;
+        {
+            LockHolder locker(m_lock);
+            for (;;) {
+                bool didFindUnfinishedPlan = false;
+                m_plans.removeAllMatching(
+                    [&] (RefPtr<Plan>& plan) {
+                        if (plan->vm() != &vm)
+                            return false;
+                        if (!plan->isFinishedCompiling()) {
+                            didFindUnfinishedPlan = true;
+                            return false;
+                        }
+                        myPlans.append(WTFMove(plan));
+                        return true;
+                    });
+                
+                // If we found plans then we should finalize them now.
+                if (!myPlans.isEmpty())
+                    break;
+                
+                // If we don't find plans, then we're either done or we need to wait, depending on
+                // whether we found some unfinished plans.
+                if (!didFindUnfinishedPlan)
+                    return;
+                
+                m_condition.wait(m_lock);
+            }
+        }
+        
+        finalizePlans(myPlans);
+    }
+}
+
+void JITWorklist::poll(VM& vm)
+{
+    DeferGC deferGC(vm.heap);
+    Plans myPlans;
+    {
+        LockHolder locker(m_lock);
+        m_plans.removeAllMatching(
+            [&] (RefPtr<Plan>& plan) {
+                if (plan->vm() != &vm)
+                    return false;
+                if (!plan->isFinishedCompiling())
+                    return false;
+                myPlans.append(WTFMove(plan));
+                return true;
+            });
+    }
+    
+    finalizePlans(myPlans);
+}
+
+void JITWorklist::compileLater(CodeBlock* codeBlock)
+{
+    DeferGC deferGC(codeBlock->vm()->heap);
+    RELEASE_ASSERT(codeBlock->jitType() == JITCode::InterpreterThunk);
+    
+    if (codeBlock->m_didFailJITCompilation) {
+        codeBlock->dontJITAnytimeSoon();
+        return;
+    }
+    
+    if (!Options::useConcurrentJIT()) {
+        Plan plan(codeBlock);
+        plan.compileInThread();
+        plan.finalize();
+        return;
+    }
+    
+    codeBlock->jitSoon();
+    
+    Plans myPlans;
+    LockHolder locker(m_lock);
+    
+    if (!m_planned.add(codeBlock).isNewEntry)
+        return;
+    
+    RefPtr<Plan> plan = adoptRef(new Plan(codeBlock));
+    m_plans.append(plan);
+    m_queue.append(plan);
+    m_condition.notifyAll();
+}
+
+void JITWorklist::compileNow(CodeBlock* codeBlock)
+{
+    // If this ever happens, we'll have a bad time because the baseline JIT does not clean up its
+    // changes to the CodeBlock after a failed compilation.
+    // FIXME: https://bugs.webkit.org/show_bug.cgi?id=158806
+    RELEASE_ASSERT(!codeBlock->m_didFailJITCompilation);
+    
+    DeferGC deferGC(codeBlock->vm()->heap);
+    if (codeBlock->jitType() != JITCode::InterpreterThunk)
+        return;
+    
+    bool isPlanned;
+    {
+        LockHolder locker(m_lock);
+        isPlanned = m_planned.contains(codeBlock);
+    }
+    
+    if (isPlanned) {
+        RELEASE_ASSERT(Options::useConcurrentJIT());
+        // This is expensive, but probably good enough.
+        completeAllForVM(*codeBlock->vm());
+    }
+    
+    // Now it might be compiled!
+    if (codeBlock->jitType() != JITCode::InterpreterThunk)
+        return;
+    
+    // OK, just compile it.
+    JIT::compile(codeBlock->vm(), codeBlock, JITCompilationMustSucceed);
+    codeBlock->ownerScriptExecutable()->installCode(codeBlock);
+}
+
+void JITWorklist::runThread()
+{
+    for (;;) {
+        Plans myPlans;
+        {
+            LockHolder locker(m_lock);
+            while (m_queue.isEmpty())
+                m_condition.wait(m_lock);
+            
+            // This is a fun way to dequeue. I don't know if it's any better or worse than dequeuing
+            // one thing at a time.
+            myPlans = WTFMove(m_queue);
+        }
+        
+        RELEASE_ASSERT(!myPlans.isEmpty());
+        
+        for (RefPtr<Plan>& plan : myPlans) {
+            plan->compileInThread();
+            plan = nullptr;
+            
+            // Make sure that the main thread realizes that we just compiled something. Notifying
+            // a WTF condition is basically free if nobody is waiting.
+            LockHolder locker(m_lock);
+            m_condition.notifyAll();
+        }
+    }
+}
+
+void JITWorklist::finalizePlans(Plans& myPlans)
+{
+    for (RefPtr<Plan>& plan : myPlans) {
+        plan->finalize();
+        
+        LockHolder locker(m_lock);
+        m_planned.remove(plan->codeBlock());
+    }
+}
+
+JITWorklist* JITWorklist::instance()
+{
+    static JITWorklist* worklist;
+    static std::once_flag once;
+    std::call_once(
+        once,
+        [] {
+            worklist = new JITWorklist();
+        });
+    return worklist;
+}
+
+} // namespace JSC
+
+#endif // ENABLE(JIT)
+
diff --git a/Source/JavaScriptCore/jit/JITWorklist.h b/Source/JavaScriptCore/jit/JITWorklist.h
new file mode 100644 (file)
index 0000000..09ded64
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2016 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. ``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
+ * 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. 
+ */
+
+#ifndef JITWorklist_h
+#define JITWorklist_h
+
+#if ENABLE(JIT)
+
+#include <wtf/Condition.h>
+#include <wtf/FastMalloc.h>
+#include <wtf/HashSet.h>
+#include <wtf/Lock.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+namespace JSC {
+
+class CodeBlock;
+class VM;
+
+class JITWorklist {
+    WTF_MAKE_NONCOPYABLE(JITWorklist);
+    WTF_MAKE_FAST_ALLOCATED;
+
+    class Plan;
+    typedef Vector<RefPtr<Plan>, 32> Plans;
+    
+public:
+    ~JITWorklist();
+    
+    void completeAllForVM(VM&);
+    void poll(VM&);
+    
+    void compileLater(CodeBlock*);
+    
+    void compileNow(CodeBlock*);
+    
+    static JITWorklist* instance();
+    
+private:
+    JITWorklist();
+    
+    NO_RETURN void runThread();
+    
+    void finalizePlans(Plans&);
+    
+    Plans m_queue;
+    Plans m_plans;
+    HashSet<CodeBlock*> m_planned;
+    
+    Lock m_lock;
+    Condition m_condition; // We use One True Condition for everything because that's easier.
+};
+
+} // namespace JSC
+
+#endif // ENABLE(JIT)
+
+#endif // JITWorklist_h
+
index 12c8e3e..412f84f 100644 (file)
@@ -40,6 +40,7 @@
 #include "Interpreter.h"
 #include "JIT.h"
 #include "JITExceptions.h"
+#include "JITWorklist.h"
 #include "JSLexicalEnvironment.h"
 #include "JSCInlines.h"
 #include "JSCJSValue.h"
@@ -326,6 +327,8 @@ inline bool jitCompileAndSetHeuristics(CodeBlock* codeBlock, ExecState* exec)
         return false;
     }
     
+    JITWorklist::instance()->poll(vm);
+    
     switch (codeBlock->jitType()) {
     case JITCode::BaselineJIT: {
         if (Options::verboseOSR())
@@ -334,24 +337,8 @@ inline bool jitCompileAndSetHeuristics(CodeBlock* codeBlock, ExecState* exec)
         return true;
     }
     case JITCode::InterpreterThunk: {
-        CompilationResult result = JIT::compile(&vm, codeBlock, JITCompilationCanFail);
-        switch (result) {
-        case CompilationFailed:
-            CODEBLOCK_LOG_EVENT(codeBlock, "delayJITCompile", ("compilation failed"));
-            if (Options::verboseOSR())
-                dataLogF("    JIT compilation failed.\n");
-            codeBlock->dontJITAnytimeSoon();
-            return false;
-        case CompilationSuccessful:
-            if (Options::verboseOSR())
-                dataLogF("    JIT compilation successful.\n");
-            codeBlock->ownerScriptExecutable()->installCode(codeBlock);
-            codeBlock->jitSoon();
-            return true;
-        default:
-            RELEASE_ASSERT_NOT_REACHED();
-            return false;
-        }
+        JITWorklist::instance()->compileLater(codeBlock);
+        return codeBlock->jitType() == JITCode::BaselineJIT;
     }
     default:
         dataLog("Unexpected code block in LLInt: ", *codeBlock, "\n");
@@ -589,6 +576,9 @@ static void setupGetByIdPrototypeCache(ExecState* exec, VM& vm, Instruction* pc,
 
     if (structure->typeInfo().prohibitsPropertyCaching())
         return;
+    
+    if (structure->needImpurePropertyWatchpoint())
+        return;
 
     if (structure->isDictionary()) {
         if (structure->hasBeenFlattenedBefore())
index 783ce0a..e544310 100644 (file)
@@ -783,6 +783,7 @@ SLOW_PATH_DECL(slow_path_resolve_scope)
         if (resolvedScope->isGlobalObject()) {
             JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(resolvedScope);
             if (globalObject->hasProperty(exec, ident)) {
+                ConcurrentJITLocker locker(exec->codeBlock()->m_lock);
                 if (resolveType == UnresolvedProperty)
                     pc[4].u.operand = GlobalProperty;
                 else
@@ -792,6 +793,7 @@ SLOW_PATH_DECL(slow_path_resolve_scope)
             }
         } else if (resolvedScope->isGlobalLexicalEnvironment()) {
             JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalLexicalEnvironment*>(resolvedScope);
+            ConcurrentJITLocker locker(exec->codeBlock()->m_lock);
             if (resolveType == UnresolvedProperty)
                 pc[4].u.operand = GlobalLexicalVar;
             else
index abcb71f..784109c 100644 (file)
@@ -104,6 +104,7 @@ inline void tryCachePutToScopeGlobal(
             ResolveType newResolveType = resolveType == UnresolvedProperty ? GlobalProperty : GlobalPropertyWithVarInjectionChecks;
             resolveType = newResolveType;
             getPutInfo = GetPutInfo(getPutInfo.resolveMode(), newResolveType, getPutInfo.initializationMode());
+            ConcurrentJITLocker locker(codeBlock->m_lock);
             pc[4].u.operand = getPutInfo.operand();
         } else if (scope->isGlobalLexicalEnvironment()) {
             JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalLexicalEnvironment*>(scope);
@@ -111,6 +112,7 @@ inline void tryCachePutToScopeGlobal(
             pc[4].u.operand = GetPutInfo(getPutInfo.resolveMode(), newResolveType, getPutInfo.initializationMode()).operand();
             SymbolTableEntry entry = globalLexicalEnvironment->symbolTable()->get(ident.impl());
             ASSERT(!entry.isNull());
+            ConcurrentJITLocker locker(codeBlock->m_lock);
             pc[5].u.watchpointSet = entry.watchpointSet();
             pc[6].u.pointer = static_cast<void*>(globalLexicalEnvironment->variableAt(entry.scopeOffset()).slot());
         }
@@ -146,13 +148,15 @@ inline void tryCacheGetFromScopeGlobal(
         if (scope->isGlobalObject()) {
             ResolveType newResolveType = resolveType == UnresolvedProperty ? GlobalProperty : GlobalPropertyWithVarInjectionChecks;
             resolveType = newResolveType; // Allow below caching mechanism to kick in.
+            ConcurrentJITLocker locker(exec->codeBlock()->m_lock);
             pc[4].u.operand = GetPutInfo(getPutInfo.resolveMode(), newResolveType, getPutInfo.initializationMode()).operand();
         } else if (scope->isGlobalLexicalEnvironment()) {
             JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalLexicalEnvironment*>(scope);
             ResolveType newResolveType = resolveType == UnresolvedProperty ? GlobalLexicalVar : GlobalLexicalVarWithVarInjectionChecks;
-            pc[4].u.operand = GetPutInfo(getPutInfo.resolveMode(), newResolveType, getPutInfo.initializationMode()).operand();
             SymbolTableEntry entry = globalLexicalEnvironment->symbolTable()->get(ident.impl());
             ASSERT(!entry.isNull());
+            ConcurrentJITLocker locker(exec->codeBlock()->m_lock);
+            pc[4].u.operand = GetPutInfo(getPutInfo.resolveMode(), newResolveType, getPutInfo.initializationMode()).operand();
             pc[5].u.watchpointSet = entry.watchpointSet();
             pc[6].u.pointer = static_cast<void*>(globalLexicalEnvironment->variableAt(entry.scopeOffset()).slot());
         }
index 7535c00..5b9bf10 100644 (file)
@@ -57,6 +57,7 @@
 #include "InferredTypeTable.h"
 #include "Interpreter.h"
 #include "JITCode.h"
+#include "JITWorklist.h"
 #include "JSAPIValueWrapper.h"
 #include "JSArray.h"
 #include "JSCInlines.h"
@@ -342,6 +343,10 @@ VM::~VM()
     }
 #endif // ENABLE(SAMPLING_PROFILER)
     
+#if ENABLE(JIT)
+    JITWorklist::instance()->completeAllForVM(*this);
+#endif // ENABLE(JIT)
+
 #if ENABLE(DFG_JIT)
     // Make sure concurrent compilations are done, but don't install them, since there is
     // no point to doing so.
index f8434f6..11454ea 100644 (file)
@@ -1,3 +1,17 @@
+2016-06-14  Filip Pizlo  <fpizlo@apple.com>
+
+        Baseline JIT should be concurrent
+        https://bugs.webkit.org/show_bug.cgi?id=158755
+
+        Reviewed by Geoffrey Garen.
+        
+        The concurrent baseline JIT needs to be able to clone bytecode to get a consistent snapshot.
+        So, this adds such a method.
+
+        * wtf/RefCountedArray.h:
+        (WTF::RefCountedArray::RefCountedArray):
+        (WTF::RefCountedArray::clone):
+
 2016-06-16  Chris Dumez  <cdumez@apple.com>
 
         No need to ref connection in lambda inside NetworkResourceLoader::tryStoreAsCacheEntry()
index 79869a9..2fa8423 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -72,6 +72,14 @@ public:
         VectorTypeOperations<T>::initialize(begin(), end());
     }
 
+    RefCountedArray clone() const
+    {
+        RefCountedArray result(size());
+        for (unsigned i = size(); i--;)
+            result[i] = at(i);
+        return result;
+    }
+
     template<size_t inlineCapacity, typename OverflowHandler>
     explicit RefCountedArray(const Vector<T, inlineCapacity, OverflowHandler>& other)
     {
index 32e7940..8578229 100644 (file)
@@ -1,3 +1,15 @@
+2016-06-16  Filip Pizlo  <fpizlo@apple.com>
+
+        Baseline JIT should be concurrent
+        https://bugs.webkit.org/show_bug.cgi?id=158755
+
+        Reviewed by Geoffrey Garen.
+        
+        Need to disable concurrent JIT when running profiler tests. We should have been doing this
+        all along.
+
+        * Scripts/run-jsc-stress-tests:
+
 2016-06-16  Per Arne Vollan  <pvollan@apple.com>
 
         [Win] Accessibility implementation unable to recurse through document (sometimes) to find named elements
index d68aea9..381981d 100755 (executable)
@@ -1001,10 +1001,10 @@ def runProfiler
 
     profilerOutput = uniqueFilename(".json")
     if $canRunDisplayProfilerOutput
-        addRunCommand("profiler", ["ruby", (pathToHelpers + "profiler-test-helper").to_s, (SCRIPTS_PATH + "display-profiler-output").to_s, profilerOutput.to_s, pathToVM.to_s, "-p", profilerOutput.to_s, $benchmark.to_s], silentOutputHandler, simpleErrorHandler)
+        addRunCommand("profiler", ["ruby", (pathToHelpers + "profiler-test-helper").to_s, (SCRIPTS_PATH + "display-profiler-output").to_s, profilerOutput.to_s, pathToVM.to_s, "--useConcurrentJIT=false", "-p", profilerOutput.to_s, $benchmark.to_s], silentOutputHandler, simpleErrorHandler)
     else
         puts "Running simple version of #{$collectionName}/#{$benchmark} because some required Ruby features are unavailable."
-        run("profiler-simple", "-p", profilerOutput.to_s)
+        run("profiler-simple", "--useConcurrentJIT=false", "-p", profilerOutput.to_s)
     end
 end