Commit 88fedde1 authored by fpizlo@apple.com's avatar fpizlo@apple.com

Infer constant closure variables

https://bugs.webkit.org/show_bug.cgi?id=124630

Source/JavaScriptCore: 

Reviewed by Geoffrey Garen.
        
Captured variables that are assigned once (not counting op_enter's Undefined
initialization) and that are contained within a function that has thus far only been
entered once are now constant folded. It's pretty awesome.
        
This involves a watchpoint on the assignment to variables and a watchpoint on entry
into the function. The former is reused from global variable constant inference and the
latter is reused from one-time closure inference.

* GNUmakefile.list.am:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
* bytecode/Instruction.h:
(JSC::Instruction::Instruction):
* bytecode/Opcode.h:
(JSC::padOpcodeName):
* bytecode/UnlinkedCodeBlock.h:
(JSC::UnlinkedInstruction::UnlinkedInstruction):
* bytecode/VariableWatchpointSet.h:
(JSC::VariableWatchpointSet::invalidate):
* bytecode/Watchpoint.h:
(JSC::WatchpointSet::invalidate):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::addVar):
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitInitLazyRegister):
(JSC::BytecodeGenerator::emitMove):
(JSC::BytecodeGenerator::emitNewFunctionInternal):
(JSC::BytecodeGenerator::createArgumentsIfNecessary):
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::addVar):
(JSC::BytecodeGenerator::watchableVariable):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::getLocal):
(JSC::DFG::ByteCodeParser::inferredConstant):
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::parse):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::tryGetActivation):
(JSC::DFG::Graph::tryGetRegisters):
* dfg/DFGGraph.h:
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
* jit/JIT.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_mov):
(JSC::JIT::emit_op_captured_mov):
(JSC::JIT::emit_op_new_captured_func):
(JSC::JIT::emitSlow_op_captured_mov):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_mov):
(JSC::JIT::emit_op_captured_mov):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/CommonSlowPaths.h:
* runtime/ConstantMode.h: Added.
* runtime/JSGlobalObject.h:
* runtime/JSScope.cpp:
(JSC::abstractAccess):
* runtime/SymbolTable.cpp:
(JSC::SymbolTableEntry::prepareToWatch):

LayoutTests: 

Reviewed by Geoffrey Garen.
        
This adds both correctness and performance tests for constant closure variable
inference.

* js/regress/infer-closure-const-then-mov-expected.txt: Added.
* js/regress/infer-closure-const-then-mov-no-inline-expected.txt: Added.
* js/regress/infer-closure-const-then-mov-no-inline.html: Added.
* js/regress/infer-closure-const-then-mov.html: Added.
* js/regress/infer-closure-const-then-put-to-scope-expected.txt: Added.
* js/regress/infer-closure-const-then-put-to-scope-no-inline-expected.txt: Added.
* js/regress/infer-closure-const-then-put-to-scope-no-inline.html: Added.
* js/regress/infer-closure-const-then-put-to-scope.html: Added.
* js/regress/infer-closure-const-then-reenter-expected.txt: Added.
* js/regress/infer-closure-const-then-reenter-no-inline-expected.txt: Added.
* js/regress/infer-closure-const-then-reenter-no-inline.html: Added.
* js/regress/infer-closure-const-then-reenter.html: Added.
* js/regress/script-tests/infer-closure-const-then-mov-no-inline.js: Added.
* js/regress/script-tests/infer-closure-const-then-mov.js: Added.
* js/regress/script-tests/infer-closure-const-then-put-to-scope-no-inline.js: Added.
(thingy.):
(thingy):
* js/regress/script-tests/infer-closure-const-then-put-to-scope.js: Added.
(thingy.):
(thingy):
* js/regress/script-tests/infer-closure-const-then-reenter-no-inline.js: Added.
(.return.foo):
(foo):
* js/regress/script-tests/infer-closure-const-then-reenter.js: Added.
(.return.foo):
(foo):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@160109 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 07923100
2013-12-03 Filip Pizlo <fpizlo@apple.com>
Infer constant closure variables
https://bugs.webkit.org/show_bug.cgi?id=124630
Reviewed by Geoffrey Garen.
This adds both correctness and performance tests for constant closure variable
inference.
* js/regress/infer-closure-const-then-mov-expected.txt: Added.
* js/regress/infer-closure-const-then-mov-no-inline-expected.txt: Added.
* js/regress/infer-closure-const-then-mov-no-inline.html: Added.
* js/regress/infer-closure-const-then-mov.html: Added.
* js/regress/infer-closure-const-then-put-to-scope-expected.txt: Added.
* js/regress/infer-closure-const-then-put-to-scope-no-inline-expected.txt: Added.
* js/regress/infer-closure-const-then-put-to-scope-no-inline.html: Added.
* js/regress/infer-closure-const-then-put-to-scope.html: Added.
* js/regress/infer-closure-const-then-reenter-expected.txt: Added.
* js/regress/infer-closure-const-then-reenter-no-inline-expected.txt: Added.
* js/regress/infer-closure-const-then-reenter-no-inline.html: Added.
* js/regress/infer-closure-const-then-reenter.html: Added.
* js/regress/script-tests/infer-closure-const-then-mov-no-inline.js: Added.
* js/regress/script-tests/infer-closure-const-then-mov.js: Added.
* js/regress/script-tests/infer-closure-const-then-put-to-scope-no-inline.js: Added.
(thingy.):
(thingy):
* js/regress/script-tests/infer-closure-const-then-put-to-scope.js: Added.
(thingy.):
(thingy):
* js/regress/script-tests/infer-closure-const-then-reenter-no-inline.js: Added.
(.return.foo):
(foo):
* js/regress/script-tests/infer-closure-const-then-reenter.js: Added.
(.return.foo):
(foo):
2013-12-04 Mario Sanchez Prada <mario.prada@samsung.com>
Unreviewed GTK gardening. Updated expectations for GTK and share them with EFL.
......
JSRegress/infer-closure-const-then-mov
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS no exception thrown
PASS successfullyParsed is true
TEST COMPLETE
JSRegress/infer-closure-const-then-mov-no-inline
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS no exception thrown
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../../resources/js-test-pre.js"></script>
</head>
<body>
<script src="resources/regress-pre.js"></script>
<script src="script-tests/infer-closure-const-then-mov-no-inline.js"></script>
<script src="resources/regress-post.js"></script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../../resources/js-test-pre.js"></script>
</head>
<body>
<script src="resources/regress-pre.js"></script>
<script src="script-tests/infer-closure-const-then-mov.js"></script>
<script src="resources/regress-post.js"></script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>
JSRegress/infer-closure-const-then-put-to-scope
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS no exception thrown
PASS successfullyParsed is true
TEST COMPLETE
JSRegress/infer-closure-const-then-put-to-scope-no-inline
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS no exception thrown
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../../resources/js-test-pre.js"></script>
</head>
<body>
<script src="resources/regress-pre.js"></script>
<script src="script-tests/infer-closure-const-then-put-to-scope-no-inline.js"></script>
<script src="resources/regress-post.js"></script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../../resources/js-test-pre.js"></script>
</head>
<body>
<script src="resources/regress-pre.js"></script>
<script src="script-tests/infer-closure-const-then-put-to-scope.js"></script>
<script src="resources/regress-post.js"></script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>
JSRegress/infer-closure-const-then-reenter
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS no exception thrown
PASS successfullyParsed is true
TEST COMPLETE
JSRegress/infer-closure-const-then-reenter-no-inline
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS no exception thrown
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../../resources/js-test-pre.js"></script>
</head>
<body>
<script src="resources/regress-pre.js"></script>
<script src="script-tests/infer-closure-const-then-reenter-no-inline.js"></script>
<script src="resources/regress-post.js"></script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../../resources/js-test-pre.js"></script>
</head>
<body>
<script src="resources/regress-pre.js"></script>
<script src="script-tests/infer-closure-const-then-reenter.js"></script>
<script src="resources/regress-post.js"></script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>
(function(){
var a = 42;
var b = 23;
var c = 84;
var d = 13;
var e = 90;
var f = 34;
var g = 52;
function foo() {
return a + b + c + d + e + f + g;
}
noInline(foo);
for (var i = 0; i < 500000; ++i) {
var result = foo();
if (result != 42 + 23 + 84 + 13 + 90 + 34 + 52)
throw "Error: bad result: " + result;
}
a = 1;
b = 2;
c = 3;
d = 4;
e = 5;
f = 6;
g = 7;
var result = foo();
if (result != 1 + 2 + 3 + 4 + 5 + 6 + 7)
throw "Error: bad result: " + result;
})();
(function(){
var a = 42;
var b = 23;
var c = 84;
var d = 13;
var e = 90;
var f = 34;
var g = 52;
function foo() {
return a + b + c + d + e + f + g;
}
for (var i = 0; i < 10000000; ++i) {
var result = foo();
if (result != 42 + 23 + 84 + 13 + 90 + 34 + 52)
throw "Error: bad result: " + result;
}
a = 1;
b = 2;
c = 3;
d = 4;
e = 5;
f = 6;
g = 7;
var result = foo();
if (result != 1 + 2 + 3 + 4 + 5 + 6 + 7)
throw "Error: bad result: " + result;
})();
var thingy = (function(){
var a = 42;
var b = 23;
var c = 84;
var d = 13;
var e = 90;
var f = 34;
var g = 52;
return {
foo: function() {
return a + b + c + d + e + f + g;
},
bar: function() {
a = 1;
b = 2;
c = 3;
d = 4;
e = 5;
f = 6;
g = 7;
}
};
})();
noInline(thingy.foo);
for (var i = 0; i < 2000000; ++i) {
var result = thingy.foo();
if (result != 42 + 23 + 84 + 13 + 90 + 34 + 52)
throw "Error: bad result: " + result;
}
thingy.bar();
var result = thingy.foo();
if (result != 1 + 2 + 3 + 4 + 5 + 6 + 7)
throw "Error: bad result: " + result;
var thingy = (function(){
var a = 42;
var b = 23;
var c = 84;
var d = 13;
var e = 90;
var f = 34;
var g = 52;
return {
foo: function() {
return a + b + c + d + e + f + g;
},
bar: function() {
a = 1;
b = 2;
c = 3;
d = 4;
e = 5;
f = 6;
g = 7;
}
};
})();
for (var i = 0; i < 10000000; ++i) {
var result = thingy.foo();
if (result != 42 + 23 + 84 + 13 + 90 + 34 + 52)
throw "Error: bad result: " + result;
}
thingy.bar();
var result = thingy.foo();
if (result != 1 + 2 + 3 + 4 + 5 + 6 + 7)
throw "Error: bad result: " + result;
function foo(a_, b_, c_, d_, e_, f_, g_) {
var a = a_;
var b = b_;
var c = c_;
var d = d_;
var e = e_;
var f = f_;
var g = g_;
return {
foo: function() {
return a + b + c + d + e + f + g;
}
};
}
noInline(foo);
var thingy = foo(42, 23, 84, 13, 90, 34, 52);
noInline(thingy.foo);
for (var i = 0; i < 10000000; ++i) {
var result = thingy.foo();
if (result != 42 + 23 + 84 + 13 + 90 + 34 + 52)
throw "Error: bad result: " + result;
}
var result = foo(1, 2, 3, 4, 5, 6, 7).foo();
if (result != 1 + 2 + 3 + 4 + 5 + 6 + 7)
throw "Error: bad result: " + result;
function foo(a_, b_, c_, d_, e_, f_, g_) {
var a = a_;
var b = b_;
var c = c_;
var d = d_;
var e = e_;
var f = f_;
var g = g_;
return {
foo: function() {
return a + b + c + d + e + f + g;
}
};
}
var thingy = foo(42, 23, 84, 13, 90, 34, 52);
for (var i = 0; i < 10000000; ++i) {
var result = thingy.foo();
if (result != 42 + 23 + 84 + 13 + 90 + 34 + 52)
throw "Error: bad result: " + result;
}
var result = foo(1, 2, 3, 4, 5, 6, 7).foo();
if (result != 1 + 2 + 3 + 4 + 5 + 6 + 7)
throw "Error: bad result: " + result;
2013-12-03 Filip Pizlo <fpizlo@apple.com>
Infer constant closure variables
https://bugs.webkit.org/show_bug.cgi?id=124630
Reviewed by Geoffrey Garen.
Captured variables that are assigned once (not counting op_enter's Undefined
initialization) and that are contained within a function that has thus far only been
entered once are now constant folded. It's pretty awesome.
This involves a watchpoint on the assignment to variables and a watchpoint on entry
into the function. The former is reused from global variable constant inference and the
latter is reused from one-time closure inference.
* GNUmakefile.list.am:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
* bytecode/Instruction.h:
(JSC::Instruction::Instruction):
* bytecode/Opcode.h:
(JSC::padOpcodeName):
* bytecode/UnlinkedCodeBlock.h:
(JSC::UnlinkedInstruction::UnlinkedInstruction):
* bytecode/VariableWatchpointSet.h:
(JSC::VariableWatchpointSet::invalidate):
* bytecode/Watchpoint.h:
(JSC::WatchpointSet::invalidate):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::addVar):
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitInitLazyRegister):
(JSC::BytecodeGenerator::emitMove):
(JSC::BytecodeGenerator::emitNewFunctionInternal):
(JSC::BytecodeGenerator::createArgumentsIfNecessary):
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::addVar):
(JSC::BytecodeGenerator::watchableVariable):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::getLocal):
(JSC::DFG::ByteCodeParser::inferredConstant):
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::parse):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::tryGetActivation):
(JSC::DFG::Graph::tryGetRegisters):
* dfg/DFGGraph.h:
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
* jit/JIT.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_mov):
(JSC::JIT::emit_op_captured_mov):
(JSC::JIT::emit_op_new_captured_func):
(JSC::JIT::emitSlow_op_captured_mov):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_mov):
(JSC::JIT::emit_op_captured_mov):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/CommonSlowPaths.h:
* runtime/ConstantMode.h: Added.
* runtime/JSGlobalObject.h:
* runtime/JSScope.cpp:
(JSC::abstractAccess):
* runtime/SymbolTable.cpp:
(JSC::SymbolTableEntry::prepareToWatch):
2013-12-04 Brent Fulgham <bfulgham@apple.com>
[Win] Unreviewed project file gardening.
......
......@@ -822,6 +822,7 @@ javascriptcore_sources += \
Source/JavaScriptCore/runtime/Completion.cpp \
Source/JavaScriptCore/runtime/Completion.h \
Source/JavaScriptCore/runtime/ConcurrentJITLock.h \
Source/JavaScriptCore/runtime/ConstantMode.h \
Source/JavaScriptCore/runtime/ConstructData.cpp \
Source/JavaScriptCore/runtime/ConstructData.h \
Source/JavaScriptCore/runtime/DataView.cpp \
......
......@@ -1113,6 +1113,7 @@
<ClInclude Include="..\runtime\CommonSlowPathsExceptions.h" />
<ClInclude Include="..\runtime\CompilationResult.h" />
<ClInclude Include="..\runtime\Completion.h" />
<ClInclude Include="..\runtime\ConstantMode.h" />
<ClInclude Include="..\runtime\ConstructData.h" />
<ClInclude Include="..\runtime\DataView.h" />
<ClInclude Include="..\runtime\DateConstructor.h" />
......
......@@ -541,6 +541,7 @@
0FFB921E16D02F470055A5DB /* DFGVariadicFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F85A31E16AB76AE0077571E /* DFGVariadicFunction.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FFB921F16D033050055A5DB /* (null) in Headers */ = {isa = PBXBuildFile; settings = {ATTRIBUTES = (Private, ); }; };
0FFB922016D033B70055A5DB /* NodeConstructors.h in Headers */ = {isa = PBXBuildFile; fileRef = 930DAD030FB1EB1A0082D205 /* NodeConstructors.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FFC99D1184EC8AD009C10AB /* ConstantMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFC99D0184EC8AD009C10AB /* ConstantMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FFFC95714EF90A000C72532 /* DFGCFAPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FFFC94B14EF909500C72532 /* DFGCFAPhase.cpp */; };
0FFFC95814EF90A200C72532 /* DFGCFAPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFFC94C14EF909500C72532 /* DFGCFAPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FFFC95914EF90A600C72532 /* DFGCSEPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FFFC94D14EF909500C72532 /* DFGCSEPhase.cpp */; };
......@@ -1845,6 +1846,7 @@
0FF729A1166AD347000F5BA3 /* ProfilerOriginStack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProfilerOriginStack.cpp; path = profiler/ProfilerOriginStack.cpp; sourceTree = "<group>"; };
0FF729A2166AD347000F5BA3 /* ProfilerOriginStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProfilerOriginStack.h; path = profiler/ProfilerOriginStack.h; sourceTree = "<group>"; };
0FF922CF14F46B130041A24E /* JSCLLIntOffsetsExtractor */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = JSCLLIntOffsetsExtractor; sourceTree = BUILT_PRODUCTS_DIR; };
0FFC99D0184EC8AD009C10AB /* ConstantMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConstantMode.h; sourceTree = "<group>"; };
0FFFC94B14EF909500C72532 /* DFGCFAPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCFAPhase.cpp; path = dfg/DFGCFAPhase.cpp; sourceTree = "<group>"; };
0FFFC94C14EF909500C72532 /* DFGCFAPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCFAPhase.h; path = dfg/DFGCFAPhase.h; sourceTree = "<group>"; };
0FFFC94D14EF909500C72532 /* DFGCSEPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCSEPhase.cpp; path = dfg/DFGCSEPhase.cpp; sourceTree = "<group>"; };
......@@ -3404,6 +3406,7 @@
969A09220ED1E09C00F1F681 /* Completion.cpp */,
F5BB2BC5030F772101FCFE1D /* Completion.h */,
0FDB2CE9174896C7007B3C1B /* ConcurrentJITLock.h */,
0FFC99D0184EC8AD009C10AB /* ConstantMode.h */,
BCA62DFF0E2826310004F30D /* ConstructData.cpp */,
BC8F3CCF0DAF17BA00577A80 /* ConstructData.h */,
0F2B66B017B6B5AB00A7AE3F /* DataView.cpp */,
......@@ -4418,6 +4421,7 @@
0FD82E57141DAF1000179C94 /* DFGOSREntry.h in Headers */,
0FD8A32617D51F5700CA2C40 /* DFGOSREntrypointCreationPhase.h in Headers */,
0FC0976A1468A6F700CF2442 /* DFGOSRExit.h in Headers */,
0FFC99D1184EC8AD009C10AB /* ConstantMode.h in Headers */,
0F235BEC17178E7300690C7F /* DFGOSRExitBase.h in Headers */,
A5BA15ED182340B400A82E69 /* RemoteInspectorXPCConnection.h in Headers */,
0FFB921C16D02F110055A5DB /* DFGOSRExitCompilationInfo.h in Headers */,
......
......@@ -768,6 +768,7 @@ void CodeBlock::dumpBytecode(PrintStream& out, ExecState* exec, const Instructio
int r1 = (++it)->u.operand;
printLocationAndOp(out, exec, location, it, "captured_mov");
out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
++it;
break;
}
case op_not: {
......@@ -1224,9 +1225,9 @@ void CodeBlock::dumpBytecode(PrintStream& out, ExecState* exec, const Instructio
case op_new_captured_func: {
int r0 = (++it)->u.operand;
int f0 = (++it)->u.operand;
int shouldCheck = (++it)->u.operand;
printLocationAndOp(out, exec, location, it, "new_captured_func");
out.printf("%s, f%d, %s", registerName(r0).data(), f0, shouldCheck ? "<Checked>" : "<Unchecked>");
out.printf("%s, f%d", registerName(r0).data(), f0);
++it;
break;
}
case op_new_func_exp: {
......@@ -1551,10 +1552,13 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
{
ASSERT(m_heap->isDeferred());
bool didCloneSymbolTable = false;
if (SymbolTable* symbolTable = unlinkedCodeBlock->symbolTable()) {
if (codeType() == FunctionCode && symbolTable->captureCount())
if (codeType() == FunctionCode && symbolTable->captureCount()) {
m_symbolTable.set(*m_vm, m_ownerExecutable.get(), symbolTable->clone(*m_vm));
else
didCloneSymbolTable = true;
} else
m_symbolTable.set(*m_vm, m_ownerExecutable.get(), symbolTable);
}
......@@ -1820,11 +1824,28 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
instructions[i + 4].u.operand = ResolveModeAndType(modeAndType.mode(), op.type).operand();
if (op.type == GlobalVar || op.type == GlobalVarWithVarInjectionChecks)
instructions[i + 5].u.watchpointSet = op.watchpointSet;
else if (op.structure)
else if (op.type == ClosureVar || op.type == ClosureVarWithVarInjectionChecks) {
if (op.watchpointSet)
op.watchpointSet->invalidate();
} else if (op.structure)
instructions[i + 5].u.structure.set(*vm(), ownerExecutable, op.structure);
instructions[i + 6].u.pointer = reinterpret_cast<void*>(op.operand);
break;
}
case op_captured_mov:
case op_new_captured_func: {
StringImpl* uid = pc[i + 3].u.uid;
if (!uid)
break;
RELEASE_ASSERT(didCloneSymbolTable);
ConcurrentJITLocker locker(m_symbolTable->m_lock);
SymbolTable::Map::iterator iter = m_symbolTable->find(locker, uid);
ASSERT(iter != m_symbolTable->end(locker));
iter->value.prepareToWatch();
instructions[i + 3].u.watchpointSet = iter->value.watchpointSet();
break;
}
default:
break;
......
......@@ -90,16 +90,13 @@ struct Instruction {
Instruction(PropertySlot::GetValueFunc getterFunc) { u.getterFunc = getterFunc; }
Instruction(LLIntCallLinkInfo* callLinkInfo) { u.callLinkInfo = callLinkInfo; }
Instruction(ValueProfile* profile) { u.profile = profile; }
Instruction(ArrayProfile* profile) { u.arrayProfile = profile; }
Instruction(ArrayAllocationProfile* profile) { u.arrayAllocationProfile = profile; }
Instruction(ObjectAllocationProfile* profile) { u.objectAllocationProfile = profile; }
Instruction(WriteBarrier<Unknown>* registerPointer) { u.registerPointer = registerPointer; }
Instruction(Special::Pointer pointer) { u.specialPointer = pointer; }
Instruction(StringImpl* uid) { u.uid = uid; }
Instruction(bool* predicatePointer) { u.predicatePointer = predicatePointer; }
union {
......@@ -112,6 +109,7 @@ struct Instruction {
Special::Pointer specialPointer;
PropertySlot::GetValueFunc getterFunc;
LLIntCallLinkInfo* callLinkInfo;
StringImpl* uid;
ValueProfile* profile;
ArrayProfile* arrayProfile;
ArrayAllocationProfile* arrayAllocationProfile;
......
......@@ -55,7 +55,7 @@ namespace JSC {
macro(op_new_array_buffer, 5) \
macro(op_new_regexp, 3) \
macro(op_mov, 3) \
macro(op_captured_mov, 3) \
macro(op_captured_mov, 4) \
\
macro(op_not, 3) \
macro(op_eq, 4) \
......
......@@ -229,9 +229,11 @@ struct UnlinkedInstruction {
UnlinkedInstruction() { u.operand = 0; }
UnlinkedInstruction(OpcodeID opcode) { u.opcode = opcode; }
UnlinkedInstruction(int operand) { u.operand = operand; }
UnlinkedInstruction(StringImpl* uid) { u.uid = uid; }
union {
OpcodeID opcode;
int32_t operand;
StringImpl* uid;
} u;
};
......
......@@ -80,10 +80,8 @@ public:
void invalidate()
{
ASSERT(!!m_inferredValue);
ASSERT(state() == IsWatched);
m_inferredValue = JSValue();
fireAll();
WatchpointSet::invalidate();
}
void finalizeUnconditionally()
......
......@@ -115,6 +115,13 @@ public:
else
fireAll();
}
void invalidate()
{
if (state() == IsWatched)
fireAll();
m_state = IsInvalidated;
}
int8_t* addressOfState() { return &m_state; }
int8_t* addressOfSetIsNotEmpty() { return &m_setIsNotEmpty; }
......
......@@ -115,19 +115,31 @@ ParserError BytecodeGenerator::generate()