<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[200586] trunk/Source/JavaScriptCore</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/200586">200586</a></dd>
<dt>Author</dt> <dd>sbarati@apple.com</dd>
<dt>Date</dt> <dd>2016-05-09 13:17:23 -0700 (Mon, 09 May 2016)</dd>
</dl>
<h3>Log Message</h3>
<pre>Getter and setter on super are called with wrong "this" object
https://bugs.webkit.org/show_bug.cgi?id=147064
<rdar://problem/21885916>
Reviewed by Filip Pizlo.
This patch implements calls to 'super' getters and setters.
The problem before is we were passing the 'super' (i.e, the prototype
object) as the this value to these getters/setters, which is wrong.
We should be passing the caller's this value.
To implement this behavior, I've introduced four new opcodes and their corresponding DFG nodes:
- op_get_by_id_with_this | GetByIdWithThis
- op_put_by_id_with_this | PutByIdWithThis
- op_get_by_val_with_this | GetByValWithThis
- op_put_by_val_with_this | PutByValWithThis
These are implemented with no optimizations. The future plan is
to unite them with the *by_id and *by_val opcodes and nodes:
https://bugs.webkit.org/show_bug.cgi?id=157215
* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitGetById):
(JSC::BytecodeGenerator::emitPutById):
(JSC::BytecodeGenerator::emitDirectPutById):
(JSC::BytecodeGenerator::emitGetByVal):
(JSC::BytecodeGenerator::emitPutByVal):
(JSC::BytecodeGenerator::emitDirectPutByVal):
(JSC::BytecodeGenerator::emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment):
(JSC::BytecodeGenerator::ensureThis):
(JSC::BytecodeGenerator::isThisUsedInInnerArrowFunction):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::ThisNode::emitBytecode):
(JSC::emitHomeObjectForCallee):
(JSC::emitSuperBaseForCallee):
(JSC::emitGetSuperFunctionForConstruct):
(JSC::SuperNode::emitBytecode):
(JSC::NewTargetNode::emitBytecode):
(JSC::TaggedTemplateNode::emitBytecode):
(JSC::BracketAccessorNode::emitBytecode):
(JSC::DotAccessorNode::emitBytecode):
(JSC::FunctionCallValueNode::emitBytecode):
(JSC::FunctionCallBracketNode::emitBytecode):
(JSC::FunctionCallDotNode::emitBytecode):
(JSC::CallFunctionCallDotNode::emitBytecode):
(JSC::ApplyFunctionCallDotNode::emitBytecode):
(JSC::PostfixNode::emitBracket):
(JSC::PostfixNode::emitDot):
(JSC::PrefixNode::emitBracket):
(JSC::PrefixNode::emitDot):
(JSC::AssignDotNode::emitBytecode):
(JSC::ReadModifyDotNode::emitBytecode):
(JSC::AssignBracketNode::emitBytecode):
(JSC::ReadModifyBracketNode::emitBytecode):
(JSC::ForInNode::emitLoopHeader):
(JSC::ForOfNode::emitBytecode):
(JSC::AssignmentElementNode::bindValue):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasIdentifier):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
(JSC::DFG::newTypedArrayWithSize):
(JSC::DFG::putWithThis):
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileGetById):
(JSC::FTL::DFG::LowerDFGToB3::compileGetByIdWithThis):
(JSC::FTL::DFG::LowerDFGToB3::compileGetByValWithThis):
(JSC::FTL::DFG::LowerDFGToB3::compilePutByIdWithThis):
(JSC::FTL::DFG::LowerDFGToB3::compilePutByValWithThis):
(JSC::FTL::DFG::LowerDFGToB3::compilePutById):
* jit/CCallHelpers.cpp:
(JSC::CCallHelpers::setupShadowChickenPacket):
(JSC::CCallHelpers::setupFourStubArgsGPR):
* jit/CCallHelpers.h:
(JSC::CCallHelpers::setupArgumentsWithExecState):
(JSC::CCallHelpers::setupThreeStubArgsGPR):
(JSC::CCallHelpers::setupTwoStubArgsFPR):
(JSC::CCallHelpers::setupStubArguments134):
* jit/GPRInfo.h:
(JSC::argumentRegisterFor): Deleted.
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
* jit/JITOperations.h:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::emit_op_put_by_val_with_this):
(JSC::JIT::emitGenericContiguousPutByVal):
(JSC::JIT::emit_op_get_by_id):
(JSC::JIT::emit_op_get_by_id_with_this):
(JSC::JIT::emit_op_get_by_val_with_this):
(JSC::JIT::emitSlow_op_get_by_id):
(JSC::JIT::emit_op_put_by_id):
(JSC::JIT::emit_op_put_by_id_with_this):
(JSC::JIT::emitSlow_op_put_by_id):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_put_to_arguments):
(JSC::JIT::emit_op_get_by_id_with_this):
(JSC::JIT::emit_op_get_by_val_with_this):
(JSC::JIT::emit_op_put_by_id_with_this):
(JSC::JIT::emit_op_put_by_val_with_this):
* llint/LowLevelInterpreter.asm:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/CommonSlowPaths.h:
* tests/stress/super-property-access-exceptions.js: Added.
(assert):
(test):
(test.fooProp):
(test.A.prototype.get foo):
(test.A.prototype.get x):
(test.A):
(test.B):
(test.B.prototype.bar):
(test.B.prototype.baz):
(test.foo):
(test.func):
(test.A.prototype.set foo):
* tests/stress/super-property-access-tdz.js: Added.
(assert):
(test):
(shouldThrowTDZ):
(test.A.prototype.get foo):
(test.A.prototype.set foo):
(test.A):
(test.fooProp):
(test.B):
(test.C):
(test.D):
(test.E):
(test.F):
* tests/stress/super-property-access.js: Added.
(assert):
(test):
(func):
(test.A):
(test.A.prototype.set value):
(test.A.prototype.get value):
(test.B.prototype.set value):
(test.B.prototype.get value):
(test.B):
(test.value):
(test.A.prototype.get func):
(test.B.prototype.inc):
(test.B.prototype.dec):
(test.B.prototype.preInc):
(test.B.prototype.preDec):
(test.B.prototype.plusEq):
(test.B.prototype.minusEq):
(test.B.prototype.timesEq):
(test.B.prototype.divEq):
(test.B.prototype.funcDot):
(test.B.prototype.funcBracket):
(test.foo):
(test.B.prototype.baz):
(test.B.prototype.jaz):
(test.B.prototype.bar):
(test.B.prototype.index):
(test.):
(test.prototype.bar):
(test.A.prototype.set foo):
(test.A.prototype.get array):
(test.A.prototype.get foo):
(test.obj):
(test.A.prototype.get call):
(test.A.prototype.get apply):
(test.B.prototype.foo):
(test.A.prototype.get i):</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeBytecodeListjson">trunk/Source/JavaScriptCore/bytecode/BytecodeList.json</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeBytecodeUseDefh">trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeCodeBlockcpp">trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp">trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorh">trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerNodesCodegencpp">trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh">trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp">trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGCapabilitiescpp">trunk/Source/JavaScriptCore/dfg/DFGCapabilities.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGClobberizeh">trunk/Source/JavaScriptCore/dfg/DFGClobberize.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGDoesGCcpp">trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGFixupPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeh">trunk/Source/JavaScriptCore/dfg/DFGNode.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeTypeh">trunk/Source/JavaScriptCore/dfg/DFGNodeType.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGOperationscpp">trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGOperationsh">trunk/Source/JavaScriptCore/dfg/DFGOperations.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSafeToExecuteh">trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJITh">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCapabilitiescpp">trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitCCallHelperscpp">trunk/Source/JavaScriptCore/jit/CCallHelpers.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitCCallHelpersh">trunk/Source/JavaScriptCore/jit/CCallHelpers.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitGPRInfoh">trunk/Source/JavaScriptCore/jit/GPRInfo.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITcpp">trunk/Source/JavaScriptCore/jit/JIT.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITh">trunk/Source/JavaScriptCore/jit/JIT.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOperationsh">trunk/Source/JavaScriptCore/jit/JITOperations.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITPropertyAccesscpp">trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITPropertyAccess32_64cpp">trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLowLevelInterpreterasm">trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeCommonSlowPathscpp">trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeCommonSlowPathsh">trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.h</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestsstresssuperpropertyaccessexceptionsjs">trunk/Source/JavaScriptCore/tests/stress/super-property-access-exceptions.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstresssuperpropertyaccesstdzjs">trunk/Source/JavaScriptCore/tests/stress/super-property-access-tdz.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstresssuperpropertyaccessjs">trunk/Source/JavaScriptCore/tests/stress/super-property-access.js</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -1,3 +1,206 @@
</span><ins>+2016-05-09 Saam barati <sbarati@apple.com>
+
+ Getter and setter on super are called with wrong "this" object
+ https://bugs.webkit.org/show_bug.cgi?id=147064
+ <rdar://problem/21885916>
+
+ Reviewed by Filip Pizlo.
+
+ This patch implements calls to 'super' getters and setters.
+ The problem before is we were passing the 'super' (i.e, the prototype
+ object) as the this value to these getters/setters, which is wrong.
+ We should be passing the caller's this value.
+
+ To implement this behavior, I've introduced four new opcodes and their corresponding DFG nodes:
+ - op_get_by_id_with_this | GetByIdWithThis
+ - op_put_by_id_with_this | PutByIdWithThis
+ - op_get_by_val_with_this | GetByValWithThis
+ - op_put_by_val_with_this | PutByValWithThis
+
+ These are implemented with no optimizations. The future plan is
+ to unite them with the *by_id and *by_val opcodes and nodes:
+ https://bugs.webkit.org/show_bug.cgi?id=157215
+
+ * bytecode/BytecodeList.json:
+ * bytecode/BytecodeUseDef.h:
+ (JSC::computeUsesForBytecodeOffset):
+ (JSC::computeDefsForBytecodeOffset):
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::dumpBytecode):
+ * bytecompiler/BytecodeGenerator.cpp:
+ (JSC::BytecodeGenerator::emitGetById):
+ (JSC::BytecodeGenerator::emitPutById):
+ (JSC::BytecodeGenerator::emitDirectPutById):
+ (JSC::BytecodeGenerator::emitGetByVal):
+ (JSC::BytecodeGenerator::emitPutByVal):
+ (JSC::BytecodeGenerator::emitDirectPutByVal):
+ (JSC::BytecodeGenerator::emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment):
+ (JSC::BytecodeGenerator::ensureThis):
+ (JSC::BytecodeGenerator::isThisUsedInInnerArrowFunction):
+ * bytecompiler/BytecodeGenerator.h:
+ * bytecompiler/NodesCodegen.cpp:
+ (JSC::ThisNode::emitBytecode):
+ (JSC::emitHomeObjectForCallee):
+ (JSC::emitSuperBaseForCallee):
+ (JSC::emitGetSuperFunctionForConstruct):
+ (JSC::SuperNode::emitBytecode):
+ (JSC::NewTargetNode::emitBytecode):
+ (JSC::TaggedTemplateNode::emitBytecode):
+ (JSC::BracketAccessorNode::emitBytecode):
+ (JSC::DotAccessorNode::emitBytecode):
+ (JSC::FunctionCallValueNode::emitBytecode):
+ (JSC::FunctionCallBracketNode::emitBytecode):
+ (JSC::FunctionCallDotNode::emitBytecode):
+ (JSC::CallFunctionCallDotNode::emitBytecode):
+ (JSC::ApplyFunctionCallDotNode::emitBytecode):
+ (JSC::PostfixNode::emitBracket):
+ (JSC::PostfixNode::emitDot):
+ (JSC::PrefixNode::emitBracket):
+ (JSC::PrefixNode::emitDot):
+ (JSC::AssignDotNode::emitBytecode):
+ (JSC::ReadModifyDotNode::emitBytecode):
+ (JSC::AssignBracketNode::emitBytecode):
+ (JSC::ReadModifyBracketNode::emitBytecode):
+ (JSC::ForInNode::emitLoopHeader):
+ (JSC::ForOfNode::emitBytecode):
+ (JSC::AssignmentElementNode::bindValue):
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ * dfg/DFGCapabilities.cpp:
+ (JSC::DFG::capabilityLevel):
+ * dfg/DFGClobberize.h:
+ (JSC::DFG::clobberize):
+ * dfg/DFGDoesGC.cpp:
+ (JSC::DFG::doesGC):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::hasIdentifier):
+ * dfg/DFGNodeType.h:
+ * dfg/DFGOperations.cpp:
+ (JSC::DFG::newTypedArrayWithSize):
+ (JSC::DFG::putWithThis):
+ * dfg/DFGOperations.h:
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ * dfg/DFGSafeToExecute.h:
+ (JSC::DFG::safeToExecute):
+ * dfg/DFGSpeculativeJIT.h:
+ (JSC::DFG::SpeculativeJIT::callOperation):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * ftl/FTLCapabilities.cpp:
+ (JSC::FTL::canCompile):
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+ (JSC::FTL::DFG::LowerDFGToB3::compileGetById):
+ (JSC::FTL::DFG::LowerDFGToB3::compileGetByIdWithThis):
+ (JSC::FTL::DFG::LowerDFGToB3::compileGetByValWithThis):
+ (JSC::FTL::DFG::LowerDFGToB3::compilePutByIdWithThis):
+ (JSC::FTL::DFG::LowerDFGToB3::compilePutByValWithThis):
+ (JSC::FTL::DFG::LowerDFGToB3::compilePutById):
+ * jit/CCallHelpers.cpp:
+ (JSC::CCallHelpers::setupShadowChickenPacket):
+ (JSC::CCallHelpers::setupFourStubArgsGPR):
+ * jit/CCallHelpers.h:
+ (JSC::CCallHelpers::setupArgumentsWithExecState):
+ (JSC::CCallHelpers::setupThreeStubArgsGPR):
+ (JSC::CCallHelpers::setupTwoStubArgsFPR):
+ (JSC::CCallHelpers::setupStubArguments134):
+ * jit/GPRInfo.h:
+ (JSC::argumentRegisterFor): Deleted.
+ * jit/JIT.cpp:
+ (JSC::JIT::privateCompileMainPass):
+ * jit/JIT.h:
+ * jit/JITOperations.h:
+ * jit/JITPropertyAccess.cpp:
+ (JSC::JIT::emit_op_put_by_val):
+ (JSC::JIT::emit_op_put_by_val_with_this):
+ (JSC::JIT::emitGenericContiguousPutByVal):
+ (JSC::JIT::emit_op_get_by_id):
+ (JSC::JIT::emit_op_get_by_id_with_this):
+ (JSC::JIT::emit_op_get_by_val_with_this):
+ (JSC::JIT::emitSlow_op_get_by_id):
+ (JSC::JIT::emit_op_put_by_id):
+ (JSC::JIT::emit_op_put_by_id_with_this):
+ (JSC::JIT::emitSlow_op_put_by_id):
+ * jit/JITPropertyAccess32_64.cpp:
+ (JSC::JIT::emit_op_put_to_arguments):
+ (JSC::JIT::emit_op_get_by_id_with_this):
+ (JSC::JIT::emit_op_get_by_val_with_this):
+ (JSC::JIT::emit_op_put_by_id_with_this):
+ (JSC::JIT::emit_op_put_by_val_with_this):
+ * llint/LowLevelInterpreter.asm:
+ * runtime/CommonSlowPaths.cpp:
+ (JSC::SLOW_PATH_DECL):
+ * runtime/CommonSlowPaths.h:
+ * tests/stress/super-property-access-exceptions.js: Added.
+ (assert):
+ (test):
+ (test.fooProp):
+ (test.A.prototype.get foo):
+ (test.A.prototype.get x):
+ (test.A):
+ (test.B):
+ (test.B.prototype.bar):
+ (test.B.prototype.baz):
+ (test.foo):
+ (test.func):
+ (test.A.prototype.set foo):
+ * tests/stress/super-property-access-tdz.js: Added.
+ (assert):
+ (test):
+ (shouldThrowTDZ):
+ (test.A.prototype.get foo):
+ (test.A.prototype.set foo):
+ (test.A):
+ (test.fooProp):
+ (test.B):
+ (test.C):
+ (test.D):
+ (test.E):
+ (test.F):
+ * tests/stress/super-property-access.js: Added.
+ (assert):
+ (test):
+ (func):
+ (test.A):
+ (test.A.prototype.set value):
+ (test.A.prototype.get value):
+ (test.B.prototype.set value):
+ (test.B.prototype.get value):
+ (test.B):
+ (test.value):
+ (test.A.prototype.get func):
+ (test.B.prototype.inc):
+ (test.B.prototype.dec):
+ (test.B.prototype.preInc):
+ (test.B.prototype.preDec):
+ (test.B.prototype.plusEq):
+ (test.B.prototype.minusEq):
+ (test.B.prototype.timesEq):
+ (test.B.prototype.divEq):
+ (test.B.prototype.funcDot):
+ (test.B.prototype.funcBracket):
+ (test.foo):
+ (test.B.prototype.baz):
+ (test.B.prototype.jaz):
+ (test.B.prototype.bar):
+ (test.B.prototype.index):
+ (test.):
+ (test.prototype.bar):
+ (test.A.prototype.set foo):
+ (test.A.prototype.get array):
+ (test.A.prototype.get foo):
+ (test.obj):
+ (test.A.prototype.get call):
+ (test.A.prototype.get apply):
+ (test.B.prototype.foo):
+ (test.A.prototype.get i):
+
</ins><span class="cx"> 2016-05-08 Chris Dumez <cdumez@apple.com>
</span><span class="cx">
</span><span class="cx"> [COCOA] Disable HAVE_DTRACE at build time
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeBytecodeListjson"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/BytecodeList.json (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/BytecodeList.json        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/bytecode/BytecodeList.json        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -60,11 +60,15 @@
</span><span class="cx"> { "name" : "op_in", "length" : 4 },
</span><span class="cx"> { "name" : "op_try_get_by_id", "length" : 4 },
</span><span class="cx"> { "name" : "op_get_by_id", "length" : 9 },
</span><ins>+ { "name" : "op_get_by_id_with_this", "length" : 5 },
+ { "name" : "op_get_by_val_with_this", "length" : 5 },
</ins><span class="cx"> { "name" : "op_get_array_length", "length" : 9 },
</span><span class="cx"> { "name" : "op_put_by_id", "length" : 9 },
</span><ins>+ { "name" : "op_put_by_id_with_this", "length" : 5 },
</ins><span class="cx"> { "name" : "op_del_by_id", "length" : 4 },
</span><span class="cx"> { "name" : "op_get_by_val", "length" : 6 },
</span><span class="cx"> { "name" : "op_put_by_val", "length" : 5 },
</span><ins>+ { "name" : "op_put_by_val_with_this", "length" : 5 },
</ins><span class="cx"> { "name" : "op_put_by_val_direct", "length" : 5 },
</span><span class="cx"> { "name" : "op_del_by_val", "length" : 4 },
</span><span class="cx"> { "name" : "op_put_by_index", "length" : 4 },
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeBytecodeUseDefh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.h (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.h        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.h        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -111,6 +111,21 @@
</span><span class="cx"> functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
</span><span class="cx"> return;
</span><span class="cx"> }
</span><ins>+ case op_put_by_id_with_this: {
+ ASSERT(opcodeLengths[opcodeID] > 4);
+ functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
+ functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
+ functor(codeBlock, instruction, opcodeID, instruction[4].u.operand);
+ return;
+ }
+ case op_put_by_val_with_this: {
+ ASSERT(opcodeLengths[opcodeID] > 4);
+ functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
+ functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
+ functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
+ functor(codeBlock, instruction, opcodeID, instruction[4].u.operand);
+ return;
+ }
</ins><span class="cx"> case op_put_getter_by_id:
</span><span class="cx"> case op_put_setter_by_id: {
</span><span class="cx"> ASSERT(opcodeLengths[opcodeID] > 4);
</span><span class="lines">@@ -203,12 +218,20 @@
</span><span class="cx"> case op_neq:
</span><span class="cx"> case op_eq:
</span><span class="cx"> case op_push_with_scope:
</span><ins>+ case op_get_by_id_with_this:
</ins><span class="cx"> case op_del_by_val: {
</span><span class="cx"> ASSERT(opcodeLengths[opcodeID] > 3);
</span><span class="cx"> functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
</span><span class="cx"> functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
</span><span class="cx"> return;
</span><span class="cx"> }
</span><ins>+ case op_get_by_val_with_this: {
+ ASSERT(opcodeLengths[opcodeID] > 4);
+ functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
+ functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
+ functor(codeBlock, instruction, opcodeID, instruction[4].u.operand);
+ return;
+ }
</ins><span class="cx"> case op_instanceof_custom:
</span><span class="cx"> case op_has_structure_property:
</span><span class="cx"> case op_construct_varargs:
</span><span class="lines">@@ -316,6 +339,8 @@
</span><span class="cx"> case op_switch_char:
</span><span class="cx"> case op_switch_string:
</span><span class="cx"> case op_put_by_id:
</span><ins>+ case op_put_by_id_with_this:
+ case op_put_by_val_with_this:
</ins><span class="cx"> case op_put_getter_by_id:
</span><span class="cx"> case op_put_setter_by_id:
</span><span class="cx"> case op_put_getter_setter_by_id:
</span><span class="lines">@@ -371,6 +396,8 @@
</span><span class="cx"> case op_construct:
</span><span class="cx"> case op_try_get_by_id:
</span><span class="cx"> case op_get_by_id:
</span><ins>+ case op_get_by_id_with_this:
+ case op_get_by_val_with_this:
</ins><span class="cx"> case op_get_array_length:
</span><span class="cx"> case op_overrides_has_instance:
</span><span class="cx"> case op_instanceof:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -1117,11 +1117,47 @@
</span><span class="cx"> dumpValueProfiling(out, it, hasPrintedProfiling);
</span><span class="cx"> break;
</span><span class="cx"> }
</span><ins>+ case op_get_by_id_with_this: {
+ printLocationAndOp(out, exec, location, it, "get_by_id_with_this");
+ int r0 = (++it)->u.operand;
+ int r1 = (++it)->u.operand;
+ int r2 = (++it)->u.operand;
+ int id0 = (++it)->u.operand;
+ out.printf("%s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), idName(id0, identifier(id0)).data());
+ break;
+ }
+ case op_get_by_val_with_this: {
+ int r0 = (++it)->u.operand;
+ int r1 = (++it)->u.operand;
+ int r2 = (++it)->u.operand;
+ int r3 = (++it)->u.operand;
+ printLocationAndOp(out, exec, location, it, "get_by_val_with_this");
+ out.printf("%s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), registerName(r3).data());
+ break;
+ }
</ins><span class="cx"> case op_put_by_id: {
</span><span class="cx"> printPutByIdOp(out, exec, location, it, "put_by_id");
</span><span class="cx"> printPutByIdCacheStatus(out, location, stubInfos);
</span><span class="cx"> break;
</span><span class="cx"> }
</span><ins>+ case op_put_by_id_with_this: {
+ int r0 = (++it)->u.operand;
+ int r1 = (++it)->u.operand;
+ int id0 = (++it)->u.operand;
+ int r2 = (++it)->u.operand;
+ printLocationAndOp(out, exec, location, it, "put_by_id_with_this");
+ out.printf("%s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), idName(id0, identifier(id0)).data(), registerName(r2).data());
+ break;
+ }
+ case op_put_by_val_with_this: {
+ int r0 = (++it)->u.operand;
+ int r1 = (++it)->u.operand;
+ int r2 = (++it)->u.operand;
+ int r3 = (++it)->u.operand;
+ printLocationAndOp(out, exec, location, it, "put_by_val_with_this");
+ out.printf("%s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), registerName(r3).data());
+ break;
+ }
</ins><span class="cx"> case op_put_getter_by_id: {
</span><span class="cx"> int r0 = (++it)->u.operand;
</span><span class="cx"> int id0 = (++it)->u.operand;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -2410,6 +2410,18 @@
</span><span class="cx"> return dst;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+RegisterID* BytecodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, RegisterID* thisVal, const Identifier& property)
+{
+ ASSERT_WITH_MESSAGE(!parseIndex(property), "Indexed properties should be handled with get_by_val.");
+
+ emitOpcode(op_get_by_id_with_this);
+ instructions().append(kill(dst));
+ instructions().append(base->index());
+ instructions().append(thisVal->index());
+ instructions().append(addConstant(property));
+ return dst;
+}
+
</ins><span class="cx"> RegisterID* BytecodeGenerator::emitPutById(RegisterID* base, const Identifier& property, RegisterID* value)
</span><span class="cx"> {
</span><span class="cx"> ASSERT_WITH_MESSAGE(!parseIndex(property), "Indexed properties should be handled with put_by_val.");
</span><span class="lines">@@ -2433,6 +2445,21 @@
</span><span class="cx"> return value;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+RegisterID* BytecodeGenerator::emitPutById(RegisterID* base, RegisterID* thisValue, const Identifier& property, RegisterID* value)
+{
+ ASSERT_WITH_MESSAGE(!parseIndex(property), "Indexed properties should be handled with put_by_val.");
+
+ unsigned propertyIndex = addConstant(property);
+
+ emitOpcode(op_put_by_id_with_this);
+ instructions().append(base->index());
+ instructions().append(thisValue->index());
+ instructions().append(propertyIndex);
+ instructions().append(value->index());
+
+ return value;
+}
+
</ins><span class="cx"> RegisterID* BytecodeGenerator::emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value, PropertyNode::PutType putType)
</span><span class="cx"> {
</span><span class="cx"> ASSERT_WITH_MESSAGE(!parseIndex(property), "Indexed properties should be handled with put_by_val(direct).");
</span><span class="lines">@@ -2557,6 +2584,16 @@
</span><span class="cx"> return dst;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+RegisterID* BytecodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* thisValue, RegisterID* property)
+{
+ emitOpcode(op_get_by_val_with_this);
+ instructions().append(kill(dst));
+ instructions().append(base->index());
+ instructions().append(thisValue->index());
+ instructions().append(property->index());
+ return dst;
+}
+
</ins><span class="cx"> RegisterID* BytecodeGenerator::emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value)
</span><span class="cx"> {
</span><span class="cx"> UnlinkedArrayProfile arrayProfile = newArrayProfile();
</span><span class="lines">@@ -2569,6 +2606,17 @@
</span><span class="cx"> return value;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+RegisterID* BytecodeGenerator::emitPutByVal(RegisterID* base, RegisterID* thisValue, RegisterID* property, RegisterID* value)
+{
+ emitOpcode(op_put_by_val_with_this);
+ instructions().append(base->index());
+ instructions().append(thisValue->index());
+ instructions().append(property->index());
+ instructions().append(value->index());
+
+ return value;
+}
+
</ins><span class="cx"> RegisterID* BytecodeGenerator::emitDirectPutByVal(RegisterID* base, RegisterID* property, RegisterID* value)
</span><span class="cx"> {
</span><span class="cx"> UnlinkedArrayProfile arrayProfile = newArrayProfile();
</span><span class="lines">@@ -4215,6 +4263,17 @@
</span><span class="cx"> Variable protoScopeVar = variable(propertyNames().derivedConstructorPrivateName);
</span><span class="cx"> return emitGetFromScope(newTemporary(), emitLoadArrowFunctionLexicalEnvironment(propertyNames().derivedConstructorPrivateName), protoScopeVar, ThrowIfNotFound);
</span><span class="cx"> }
</span><ins>+
+RegisterID* BytecodeGenerator::ensureThis()
+{
+ if (constructorKind() == ConstructorKind::Derived && needsToUpdateArrowFunctionContext() && isSuperCallUsedInInnerArrowFunction())
+ emitLoadThisFromArrowFunctionLexicalEnvironment();
+
+ if (constructorKind() == ConstructorKind::Derived || isDerivedConstructorContext())
+ emitTDZCheck(thisRegister());
+
+ return thisRegister();
+}
</ins><span class="cx">
</span><span class="cx"> bool BytecodeGenerator::isThisUsedInInnerArrowFunction()
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -502,6 +502,7 @@
</span><span class="cx"> void emitProfileControlFlow(int);
</span><span class="cx">
</span><span class="cx"> RegisterID* emitLoadArrowFunctionLexicalEnvironment(const Identifier&);
</span><ins>+ RegisterID* ensureThis();
</ins><span class="cx"> void emitLoadThisFromArrowFunctionLexicalEnvironment();
</span><span class="cx"> RegisterID* emitLoadNewTargetFromArrowFunctionLexicalEnvironment();
</span><span class="cx">
</span><span class="lines">@@ -550,12 +551,16 @@
</span><span class="cx">
</span><span class="cx"> RegisterID* emitTryGetById(RegisterID* dst, RegisterID* base, const Identifier& property);
</span><span class="cx"> RegisterID* emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property);
</span><ins>+ RegisterID* emitGetById(RegisterID* dst, RegisterID* base, RegisterID* thisVal, const Identifier& property);
</ins><span class="cx"> RegisterID* emitPutById(RegisterID* base, const Identifier& property, RegisterID* value);
</span><ins>+ RegisterID* emitPutById(RegisterID* base, RegisterID* thisValue, const Identifier& property, RegisterID* value);
</ins><span class="cx"> RegisterID* emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value, PropertyNode::PutType);
</span><span class="cx"> RegisterID* emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier&);
</span><span class="cx"> RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
</span><ins>+ RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* thisValue, RegisterID* property);
</ins><span class="cx"> RegisterID* emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
</span><span class="cx"> RegisterID* emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value);
</span><ins>+ RegisterID* emitPutByVal(RegisterID* base, RegisterID* thisValue, RegisterID* property, RegisterID* value);
</ins><span class="cx"> RegisterID* emitDirectPutByVal(RegisterID* base, RegisterID* property, RegisterID* value);
</span><span class="cx"> RegisterID* emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
</span><span class="cx"> RegisterID* emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerNodesCodegencpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -145,12 +145,8 @@
</span><span class="cx">
</span><span class="cx"> RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
</span><span class="cx"> {
</span><del>- if (generator.constructorKind() == ConstructorKind::Derived && generator.needsToUpdateArrowFunctionContext() && generator.isSuperCallUsedInInnerArrowFunction())
- generator.emitLoadThisFromArrowFunctionLexicalEnvironment();
-
- if (m_shouldAlwaysEmitTDZCheck || generator.constructorKind() == ConstructorKind::Derived || generator.isDerivedConstructorContext())
- generator.emitTDZCheck(generator.thisRegister());
-
</del><ins>+ generator.ensureThis();
+ UNUSED_PARAM(m_shouldAlwaysEmitTDZCheck);
</ins><span class="cx"> if (dst == generator.ignoredResult())
</span><span class="cx"> return 0;
</span><span class="cx">
</span><span class="lines">@@ -162,19 +158,6 @@
</span><span class="cx">
</span><span class="cx"> // ------------------------------ SuperNode -------------------------------------
</span><span class="cx">
</span><del>-RegisterID* SuperNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
-{
- if (dst == generator.ignoredResult())
- return 0;
-
- if (generator.isDerivedConstructorContext())
- return generator.emitGetById(generator.finalDestination(dst), generator.emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment(), generator.propertyNames().underscoreProto);
-
- RegisterID callee;
- callee.setIndex(JSStack::Callee);
- return generator.emitGetById(generator.finalDestination(dst), &callee, generator.propertyNames().underscoreProto);
-}
-
</del><span class="cx"> static RegisterID* emitHomeObjectForCallee(BytecodeGenerator& generator)
</span><span class="cx"> {
</span><span class="cx"> if (generator.isDerivedClassContext() || generator.isDerivedConstructorContext()) {
</span><span class="lines">@@ -193,6 +176,22 @@
</span><span class="cx"> return generator.emitGetById(generator.newTemporary(), homeObject.get(), generator.propertyNames().underscoreProto);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+static RegisterID* emitGetSuperFunctionForConstruct(BytecodeGenerator& generator)
+{
+ if (generator.isDerivedConstructorContext())
+ return generator.emitGetById(generator.newTemporary(), generator.emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment(), generator.propertyNames().underscoreProto);
+
+ RegisterID callee;
+ callee.setIndex(JSStack::Callee);
+ return generator.emitGetById(generator.newTemporary(), &callee, generator.propertyNames().underscoreProto);
+}
+
+RegisterID* SuperNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+{
+ RegisterID* result = emitSuperBaseForCallee(generator);
+ return generator.moveToDestinationIfNeeded(generator.finalDestination(dst), result);
+}
+
</ins><span class="cx"> // ------------------------------ NewTargetNode ----------------------------------
</span><span class="cx">
</span><span class="cx"> RegisterID* NewTargetNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
</span><span class="lines">@@ -309,13 +308,21 @@
</span><span class="cx"> base = generator.newTemporary();
</span><span class="cx"> base = generator.emitNode(base.get(), bracket->base());
</span><span class="cx"> RefPtr<RegisterID> property = generator.emitNode(bracket->subscript());
</span><del>- tag = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get());
</del><ins>+ if (bracket->base()->isSuperNode()) {
+ RefPtr<RegisterID> thisValue = generator.ensureThis();
+ tag = generator.emitGetByVal(generator.newTemporary(), base.get(), thisValue.get(), property.get());
+ } else
+ tag = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get());
</ins><span class="cx"> } else {
</span><span class="cx"> ASSERT(m_tag->isDotAccessorNode());
</span><span class="cx"> DotAccessorNode* dot = static_cast<DotAccessorNode*>(m_tag);
</span><span class="cx"> base = generator.newTemporary();
</span><span class="cx"> base = generator.emitNode(base.get(), dot->base());
</span><del>- tag = generator.emitGetById(generator.newTemporary(), base.get(), dot->identifier());
</del><ins>+ if (dot->base()->isSuperNode()) {
+ RefPtr<RegisterID> thisValue = generator.ensureThis();
+ tag = generator.emitGetById(generator.newTemporary(), base.get(), thisValue.get(), dot->identifier());
+ } else
+ tag = generator.emitGetById(generator.newTemporary(), base.get(), dot->identifier());
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> RefPtr<RegisterID> templateObject = generator.emitGetTemplateObject(generator.newTemporary(), this);
</span><span class="lines">@@ -620,29 +627,37 @@
</span><span class="cx"> RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
</span><span class="cx"> {
</span><span class="cx"> if (m_base->isSuperNode()) {
</span><del>- // FIXME: Should we generate the profiler info?
</del><ins>+ RefPtr<RegisterID> finalDest = generator.finalDestination(dst);
+ RefPtr<RegisterID> thisValue = generator.ensureThis();
+ RefPtr<RegisterID> superBase = emitSuperBaseForCallee(generator);
</ins><span class="cx"> if (isNonIndexStringElement(*m_subscript)) {
</span><span class="cx"> const Identifier& id = static_cast<StringNode*>(m_subscript)->value();
</span><del>- return generator.emitGetById(generator.finalDestination(dst), emitSuperBaseForCallee(generator), id);
</del><ins>+ generator.emitGetById(finalDest.get(), superBase.get(), thisValue.get(), id);
+ } else {
+ RefPtr<RegisterID> subscript = generator.emitNode(m_subscript);
+ generator.emitGetByVal(finalDest.get(), superBase.get(), thisValue.get(), subscript.get());
</ins><span class="cx"> }
</span><del>- return generator.emitGetByVal(generator.finalDestination(dst), emitSuperBaseForCallee(generator), generator.emitNode(m_subscript));
</del><ins>+
+ generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
+ generator.emitProfileType(finalDest.get(), divotStart(), divotEnd());
+ return finalDest.get();
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> RegisterID* ret;
</span><del>- RegisterID* finalDest = generator.finalDestination(dst);
</del><ins>+ RefPtr<RegisterID> finalDest = generator.finalDestination(dst);
</ins><span class="cx">
</span><span class="cx"> if (isNonIndexStringElement(*m_subscript)) {
</span><span class="cx"> RefPtr<RegisterID> base = generator.emitNode(m_base);
</span><del>- ret = generator.emitGetById(finalDest, base.get(), static_cast<StringNode*>(m_subscript)->value());
</del><ins>+ ret = generator.emitGetById(finalDest.get(), base.get(), static_cast<StringNode*>(m_subscript)->value());
</ins><span class="cx"> } else {
</span><span class="cx"> RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator));
</span><span class="cx"> RegisterID* property = generator.emitNode(m_subscript);
</span><del>- ret = generator.emitGetByVal(finalDest, base.get(), property);
</del><ins>+ ret = generator.emitGetByVal(finalDest.get(), base.get(), property);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
</span><span class="cx">
</span><del>- generator.emitProfileType(finalDest, divotStart(), divotEnd());
</del><ins>+ generator.emitProfileType(finalDest.get(), divotStart(), divotEnd());
</ins><span class="cx"> return ret;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -650,10 +665,16 @@
</span><span class="cx">
</span><span class="cx"> RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
</span><span class="cx"> {
</span><del>- RefPtr<RegisterID> base = m_base->isSuperNode() ? emitSuperBaseForCallee(generator) : generator.emitNode(m_base);
</del><ins>+ bool baseIsSuper = m_base->isSuperNode();
+ RefPtr<RegisterID> base = baseIsSuper ? emitSuperBaseForCallee(generator) : generator.emitNode(m_base);
</ins><span class="cx"> generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
</span><span class="cx"> RegisterID* finalDest = generator.finalDestination(dst);
</span><del>- RegisterID* ret = generator.emitGetById(finalDest, base.get(), m_ident);
</del><ins>+ RegisterID* ret;
+ if (baseIsSuper) {
+ RefPtr<RegisterID> thisValue = generator.ensureThis();
+ ret = generator.emitGetById(finalDest, base.get(), thisValue.get(), m_ident);
+ } else
+ ret = generator.emitGetById(finalDest, base.get(), m_ident);
</ins><span class="cx"> generator.emitProfileType(finalDest, divotStart(), divotEnd());
</span><span class="cx"> return ret;
</span><span class="cx"> }
</span><span class="lines">@@ -755,10 +776,11 @@
</span><span class="cx">
</span><span class="cx"> RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
</span><span class="cx"> {
</span><del>- RefPtr<RegisterID> func = generator.emitNode(m_expr);
- RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get());
- CallArguments callArguments(generator, m_args);
</del><span class="cx"> if (m_expr->isSuperNode()) {
</span><ins>+ RefPtr<RegisterID> func = emitGetSuperFunctionForConstruct(generator);
+ RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get());
+ CallArguments callArguments(generator, m_args);
+
</ins><span class="cx"> ASSERT(generator.isConstructor() || generator.derivedContextType() == DerivedContextType::DerivedConstructorContext);
</span><span class="cx"> ASSERT(generator.constructorKind() == ConstructorKind::Derived || generator.derivedContextType() == DerivedContextType::DerivedConstructorContext);
</span><span class="cx"> generator.emitMove(callArguments.thisRegister(), generator.newTarget());
</span><span class="lines">@@ -782,6 +804,9 @@
</span><span class="cx">
</span><span class="cx"> return ret;
</span><span class="cx"> }
</span><ins>+ RefPtr<RegisterID> func = generator.emitNode(m_expr);
+ RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get());
+ CallArguments callArguments(generator, m_args);
</ins><span class="cx"> generator.emitLoad(callArguments.thisRegister(), jsUndefined());
</span><span class="cx"> RegisterID* ret = generator.emitCallInTailPosition(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd());
</span><span class="cx"> generator.emitProfileType(returnValue.get(), divotStart(), divotEnd());
</span><span class="lines">@@ -922,20 +947,31 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> RefPtr<RegisterID> function;
</span><ins>+ RefPtr<RegisterID> thisRegister;
+ if (baseIsSuper) {
+ // Note that we only need to do this once because we either have a non-TDZ this or we throw. Once we have a non-TDZ this, we can't change its value back to TDZ.
+ thisRegister = generator.ensureThis();
+ }
</ins><span class="cx"> if (subscriptIsNonIndexString) {
</span><span class="cx"> generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd());
</span><del>- function = generator.emitGetById(generator.tempDestination(dst), base.get(), static_cast<StringNode*>(m_subscript)->value());
</del><ins>+ if (baseIsSuper)
+ function = generator.emitGetById(generator.tempDestination(dst), base.get(), thisRegister.get(), static_cast<StringNode*>(m_subscript)->value());
+ else
+ function = generator.emitGetById(generator.tempDestination(dst), base.get(), static_cast<StringNode*>(m_subscript)->value());
</ins><span class="cx"> } else {
</span><span class="cx"> RefPtr<RegisterID> property = generator.emitNode(m_subscript);
</span><span class="cx"> generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd());
</span><del>- function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get());
</del><ins>+ if (baseIsSuper)
+ function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), thisRegister.get(), property.get());
+ else
+ function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get());
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> RefPtr<RegisterID> returnValue = generator.finalDestination(dst, function.get());
</span><span class="cx"> CallArguments callArguments(generator, m_args);
</span><span class="cx"> if (baseIsSuper) {
</span><span class="cx"> generator.emitTDZCheck(generator.thisRegister());
</span><del>- generator.emitMove(callArguments.thisRegister(), generator.thisRegister());
</del><ins>+ generator.emitMove(callArguments.thisRegister(), thisRegister.get());
</ins><span class="cx"> } else
</span><span class="cx"> generator.emitMove(callArguments.thisRegister(), base.get());
</span><span class="cx"> RegisterID* ret = generator.emitCallInTailPosition(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd());
</span><span class="lines">@@ -951,13 +987,16 @@
</span><span class="cx"> RefPtr<RegisterID> returnValue = generator.finalDestination(dst, function.get());
</span><span class="cx"> CallArguments callArguments(generator, m_args);
</span><span class="cx"> bool baseIsSuper = m_base->isSuperNode();
</span><ins>+ if (baseIsSuper)
+ generator.emitMove(callArguments.thisRegister(), generator.ensureThis());
+ else
+ generator.emitNode(callArguments.thisRegister(), m_base);
+ generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd());
</ins><span class="cx"> if (baseIsSuper) {
</span><del>- generator.emitTDZCheck(generator.thisRegister());
- generator.emitMove(callArguments.thisRegister(), generator.thisRegister());
</del><ins>+ RefPtr<RegisterID> superBase = emitSuperBaseForCallee(generator);
+ generator.emitGetById(function.get(), superBase.get(), callArguments.thisRegister(), m_ident);
</ins><span class="cx"> } else
</span><del>- generator.emitNode(callArguments.thisRegister(), m_base);
- generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd());
- generator.emitGetById(function.get(), baseIsSuper ? emitSuperBaseForCallee(generator) : callArguments.thisRegister(), m_ident);
</del><ins>+ generator.emitGetById(function.get(), callArguments.thisRegister(), m_ident);
</ins><span class="cx"> RegisterID* ret = generator.emitCallInTailPosition(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd());
</span><span class="cx"> generator.emitProfileType(returnValue.get(), divotStart(), divotEnd());
</span><span class="cx"> return ret;
</span><span class="lines">@@ -972,7 +1011,11 @@
</span><span class="cx"> RefPtr<RegisterID> function;
</span><span class="cx"> bool emitCallCheck = !generator.isBuiltinFunction();
</span><span class="cx"> if (emitCallCheck) {
</span><del>- function = generator.emitGetById(generator.tempDestination(dst), base.get(), generator.propertyNames().builtinNames().callPublicName());
</del><ins>+ if (m_base->isSuperNode()) {
+ RefPtr<RegisterID> thisValue = generator.ensureThis();
+ function = generator.emitGetById(generator.tempDestination(dst), base.get(), thisValue.get(), generator.propertyNames().builtinNames().callPublicName());
+ } else
+ function = generator.emitGetById(generator.tempDestination(dst), base.get(), generator.propertyNames().builtinNames().callPublicName());
</ins><span class="cx"> generator.emitJumpIfNotFunctionCall(function.get(), realCall.get());
</span><span class="cx"> }
</span><span class="cx"> RefPtr<RegisterID> returnValue = generator.finalDestination(dst);
</span><span class="lines">@@ -1039,7 +1082,11 @@
</span><span class="cx"> RefPtr<RegisterID> returnValue = generator.finalDestination(dst, function.get());
</span><span class="cx"> bool emitCallCheck = !generator.isBuiltinFunction();
</span><span class="cx"> if (emitCallCheck) {
</span><del>- function = generator.emitGetById(generator.tempDestination(dst), base.get(), generator.propertyNames().builtinNames().applyPublicName());
</del><ins>+ if (m_base->isSuperNode()) {
+ RefPtr<RegisterID> thisValue = generator.ensureThis();
+ function = generator.emitGetById(generator.tempDestination(dst), base.get(), thisValue.get(), generator.propertyNames().builtinNames().applyPublicName());
+ } else
+ function = generator.emitGetById(generator.tempDestination(dst), base.get(), generator.propertyNames().builtinNames().applyPublicName());
</ins><span class="cx"> generator.emitJumpIfNotFunctionApply(function.get(), realCall.get());
</span><span class="cx"> }
</span><span class="cx"> if (mayBeCall) {
</span><span class="lines">@@ -1196,10 +1243,19 @@
</span><span class="cx"> RefPtr<RegisterID> property = generator.emitNode(subscript);
</span><span class="cx">
</span><span class="cx"> generator.emitExpressionInfo(bracketAccessor->divot(), bracketAccessor->divotStart(), bracketAccessor->divotEnd());
</span><del>- RefPtr<RegisterID> value = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get());
</del><ins>+ RefPtr<RegisterID> value;
+ RefPtr<RegisterID> thisValue;
+ if (baseNode->isSuperNode()) {
+ thisValue = generator.ensureThis();
+ value = generator.emitGetByVal(generator.newTemporary(), base.get(), thisValue.get(), property.get());
+ } else
+ value = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get());
</ins><span class="cx"> RegisterID* oldValue = emitPostIncOrDec(generator, generator.tempDestination(dst), value.get(), m_operator);
</span><span class="cx"> generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
</span><del>- generator.emitPutByVal(base.get(), property.get(), value.get());
</del><ins>+ if (baseNode->isSuperNode())
+ generator.emitPutByVal(base.get(), thisValue.get(), property.get(), value.get());
+ else
+ generator.emitPutByVal(base.get(), property.get(), value.get());
</ins><span class="cx"> generator.emitProfileType(value.get(), divotStart(), divotEnd());
</span><span class="cx"> return generator.moveToDestinationIfNeeded(dst, oldValue);
</span><span class="cx"> }
</span><span class="lines">@@ -1212,15 +1268,25 @@
</span><span class="cx"> ASSERT(m_expr->isDotAccessorNode());
</span><span class="cx"> DotAccessorNode* dotAccessor = static_cast<DotAccessorNode*>(m_expr);
</span><span class="cx"> ExpressionNode* baseNode = dotAccessor->base();
</span><ins>+ bool baseIsSuper = baseNode->isSuperNode();
</ins><span class="cx"> const Identifier& ident = dotAccessor->identifier();
</span><span class="cx">
</span><span class="cx"> RefPtr<RegisterID> base = generator.emitNode(baseNode);
</span><span class="cx">
</span><span class="cx"> generator.emitExpressionInfo(dotAccessor->divot(), dotAccessor->divotStart(), dotAccessor->divotEnd());
</span><del>- RefPtr<RegisterID> value = generator.emitGetById(generator.newTemporary(), base.get(), ident);
</del><ins>+ RefPtr<RegisterID> value;
+ RefPtr<RegisterID> thisValue;
+ if (baseIsSuper) {
+ thisValue = generator.ensureThis();
+ value = generator.emitGetById(generator.newTemporary(), base.get(), thisValue.get(), ident);
+ } else
+ value = generator.emitGetById(generator.newTemporary(), base.get(), ident);
</ins><span class="cx"> RegisterID* oldValue = emitPostIncOrDec(generator, generator.tempDestination(dst), value.get(), m_operator);
</span><span class="cx"> generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
</span><del>- generator.emitPutById(base.get(), ident, value.get());
</del><ins>+ if (baseIsSuper)
+ generator.emitPutById(base.get(), thisValue.get(), ident, value.get());
+ else
+ generator.emitPutById(base.get(), ident, value.get());
</ins><span class="cx"> generator.emitProfileType(value.get(), divotStart(), divotEnd());
</span><span class="cx"> return generator.moveToDestinationIfNeeded(dst, oldValue);
</span><span class="cx"> }
</span><span class="lines">@@ -1393,10 +1459,19 @@
</span><span class="cx"> RefPtr<RegisterID> propDst = generator.tempDestination(dst);
</span><span class="cx">
</span><span class="cx"> generator.emitExpressionInfo(bracketAccessor->divot(), bracketAccessor->divotStart(), bracketAccessor->divotEnd());
</span><del>- RegisterID* value = generator.emitGetByVal(propDst.get(), base.get(), property.get());
</del><ins>+ RegisterID* value;
+ RefPtr<RegisterID> thisValue;
+ if (baseNode->isSuperNode()) {
+ thisValue = generator.ensureThis();
+ value = generator.emitGetByVal(propDst.get(), base.get(), thisValue.get(), property.get());
+ } else
+ value = generator.emitGetByVal(propDst.get(), base.get(), property.get());
</ins><span class="cx"> emitIncOrDec(generator, value, m_operator);
</span><span class="cx"> generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
</span><del>- generator.emitPutByVal(base.get(), property.get(), value);
</del><ins>+ if (baseNode->isSuperNode())
+ generator.emitPutByVal(base.get(), thisValue.get(), property.get(), value);
+ else
+ generator.emitPutByVal(base.get(), property.get(), value);
</ins><span class="cx"> generator.emitProfileType(value, divotStart(), divotEnd());
</span><span class="cx"> return generator.moveToDestinationIfNeeded(dst, propDst.get());
</span><span class="cx"> }
</span><span class="lines">@@ -1412,10 +1487,19 @@
</span><span class="cx"> RefPtr<RegisterID> propDst = generator.tempDestination(dst);
</span><span class="cx">
</span><span class="cx"> generator.emitExpressionInfo(dotAccessor->divot(), dotAccessor->divotStart(), dotAccessor->divotEnd());
</span><del>- RegisterID* value = generator.emitGetById(propDst.get(), base.get(), ident);
</del><ins>+ RegisterID* value;
+ RefPtr<RegisterID> thisValue;
+ if (baseNode->isSuperNode()) {
+ thisValue = generator.ensureThis();
+ value = generator.emitGetById(propDst.get(), base.get(), thisValue.get(), ident);
+ } else
+ value = generator.emitGetById(propDst.get(), base.get(), ident);
</ins><span class="cx"> emitIncOrDec(generator, value, m_operator);
</span><span class="cx"> generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
</span><del>- generator.emitPutById(base.get(), ident, value);
</del><ins>+ if (baseNode->isSuperNode())
+ generator.emitPutById(base.get(), thisValue.get(), ident, value);
+ else
+ generator.emitPutById(base.get(), ident, value);
</ins><span class="cx"> generator.emitProfileType(value, divotStart(), divotEnd());
</span><span class="cx"> return generator.moveToDestinationIfNeeded(dst, propDst.get());
</span><span class="cx"> }
</span><span class="lines">@@ -2015,10 +2099,14 @@
</span><span class="cx"> RefPtr<RegisterID> value = generator.destinationForAssignResult(dst);
</span><span class="cx"> RefPtr<RegisterID> result = generator.emitNode(value.get(), m_right);
</span><span class="cx"> generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
</span><del>- RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result.get() : generator.moveToDestinationIfNeeded(generator.tempDestination(result.get()), result.get());
- generator.emitPutById(base.get(), m_ident, forwardResult);
- generator.emitProfileType(forwardResult, divotStart(), divotEnd());
- return generator.moveToDestinationIfNeeded(dst, forwardResult);
</del><ins>+ RefPtr<RegisterID> forwardResult = (dst == generator.ignoredResult()) ? result.get() : generator.moveToDestinationIfNeeded(generator.tempDestination(result.get()), result.get());
+ if (m_base->isSuperNode()) {
+ RefPtr<RegisterID> thisValue = generator.ensureThis();
+ generator.emitPutById(base.get(), thisValue.get(), m_ident, forwardResult.get());
+ } else
+ generator.emitPutById(base.get(), m_ident, forwardResult.get());
+ generator.emitProfileType(forwardResult.get(), divotStart(), divotEnd());
+ return generator.moveToDestinationIfNeeded(dst, forwardResult.get());
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // ------------------------------ ReadModifyDotNode -----------------------------------
</span><span class="lines">@@ -2028,11 +2116,21 @@
</span><span class="cx"> RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_rightHasAssignments, m_right->isPure(generator));
</span><span class="cx">
</span><span class="cx"> generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd());
</span><del>- RefPtr<RegisterID> value = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident);
</del><ins>+ RefPtr<RegisterID> value;
+ RefPtr<RegisterID> thisValue;
+ if (m_base->isSuperNode()) {
+ thisValue = generator.ensureThis();
+ value = generator.emitGetById(generator.tempDestination(dst), base.get(), thisValue.get(), m_ident);
+ } else
+ value = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident);
</ins><span class="cx"> RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, static_cast<JSC::Operator>(m_operator), OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
</span><span class="cx">
</span><span class="cx"> generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
</span><del>- RegisterID* ret = generator.emitPutById(base.get(), m_ident, updatedValue);
</del><ins>+ RegisterID* ret;
+ if (m_base->isSuperNode())
+ ret = generator.emitPutById(base.get(), thisValue.get(), m_ident, updatedValue);
+ else
+ ret = generator.emitPutById(base.get(), m_ident, updatedValue);
</ins><span class="cx"> generator.emitProfileType(updatedValue, divotStart(), divotEnd());
</span><span class="cx"> return ret;
</span><span class="cx"> }
</span><span class="lines">@@ -2056,10 +2154,19 @@
</span><span class="cx"> generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
</span><span class="cx"> RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result.get() : generator.moveToDestinationIfNeeded(generator.tempDestination(result.get()), result.get());
</span><span class="cx">
</span><del>- if (isNonIndexStringElement(*m_subscript))
- generator.emitPutById(base.get(), static_cast<StringNode*>(m_subscript)->value(), forwardResult);
- else
- generator.emitPutByVal(base.get(), property.get(), forwardResult);
</del><ins>+ if (isNonIndexStringElement(*m_subscript)) {
+ if (m_base->isSuperNode()) {
+ RefPtr<RegisterID> thisValue = generator.ensureThis();
+ generator.emitPutById(base.get(), thisValue.get(), static_cast<StringNode*>(m_subscript)->value(), forwardResult);
+ } else
+ generator.emitPutById(base.get(), static_cast<StringNode*>(m_subscript)->value(), forwardResult);
+ } else {
+ if (m_base->isSuperNode()) {
+ RefPtr<RegisterID> thisValue = generator.ensureThis();
+ generator.emitPutByVal(base.get(), thisValue.get(), property.get(), forwardResult);
+ } else
+ generator.emitPutByVal(base.get(), property.get(), forwardResult);
+ }
</ins><span class="cx">
</span><span class="cx"> generator.emitProfileType(forwardResult, divotStart(), divotEnd());
</span><span class="cx"> return generator.moveToDestinationIfNeeded(dst, forwardResult);
</span><span class="lines">@@ -2073,11 +2180,20 @@
</span><span class="cx"> RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript, m_rightHasAssignments, m_right->isPure(generator));
</span><span class="cx">
</span><span class="cx"> generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd());
</span><del>- RefPtr<RegisterID> value = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get());
</del><ins>+ RefPtr<RegisterID> value;
+ RefPtr<RegisterID> thisValue;
+ if (m_base->isSuperNode()) {
+ thisValue = generator.ensureThis();
+ value = generator.emitGetByVal(generator.tempDestination(dst), base.get(), thisValue.get(), property.get());
+ } else
+ value = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get());
</ins><span class="cx"> RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, static_cast<JSC::Operator>(m_operator), OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
</span><span class="cx">
</span><span class="cx"> generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
</span><del>- generator.emitPutByVal(base.get(), property.get(), updatedValue);
</del><ins>+ if (m_base->isSuperNode())
+ generator.emitPutByVal(base.get(), thisValue.get(), property.get(), updatedValue);
+ else
+ generator.emitPutByVal(base.get(), property.get(), updatedValue);
</ins><span class="cx"> generator.emitProfileType(updatedValue, divotStart(), divotEnd());
</span><span class="cx">
</span><span class="cx"> return updatedValue;
</span><span class="lines">@@ -2409,18 +2525,26 @@
</span><span class="cx"> if (m_lexpr->isDotAccessorNode()) {
</span><span class="cx"> DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr);
</span><span class="cx"> const Identifier& ident = assignNode->identifier();
</span><del>- RegisterID* base = generator.emitNode(assignNode->base());
</del><ins>+ RefPtr<RegisterID> base = generator.emitNode(assignNode->base());
</ins><span class="cx"> generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
</span><del>- generator.emitPutById(base, ident, propertyName);
</del><ins>+ if (assignNode->base()->isSuperNode()) {
+ RefPtr<RegisterID> thisValue = generator.ensureThis();
+ generator.emitPutById(base.get(), thisValue.get(), ident, propertyName);
+ } else
+ generator.emitPutById(base.get(), ident, propertyName);
</ins><span class="cx"> generator.emitProfileType(propertyName, assignNode->divotStart(), assignNode->divotEnd());
</span><span class="cx"> return;
</span><span class="cx"> }
</span><span class="cx"> if (m_lexpr->isBracketAccessorNode()) {
</span><span class="cx"> BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr);
</span><span class="cx"> RefPtr<RegisterID> base = generator.emitNode(assignNode->base());
</span><del>- RegisterID* subscript = generator.emitNode(assignNode->subscript());
</del><ins>+ RefPtr<RegisterID> subscript = generator.emitNode(assignNode->subscript());
</ins><span class="cx"> generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
</span><del>- generator.emitPutByVal(base.get(), subscript, propertyName);
</del><ins>+ if (assignNode->base()->isSuperNode()) {
+ RefPtr<RegisterID> thisValue = generator.ensureThis();
+ generator.emitPutByVal(base.get(), thisValue.get(), subscript.get(), propertyName);
+ } else
+ generator.emitPutByVal(base.get(), subscript.get(), propertyName);
</ins><span class="cx"> generator.emitProfileType(propertyName, assignNode->divotStart(), assignNode->divotEnd());
</span><span class="cx"> return;
</span><span class="cx"> }
</span><span class="lines">@@ -2631,7 +2755,11 @@
</span><span class="cx"> RefPtr<RegisterID> base = generator.emitNode(assignNode->base());
</span><span class="cx">
</span><span class="cx"> generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
</span><del>- generator.emitPutById(base.get(), ident, value);
</del><ins>+ if (assignNode->base()->isSuperNode()) {
+ RefPtr<RegisterID> thisValue = generator.ensureThis();
+ generator.emitPutById(base.get(), thisValue.get(), ident, value);
+ } else
+ generator.emitPutById(base.get(), ident, value);
</ins><span class="cx"> generator.emitProfileType(value, assignNode->divotStart(), assignNode->divotEnd());
</span><span class="cx"> } else if (m_lexpr->isBracketAccessorNode()) {
</span><span class="cx"> BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr);
</span><span class="lines">@@ -2639,7 +2767,11 @@
</span><span class="cx"> RegisterID* subscript = generator.emitNode(assignNode->subscript());
</span><span class="cx">
</span><span class="cx"> generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
</span><del>- generator.emitPutByVal(base.get(), subscript, value);
</del><ins>+ if (assignNode->base()->isSuperNode()) {
+ RefPtr<RegisterID> thisValue = generator.ensureThis();
+ generator.emitPutByVal(base.get(), thisValue.get(), subscript, value);
+ } else
+ generator.emitPutByVal(base.get(), subscript, value);
</ins><span class="cx"> generator.emitProfileType(value, assignNode->divotStart(), assignNode->divotEnd());
</span><span class="cx"> } else {
</span><span class="cx"> ASSERT(m_lexpr->isDestructuringNode());
</span><span class="lines">@@ -3696,14 +3828,22 @@
</span><span class="cx"> DotAccessorNode* lhs = static_cast<DotAccessorNode*>(m_assignmentTarget);
</span><span class="cx"> RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(lhs->base(), true, false);
</span><span class="cx"> generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd());
</span><del>- generator.emitPutById(base.get(), lhs->identifier(), value);
</del><ins>+ if (lhs->base()->isSuperNode()) {
+ RefPtr<RegisterID> thisValue = generator.ensureThis();
+ generator.emitPutById(base.get(), thisValue.get(), lhs->identifier(), value);
+ } else
+ generator.emitPutById(base.get(), lhs->identifier(), value);
</ins><span class="cx"> generator.emitProfileType(value, divotStart(), divotEnd());
</span><span class="cx"> } else if (m_assignmentTarget->isBracketAccessorNode()) {
</span><span class="cx"> BracketAccessorNode* lhs = static_cast<BracketAccessorNode*>(m_assignmentTarget);
</span><span class="cx"> RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(lhs->base(), true, false);
</span><span class="cx"> RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(lhs->subscript(), true, false);
</span><span class="cx"> generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd());
</span><del>- generator.emitPutByVal(base.get(), property.get(), value);
</del><ins>+ if (lhs->base()->isSuperNode()) {
+ RefPtr<RegisterID> thisValue = generator.ensureThis();
+ generator.emitPutByVal(base.get(), thisValue.get(), property.get(), value);
+ } else
+ generator.emitPutByVal(base.get(), property.get(), value);
</ins><span class="cx"> generator.emitProfileType(value, divotStart(), divotEnd());
</span><span class="cx"> }
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -2179,6 +2179,12 @@
</span><span class="cx"> forNode(node).makeHeapTop();
</span><span class="cx"> break;
</span><span class="cx"> }
</span><ins>+
+ case GetByValWithThis:
+ case GetByIdWithThis:
+ clobberWorld(node->origin.semantic, clobberLimit);
+ forNode(node).makeHeapTop();
+ break;
</ins><span class="cx">
</span><span class="cx"> case GetArrayLength: {
</span><span class="cx"> JSArrayBufferView* view = m_graph.tryGetFoldableView(
</span><span class="lines">@@ -2678,6 +2684,11 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ case PutByValWithThis:
+ case PutByIdWithThis:
+ clobberWorld(node->origin.semantic, clobberLimit);
+ break;
+
</ins><span class="cx"> case PutGetterById:
</span><span class="cx"> case PutSetterById:
</span><span class="cx"> case PutGetterSetterById:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -4029,6 +4029,16 @@
</span><span class="cx"> NEXT_OPCODE(op_get_by_val);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ case op_get_by_val_with_this: {
+ Node* base = get(VirtualRegister(currentInstruction[2].u.operand));
+ Node* thisValue = get(VirtualRegister(currentInstruction[3].u.operand));
+ Node* property = get(VirtualRegister(currentInstruction[4].u.operand));
+ Node* getByValWithThis = addToGraph(GetByValWithThis, base, thisValue, property);
+ set(VirtualRegister(currentInstruction[1].u.operand), getByValWithThis);
+
+ NEXT_OPCODE(op_get_by_val_with_this);
+ }
+
</ins><span class="cx"> case op_put_by_val_direct:
</span><span class="cx"> case op_put_by_val: {
</span><span class="cx"> Node* base = get(VirtualRegister(currentInstruction[1].u.operand));
</span><span class="lines">@@ -4070,6 +4080,21 @@
</span><span class="cx"> NEXT_OPCODE(op_put_by_val);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ case op_put_by_val_with_this: {
+ Node* base = get(VirtualRegister(currentInstruction[1].u.operand));
+ Node* thisValue = get(VirtualRegister(currentInstruction[2].u.operand));
+ Node* property = get(VirtualRegister(currentInstruction[3].u.operand));
+ Node* value = get(VirtualRegister(currentInstruction[4].u.operand));
+
+ addVarArgChild(base);
+ addVarArgChild(thisValue);
+ addVarArgChild(property);
+ addVarArgChild(value);
+ addToGraph(Node::VarArg, PutByValWithThis, OpInfo(0), OpInfo(0));
+
+ NEXT_OPCODE(op_put_by_val_with_this);
+ }
+
</ins><span class="cx"> case op_try_get_by_id: {
</span><span class="cx"> Node* base = get(VirtualRegister(currentInstruction[2].u.operand));
</span><span class="cx"> unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand];
</span><span class="lines">@@ -4103,6 +4128,16 @@
</span><span class="cx">
</span><span class="cx"> NEXT_OPCODE(op_get_by_id);
</span><span class="cx"> }
</span><ins>+ case op_get_by_id_with_this: {
+ Node* base = get(VirtualRegister(currentInstruction[2].u.operand));
+ Node* thisValue = get(VirtualRegister(currentInstruction[3].u.operand));
+ unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[4].u.operand];
+
+ set(VirtualRegister(currentInstruction[1].u.operand),
+ addToGraph(GetByIdWithThis, OpInfo(identifierNumber), base, thisValue));
+
+ NEXT_OPCODE(op_get_by_id_with_this);
+ }
</ins><span class="cx"> case op_put_by_id: {
</span><span class="cx"> Node* value = get(VirtualRegister(currentInstruction[3].u.operand));
</span><span class="cx"> Node* base = get(VirtualRegister(currentInstruction[1].u.operand));
</span><span class="lines">@@ -4118,6 +4153,16 @@
</span><span class="cx"> NEXT_OPCODE(op_put_by_id);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ case op_put_by_id_with_this: {
+ Node* base = get(VirtualRegister(currentInstruction[1].u.operand));
+ Node* thisValue = get(VirtualRegister(currentInstruction[2].u.operand));
+ Node* value = get(VirtualRegister(currentInstruction[4].u.operand));
+ unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand];
+
+ addToGraph(PutByIdWithThis, OpInfo(identifierNumber), base, thisValue, value);
+ NEXT_OPCODE(op_put_by_id_with_this);
+ }
+
</ins><span class="cx"> case op_put_getter_by_id:
</span><span class="cx"> case op_put_setter_by_id: {
</span><span class="cx"> Node* base = get(VirtualRegister(currentInstruction[1].u.operand));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGCapabilities.cpp (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGCapabilities.cpp        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/dfg/DFGCapabilities.cpp        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -156,8 +156,12 @@
</span><span class="cx"> case op_put_by_val_direct:
</span><span class="cx"> case op_try_get_by_id:
</span><span class="cx"> case op_get_by_id:
</span><ins>+ case op_get_by_id_with_this:
+ case op_get_by_val_with_this:
</ins><span class="cx"> case op_get_array_length:
</span><span class="cx"> case op_put_by_id:
</span><ins>+ case op_put_by_id_with_this:
+ case op_put_by_val_with_this:
</ins><span class="cx"> case op_put_getter_by_id:
</span><span class="cx"> case op_put_setter_by_id:
</span><span class="cx"> case op_put_getter_setter_by_id:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGClobberizeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGClobberize.h (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -439,7 +439,11 @@
</span><span class="cx">
</span><span class="cx"> case GetById:
</span><span class="cx"> case GetByIdFlush:
</span><ins>+ case GetByIdWithThis:
+ case GetByValWithThis:
</ins><span class="cx"> case PutById:
</span><ins>+ case PutByIdWithThis:
+ case PutByValWithThis:
</ins><span class="cx"> case PutByIdFlush:
</span><span class="cx"> case PutByIdDirect:
</span><span class="cx"> case PutGetterById:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGDoesGCcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -99,8 +99,11 @@
</span><span class="cx"> case TryGetById:
</span><span class="cx"> case GetById:
</span><span class="cx"> case GetByIdFlush:
</span><ins>+ case GetByIdWithThis:
</ins><span class="cx"> case PutById:
</span><span class="cx"> case PutByIdFlush:
</span><ins>+ case PutByIdWithThis:
+ case PutByValWithThis:
</ins><span class="cx"> case PutByIdDirect:
</span><span class="cx"> case PutGetterById:
</span><span class="cx"> case PutSetterById:
</span><span class="lines">@@ -203,6 +206,7 @@
</span><span class="cx"> case GetGetter:
</span><span class="cx"> case GetSetter:
</span><span class="cx"> case GetByVal:
</span><ins>+ case GetByValWithThis:
</ins><span class="cx"> case GetIndexedPropertyStorage:
</span><span class="cx"> case GetArrayLength:
</span><span class="cx"> case ArrayPush:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -1147,7 +1147,7 @@
</span><span class="cx"> fixEdge<CellUse>(node->child1());
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>-
</del><ins>+
</ins><span class="cx"> case PutById:
</span><span class="cx"> case PutByIdFlush:
</span><span class="cx"> case PutByIdDirect: {
</span><span class="lines">@@ -1575,7 +1575,13 @@
</span><span class="cx"> case ExitOK:
</span><span class="cx"> case BottomValue:
</span><span class="cx"> case TypeOf:
</span><ins>+ case GetByIdWithThis:
+ case PutByIdWithThis:
+ case PutByValWithThis:
+ case GetByValWithThis:
</ins><span class="cx"> break;
</span><ins>+
+ break;
</ins><span class="cx"> #else
</span><span class="cx"> default:
</span><span class="cx"> break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNode.h (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNode.h        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/dfg/DFGNode.h        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -862,9 +862,11 @@
</span><span class="cx"> case TryGetById:
</span><span class="cx"> case GetById:
</span><span class="cx"> case GetByIdFlush:
</span><ins>+ case GetByIdWithThis:
</ins><span class="cx"> case PutById:
</span><span class="cx"> case PutByIdFlush:
</span><span class="cx"> case PutByIdDirect:
</span><ins>+ case PutByIdWithThis:
</ins><span class="cx"> case PutGetterById:
</span><span class="cx"> case PutSetterById:
</span><span class="cx"> case PutGetterSetterById:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeTypeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNodeType.h (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -176,6 +176,7 @@
</span><span class="cx"> /* this must be the directly subsequent property put. Note that PutByVal */\
</span><span class="cx"> /* opcodes use VarArgs beause they may have up to 4 children. */\
</span><span class="cx"> macro(GetByVal, NodeResultJS | NodeMustGenerate) \
</span><ins>+ macro(GetByValWithThis, NodeResultJS | NodeMustGenerate) \
</ins><span class="cx"> macro(GetMyArgumentByVal, NodeResultJS | NodeMustGenerate) \
</span><span class="cx"> macro(GetMyArgumentByValOutOfBounds, NodeResultJS | NodeMustGenerate) \
</span><span class="cx"> macro(LoadVarargs, NodeMustGenerate) \
</span><span class="lines">@@ -186,9 +187,12 @@
</span><span class="cx"> macro(TryGetById, NodeResultJS) \
</span><span class="cx"> macro(GetById, NodeResultJS | NodeMustGenerate) \
</span><span class="cx"> macro(GetByIdFlush, NodeResultJS | NodeMustGenerate) \
</span><ins>+ macro(GetByIdWithThis, NodeResultJS | NodeMustGenerate) \
</ins><span class="cx"> macro(PutById, NodeMustGenerate) \
</span><span class="cx"> macro(PutByIdFlush, NodeMustGenerate) \
</span><span class="cx"> macro(PutByIdDirect, NodeMustGenerate) \
</span><ins>+ macro(PutByIdWithThis, NodeMustGenerate) \
+ macro(PutByValWithThis, NodeMustGenerate | NodeHasVarArgs) \
</ins><span class="cx"> macro(PutGetterById, NodeMustGenerate) \
</span><span class="cx"> macro(PutSetterById, NodeMustGenerate) \
</span><span class="cx"> macro(PutGetterSetterById, NodeMustGenerate) \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOperationscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -144,6 +144,16 @@
</span><span class="cx"> return bitwise_cast<char*>(ViewClass::create(exec, structure, size));
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+template <bool strict>
+static ALWAYS_INLINE void putWithThis(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedValue, const Identifier& ident)
+{
+ JSValue baseValue = JSValue::decode(encodedBase);
+ JSValue thisVal = JSValue::decode(encodedThis);
+ JSValue putValue = JSValue::decode(encodedValue);
+ PutPropertySlot slot(thisVal, strict);
+ baseValue.putInline(exec, ident, putValue, slot);
+}
+
</ins><span class="cx"> extern "C" {
</span><span class="cx">
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationToThis(ExecState* exec, EncodedJSValue encodedOp)
</span><span class="lines">@@ -773,6 +783,94 @@
</span><span class="cx"> return JSValue::encode(JSValue::decode(value).toPrimitive(exec));
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+EncodedJSValue JIT_OPERATION operationGetByIdWithThis(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, UniquedStringImpl* impl)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+
+ JSValue baseValue = JSValue::decode(encodedBase);
+ JSValue thisVal = JSValue::decode(encodedThis);
+ PropertySlot slot(thisVal, PropertySlot::PropertySlot::InternalMethodType::Get);
+ JSValue result = baseValue.get(exec, Identifier::fromUid(exec, impl), slot);
+ return JSValue::encode(result);
+}
+
+EncodedJSValue JIT_OPERATION operationGetByValWithThis(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedSubscript)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+
+ JSValue baseValue = JSValue::decode(encodedBase);
+ JSValue thisVal = JSValue::decode(encodedThis);
+ JSValue subscript = JSValue::decode(encodedSubscript);
+
+ if (LIKELY(baseValue.isCell() && subscript.isString())) {
+ Structure& structure = *baseValue.asCell()->structure(vm);
+ if (JSCell::canUseFastGetOwnProperty(structure)) {
+ if (RefPtr<AtomicStringImpl> existingAtomicString = asString(subscript)->toExistingAtomicString(exec)) {
+ if (JSValue result = baseValue.asCell()->fastGetOwnProperty(vm, structure, existingAtomicString.get()))
+ return JSValue::encode(result);
+ }
+ }
+ }
+
+ PropertySlot slot(thisVal, PropertySlot::PropertySlot::InternalMethodType::Get);
+ if (subscript.isUInt32()) {
+ uint32_t i = subscript.asUInt32();
+ if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i))
+ return JSValue::encode(asString(baseValue)->getIndex(exec, i));
+
+ return JSValue::encode(baseValue.get(exec, i, slot));
+ }
+
+ baseValue.requireObjectCoercible(exec);
+ if (vm.exception())
+ return JSValue::encode(JSValue());
+
+ auto property = subscript.toPropertyKey(exec);
+ if (vm.exception())
+ return JSValue::encode(JSValue());
+ return JSValue::encode(baseValue.get(exec, property, slot));
+}
+
+void JIT_OPERATION operationPutByIdWithThisStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedValue, UniquedStringImpl* impl)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+
+ putWithThis<true>(exec, encodedBase, encodedThis, encodedValue, Identifier::fromUid(exec, impl));
+}
+
+void JIT_OPERATION operationPutByIdWithThis(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedValue, UniquedStringImpl* impl)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+
+ putWithThis<false>(exec, encodedBase, encodedThis, encodedValue, Identifier::fromUid(exec, impl));
+}
+
+void JIT_OPERATION operationPutByValWithThisStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+
+ Identifier property = JSValue::decode(encodedSubscript).toPropertyKey(exec);
+ if (vm.exception())
+ return;
+ putWithThis<true>(exec, encodedBase, encodedThis, encodedValue, property);
+}
+
+void JIT_OPERATION operationPutByValWithThis(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+
+ Identifier property = JSValue::decode(encodedSubscript).toPropertyKey(exec);
+ if (vm.exception())
+ return;
+ putWithThis<false>(exec, encodedBase, encodedThis, encodedValue, property);
+}
+
</ins><span class="cx"> char* JIT_OPERATION operationNewArray(ExecState* exec, Structure* arrayStructure, void* buffer, size_t size)
</span><span class="cx"> {
</span><span class="cx"> VM* vm = &exec->vm();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOperationsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOperations.h (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOperations.h        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/dfg/DFGOperations.h        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -61,6 +61,8 @@
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationGetByValArrayInt(ExecState*, JSArray*, int32_t) WTF_INTERNAL;
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationGetByValStringInt(ExecState*, JSString*, int32_t) WTF_INTERNAL;
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationToPrimitive(ExecState*, EncodedJSValue) WTF_INTERNAL;
</span><ins>+EncodedJSValue JIT_OPERATION operationGetByIdWithThis(ExecState*, EncodedJSValue, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationGetByValWithThis(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
</ins><span class="cx"> char* JIT_OPERATION operationNewArray(ExecState*, Structure*, void*, size_t) WTF_INTERNAL;
</span><span class="cx"> char* JIT_OPERATION operationNewArrayBuffer(ExecState*, Structure*, size_t, size_t) WTF_INTERNAL;
</span><span class="cx"> char* JIT_OPERATION operationNewEmptyArray(ExecState*, Structure*) WTF_INTERNAL;
</span><span class="lines">@@ -98,6 +100,10 @@
</span><span class="cx"> void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsNonStrict(ExecState*, JSObject*, int32_t index, EncodedJSValue encodedValue) WTF_INTERNAL;
</span><span class="cx"> void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsStrict(ExecState*, JSObject*, int32_t index, double value) WTF_INTERNAL;
</span><span class="cx"> void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState*, JSObject*, int32_t index, double value) WTF_INTERNAL;
</span><ins>+void JIT_OPERATION operationPutByIdWithThis(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
+void JIT_OPERATION operationPutByIdWithThisStrict(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
+void JIT_OPERATION operationPutByValWithThis(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
+void JIT_OPERATION operationPutByValWithThisStrict(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
</ins><span class="cx"> EncodedJSValue JIT_OPERATION operationArrayPush(ExecState*, EncodedJSValue encodedValue, JSArray*) WTF_INTERNAL;
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationArrayPushDouble(ExecState*, double value, JSArray*) WTF_INTERNAL;
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationArrayPop(ExecState*, JSArray*) WTF_INTERNAL;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -661,6 +661,11 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ case GetByValWithThis:
+ case GetByIdWithThis: {
+ setPrediction(SpecBytecodeTop);
+ break;
+ }
</ins><span class="cx"> case TryGetById: {
</span><span class="cx"> setPrediction(SpecBytecodeTop);
</span><span class="cx"> break;
</span><span class="lines">@@ -988,6 +993,8 @@
</span><span class="cx"> #ifndef NDEBUG
</span><span class="cx"> // These get ignored because they don't return anything.
</span><span class="cx"> case PutByValDirect:
</span><ins>+ case PutByValWithThis:
+ case PutByIdWithThis:
</ins><span class="cx"> case PutByVal:
</span><span class="cx"> case PutClosureVar:
</span><span class="cx"> case PutToArguments:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSafeToExecuteh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -195,9 +195,13 @@
</span><span class="cx"> case DeleteById:
</span><span class="cx"> case DeleteByVal:
</span><span class="cx"> case GetById:
</span><ins>+ case GetByIdWithThis:
+ case GetByValWithThis:
</ins><span class="cx"> case GetByIdFlush:
</span><span class="cx"> case PutById:
</span><span class="cx"> case PutByIdFlush:
</span><ins>+ case PutByIdWithThis:
+ case PutByValWithThis:
</ins><span class="cx"> case PutByIdDirect:
</span><span class="cx"> case PutGetterById:
</span><span class="cx"> case PutSetterById:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -1270,6 +1270,21 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> #if USE(JSVALUE64)
</span><ins>+ JITCompiler::Call callOperation(J_JITOperation_EJJI operation, GPRReg result, GPRReg arg1, GPRReg arg2, UniquedStringImpl* uid)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2, TrustedImmPtr(uid));
+ return appendCallSetResult(operation, result);
+ }
+ JITCompiler::Call callOperation(V_JITOperation_EJJJI operation, GPRReg arg1, GPRReg arg2, GPRReg arg3, UniquedStringImpl* uid)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2, arg3, TrustedImmPtr(uid));
+ return appendCall(operation);
+ }
+ JITCompiler::Call callOperation(V_JITOperation_EJJJJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2, arg3, arg4);
+ return appendCall(operation);
+ }
</ins><span class="cx"> JITCompiler::Call callOperation(V_JITOperation_EOJIUi operation, GPRReg arg1, GPRReg arg2, UniquedStringImpl* impl, unsigned value)
</span><span class="cx"> {
</span><span class="cx"> m_jit.setupArgumentsWithExecState(arg1, arg2, TrustedImmPtr(impl), TrustedImm32(value));
</span><span class="lines">@@ -1689,6 +1704,22 @@
</span><span class="cx"> #define SH4_32BIT_DUMMY_ARG
</span><span class="cx"> #endif
</span><span class="cx">
</span><ins>+ JITCompiler::Call callOperation(J_JITOperation_EJJI operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Tag, GPRReg arg2Payload, UniquedStringImpl* uid)
+ {
+ m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, arg2Payload, arg2Tag, TrustedImmPtr(uid));
+ return appendCallSetResult(operation, resultPayload, resultTag);
+ }
+ JITCompiler::Call callOperation(V_JITOperation_EJJJI operation, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Tag, GPRReg arg2Payload, GPRReg arg3Tag, GPRReg arg3Payload, UniquedStringImpl* uid)
+ {
+ m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, arg2Payload, arg2Tag, arg3Payload, arg3Tag, TrustedImmPtr(uid));
+ return appendCall(operation);
+ }
+ JITCompiler::Call callOperation(V_JITOperation_EJJJJ operation, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Tag, GPRReg arg2Payload, GPRReg arg3Tag, GPRReg arg3Payload, GPRReg arg4Tag, GPRReg arg4Payload)
+ {
+ m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, arg2Payload, arg2Tag, arg3Payload, arg3Tag, arg4Payload, arg4Tag);
+ return appendCall(operation);
+ }
+
</ins><span class="cx"> JITCompiler::Call callOperation(V_JITOperation_EOJIUi operation, GPRReg arg1, GPRReg arg2Tag, GPRReg arg2Payload, UniquedStringImpl* impl, unsigned value)
</span><span class="cx"> {
</span><span class="cx"> m_jit.setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag, TrustedImmPtr(impl), TrustedImm32(value));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -2681,6 +2681,30 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ case GetByValWithThis: {
+ JSValueOperand base(this, node->child1());
+ GPRReg baseTag = base.tagGPR();
+ GPRReg basePayload = base.payloadGPR();
+ JSValueOperand thisValue(this, node->child2());
+ GPRReg thisValueTag = thisValue.tagGPR();
+ GPRReg thisValuePayload = thisValue.payloadGPR();
+ JSValueOperand subscript(this, node->child3());
+ GPRReg subscriptTag = subscript.tagGPR();
+ GPRReg subscriptPayload = subscript.payloadGPR();
+
+ GPRFlushedCallResult resultPayload(this);
+ GPRFlushedCallResult2 resultTag(this);
+ GPRReg resultPayloadGPR = resultPayload.gpr();
+ GPRReg resultTagGPR = resultTag.gpr();
+
+ flushRegisters();
+ callOperation(operationGetByValWithThis, resultTagGPR, resultPayloadGPR, baseTag, basePayload, thisValueTag, thisValuePayload, subscriptTag, subscriptPayload);
+ m_jit.exceptionCheck();
+
+ jsValueResult(resultTagGPR, resultPayloadGPR, node);
+ break;
+ }
+
</ins><span class="cx"> case PutByValDirect:
</span><span class="cx"> case PutByVal:
</span><span class="cx"> case PutByValAlias: {
</span><span class="lines">@@ -2859,6 +2883,76 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ case PutByValWithThis: {
+#if CPU(X86)
+ // We don't have enough registers on X86 to do this
+ // without setting up the call frame incrementally.
+ unsigned index = 0;
+ m_jit.poke(GPRInfo::callFrameRegister, index++);
+
+ {
+ JSValueOperand base(this, m_jit.graph().varArgChild(node, 0));
+ GPRReg baseTag = base.tagGPR();
+ GPRReg basePayload = base.payloadGPR();
+
+ JSValueOperand thisValue(this, m_jit.graph().varArgChild(node, 1));
+ GPRReg thisValueTag = thisValue.tagGPR();
+ GPRReg thisValuePayload = thisValue.payloadGPR();
+
+ JSValueOperand property(this, m_jit.graph().varArgChild(node, 2));
+ GPRReg propertyTag = property.tagGPR();
+ GPRReg propertyPayload = property.payloadGPR();
+
+ m_jit.poke(basePayload, index++);
+ m_jit.poke(baseTag, index++);
+
+ m_jit.poke(thisValuePayload, index++);
+ m_jit.poke(thisValueTag, index++);
+
+ m_jit.poke(propertyPayload, index++);
+ m_jit.poke(propertyTag, index++);
+
+ flushRegisters();
+ }
+
+ JSValueOperand value(this, m_jit.graph().varArgChild(node, 3));
+ GPRReg valueTag = value.tagGPR();
+ GPRReg valuePayload = value.payloadGPR();
+ m_jit.poke(valuePayload, index++);
+ m_jit.poke(valueTag, index++);
+
+ flushRegisters();
+ appendCall(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValWithThisStrict : operationPutByValWithThis);
+ m_jit.exceptionCheck();
+#else
+ static_assert(GPRInfo::numberOfRegisters >= 8, "We are assuming we have enough registers to make this call without incrementally setting up the arguments.");
+
+ JSValueOperand base(this, m_jit.graph().varArgChild(node, 0));
+ GPRReg baseTag = base.tagGPR();
+ GPRReg basePayload = base.payloadGPR();
+
+ JSValueOperand thisValue(this, m_jit.graph().varArgChild(node, 1));
+ GPRReg thisValueTag = thisValue.tagGPR();
+ GPRReg thisValuePayload = thisValue.payloadGPR();
+
+ JSValueOperand property(this, m_jit.graph().varArgChild(node, 2));
+ GPRReg propertyTag = property.tagGPR();
+ GPRReg propertyPayload = property.payloadGPR();
+
+ JSValueOperand value(this, m_jit.graph().varArgChild(node, 3));
+ GPRReg valueTag = value.tagGPR();
+ GPRReg valuePayload = value.payloadGPR();
+
+ flushRegisters();
+ callOperation(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValWithThisStrict : operationPutByValWithThis,
+ NoResult, baseTag, basePayload, thisValueTag, thisValuePayload, propertyTag, propertyPayload, valueTag, valuePayload);
+ m_jit.exceptionCheck();
+#endif // CPU(X86)
+
+ noResult(node);
+ break;
+ }
+
</ins><span class="cx"> case RegExpExec: {
</span><span class="cx"> SpeculateCellOperand globalObject(this, node->child1());
</span><span class="cx"> GPRReg globalObjectGPR = globalObject.gpr();
</span><span class="lines">@@ -4038,6 +4132,27 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ case GetByIdWithThis: {
+ JSValueOperand base(this, node->child1());
+ GPRReg baseTag = base.tagGPR();
+ GPRReg basePayload = base.payloadGPR();
+ JSValueOperand thisValue(this, node->child2());
+ GPRReg thisTag = thisValue.tagGPR();
+ GPRReg thisPayload = thisValue.payloadGPR();
+
+ GPRFlushedCallResult resultPayload(this);
+ GPRFlushedCallResult2 resultTag(this);
+ GPRReg resultPayloadGPR = resultPayload.gpr();
+ GPRReg resultTagGPR = resultTag.gpr();
+
+ flushRegisters();
+ callOperation(operationGetByIdWithThis, resultTagGPR, resultPayloadGPR, baseTag, basePayload, thisTag, thisPayload, identifierUID(node->identifierNumber()));
+ m_jit.exceptionCheck();
+
+ jsValueResult(resultTagGPR, resultPayloadGPR, node);
+ break;
+ }
+
</ins><span class="cx"> case GetByIdFlush: {
</span><span class="cx"> if (!node->prediction()) {
</span><span class="cx"> terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
</span><span class="lines">@@ -4315,6 +4430,26 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ case PutByIdWithThis: {
+ JSValueOperand base(this, node->child1());
+ GPRReg baseTag = base.tagGPR();
+ GPRReg basePayload = base.payloadGPR();
+ JSValueOperand thisValue(this, node->child2());
+ GPRReg thisValueTag = thisValue.tagGPR();
+ GPRReg thisValuePayload = thisValue.payloadGPR();
+ JSValueOperand value(this, node->child3());
+ GPRReg valueTag = value.tagGPR();
+ GPRReg valuePayload = value.payloadGPR();
+
+ flushRegisters();
+ callOperation(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByIdWithThisStrict : operationPutByIdWithThis,
+ NoResult, baseTag, basePayload, thisValueTag, thisValuePayload, valueTag, valuePayload, identifierUID(node->identifierNumber()));
+ m_jit.exceptionCheck();
+
+ noResult(node);
+ break;
+ }
+
</ins><span class="cx"> case PutGetterById:
</span><span class="cx"> case PutSetterById: {
</span><span class="cx"> compilePutAccessorById(node);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -2763,6 +2763,25 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ case GetByValWithThis: {
+ JSValueOperand base(this, node->child1());
+ GPRReg baseGPR = base.gpr();
+ JSValueOperand thisValue(this, node->child2());
+ GPRReg thisValueGPR = thisValue.gpr();
+ JSValueOperand subscript(this, node->child3());
+ GPRReg subscriptGPR = subscript.gpr();
+
+ GPRFlushedCallResult result(this);
+ GPRReg resultGPR = result.gpr();
+
+ flushRegisters();
+ callOperation(operationGetByValWithThis, resultGPR, baseGPR, thisValueGPR, subscriptGPR);
+ m_jit.exceptionCheck();
+
+ jsValueResult(resultGPR, node);
+ break;
+ }
+
</ins><span class="cx"> case PutByValDirect:
</span><span class="cx"> case PutByVal:
</span><span class="cx"> case PutByValAlias: {
</span><span class="lines">@@ -4135,6 +4154,23 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ case GetByIdWithThis: {
+ JSValueOperand base(this, node->child1());
+ GPRReg baseGPR = base.gpr();
+ JSValueOperand thisValue(this, node->child2());
+ GPRReg thisValueGPR = thisValue.gpr();
+
+ GPRFlushedCallResult result(this);
+ GPRReg resultGPR = result.gpr();
+
+ flushRegisters();
+ callOperation(operationGetByIdWithThis, resultGPR, baseGPR, thisValueGPR, identifierUID(node->identifierNumber()));
+ m_jit.exceptionCheck();
+
+ jsValueResult(resultGPR, node);
+ break;
+ }
+
</ins><span class="cx"> case GetArrayLength:
</span><span class="cx"> compileGetArrayLength(node);
</span><span class="cx"> break;
</span><span class="lines">@@ -4319,6 +4355,40 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ case PutByIdWithThis: {
+ JSValueOperand base(this, node->child1());
+ GPRReg baseGPR = base.gpr();
+ JSValueOperand thisValue(this, node->child2());
+ GPRReg thisValueGPR = thisValue.gpr();
+ JSValueOperand value(this, node->child3());
+ GPRReg valueGPR = value.gpr();
+
+ flushRegisters();
+ callOperation(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByIdWithThisStrict : operationPutByIdWithThis, NoResult, baseGPR, thisValueGPR, valueGPR, identifierUID(node->identifierNumber()));
+ m_jit.exceptionCheck();
+
+ noResult(node);
+ break;
+ }
+
+ case PutByValWithThis: {
+ JSValueOperand base(this, m_jit.graph().varArgChild(node, 0));
+ GPRReg baseGPR = base.gpr();
+ JSValueOperand thisValue(this, m_jit.graph().varArgChild(node, 1));
+ GPRReg thisValueGPR = thisValue.gpr();
+ JSValueOperand property(this, m_jit.graph().varArgChild(node, 2));
+ GPRReg propertyGPR = property.gpr();
+ JSValueOperand value(this, m_jit.graph().varArgChild(node, 3));
+ GPRReg valueGPR = value.gpr();
+
+ flushRegisters();
+ callOperation(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValWithThisStrict : operationPutByValWithThis, NoResult, baseGPR, thisValueGPR, propertyGPR, valueGPR);
+ m_jit.exceptionCheck();
+
+ noResult(node);
+ break;
+ }
+
</ins><span class="cx"> case PutByIdDirect: {
</span><span class="cx"> SpeculateCellOperand base(this, node->child1());
</span><span class="cx"> JSValueOperand value(this, node->child2());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -169,6 +169,7 @@
</span><span class="cx"> case TryGetById:
</span><span class="cx"> case GetById:
</span><span class="cx"> case GetByIdFlush:
</span><ins>+ case GetByIdWithThis:
</ins><span class="cx"> case ToThis:
</span><span class="cx"> case MultiGetByOffset:
</span><span class="cx"> case MultiPutByOffset:
</span><span class="lines">@@ -262,6 +263,8 @@
</span><span class="cx"> if (node->child1().useKind() == CellUse)
</span><span class="cx"> break;
</span><span class="cx"> return CannotCompile;
</span><ins>+ case PutByIdWithThis:
+ break;
</ins><span class="cx"> case GetIndexedPropertyStorage:
</span><span class="cx"> if (node->arrayMode().type() == Array::String)
</span><span class="cx"> break;
</span><span class="lines">@@ -326,6 +329,8 @@
</span><span class="cx"> return CannotCompile;
</span><span class="cx"> }
</span><span class="cx"> break;
</span><ins>+ case GetByValWithThis:
+ break;
</ins><span class="cx"> case PutByVal:
</span><span class="cx"> case PutByValAlias:
</span><span class="cx"> case PutByValDirect:
</span><span class="lines">@@ -342,6 +347,8 @@
</span><span class="cx"> return CannotCompile;
</span><span class="cx"> }
</span><span class="cx"> break;
</span><ins>+ case PutByValWithThis:
+ break;
</ins><span class="cx"> case ArrayPush:
</span><span class="cx"> case ArrayPop:
</span><span class="cx"> switch (node->arrayMode().type()) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -605,6 +605,9 @@
</span><span class="cx"> case GetByIdFlush:
</span><span class="cx"> compileGetById(AccessType::Get);
</span><span class="cx"> break;
</span><ins>+ case GetByIdWithThis:
+ compileGetByIdWithThis();
+ break;
</ins><span class="cx"> case In:
</span><span class="cx"> compileIn();
</span><span class="cx"> break;
</span><span class="lines">@@ -613,6 +616,9 @@
</span><span class="cx"> case PutByIdFlush:
</span><span class="cx"> compilePutById();
</span><span class="cx"> break;
</span><ins>+ case PutByIdWithThis:
+ compilePutByIdWithThis();
+ break;
</ins><span class="cx"> case PutGetterById:
</span><span class="cx"> case PutSetterById:
</span><span class="cx"> compilePutAccessorById();
</span><span class="lines">@@ -649,11 +655,17 @@
</span><span class="cx"> case GetMyArgumentByValOutOfBounds:
</span><span class="cx"> compileGetMyArgumentByVal();
</span><span class="cx"> break;
</span><ins>+ case GetByValWithThis:
+ compileGetByValWithThis();
+ break;
</ins><span class="cx"> case PutByVal:
</span><span class="cx"> case PutByValAlias:
</span><span class="cx"> case PutByValDirect:
</span><span class="cx"> compilePutByVal();
</span><span class="cx"> break;
</span><ins>+ case PutByValWithThis:
+ compilePutByValWithThis();
+ break;
</ins><span class="cx"> case ArrayPush:
</span><span class="cx"> compileArrayPush();
</span><span class="cx"> break;
</span><span class="lines">@@ -2483,6 +2495,45 @@
</span><span class="cx"> return;
</span><span class="cx"> }
</span><span class="cx"> }
</span><ins>+
+ void compileGetByIdWithThis()
+ {
+ LValue base = lowJSValue(m_node->child1());
+ LValue thisValue = lowJSValue(m_node->child2());
+ LValue result = vmCall(m_out.int64, m_out.operation(operationGetByIdWithThis), m_callFrame, base, thisValue, m_out.constIntPtr(m_graph.identifiers()[m_node->identifierNumber()]));
+ setJSValue(result);
+ }
+
+ void compileGetByValWithThis()
+ {
+ LValue base = lowJSValue(m_node->child1());
+ LValue thisValue = lowJSValue(m_node->child2());
+ LValue subscript = lowJSValue(m_node->child3());
+
+ LValue result = vmCall(m_out.int64, m_out.operation(operationGetByValWithThis), m_callFrame, base, thisValue, subscript);
+ setJSValue(result);
+ }
+
+ void compilePutByIdWithThis()
+ {
+ LValue base = lowJSValue(m_node->child1());
+ LValue thisValue = lowJSValue(m_node->child2());
+ LValue value = lowJSValue(m_node->child3());
+
+ vmCall(m_out.voidType, m_out.operation(m_graph.isStrictModeFor(m_node->origin.semantic) ? operationPutByIdWithThisStrict : operationPutByIdWithThis),
+ m_callFrame, base, thisValue, value, m_out.constIntPtr(m_graph.identifiers()[m_node->identifierNumber()]));
+ }
+
+ void compilePutByValWithThis()
+ {
+ LValue base = lowJSValue(m_graph.varArgChild(m_node, 0));
+ LValue thisValue = lowJSValue(m_graph.varArgChild(m_node, 1));
+ LValue property = lowJSValue(m_graph.varArgChild(m_node, 2));
+ LValue value = lowJSValue(m_graph.varArgChild(m_node, 3));
+
+ vmCall(m_out.voidType, m_out.operation(m_graph.isStrictModeFor(m_node->origin.semantic) ? operationPutByValWithThisStrict : operationPutByValWithThis),
+ m_callFrame, base, thisValue, property, value);
+ }
</ins><span class="cx">
</span><span class="cx"> void compilePutById()
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitCCallHelperscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/CCallHelpers.cpp (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/CCallHelpers.cpp        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/jit/CCallHelpers.cpp        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -64,6 +64,107 @@
</span><span class="cx"> storePtr(GPRInfo::regT2, Address(GPRInfo::regT0));
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+#if NUMBER_OF_ARGUMENT_REGISTERS >= 4
+void CCallHelpers::setupFourStubArgsGPR(GPRReg destA, GPRReg destB, GPRReg destC, GPRReg destD, GPRReg srcA, GPRReg srcB, GPRReg srcC, GPRReg srcD)
+{
+ if (!ASSERT_DISABLED) {
+ RegisterSet destinations(destA, destB, destC, destD);
+ ASSERT_WITH_MESSAGE(destinations.numberOfSetGPRs() == 4, "Destinations should not be aliased.");
+ }
+
+ typedef std::pair<GPRReg, GPRReg> RegPair;
+ Vector<RegPair, 4> pairs;
+
+ if (srcA != destA)
+ pairs.append(std::make_pair(srcA, destA));
+ if (srcB != destB)
+ pairs.append(std::make_pair(srcB, destB));
+ if (srcC != destC)
+ pairs.append(std::make_pair(srcC, destC));
+ if (srcD != destD)
+ pairs.append(std::make_pair(srcD, destD));
+
+
+#if !ASSERT_DISABLED
+ auto numUniqueSources = [&] () -> unsigned {
+ RegisterSet set;
+ for (auto& pair : pairs) {
+ GPRReg source = pair.first;
+ set.set(source);
+ }
+ return set.numberOfSetGPRs();
+ };
+
+ auto numUniqueDests = [&] () -> unsigned {
+ RegisterSet set;
+ for (auto& pair : pairs) {
+ GPRReg dest = pair.second;
+ set.set(dest);
+ }
+ return set.numberOfSetGPRs();
+ };
+#endif
+
+ while (pairs.size()) {
+ RegisterSet freeDestinations;
+ for (auto& pair : pairs) {
+ GPRReg dest = pair.second;
+ freeDestinations.set(dest);
+ }
+ for (auto& pair : pairs) {
+ GPRReg source = pair.first;
+ freeDestinations.clear(source);
+ }
+
+ if (freeDestinations.numberOfSetGPRs()) {
+ bool madeMove = false;
+ for (unsigned i = 0; i < pairs.size(); i++) {
+ auto& pair = pairs[i];
+ GPRReg source = pair.first;
+ GPRReg dest = pair.second;
+ if (freeDestinations.get(dest)) {
+ move(source, dest);
+ pairs.remove(i);
+ madeMove = true;
+ break;
+ }
+ }
+ ASSERT_UNUSED(madeMove, madeMove);
+ continue;
+ }
+
+ ASSERT(numUniqueDests() == numUniqueSources());
+ ASSERT(numUniqueDests() == pairs.size());
+ // The set of source and destination registers are equivalent sets. This means we don't have
+ // any free destination registers that won't also clobber a source. We get around this by
+ // exchanging registers.
+
+ GPRReg source = pairs[0].first;
+ GPRReg dest = pairs[0].second;
+ swap(source, dest);
+ pairs.remove(0);
+
+ GPRReg newSource = source;
+ for (auto& pair : pairs) {
+ GPRReg source = pair.first;
+ if (source == dest) {
+ pair.first = newSource;
+ break;
+ }
+ }
+
+ // We may have introduced pairs that have the same source and destination. Remove those now.
+ for (unsigned i = 0; i < pairs.size(); i++) {
+ auto& pair = pairs[i];
+ if (pair.first == pair.second) {
+ pairs.remove(i);
+ i--;
+ }
+ }
+ }
+}
+#endif // NUMBER_OF_ARGUMENT_REGISTERS >= 4
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx">
</span><span class="cx"> #endif // ENABLE(JIT)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitCCallHelpersh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/CCallHelpers.h (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/CCallHelpers.h        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/jit/CCallHelpers.h        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx">
</span><span class="cx"> #include "AssemblyHelpers.h"
</span><span class="cx"> #include "GPRInfo.h"
</span><ins>+#include "RegisterMap.h"
</ins><span class="cx"> #include "StackAlignment.h"
</span><span class="cx">
</span><span class="cx"> namespace JSC {
</span><span class="lines">@@ -827,6 +828,21 @@
</span><span class="cx"> addCallArgument(arg2);
</span><span class="cx"> addCallArgument(arg3);
</span><span class="cx"> }
</span><ins>+
+ ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5, GPRReg arg6, GPRReg arg7, GPRReg arg8)
+ {
+ resetCallArguments();
+ addCallArgument(GPRInfo::callFrameRegister);
+ addCallArgument(arg1);
+ addCallArgument(arg2);
+ addCallArgument(arg3);
+ addCallArgument(arg4);
+ addCallArgument(arg5);
+ addCallArgument(arg6);
+ addCallArgument(arg7);
+ addCallArgument(arg8);
+ }
+
</ins><span class="cx"> #endif // !NUMBER_OF_ARGUMENT_REGISTERS
</span><span class="cx"> // These methods are suitable for any calling convention that provides for
</span><span class="cx"> // at least 4 argument registers, e.g. X86_64, ARMv7.
</span><span class="lines">@@ -913,6 +929,8 @@
</span><span class="cx"> swap(destB, destC);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ void setupFourStubArgsGPR(GPRReg destA, GPRReg destB, GPRReg destC, GPRReg destD, GPRReg srcA, GPRReg srcB, GPRReg srcC, GPRReg srcD);
+
</ins><span class="cx"> #if CPU(X86_64) || CPU(ARM64)
</span><span class="cx"> template<FPRReg destA, FPRReg destB>
</span><span class="cx"> void setupTwoStubArgsFPR(FPRReg srcA, FPRReg srcB)
</span><span class="lines">@@ -1951,6 +1969,27 @@
</span><span class="cx"> setupArgumentsWithExecState(arg1, arg2, arg3);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5, GPRReg arg6, GPRReg arg7, GPRReg arg8)
+ {
+ poke(arg8, POKE_ARGUMENT_OFFSET + 4);
+ poke(arg7, POKE_ARGUMENT_OFFSET + 3);
+ poke(arg6, POKE_ARGUMENT_OFFSET + 2);
+ poke(arg5, POKE_ARGUMENT_OFFSET + 1);
+ poke(arg4, POKE_ARGUMENT_OFFSET);
+ setupArgumentsWithExecState(arg1, arg2, arg3);
+ }
+
+ ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5, GPRReg arg6, GPRReg arg7, GPRReg arg8, GPRReg arg9)
+ {
+ poke(arg9, POKE_ARGUMENT_OFFSET + 5);
+ poke(arg8, POKE_ARGUMENT_OFFSET + 4);
+ poke(arg7, POKE_ARGUMENT_OFFSET + 3);
+ poke(arg6, POKE_ARGUMENT_OFFSET + 2);
+ poke(arg5, POKE_ARGUMENT_OFFSET + 1);
+ poke(arg4, POKE_ARGUMENT_OFFSET);
+ setupArgumentsWithExecState(arg1, arg2, arg3);
+ }
+
</ins><span class="cx"> ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, GPRReg arg2, GPRReg arg3, TrustedImm32 arg4, TrustedImm32 arg5, GPRReg arg6, GPRReg arg7)
</span><span class="cx"> {
</span><span class="cx"> poke(arg7, POKE_ARGUMENT_OFFSET + 3);
</span><span class="lines">@@ -1986,6 +2025,12 @@
</span><span class="cx"> #endif // NUMBER_OF_ARGUMENT_REGISTERS == 4
</span><span class="cx">
</span><span class="cx"> #if NUMBER_OF_ARGUMENT_REGISTERS >= 5
</span><ins>+ ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4)
+ {
+ setupFourStubArgsGPR(GPRInfo::argumentGPR1, GPRInfo::argumentGPR2, GPRInfo::argumentGPR3, GPRInfo::argumentGPR4, arg1, arg2, arg3, arg4);
+ move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ }
+
</ins><span class="cx"> void setupStubArguments134(GPRReg arg1, GPRReg arg3, GPRReg arg4)
</span><span class="cx"> {
</span><span class="cx"> setupThreeStubArgsGPR<GPRInfo::argumentGPR1, GPRInfo::argumentGPR3, GPRInfo::argumentGPR4>(arg1, arg3, arg4);
</span><span class="lines">@@ -2036,7 +2081,7 @@
</span><span class="cx"> move(arg4, GPRInfo::argumentGPR4);
</span><span class="cx"> move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
</span><span class="cx"> }
</span><del>-
</del><ins>+
</ins><span class="cx"> ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, GPRReg arg2, TrustedImm32 arg3, TrustedImm32 arg4)
</span><span class="cx"> {
</span><span class="cx"> move(arg2, GPRInfo::argumentGPR2); // In case arg2 is argumentGPR1.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitGPRInfoh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/GPRInfo.h (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/GPRInfo.h        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/jit/GPRInfo.h        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -880,20 +880,6 @@
</span><span class="cx">
</span><span class="cx"> #endif // CPU(SH4)
</span><span class="cx">
</span><del>-inline GPRReg argumentRegisterFor(unsigned argumentIndex)
-{
-#if USE(JSVALUE64)
- if (argumentIndex >= NUMBER_OF_ARGUMENT_REGISTERS)
- return InvalidGPRReg;
-
- return GPRInfo::toArgumentRegister(argumentIndex);
-#else
- UNUSED_PARAM(argumentIndex);
-
- return InvalidGPRReg;
-#endif
-}
-
</del><span class="cx"> // The baseline JIT uses "accumulator" style execution with regT0 (for 64-bit)
</span><span class="cx"> // and regT0 + regT1 (for 32-bit) serving as the accumulator register(s) for
</span><span class="cx"> // passing results of one opcode to the next. Hence:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JIT.cpp (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JIT.cpp        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/jit/JIT.cpp        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -237,7 +237,9 @@
</span><span class="cx"> DEFINE_OP(op_try_get_by_id)
</span><span class="cx"> case op_get_array_length:
</span><span class="cx"> DEFINE_OP(op_get_by_id)
</span><ins>+ DEFINE_OP(op_get_by_id_with_this)
</ins><span class="cx"> DEFINE_OP(op_get_by_val)
</span><ins>+ DEFINE_OP(op_get_by_val_with_this)
</ins><span class="cx"> DEFINE_OP(op_overrides_has_instance)
</span><span class="cx"> DEFINE_OP(op_instanceof)
</span><span class="cx"> DEFINE_OP(op_instanceof_custom)
</span><span class="lines">@@ -292,9 +294,11 @@
</span><span class="cx"> DEFINE_OP(op_create_lexical_environment)
</span><span class="cx"> DEFINE_OP(op_get_parent_scope)
</span><span class="cx"> DEFINE_OP(op_put_by_id)
</span><ins>+ DEFINE_OP(op_put_by_id_with_this)
</ins><span class="cx"> DEFINE_OP(op_put_by_index)
</span><span class="cx"> case op_put_by_val_direct:
</span><span class="cx"> DEFINE_OP(op_put_by_val)
</span><ins>+ DEFINE_OP(op_put_by_val_with_this)
</ins><span class="cx"> DEFINE_OP(op_put_getter_by_id)
</span><span class="cx"> DEFINE_OP(op_put_setter_by_id)
</span><span class="cx"> DEFINE_OP(op_put_getter_setter_by_id)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JIT.h (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JIT.h        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/jit/JIT.h        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -507,6 +507,8 @@
</span><span class="cx"> void emit_op_eq_null(Instruction*);
</span><span class="cx"> void emit_op_try_get_by_id(Instruction*);
</span><span class="cx"> void emit_op_get_by_id(Instruction*);
</span><ins>+ void emit_op_get_by_id_with_this(Instruction*);
+ void emit_op_get_by_val_with_this(Instruction*);
</ins><span class="cx"> void emit_op_get_arguments_length(Instruction*);
</span><span class="cx"> void emit_op_get_by_val(Instruction*);
</span><span class="cx"> void emit_op_get_argument_by_val(Instruction*);
</span><span class="lines">@@ -565,8 +567,10 @@
</span><span class="cx"> void emit_op_create_lexical_environment(Instruction*);
</span><span class="cx"> void emit_op_get_parent_scope(Instruction*);
</span><span class="cx"> void emit_op_put_by_id(Instruction*);
</span><ins>+ void emit_op_put_by_id_with_this(Instruction*);
</ins><span class="cx"> void emit_op_put_by_index(Instruction*);
</span><span class="cx"> void emit_op_put_by_val(Instruction*);
</span><ins>+ void emit_op_put_by_val_with_this(Instruction*);
</ins><span class="cx"> void emit_op_put_getter_by_id(Instruction*);
</span><span class="cx"> void emit_op_put_setter_by_id(Instruction*);
</span><span class="cx"> void emit_op_put_getter_setter_by_id(Instruction*);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOperationsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOperations.h (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOperations.h        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/jit/JITOperations.h        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -156,6 +156,7 @@
</span><span class="cx"> typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EZZ)(ExecState*, int32_t, int32_t);
</span><span class="cx"> typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EZSymtabJ)(ExecState*, int32_t, SymbolTable*, EncodedJSValue);
</span><span class="cx"> typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EOIUi)(ExecState*, JSObject*, UniquedStringImpl*, uint32_t);
</span><ins>+typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJJI)(ExecState*, EncodedJSValue, EncodedJSValue, UniquedStringImpl*);
</ins><span class="cx"> typedef JSCell* JIT_OPERATION (*C_JITOperation_E)(ExecState*);
</span><span class="cx"> typedef JSCell* JIT_OPERATION (*C_JITOperation_EZ)(ExecState*, int32_t);
</span><span class="cx"> typedef JSCell* JIT_OPERATION (*C_JITOperation_EC)(ExecState*, JSCell*);
</span><span class="lines">@@ -249,6 +250,8 @@
</span><span class="cx"> typedef void JIT_OPERATION (*V_JITOperation_EPc)(ExecState*, Instruction*);
</span><span class="cx"> typedef void JIT_OPERATION (*V_JITOperation_EPZJ)(ExecState*, void*, int32_t, EncodedJSValue);
</span><span class="cx"> typedef void JIT_OPERATION (*V_JITOperation_ESsiJJI)(ExecState*, StructureStubInfo*, EncodedJSValue, EncodedJSValue, UniquedStringImpl*);
</span><ins>+typedef void JIT_OPERATION (*V_JITOperation_EJJJI)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, UniquedStringImpl*);
+typedef void JIT_OPERATION (*V_JITOperation_EJJJJ)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, EncodedJSValue);
</ins><span class="cx"> typedef void JIT_OPERATION (*V_JITOperation_EWs)(ExecState*, WatchpointSet*);
</span><span class="cx"> typedef void JIT_OPERATION (*V_JITOperation_EZ)(ExecState*, int32_t);
</span><span class="cx"> typedef void JIT_OPERATION (*V_JITOperation_EZJ)(ExecState*, int32_t, EncodedJSValue);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITPropertyAccesscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -313,6 +313,12 @@
</span><span class="cx"> m_byValCompilationInfo.append(ByValCompilationInfo(byValInfo, m_bytecodeOffset, notIndex, badType, mode, profile, done, done));
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+void JIT::emit_op_put_by_val_with_this(Instruction* currentInstruction)
+{
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_put_by_val_with_this);
+ slowPathCall.call();
+}
+
</ins><span class="cx"> JIT::JumpList JIT::emitGenericContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType, IndexingType indexingShape)
</span><span class="cx"> {
</span><span class="cx"> int value = currentInstruction[3].u.operand;
</span><span class="lines">@@ -603,6 +609,18 @@
</span><span class="cx"> emitPutVirtualRegister(resultVReg);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+void JIT::emit_op_get_by_id_with_this(Instruction* currentInstruction)
+{
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_by_id_with_this);
+ slowPathCall.call();
+}
+
+void JIT::emit_op_get_by_val_with_this(Instruction* currentInstruction)
+{
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_by_val_with_this);
+ slowPathCall.call();
+}
+
</ins><span class="cx"> void JIT::emitSlow_op_get_by_id(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
</span><span class="cx"> {
</span><span class="cx"> int resultVReg = currentInstruction[1].u.operand;
</span><span class="lines">@@ -648,6 +666,12 @@
</span><span class="cx"> m_putByIds.append(gen);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+void JIT::emit_op_put_by_id_with_this(Instruction* currentInstruction)
+{
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_put_by_id_with_this);
+ slowPathCall.call();
+}
+
</ins><span class="cx"> void JIT::emitSlow_op_put_by_id(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
</span><span class="cx"> {
</span><span class="cx"> int baseVReg = currentInstruction[1].u.operand;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITPropertyAccess32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -1163,6 +1163,30 @@
</span><span class="cx"> store32(regT2, Address(regT0, DirectArguments::storageOffset() + index * sizeof(WriteBarrier<Unknown>) + PayloadOffset));
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+void JIT::emit_op_get_by_id_with_this(Instruction* currentInstruction)
+{
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_by_id_with_this);
+ slowPathCall.call();
+}
+
+void JIT::emit_op_get_by_val_with_this(Instruction* currentInstruction)
+{
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_by_val_with_this);
+ slowPathCall.call();
+}
+
+void JIT::emit_op_put_by_id_with_this(Instruction* currentInstruction)
+{
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_put_by_id_with_this);
+ slowPathCall.call();
+}
+
+void JIT::emit_op_put_by_val_with_this(Instruction* currentInstruction)
+{
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_put_by_val_with_this);
+ slowPathCall.call();
+}
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx">
</span><span class="cx"> #endif // USE(JSVALUE32_64)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLowLevelInterpreterasm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -1752,7 +1752,26 @@
</span><span class="cx"> callSlowPath(_llint_slow_path_instanceof)
</span><span class="cx"> dispatch(4)
</span><span class="cx">
</span><ins>+_llint_op_get_by_id_with_this:
+ traceExecution()
+ callSlowPath(_slow_path_get_by_id_with_this)
+ dispatch(5)
</ins><span class="cx">
</span><ins>+_llint_op_get_by_val_with_this:
+ traceExecution()
+ callSlowPath(_slow_path_get_by_val_with_this)
+ dispatch(5)
+
+_llint_op_put_by_id_with_this:
+ traceExecution()
+ callSlowPath(_slow_path_put_by_id_with_this)
+ dispatch(5)
+
+_llint_op_put_by_val_with_this:
+ traceExecution()
+ callSlowPath(_slow_path_put_by_val_with_this)
+ dispatch(5)
+
</ins><span class="cx"> # Lastly, make sure that we can link even though we don't support all opcodes.
</span><span class="cx"> # These opcodes should never arise when using LLInt or either JIT. We assert
</span><span class="cx"> # as much.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeCommonSlowPathscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -815,4 +815,78 @@
</span><span class="cx"> END();
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+SLOW_PATH_DECL(slow_path_get_by_id_with_this)
+{
+ BEGIN();
+ const Identifier& ident = exec->codeBlock()->identifier(pc[4].u.operand);
+ JSValue baseValue = OP_C(2).jsValue();
+ JSValue thisVal = OP_C(3).jsValue();
+ PropertySlot slot(thisVal, PropertySlot::PropertySlot::InternalMethodType::Get);
+ JSValue result = baseValue.get(exec, ident, slot);
+ RETURN(result);
+}
+
+SLOW_PATH_DECL(slow_path_get_by_val_with_this)
+{
+ BEGIN();
+
+ JSValue baseValue = OP_C(2).jsValue();
+ JSValue thisValue = OP_C(3).jsValue();
+ JSValue subscript = OP_C(4).jsValue();
+
+ if (LIKELY(baseValue.isCell() && subscript.isString())) {
+ VM& vm = exec->vm();
+ Structure& structure = *baseValue.asCell()->structure(vm);
+ if (JSCell::canUseFastGetOwnProperty(structure)) {
+ if (RefPtr<AtomicStringImpl> existingAtomicString = asString(subscript)->toExistingAtomicString(exec)) {
+ if (JSValue result = baseValue.asCell()->fastGetOwnProperty(vm, structure, existingAtomicString.get()))
+ RETURN(result);
+ }
+ }
+ }
+
+ PropertySlot slot(thisValue, PropertySlot::PropertySlot::InternalMethodType::Get);
+ if (subscript.isUInt32()) {
+ uint32_t i = subscript.asUInt32();
+ if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i))
+ RETURN(asString(baseValue)->getIndex(exec, i));
+
+ RETURN(baseValue.get(exec, i, slot));
+ }
+
+ baseValue.requireObjectCoercible(exec);
+ CHECK_EXCEPTION();
+ auto property = subscript.toPropertyKey(exec);
+ CHECK_EXCEPTION();
+ RETURN(baseValue.get(exec, property, slot));
+}
+
+SLOW_PATH_DECL(slow_path_put_by_id_with_this)
+{
+ BEGIN();
+ CodeBlock* codeBlock = exec->codeBlock();
+ const Identifier& ident = codeBlock->identifier(pc[3].u.operand);
+ JSValue baseValue = OP_C(1).jsValue();
+ JSValue thisVal = OP_C(2).jsValue();
+ JSValue putValue = OP_C(4).jsValue();
+ PutPropertySlot slot(thisVal, codeBlock->isStrictMode(), codeBlock->putByIdContext());
+ baseValue.putInline(exec, ident, putValue, slot);
+ END();
+}
+
+SLOW_PATH_DECL(slow_path_put_by_val_with_this)
+{
+ BEGIN();
+ JSValue baseValue = OP_C(1).jsValue();
+ JSValue thisValue = OP_C(2).jsValue();
+ JSValue subscript = OP_C(3).jsValue();
+ JSValue value = OP_C(4).jsValue();
+
+ auto property = subscript.toPropertyKey(exec);
+ CHECK_EXCEPTION();
+ PutPropertySlot slot(thisValue, exec->codeBlock()->isStrictMode());
+ baseValue.put(exec, property, value, slot);
+ END();
+}
+
</ins><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeCommonSlowPathsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.h (200585 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.h        2016-05-09 20:10:59 UTC (rev 200585)
+++ trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.h        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -248,6 +248,10 @@
</span><span class="cx"> SLOW_PATH_HIDDEN_DECL(slow_path_push_with_scope);
</span><span class="cx"> SLOW_PATH_HIDDEN_DECL(slow_path_resolve_scope);
</span><span class="cx"> SLOW_PATH_HIDDEN_DECL(slow_path_copy_rest);
</span><ins>+SLOW_PATH_HIDDEN_DECL(slow_path_get_by_id_with_this);
+SLOW_PATH_HIDDEN_DECL(slow_path_get_by_val_with_this);
+SLOW_PATH_HIDDEN_DECL(slow_path_put_by_id_with_this);
+SLOW_PATH_HIDDEN_DECL(slow_path_put_by_val_with_this);
</ins><span class="cx">
</span><span class="cx"> } // namespace JSC
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresssuperpropertyaccessexceptionsjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/super-property-access-exceptions.js (0 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/super-property-access-exceptions.js         (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/super-property-access-exceptions.js        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -0,0 +1,153 @@
</span><ins>+function assert(b, m = "Bad!") {
+ if (!b) {
+ throw new Error(m);
+ }
+}
+
+function test(f, iters = 1000) {
+ for (let i = 0; i < iters; i++)
+ f();
+}
+
+test(function() {
+ function fooProp() { return 'foo'; }
+ noInline(fooProp);
+
+ let shouldThrow = false;
+ class A {
+ get foo() {
+ if (shouldThrow)
+ throw new Error;
+ return 20;
+ }
+ get x() { return this._x; }
+ }
+
+ class B extends A {
+ constructor(x) {
+ super();
+ this._x = x;
+ }
+
+ bar() {
+ this._x = super.foo;
+ }
+
+ baz() {
+ this._x = super[fooProp()];
+ }
+ }
+
+ function foo(i) {
+ let b = new B(i);
+ noInline(b.__lookupGetter__('foo'));
+ let threw = false;
+ try {
+ b.bar();
+ } catch(e) {
+ threw = true;
+ }
+ if (threw)
+ assert(b.x === i);
+ else
+ assert(b.x === 20);
+ }
+ function bar(i) {
+ let b = new B(i);
+ noInline(b.__lookupGetter__('foo'));
+ let threw = false;
+ try {
+ b.baz();
+ } catch(e) {
+ threw = true;
+ }
+ if (threw)
+ assert(b.x === i);
+ else
+ assert(b.x === 20, "b.x " + b.x + " " + i);
+ }
+ noInline(bar);
+
+ for (let i = 0; i < 10000; i++) {
+ foo(i);
+ bar(i);
+ }
+ shouldThrow = true;
+ foo(23);
+ bar(24);
+
+}, 1);
+
+test(function() {
+ function fooProp() { return 'foo'; }
+ noInline(fooProp);
+
+ function func(i) {
+ if (shouldThrow)
+ throw new Error();
+ return i;
+ }
+ noInline(func);
+
+ let shouldThrow = false;
+ class A {
+ set foo(x) {
+ this._x = x;
+ }
+ get x() { return this._x; }
+ }
+
+ class B extends A {
+ constructor(x) {
+ super();
+ this._x = x;
+ }
+
+ bar(x) {
+ super.foo = func(x);
+ }
+
+ baz(x) {
+ super[fooProp()] = func(x);
+ }
+ }
+
+ function foo(i) {
+ let b = new B(i);
+ noInline(b.__lookupGetter__('foo'));
+ let threw = false;
+ try {
+ b.bar(i + 1);
+ } catch(e) {
+ threw = true;
+ }
+ if (threw)
+ assert(b.x === i);
+ else
+ assert(b.x === i + 1);
+ }
+ function bar(i) {
+ let b = new B(i);
+ noInline(b.__lookupGetter__('foo'));
+ let threw = false;
+ try {
+ b.baz(i + 1);
+ } catch(e) {
+ threw = true;
+ }
+ if (threw)
+ assert(b.x === i);
+ else
+ assert(b.x === i + 1);
+ }
+ noInline(bar);
+
+ for (let i = 0; i < 10000; i++) {
+ foo(i);
+ bar(i);
+ }
+ shouldThrow = true;
+ foo(23);
+ bar(24);
+
+}, 1);
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresssuperpropertyaccesstdzjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/super-property-access-tdz.js (0 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/super-property-access-tdz.js         (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/super-property-access-tdz.js        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -0,0 +1,92 @@
</span><ins>+function assert(b, m = "Bad!") {
+ if (!b) {
+ throw new Error(m);
+ }
+}
+
+function test(f, iters = 1000) {
+ for (let i = 0; i < iters; i++)
+ f();
+}
+
+function shouldThrowTDZ(f) {
+ let threw = false;
+ try {
+ f();
+ } catch(e) {
+ assert(e instanceof ReferenceError);
+ assert(e.toString() === "ReferenceError: Cannot access uninitialized variable.");
+ threw = true;
+ }
+ assert(threw);
+}
+
+test(function() {
+ class A {
+ get foo() {
+ return this._x;
+ }
+ set foo(x) {
+ this._x = x;
+ }
+ }
+
+ function fooProp() { return 'foo'; }
+
+ class B extends A {
+ constructor() {
+ super.foo = 20;
+ }
+ }
+
+ class C extends A {
+ constructor() {
+ super[fooProp()] = 20;
+ }
+ }
+
+ class D extends A {
+ constructor() {
+ super[fooProp()];
+ }
+ }
+
+ class E extends A {
+ constructor() {
+ super.foo;
+ }
+ }
+
+ class F extends A {
+ constructor() {
+ (() => super.foo = 20)();
+ }
+ }
+
+ class G extends A {
+ constructor() {
+ (() => super[fooProp()] = 20)();
+ }
+ }
+
+ class H extends A {
+ constructor() {
+ (() => super[fooProp()])();
+ }
+ }
+
+ class I extends A {
+ constructor() {
+ (() => super.foo)();
+ }
+ }
+
+ shouldThrowTDZ(function() { new B; });
+ shouldThrowTDZ(function() { new C; });
+ shouldThrowTDZ(function() { new D; });
+ shouldThrowTDZ(function() { new E; });
+ shouldThrowTDZ(function() { new F; });
+ shouldThrowTDZ(function() { new G; });
+ shouldThrowTDZ(function() { new H; });
+ shouldThrowTDZ(function() { new I; });
+});
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresssuperpropertyaccessjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/super-property-access.js (0 => 200586)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/super-property-access.js         (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/super-property-access.js        2016-05-09 20:17:23 UTC (rev 200586)
</span><span class="lines">@@ -0,0 +1,586 @@
</span><ins>+function assert(b, m = "Bad!") {
+ if (!b) {
+ throw new Error(m);
+ }
+}
+
+function test(f, iters = 1000) {
+ for (let i = 0; i < iters; i++)
+ f();
+}
+
+function func(x) {
+ return x;
+}
+noInline(func);
+
+test(function() {
+ class A {
+ constructor(x)
+ {
+ this._value = x;
+ }
+
+ set value(x) { this._value = x; }
+ get value() { return this._value; }
+ }
+
+ class B extends A {
+ set value(x) { super.value = x; }
+ get value() { return super.value; }
+ }
+
+ let arr = [];
+ for (let i = 0; i < 1000; i++) {
+ arr.push(new B(20));
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].value === 20);
+ }
+ for (let i = 0; i < 1000; i++) {
+ arr[i].value = i;
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].value === i);
+ }
+}, 10);
+
+test(function() {
+ function value() { return 'value'; }
+ noInline(value);
+
+ class A {
+ constructor(x, f = func)
+ {
+ this._value = x;
+ this._func = f;
+ }
+
+ set value(x) { this._value = x; }
+ get value() { return this._value; }
+ get func() { return this._func; }
+ }
+
+ class B extends A {
+ set value(x) { super[value()] = x; }
+ get value() { return super[value()]; }
+ inc() { return super[value()]++; }
+ dec() { return super[value()]--; }
+ preInc() { return ++super[value()]; }
+ preDec() { return --super[value()]; }
+ plusEq(x) { super[value()] += x; }
+ minusEq(x) { super[value()] -= x; }
+ timesEq(x) { super[value()] *= x; }
+ divEq(x) { super[value()] /= x; }
+
+ funcDot(x) { return super.func(x); }
+ funcBracket(x) { return super.func(x); }
+ }
+
+ let arr = [];
+ for (let i = 0; i < 1000; i++) {
+ arr.push(new B(20));
+ }
+ for (let i = 0; i < 1000; i++) {
+ let t = arr[i].value;
+ assert(t === 20);
+ }
+ for (let i = 0; i < 1000; i++) {
+ arr[i].value = i;
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].value === i);
+ }
+
+ for (let i = 0; i < 1000; i++) {
+ let v = arr[i].inc();
+ assert(v === i);
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].value === i+1);
+ }
+
+ for (let i = 0; i < 1000; i++) {
+ let v = arr[i].dec();
+ assert(v === i+1);
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].value === i);
+ }
+
+ for (let i = 0; i < 1000; i++) {
+ let v = arr[i].preInc();
+ assert(v === i+1);
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].value === i+1);
+ }
+
+ for (let i = 0; i < 1000; i++) {
+ let v = arr[i].preDec();
+ assert(v === i);
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].value === i);
+ }
+
+ for (let i = 0; i < 1000; i++) {
+ arr[i].plusEq(i);
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].value === i+i);
+ }
+
+ for (let i = 0; i < 1000; i++) {
+ arr[i].minusEq(i);
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].value === i);
+ }
+
+ for (let i = 0; i < 1000; i++) {
+ arr[i].timesEq(i);
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].value === i*i);
+ }
+
+ for (let i = 0; i < 1000; i++) {
+ if (i === 0)
+ arr[i].value = 0;
+ else
+ arr[i].divEq(i);
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].value === i);
+ }
+
+ for (let i = 0; i < 1000; i++) {
+ arr[i] = new B(0, function(a) { return i + a; });
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].funcDot(i) === i + i);
+ assert(arr[i].funcBracket(i*2) === i + i*2);
+ }
+
+}, 10);
+
+
+test(function() {
+ class A {
+ constructor(x, f = func)
+ {
+ this._value = x;
+ this._func = f;
+ }
+
+ set value(x) { this._value = x; }
+ get value() { return this._value; }
+ get func() { return this._func; }
+ }
+
+ class B extends A {
+ set value(x) { (() => super.value = x)(); }
+ get value() { return (() => super.value)(); }
+ inc() { return (() => super.value++)(); }
+ dec() { return (() => super.value--)(); }
+ preInc() { return (() => ++super.value)(); }
+ preDec() { return (() => --super.value)(); }
+ plusEq(x) { (() => super.value += x)(); }
+ minusEq(x) { (() => super.value -= x)(); }
+ timesEq(x) { (() => super.value *= x)(); }
+ divEq(x) { (() => super.value /= x)(); }
+
+ funcDot(x) { return (() => super.func(x))(); }
+ funcBracket(x) { return (() => super.func(x))(); }
+ }
+
+ let arr = [];
+ for (let i = 0; i < 1000; i++) {
+ arr.push(new B(20));
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].value === 20);
+ }
+ for (let i = 0; i < 1000; i++) {
+ arr[i].value = i;
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].value === i);
+ }
+
+ for (let i = 0; i < 1000; i++) {
+ let v = arr[i].inc();
+ assert(v === i);
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].value === i+1);
+ }
+
+ for (let i = 0; i < 1000; i++) {
+ let v = arr[i].dec();
+ assert(v === i+1);
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].value === i);
+ }
+
+ for (let i = 0; i < 1000; i++) {
+ let v = arr[i].preInc();
+ assert(v === i+1);
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].value === i+1);
+ }
+
+ for (let i = 0; i < 1000; i++) {
+ let v = arr[i].preDec();
+ assert(v === i);
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].value === i);
+ }
+
+ for (let i = 0; i < 1000; i++) {
+ arr[i].plusEq(i);
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].value === i+i);
+ }
+
+ for (let i = 0; i < 1000; i++) {
+ arr[i].minusEq(i);
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].value === i);
+ }
+
+ for (let i = 0; i < 1000; i++) {
+ arr[i].timesEq(i);
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].value === i*i);
+ }
+
+ for (let i = 0; i < 1000; i++) {
+ if (i === 0)
+ arr[i].value = 0;
+ else
+ arr[i].divEq(i);
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].value === i);
+ }
+
+ for (let i = 0; i < 1000; i++) {
+ arr[i] = new B(0, function(a) { return i + a; });
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].funcDot(i) === i + i);
+ assert(arr[i].funcBracket(i*2) === i + i*2);
+ }
+
+}, 10);
+
+test(function() {
+ function foo() { return 'foo'; }
+ noInline(foo);
+ class A { }
+ let obj = {};
+ A.prototype.foo = obj;
+ A.prototype[0] = obj;
+
+
+ class B extends A {
+ baz() { return super[foo()]; }
+ jaz() { return super.foo; }
+ bar() { return super[0]; }
+
+ }
+
+ assert((new B).baz() === obj);
+ assert((new B).jaz() === obj);
+ assert((new B).bar() === obj);
+});
+
+test(function() {
+ class A { }
+ for (let i = 0; i < 1000; i++)
+ A.prototype[i] = i;
+
+
+ class B extends A {
+ index(i) { return super[i]; }
+ }
+
+ let b = new B;
+ for (let i = 0; i < 1000; i++) {
+ assert(b.index(i) === i);
+ }
+}, 50);
+
+test(function() {
+ let obj = {};
+ class A { constructor(r) { this._foo = r; } }
+ Object.defineProperty(A.prototype, '0', { get: function() { return this._foo; } });
+
+ class B extends A {
+ bar() { return super[0]; }
+ }
+
+ let rand = Math.random();
+ assert((new B(rand)).bar() === rand);
+});
+
+test(function() { class A {
+ constructor() { this._array = []; }
+ set foo(x) {
+ this._array.push(x);
+ }
+ get array() { return this._array; }
+ }
+
+ class B extends A {
+ baz(i) {
+ let o = {x:20, y:30, [i]:i};
+ for (super.foo in o) { }
+ }
+ }
+ let arr = [];
+ for (let i = 0; i < 20; i++)
+ arr.push(new B);
+ for (let i = 0; i < arr.length; i++) {
+ let obj = arr[i];
+ obj.baz(i);
+ }
+ for (let i = 0; i < arr.length; i++) {
+ let obj = arr[i].array;
+ assert(obj.length === 3)
+ assert(obj[0] === '' + i);
+ assert(obj[1] === 'x')
+ assert(obj[2] === 'y')
+ }
+}, 1000);
+
+test(function() {
+ function foo() { return 'foo'; }
+ noInline(foo);
+ class A {
+ constructor() { this._array = []; }
+ set foo(x) {
+ this._array.push(x);
+ }
+ get array() { return this._array; }
+ }
+
+ class B extends A {
+ baz(i) {
+ let o = {x:20, y:30, [i]:i};
+ for (super[foo()] in o) { }
+ }
+ }
+ let arr = [];
+ for (let i = 0; i < 20; i++)
+ arr.push(new B);
+ for (let i = 0; i < arr.length; i++) {
+ let obj = arr[i];
+ obj.baz(i);
+ }
+ for (let i = 0; i < arr.length; i++) {
+ let obj = arr[i].array;
+ assert(obj.length === 3)
+ assert(obj[0] === '' + i);
+ assert(obj[1] === 'x')
+ assert(obj[2] === 'y')
+ }
+}, 1000);
+
+test(function() {
+ class A {
+ constructor() { this._array = []; }
+ set foo(x) {
+ this._array.push(x);
+ }
+ get array() { return this._array; }
+ }
+
+ class B extends A {
+ baz(i) {
+ let o = ['' + i, "x", "y"];
+ for (super.foo of o) { }
+ }
+ }
+ let arr = [];
+ for (let i = 0; i < 20; i++)
+ arr.push(new B);
+ for (let i = 0; i < arr.length; i++) {
+ let obj = arr[i];
+ obj.baz(i);
+ }
+ for (let i = 0; i < arr.length; i++) {
+ let obj = arr[i].array;
+ assert(obj.length === 3)
+ assert(obj[0] === '' + i);
+ assert(obj[1] === 'x')
+ assert(obj[2] === 'y')
+ }
+}, 1000);
+
+test(function() {
+ function foo() { return 'foo'; }
+ class A {
+ constructor() { this._array = []; }
+ set foo(x) {
+ this._array.push(x);
+ }
+ get array() { return this._array; }
+ }
+
+ class B extends A {
+ baz(i) {
+ let o = ['' + i, "x", "y"];
+ for (super[foo()] of o) { }
+ }
+ }
+ let arr = [];
+ for (let i = 0; i < 20; i++)
+ arr.push(new B);
+ for (let i = 0; i < arr.length; i++) {
+ let obj = arr[i];
+ obj.baz(i);
+ }
+ for (let i = 0; i < arr.length; i++) {
+ let obj = arr[i].array;
+ assert(obj.length === 3)
+ assert(obj[0] === '' + i);
+ assert(obj[1] === 'x')
+ assert(obj[2] === 'y')
+ }
+}, 1000);
+
+test(function() {
+ class A {
+ constructor() {
+ this._foo = null;
+ }
+ set foo(x) {
+ this._foo = x;
+ }
+ get foo() { return this._foo; }
+ }
+ function obj(i) { return {o: i}; }
+ noInline(obj);
+
+ class B extends A {
+ baz(i) {
+ ;({o: super.foo} = obj(i));
+ }
+ }
+ let arr = [];
+ for (let i = 0; i < 1000; i++) {
+ arr.push((new B));
+ }
+ for (let i = 0; i < 1000; i++) {
+ arr[i].baz(i);
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].foo === i);
+ }
+}, 100);
+
+test(function() {
+ function foo() { return 'foo'; }
+ noInline(foo);
+ class A {
+ constructor() {
+ this._foo = null;
+ }
+ set foo(x) {
+ this._foo = x;
+ }
+ get foo() { return this._foo; }
+ }
+ function obj(i) { return {o: i}; }
+ noInline(obj);
+
+ class B extends A {
+ baz(i) {
+ ;({o: super[foo()]} = obj(i));
+ }
+ }
+ let arr = [];
+ for (let i = 0; i < 1000; i++) {
+ arr.push((new B));
+ }
+ for (let i = 0; i < 1000; i++) {
+ arr[i].baz(i);
+ }
+ for (let i = 0; i < 1000; i++) {
+ assert(arr[i].foo === i);
+ }
+}, 100);
+
+test(function() {
+ class A {
+ constructor() {
+ this._foo = null;
+ }
+ get call() {
+ let ret = () => 'call';
+ noInline(ret);
+ return ret;
+ }
+ get apply() {
+ let ret = () => 'apply';
+ noInline(ret);
+ return ret;
+ }
+ }
+
+ class B extends A {
+ foo() {
+ return super.call({}, 20, 30);
+ }
+ bar() {
+ return super.apply({}, [10, 20]);
+ }
+ }
+ for (let i = 0; i < 100; i++) {
+ let b = new B;
+ assert(b.foo() === 'call');
+ assert(b.bar() === 'apply');
+ }
+});
+
+test(function() {
+ class A {
+ constructor(i) { this._i = i; }
+ get foo() {
+ return function(strings, ...values) {
+ return [strings, values];
+ }
+ }
+ get i() { return this._i; }
+ }
+
+ class B extends A {
+ baz() {
+ return super.foo`hello${super.i}world`;
+ }
+ }
+
+ let arr = [];
+ for (let i = 0; i < 1000; i++) {
+ let b = new B(i);
+ arr.push(b);
+ }
+ for (let i = 0; i < 1000; i++) {
+ let r = arr[i].baz();
+ assert(r.length === 2);
+ assert(r[0].length === 2);
+ assert(r[0][0] === 'hello');
+ assert(r[0][1] === 'world');
+ assert(r[1].length === 1);
+ assert(r[1][0] === i);
+ }
+});
</ins></span></pre>
</div>
</div>
</body>
</html>