<!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>[209725] trunk</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/209725">209725</a></dd>
<dt>Author</dt> <dd>msaboff@apple.com</dd>
<dt>Date</dt> <dd>2016-12-12 13:46:45 -0800 (Mon, 12 Dec 2016)</dd>
</dl>
<h3>Log Message</h3>
<pre>REGRESSION(<a href="http://trac.webkit.org/projects/webkit/changeset/209653">r209653</a>): speedometer crashes making virtual slow path tailcalls
https://bugs.webkit.org/show_bug.cgi?id=165748
Reviewed by Filip Pizlo.
JSTests:
New regression test.
* stress/regress-165748.js: Added.
(sum1):
(sum2):
(sum3):
(sum4):
(sum5):
(sum6):
(tailCaller):
(test):
Source/JavaScriptCore:
The virtual slow path for tailcalls always passes arguments on the stack.
The fix here is to link to the stack argument entrypoint instead of a register
argument entrypoint.
While fixing this bug, I found that we weren't clearing the code origin when
shuffling the call frame for a register argument tailcall.
Also rolling back in <a href="http://trac.webkit.org/projects/webkit/changeset/209653">r209653</a>, <a href="http://trac.webkit.org/projects/webkit/changeset/209654">r209654</a>, <a href="http://trac.webkit.org/projects/webkit/changeset/209663">r209663</a>, and <a href="http://trac.webkit.org/projects/webkit/changeset/209673">r209673</a>.
* jit/CallFrameShuffler.cpp:
(JSC::CallFrameShuffler::prepareAny):
* jit/ThunkGenerators.cpp:
(JSC::virtualThunkFor):
Source/WTF:
Rolling back in <a href="http://trac.webkit.org/projects/webkit/changeset/209653">r209653</a>, <a href="http://trac.webkit.org/projects/webkit/changeset/209654">r209654</a>, <a href="http://trac.webkit.org/projects/webkit/changeset/209663">r209663</a>, and <a href="http://trac.webkit.org/projects/webkit/changeset/209673">r209673</a>.
* wtf/Platform.h:</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3ArgumentRegValueh">trunk/Source/JavaScriptCore/b3/B3ArgumentRegValue.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Validatecpp">trunk/Source/JavaScriptCore/b3/B3Validate.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeCallLinkInfocpp">trunk/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeCallLinkInfoh">trunk/Source/JavaScriptCore/bytecode/CallLinkInfo.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodePolymorphicAccesscpp">trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.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="#trunkSourceJavaScriptCoredfgDFGCPSRethreadingPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGClobberizeh">trunk/Source/JavaScriptCore/dfg/DFGClobberize.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGCommonh">trunk/Source/JavaScriptCore/dfg/DFGCommon.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGDCEPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGDCEPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGDoesGCcpp">trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGDrivercpp">trunk/Source/JavaScriptCore/dfg/DFGDriver.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGFixupPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGGenerationInfoh">trunk/Source/JavaScriptCore/dfg/DFGGenerationInfo.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGGraphcpp">trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGGraphh">trunk/Source/JavaScriptCore/dfg/DFGGraph.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGInPlaceAbstractStatecpp">trunk/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGJITCompilercpp">trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGJITCompilerh">trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGJITFinalizercpp">trunk/Source/JavaScriptCore/dfg/DFGJITFinalizer.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGJITFinalizerh">trunk/Source/JavaScriptCore/dfg/DFGJITFinalizer.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGLiveCatchVariablePreservationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGLiveCatchVariablePreservationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGMaximalFlushInsertionPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGMaximalFlushInsertionPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGMayExitcpp">trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGMinifiedNodecpp">trunk/Source/JavaScriptCore/dfg/DFGMinifiedNode.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGMinifiedNodeh">trunk/Source/JavaScriptCore/dfg/DFGMinifiedNode.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodecpp">trunk/Source/JavaScriptCore/dfg/DFGNode.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="#trunkSourceJavaScriptCoredfgDFGOSRAvailabilityAnalysisPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGOSREntrypointCreationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGOSREntrypointCreationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPlancpp">trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPreciseLocalClobberizeh">trunk/Source/JavaScriptCore/dfg/DFGPreciseLocalClobberize.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPredictionInjectionPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGPredictionInjectionPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPutStackSinkingPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGPutStackSinkingPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGRegisterBankh">trunk/Source/JavaScriptCore/dfg/DFGRegisterBank.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSSAConversionPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSafeToExecuteh">trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp</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="#trunkSourceJavaScriptCoredfgDFGStrengthReductionPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGThunkscpp">trunk/Source/JavaScriptCore/dfg/DFGThunks.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGVariableEventStreamcpp">trunk/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGVirtualRegisterAllocationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCapabilitiescpp">trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLJITCodecpp">trunk/Source/JavaScriptCore/ftl/FTLJITCode.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLJITCodeh">trunk/Source/JavaScriptCore/ftl/FTLJITCode.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLJITFinalizercpp">trunk/Source/JavaScriptCore/ftl/FTLJITFinalizer.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLinkcpp">trunk/Source/JavaScriptCore/ftl/FTLLink.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLOSREntrycpp">trunk/Source/JavaScriptCore/ftl/FTLOSREntry.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLOutputcpp">trunk/Source/JavaScriptCore/ftl/FTLOutput.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLOutputh">trunk/Source/JavaScriptCore/ftl/FTLOutput.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreinterpreterShadowChickencpp">trunk/Source/JavaScriptCore/interpreter/ShadowChicken.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitAssemblyHelperscpp">trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitAssemblyHelpersh">trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitCachedRecoverycpp">trunk/Source/JavaScriptCore/jit/CachedRecovery.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitCachedRecoveryh">trunk/Source/JavaScriptCore/jit/CachedRecovery.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitCallFrameShuffleDatah">trunk/Source/JavaScriptCore/jit/CallFrameShuffleData.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitCallFrameShufflercpp">trunk/Source/JavaScriptCore/jit/CallFrameShuffler.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitCallFrameShufflerh">trunk/Source/JavaScriptCore/jit/CallFrameShuffler.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitCallFrameShuffler64cpp">trunk/Source/JavaScriptCore/jit/CallFrameShuffler64.cpp</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="#trunkSourceJavaScriptCorejitJITCallcpp">trunk/Source/JavaScriptCore/jit/JITCall.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITCall32_64cpp">trunk/Source/JavaScriptCore/jit/JITCall32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITCodecpp">trunk/Source/JavaScriptCore/jit/JITCode.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITCodeh">trunk/Source/JavaScriptCore/jit/JITCode.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOpcodescpp">trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOpcodes32_64cpp">trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOperationscpp">trunk/Source/JavaScriptCore/jit/JITOperations.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITThunkscpp">trunk/Source/JavaScriptCore/jit/JITThunks.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITThunksh">trunk/Source/JavaScriptCore/jit/JITThunks.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJSInterfaceJITh">trunk/Source/JavaScriptCore/jit/JSInterfaceJIT.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitRegisterSetcpp">trunk/Source/JavaScriptCore/jit/RegisterSet.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitRegisterSeth">trunk/Source/JavaScriptCore/jit/RegisterSet.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitRepatchcpp">trunk/Source/JavaScriptCore/jit/Repatch.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitSpecializedThunkJITh">trunk/Source/JavaScriptCore/jit/SpecializedThunkJIT.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitThunkGeneratorh">trunk/Source/JavaScriptCore/jit/ThunkGenerator.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitThunkGeneratorscpp">trunk/Source/JavaScriptCore/jit/ThunkGenerators.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitThunkGeneratorsh">trunk/Source/JavaScriptCore/jit/ThunkGenerators.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejsccpp">trunk/Source/JavaScriptCore/jsc.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLLIntEntrypointcpp">trunk/Source/JavaScriptCore/llint/LLIntEntrypoint.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLLIntSlowPathscpp">trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLLIntThunkscpp">trunk/Source/JavaScriptCore/llint/LLIntThunks.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLLIntThunksh">trunk/Source/JavaScriptCore/llint/LLIntThunks.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeArityCheckModeh">trunk/Source/JavaScriptCore/runtime/ArityCheckMode.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeExecutableBasecpp">trunk/Source/JavaScriptCore/runtime/ExecutableBase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeExecutableBaseh">trunk/Source/JavaScriptCore/runtime/ExecutableBase.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSBoundFunctioncpp">trunk/Source/JavaScriptCore/runtime/JSBoundFunction.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeNativeExecutablecpp">trunk/Source/JavaScriptCore/runtime/NativeExecutable.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeScriptExecutablecpp">trunk/Source/JavaScriptCore/runtime/ScriptExecutable.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeVMcpp">trunk/Source/JavaScriptCore/runtime/VM.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeVMh">trunk/Source/JavaScriptCore/runtime/VM.h</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmBindingcpp">trunk/Source/JavaScriptCore/wasm/WasmBinding.cpp</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtfPlatformh">trunk/Source/WTF/wtf/Platform.h</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkJSTestsmicrobenchmarkscallingcomputedargsjs">trunk/JSTests/microbenchmarks/calling-computed-args.js</a></li>
<li><a href="#trunkJSTestsmicrobenchmarkscallingmanycalleesjs">trunk/JSTests/microbenchmarks/calling-many-callees.js</a></li>
<li><a href="#trunkJSTestsmicrobenchmarkscallingonecalleefixedjs">trunk/JSTests/microbenchmarks/calling-one-callee-fixed.js</a></li>
<li><a href="#trunkJSTestsmicrobenchmarkscallingonecalleejs">trunk/JSTests/microbenchmarks/calling-one-callee.js</a></li>
<li><a href="#trunkJSTestsmicrobenchmarkscallingpolycalleesjs">trunk/JSTests/microbenchmarks/calling-poly-callees.js</a></li>
<li><a href="#trunkJSTestsmicrobenchmarkscallingpolyextraaritycalleesjs">trunk/JSTests/microbenchmarks/calling-poly-extra-arity-callees.js</a></li>
<li><a href="#trunkJSTestsmicrobenchmarkscallingtailcalljs">trunk/JSTests/microbenchmarks/calling-tailcall.js</a></li>
<li><a href="#trunkJSTestsmicrobenchmarkscallingvirtualarityfixupcalleesjs">trunk/JSTests/microbenchmarks/calling-virtual-arity-fixup-callees.js</a></li>
<li><a href="#trunkJSTestsmicrobenchmarkscallingvirtualarityfixupstackargsjs">trunk/JSTests/microbenchmarks/calling-virtual-arity-fixup-stackargs.js</a></li>
<li><a href="#trunkJSTestsmicrobenchmarkscallingvirtualcalleesjs">trunk/JSTests/microbenchmarks/calling-virtual-callees.js</a></li>
<li><a href="#trunkJSTestsmicrobenchmarkscallingvirtualextraaritycalleesjs">trunk/JSTests/microbenchmarks/calling-virtual-extra-arity-callees.js</a></li>
<li><a href="#trunkJSTestsstressregress165728js">trunk/JSTests/stress/regress-165728.js</a></li>
<li><a href="#trunkJSTestsstressregress165748js">trunk/JSTests/stress/regress-165748.js</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITEntryPointsh">trunk/Source/JavaScriptCore/jit/JITEntryPoints.h</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/JSTests/ChangeLog        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -1,3 +1,22 @@
</span><ins>+2016-12-12 Michael Saboff <msaboff@apple.com>
+
+ REGRESSION(r209653): speedometer crashes making virtual slow path tailcalls
+ https://bugs.webkit.org/show_bug.cgi?id=165748
+
+ Reviewed by Filip Pizlo.
+
+ New regression test.
+
+ * stress/regress-165748.js: Added.
+ (sum1):
+ (sum2):
+ (sum3):
+ (sum4):
+ (sum5):
+ (sum6):
+ (tailCaller):
+ (test):
+
</ins><span class="cx"> 2016-12-12 Mark Lam <mark.lam@apple.com>
</span><span class="cx">
</span><span class="cx"> Debug JSC test timeout: stress/string-prototype-replace-should-throw-out-of-memory-error-when-using-too-much-memory.js.ftl-no-cjit.
</span></span></pre></div>
<a id="trunkJSTestsmicrobenchmarkscallingcomputedargsjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/microbenchmarks/calling-computed-args.js (0 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/microbenchmarks/calling-computed-args.js         (rev 0)
+++ trunk/JSTests/microbenchmarks/calling-computed-args.js        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -0,0 +1,53 @@
</span><ins>+function sum2(a, b)
+{
+ return a + b;
+}
+
+noInline(sum2);
+
+function sum2b(a, b)
+{
+ return a + b;
+}
+
+noInline(sum2b);
+
+function sum3(a, b, c)
+{
+ return a + b + c;
+}
+
+noInline(sum3);
+
+function sum3b(a, b, c)
+{
+ return a + b + c;
+}
+
+noInline(sum3b);
+
+function test()
+{
+ let o1 = {
+ one: 1,
+ two: 2
+ }
+ let o2 = {
+ three: 3,
+ five: 5
+ };
+ let o3 = {
+ four: 4,
+ six: 6
+ };
+ let result = 0;
+ for (let i = 0; i < 2000000; i++)
+ result = sum2(o1.one, o2.five) + sum2b(o1.two, o1.one + o2.five)
+ + sum3(o2.three, o3.four, o2.five) + sum3b(o1.two, o2.three + o2.five, o3.six);
+
+ return result;
+}
+
+let result = test();
+if (result != 42)
+ throw "Unexpected result: " + result;
</ins></span></pre></div>
<a id="trunkJSTestsmicrobenchmarkscallingmanycalleesjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/microbenchmarks/calling-many-callees.js (0 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/microbenchmarks/calling-many-callees.js         (rev 0)
+++ trunk/JSTests/microbenchmarks/calling-many-callees.js        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -0,0 +1,40 @@
</span><ins>+function sum2(a, b)
+{
+ return a + b;
+}
+
+noInline(sum2);
+
+function sum2b(a, b)
+{
+ return a + b + b;
+}
+
+noInline(sum2b);
+
+function sum3(a, b, c)
+{
+ return a + b + c;
+}
+
+noInline(sum3);
+
+function sum3b(a, b, c)
+{
+ return a + b + b + c;
+}
+
+noInline(sum3b);
+
+function test()
+{
+ let result = 0;
+ for (let i = 0; i < 2000000; i++)
+ result = sum2(1, 2) + sum2b(2, 3) + sum3(5, 5, 5) + sum3b(2, 4, 6);
+
+ return result;
+}
+
+let result = test();
+if (result != 42)
+ throw "Unexpected result: " + result;
</ins></span></pre></div>
<a id="trunkJSTestsmicrobenchmarkscallingonecalleefixedjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/microbenchmarks/calling-one-callee-fixed.js (0 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/microbenchmarks/calling-one-callee-fixed.js         (rev 0)
+++ trunk/JSTests/microbenchmarks/calling-one-callee-fixed.js        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -0,0 +1,19 @@
</span><ins>+function sum(a, b, c)
+{
+ return a + b + c;
+}
+
+noInline(sum);
+
+function test()
+{
+ let result = 0;
+ for (let i = 0; i < 4000000; i++)
+ result = sum(1, 2, 3);
+
+ return result;
+}
+
+let result = test();
+if (result != 6)
+ throw "Unexpected result: " + result;
</ins></span></pre></div>
<a id="trunkJSTestsmicrobenchmarkscallingonecalleejs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/microbenchmarks/calling-one-callee.js (0 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/microbenchmarks/calling-one-callee.js         (rev 0)
+++ trunk/JSTests/microbenchmarks/calling-one-callee.js        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -0,0 +1,19 @@
</span><ins>+function sum(a, b, c)
+{
+ return a + b + c;
+}
+
+noInline(sum);
+
+function test(a, b, c)
+{
+ let result = 0;
+ for (let i = 0; i < 4000000; i++)
+ result = sum(a, b, c);
+
+ return result;
+}
+
+let result = test(1, 2, 3);
+if (result != 6)
+ throw "Unexpected result: " + result;
</ins></span></pre></div>
<a id="trunkJSTestsmicrobenchmarkscallingpolycalleesjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/microbenchmarks/calling-poly-callees.js (0 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/microbenchmarks/calling-poly-callees.js         (rev 0)
+++ trunk/JSTests/microbenchmarks/calling-poly-callees.js        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -0,0 +1,35 @@
</span><ins>+function sum1(a, b, c)
+{
+ return a + b + c;
+}
+
+noInline(sum1);
+
+function sum2(a, b, c)
+{
+ return b + a + c;
+}
+
+noInline(sum2);
+
+function sum3(a, b, c)
+{
+ return c + a + b;
+}
+
+noInline(sum3);
+
+let functions = [ sum1, sum2, sum3 ];
+
+function test(a, b, c)
+{
+ let result = 0;
+ for (let i = 0; i < 4000000; i++)
+ result = functions[i % 3](a, b, c);
+
+ return result;
+}
+
+let result = test(2, 10, 30);
+if (result != 42)
+ throw "Unexpected result: " + result;
</ins></span></pre></div>
<a id="trunkJSTestsmicrobenchmarkscallingpolyextraaritycalleesjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/microbenchmarks/calling-poly-extra-arity-callees.js (0 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/microbenchmarks/calling-poly-extra-arity-callees.js         (rev 0)
+++ trunk/JSTests/microbenchmarks/calling-poly-extra-arity-callees.js        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -0,0 +1,35 @@
</span><ins>+function sum1(a, b)
+{
+ return a + b;
+}
+
+noInline(sum1);
+
+function sum2(a, b)
+{
+ return b + a;
+}
+
+noInline(sum2);
+
+function sum3(a, b)
+{
+ return a + b;
+}
+
+noInline(sum3);
+
+let functions = [ sum1, sum2, sum3 ];
+
+function test(a, b, c)
+{
+ let result = 0;
+ for (let i = 0; i < 4000000; i++)
+ result = functions[i % 3](a, b, c);
+
+ return result;
+}
+
+let result = test(2, 40, "Test");
+if (result != 42)
+ throw "Unexpected result: " + result;
</ins></span></pre></div>
<a id="trunkJSTestsmicrobenchmarkscallingtailcalljs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/microbenchmarks/calling-tailcall.js (0 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/microbenchmarks/calling-tailcall.js         (rev 0)
+++ trunk/JSTests/microbenchmarks/calling-tailcall.js        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -0,0 +1,28 @@
</span><ins>+"use strict";
+
+function sum(a, b, c)
+{
+ return a + b + c;
+}
+
+noInline(sum);
+
+function tailCaller(a, b, c)
+{
+ return sum(b, a, c);
+}
+
+noInline(tailCaller);
+
+function test(a, b, c)
+{
+ let result = 0;
+ for (let i = 0; i < 4000000; i++)
+ result = tailCaller(a, b, c);
+
+ return result;
+}
+
+let result = test(1, 2, 3);
+if (result != 6)
+ throw "Unexpected result: " + result;
</ins></span></pre></div>
<a id="trunkJSTestsmicrobenchmarkscallingvirtualarityfixupcalleesjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/microbenchmarks/calling-virtual-arity-fixup-callees.js (0 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/microbenchmarks/calling-virtual-arity-fixup-callees.js         (rev 0)
+++ trunk/JSTests/microbenchmarks/calling-virtual-arity-fixup-callees.js        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -0,0 +1,56 @@
</span><ins>+function sum1(a, b, c)
+{
+ return a + b + (c | 0);
+}
+
+noInline(sum1);
+
+function sum2(a, b, c)
+{
+ return b + a + (c | 0);
+}
+
+noInline(sum2);
+
+function sum3(a, b, c)
+{
+ return (c | 0) + a + b;
+}
+
+noInline(sum3);
+
+function sum4(a, b, c)
+{
+ return (c | 0) + a + b;
+}
+
+noInline(sum4);
+
+function sum5(a, b, c)
+{
+ return (c | 0) + a + b;
+}
+
+noInline(sum5);
+
+function sum6(a, b, c)
+{
+ return (c | 0) + a + b;
+}
+
+noInline(sum6);
+
+let functions = [ sum1, sum2, sum3, sum4, sum5, sum6 ];
+
+function test(a, b)
+{
+ let result = 0;
+ for (let i = 0; i < 4000000; i++)
+ result = functions[i % 6](a, b);
+
+ return result;
+}
+
+let result = test(2, 40);
+if (result != 42)
+ throw "Unexpected result: " + result;
</ins></span></pre></div>
<a id="trunkJSTestsmicrobenchmarkscallingvirtualarityfixupstackargsjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/microbenchmarks/calling-virtual-arity-fixup-stackargs.js (0 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/microbenchmarks/calling-virtual-arity-fixup-stackargs.js         (rev 0)
+++ trunk/JSTests/microbenchmarks/calling-virtual-arity-fixup-stackargs.js        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -0,0 +1,56 @@
</span><ins>+function sum1(a, b, c, d)
+{
+ return a + b + c + (d | 0);
+}
+
+noInline(sum1);
+
+function sum2(a, b, c, d)
+{
+ return b + a + c + (d | 0);
+}
+
+noInline(sum2);
+
+function sum3(a, b, c, d)
+{
+ return (d | 0) + a + b + c;
+}
+
+noInline(sum3);
+
+function sum4(a, b, c, d)
+{
+ return (d | 0) + a + b + c;
+}
+
+noInline(sum4);
+
+function sum5(a, b, c, d)
+{
+ return (d | 0) + a + b + c;
+}
+
+noInline(sum5);
+
+function sum6(a, b, c, d)
+{
+ return (d | 0) + a + b + c;
+}
+
+noInline(sum6);
+
+let functions = [ sum1, sum2, sum3, sum4, sum5, sum6 ];
+
+function test(a, b, c)
+{
+ let result = 0;
+ for (let i = 0; i < 4000000; i++)
+ result = functions[i % 6](a, b, c);
+
+ return result;
+}
+
+let result = test(2, 10, 30);
+if (result != 42)
+ throw "Unexpected result: " + result;
</ins></span></pre></div>
<a id="trunkJSTestsmicrobenchmarkscallingvirtualcalleesjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/microbenchmarks/calling-virtual-callees.js (0 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/microbenchmarks/calling-virtual-callees.js         (rev 0)
+++ trunk/JSTests/microbenchmarks/calling-virtual-callees.js        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -0,0 +1,56 @@
</span><ins>+function sum1(a, b, c)
+{
+ return a + b + c;
+}
+
+noInline(sum1);
+
+function sum2(a, b, c)
+{
+ return b + a + c;
+}
+
+noInline(sum2);
+
+function sum3(a, b, c)
+{
+ return c + a + b;
+}
+
+noInline(sum3);
+
+function sum4(a, b, c)
+{
+ return c + a + b;
+}
+
+noInline(sum4);
+
+function sum5(a, b, c)
+{
+ return c + a + b;
+}
+
+noInline(sum5);
+
+function sum6(a, b, c)
+{
+ return c + a + b;
+}
+
+noInline(sum6);
+
+let functions = [ sum1, sum2, sum3, sum4, sum5, sum6 ];
+
+function test(a, b, c)
+{
+ let result = 0;
+ for (let i = 0; i < 4000000; i++)
+ result = functions[i % 6](a, b, c);
+
+ return result;
+}
+
+let result = test(2, 10, 30);
+if (result != 42)
+ throw "Unexpected result: " + result;
</ins></span></pre></div>
<a id="trunkJSTestsmicrobenchmarkscallingvirtualextraaritycalleesjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/microbenchmarks/calling-virtual-extra-arity-callees.js (0 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/microbenchmarks/calling-virtual-extra-arity-callees.js         (rev 0)
+++ trunk/JSTests/microbenchmarks/calling-virtual-extra-arity-callees.js        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -0,0 +1,56 @@
</span><ins>+function sum1(a, b)
+{
+ return a + b;
+}
+
+noInline(sum1);
+
+function sum2(a, b)
+{
+ return b + a;
+}
+
+noInline(sum2);
+
+function sum3(a, b)
+{
+ return a + b;
+}
+
+noInline(sum3);
+
+function sum4(a, b)
+{
+ return a + b;
+}
+
+noInline(sum4);
+
+function sum5(a, b)
+{
+ return a + b;
+}
+
+noInline(sum5);
+
+function sum6(a, b)
+{
+ return a + b;
+}
+
+noInline(sum6);
+
+let functions = [ sum1, sum2, sum3, sum4, sum5, sum6 ];
+
+function test(a, b, c)
+{
+ let result = 0;
+ for (let i = 0; i < 4000000; i++)
+ result = functions[i % 6](a, b, c);
+
+ return result;
+}
+
+let result = test(40, 2, "Test");
+if (result != 42)
+ throw "Unexpected result: " + result;
</ins></span></pre></div>
<a id="trunkJSTestsstressregress165728js"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/regress-165728.js (0 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/regress-165728.js         (rev 0)
+++ trunk/JSTests/stress/regress-165728.js        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -0,0 +1,36 @@
</span><ins>+// Test for REGRESSION(r209653) Crash in CallFrameShuffler::snapshot() - This test shouldn't crash.
+"use strict";
+
+function sum1(a, b, c)
+{
+ return a + b + c;
+}
+
+noInline(sum1);
+
+function sum2(a, b, c)
+{
+ return a + b + c;
+}
+
+noInline(sum2);
+
+function tailCaller(f, a, b)
+{
+ return f(a, b, a)
+}
+
+noInline(tailCaller);
+
+function test(a, b)
+{
+ let result = 0;
+ for (let i = 0; i < 4000000; i++)
+ result = tailCaller(i % 2 ? sum1 : sum2, a, b);
+
+ return result;
+}
+
+let result = test(20, 2);
+if (result != 42)
+ throw "Unexpected result: " + result;
</ins></span></pre></div>
<a id="trunkJSTestsstressregress165748js"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/regress-165748.js (0 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/regress-165748.js         (rev 0)
+++ trunk/JSTests/stress/regress-165748.js        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -0,0 +1,75 @@
</span><ins>+"use strict";
+
+function sum1(a, b, c)
+{
+ return a + b + c;
+}
+
+noInline(sum1);
+
+function sum2(a, b, c)
+{
+ return b + a + c;
+}
+
+noInline(sum2);
+
+function sum3(a, b, c)
+{
+ return c + a + b;
+}
+
+noInline(sum3);
+
+function sum4(a, b, c)
+{
+ return c + a + b;
+}
+
+noInline(sum4);
+
+function sum5(a, b, c)
+{
+ return c + a + b;
+}
+
+noInline(sum5);
+
+function sum6(a, b, c)
+{
+ return c + a + b;
+}
+
+noInline(sum6);
+
+let functions = [ sum1, sum2, sum3, sum4, sum5, sum6 ];
+
+function tailCaller(o)
+{
+ let a = o.a;
+ let b = o.b;
+ let c = o.c;
+
+ return functions[o.i % 6](a, b, c);
+}
+
+noInline(tailCaller);
+
+function test(a, b, c)
+{
+ let obj = {};
+ obj.a = a;
+ obj.b = b;
+ obj.c = c;
+ let result = 0;
+ for (let i = 0; i < 4000000; i++) {
+ obj.i = i;
+ obj.val = tailCaller(obj);
+ }
+
+ return obj;
+}
+
+let result = test(2, 10, 30);
+if (result.val != 42)
+ throw "Unexpected result: " + result.val;
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -1,3 +1,24 @@
</span><ins>+2016-12-12 Michael Saboff <msaboff@apple.com>
+
+ REGRESSION(r209653): speedometer crashes making virtual slow path tailcalls
+ https://bugs.webkit.org/show_bug.cgi?id=165748
+
+ Reviewed by Filip Pizlo.
+
+ The virtual slow path for tailcalls always passes arguments on the stack.
+ The fix here is to link to the stack argument entrypoint instead of a register
+ argument entrypoint.
+
+ While fixing this bug, I found that we weren't clearing the code origin when
+ shuffling the call frame for a register argument tailcall.
+
+ Also rolling back in r209653, r209654, r209663, and r209673.
+
+ * jit/CallFrameShuffler.cpp:
+ (JSC::CallFrameShuffler::prepareAny):
+ * jit/ThunkGenerators.cpp:
+ (JSC::virtualThunkFor):
+
</ins><span class="cx"> 2016-12-12 Mark Lam <mark.lam@apple.com>
</span><span class="cx">
</span><span class="cx"> Rename BytecodeGenerator's m_symbolTableStack to m_lexicalScopeStack.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -1351,6 +1351,7 @@
</span><span class="cx">                 65C02850171795E200351E35 /* ARMv7Disassembler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65C0284F171795E200351E35 /* ARMv7Disassembler.cpp */; };
</span><span class="cx">                 65C0285C1717966800351E35 /* ARMv7DOpcode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65C0285A1717966800351E35 /* ARMv7DOpcode.cpp */; };
</span><span class="cx">                 65C0285D1717966800351E35 /* ARMv7DOpcode.h in Headers */ = {isa = PBXBuildFile; fileRef = 65C0285B1717966800351E35 /* ARMv7DOpcode.h */; };
</span><ins>+                65DBF3021D93392B003AF4B0 /* JITEntryPoints.h in Headers */ = {isa = PBXBuildFile; fileRef = 650300F21C50274600D786D7 /* JITEntryPoints.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">                 65FB5117184EEE7000C12B70 /* ProtoCallFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65FB5116184EE9BC00C12B70 /* ProtoCallFrame.cpp */; };
</span><span class="cx">                 65FB63A41C8EA09C0020719B /* YarrCanonicalizeUnicode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65A946141C8E9F6F00A7209A /* YarrCanonicalizeUnicode.cpp */; };
</span><span class="cx">                 6AD2CB4D19B9140100065719 /* DebuggerEvalEnabler.h in Headers */ = {isa = PBXBuildFile; fileRef = 6AD2CB4C19B9140100065719 /* DebuggerEvalEnabler.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="lines">@@ -3722,6 +3723,7 @@
</span><span class="cx">                 62E3D5EF1B8D0B7300B868BB /* DataFormat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DataFormat.cpp; sourceTree = "<group>"; };
</span><span class="cx">                 62EC9BB41B7EB07C00303AD1 /* CallFrameShuffleData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CallFrameShuffleData.cpp; sourceTree = "<group>"; };
</span><span class="cx">                 62EC9BB51B7EB07C00303AD1 /* CallFrameShuffleData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallFrameShuffleData.h; sourceTree = "<group>"; };
</span><ins>+                650300F21C50274600D786D7 /* JITEntryPoints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITEntryPoints.h; sourceTree = "<group>"; };
</ins><span class="cx">                 6507D2970E871E4A00D7D896 /* JSTypeInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSTypeInfo.h; sourceTree = "<group>"; };
</span><span class="cx">                 651122E5140469BA002B101D /* testRegExp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = testRegExp.cpp; sourceTree = "<group>"; };
</span><span class="cx">                 6511230514046A4C002B101D /* testRegExp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testRegExp; sourceTree = BUILT_PRODUCTS_DIR; };
</span><span class="lines">@@ -5560,6 +5562,7 @@
</span><span class="cx">                                 0FAF7EFB165BA919000C8455 /* JITDisassembler.h */,
</span><span class="cx">                                 FE187A0A1C0229230038BBCA /* JITDivGenerator.cpp */,
</span><span class="cx">                                 FE187A0B1C0229230038BBCA /* JITDivGenerator.h */,
</span><ins>+                                650300F21C50274600D786D7 /* JITEntryPoints.h */,
</ins><span class="cx">                                 0F46807F14BA572700BFE272 /* JITExceptions.cpp */,
</span><span class="cx">                                 0F46808014BA572700BFE272 /* JITExceptions.h */,
</span><span class="cx">                                 0FB14E1C18124ACE009B6B4D /* JITInlineCacheGenerator.cpp */,
</span><span class="lines">@@ -7717,6 +7720,7 @@
</span><span class="cx">                                 79B00CBD1C6AB07E0088C65D /* ProxyConstructor.h in Headers */,
</span><span class="cx">                                 53D444DC1DAF08AB00B92784 /* B3WasmAddressValue.h in Headers */,
</span><span class="cx">                                 990DA67F1C8E316A00295159 /* generate_objc_protocol_type_conversions_implementation.py in Headers */,
</span><ins>+                                65DBF3021D93392B003AF4B0 /* JITEntryPoints.h in Headers */,
</ins><span class="cx">                                 DC17E8191C9C91DB008A6AB3 /* ShadowChickenInlines.h in Headers */,
</span><span class="cx">                                 DC17E8181C9C91D9008A6AB3 /* ShadowChicken.h in Headers */,
</span><span class="cx">                                 799EF7C41C56ED96002B0534 /* B3PCToOriginMap.h in Headers */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3ArgumentRegValueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3ArgumentRegValue.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3ArgumentRegValue.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/b3/B3ArgumentRegValue.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -55,6 +55,13 @@
</span><span class="cx"> ASSERT(reg.isSet());
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ ArgumentRegValue(Origin origin, Reg reg, Type type)
+ : Value(CheckedOpcode, ArgumentReg, type, origin)
+ , m_reg(reg)
+ {
+ ASSERT(reg.isSet());
+ }
+
</ins><span class="cx"> Reg m_reg;
</span><span class="cx"> };
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Validatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Validate.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Validate.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/b3/B3Validate.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -182,9 +182,12 @@
</span><span class="cx"> case ArgumentReg:
</span><span class="cx"> VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
</span><span class="cx"> VALIDATE(!value->numChildren(), ("At ", *value));
</span><del>- VALIDATE(
- (value->as<ArgumentRegValue>()->argumentReg().isGPR() ? pointerType() : Double)
- == value->type(), ("At ", *value));
</del><ins>+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=165717
+ // We need to handle Int32 arguments and Int64 arguments
+ // for the same register distinctly.
+ VALIDATE((value->as<ArgumentRegValue>()->argumentReg().isGPR()
+ ? (value->type() == pointerType() || value->type() == Int32)
+ : value->type() == Double), ("At ", *value));
</ins><span class="cx"> break;
</span><span class="cx"> case Add:
</span><span class="cx"> case Sub:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCallLinkInfocpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -60,6 +60,7 @@
</span><span class="cx"> , m_hasSeenClosure(false)
</span><span class="cx"> , m_clearedByGC(false)
</span><span class="cx"> , m_allowStubs(true)
</span><ins>+ , m_argumentsLocation(static_cast<unsigned>(ArgumentsLocation::StackArgs))
</ins><span class="cx"> , m_isLinked(false)
</span><span class="cx"> , m_callType(None)
</span><span class="cx"> , m_calleeGPR(255)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCallLinkInfoh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CallLinkInfo.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CallLinkInfo.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/bytecode/CallLinkInfo.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx"> #include "CallMode.h"
</span><span class="cx"> #include "CodeLocation.h"
</span><span class="cx"> #include "CodeSpecializationKind.h"
</span><ins>+#include "JITEntryPoints.h"
</ins><span class="cx"> #include "PolymorphicCallStubRoutine.h"
</span><span class="cx"> #include "WriteBarrier.h"
</span><span class="cx"> #include <wtf/SentinelLinkedList.h>
</span><span class="lines">@@ -157,9 +158,12 @@
</span><span class="cx"> bool isLinked() { return m_stub || m_calleeOrCodeBlock; }
</span><span class="cx"> void unlink(VM&);
</span><span class="cx">
</span><del>- void setUpCall(CallType callType, CodeOrigin codeOrigin, unsigned calleeGPR)
</del><ins>+ void setUpCall(CallType callType, ArgumentsLocation argumentsLocation, CodeOrigin codeOrigin, unsigned calleeGPR)
</ins><span class="cx"> {
</span><ins>+ ASSERT(!isVarargsCallType(callType) || (argumentsLocation == StackArgs));
+
</ins><span class="cx"> m_callType = callType;
</span><ins>+ m_argumentsLocation = static_cast<unsigned>(argumentsLocation);
</ins><span class="cx"> m_codeOrigin = codeOrigin;
</span><span class="cx"> m_calleeGPR = calleeGPR;
</span><span class="cx"> }
</span><span class="lines">@@ -275,6 +279,16 @@
</span><span class="cx"> return static_cast<CallType>(m_callType);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ ArgumentsLocation argumentsLocation()
+ {
+ return static_cast<ArgumentsLocation>(m_argumentsLocation);
+ }
+
+ bool argumentsInRegisters()
+ {
+ return m_argumentsLocation != StackArgs;
+ }
+
</ins><span class="cx"> uint32_t* addressOfMaxNumArguments()
</span><span class="cx"> {
</span><span class="cx"> return &m_maxNumArguments;
</span><span class="lines">@@ -339,6 +353,7 @@
</span><span class="cx"> bool m_hasSeenClosure : 1;
</span><span class="cx"> bool m_clearedByGC : 1;
</span><span class="cx"> bool m_allowStubs : 1;
</span><ins>+ unsigned m_argumentsLocation : 4;
</ins><span class="cx"> bool m_isLinked : 1;
</span><span class="cx"> unsigned m_callType : 4; // CallType
</span><span class="cx"> unsigned m_calleeGPR : 8;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodePolymorphicAccesscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -1032,7 +1032,7 @@
</span><span class="cx"> m_rareData->callLinkInfo->disallowStubs();
</span><span class="cx">
</span><span class="cx"> m_rareData->callLinkInfo->setUpCall(
</span><del>- CallLinkInfo::Call, stubInfo.codeOrigin, loadedValueGPR);
</del><ins>+ CallLinkInfo::Call, StackArgs, stubInfo.codeOrigin, loadedValueGPR);
</ins><span class="cx">
</span><span class="cx"> CCallHelpers::JumpList done;
</span><span class="cx">
</span><span class="lines">@@ -1105,7 +1105,7 @@
</span><span class="cx"> // We *always* know that the getter/setter, if non-null, is a cell.
</span><span class="cx"> jit.move(CCallHelpers::TrustedImm32(JSValue::CellTag), GPRInfo::regT1);
</span><span class="cx"> #endif
</span><del>- jit.move(CCallHelpers::TrustedImmPtr(m_rareData->callLinkInfo.get()), GPRInfo::regT2);
</del><ins>+ jit.move(CCallHelpers::TrustedImmPtr(m_rareData->callLinkInfo.get()), GPRInfo::nonArgGPR0);
</ins><span class="cx"> slowPathCall = jit.nearCall();
</span><span class="cx"> if (m_type == Getter)
</span><span class="cx"> jit.setupResults(valueRegs);
</span><span class="lines">@@ -1131,7 +1131,7 @@
</span><span class="cx">
</span><span class="cx"> linkBuffer.link(
</span><span class="cx"> slowPathCall,
</span><del>- CodeLocationLabel(vm.getCTIStub(linkCallThunkGenerator).code()));
</del><ins>+ CodeLocationLabel(vm.getJITCallThunkEntryStub(linkCallThunkGenerator).entryFor(StackArgs)));
</ins><span class="cx"> });
</span><span class="cx"> } else {
</span><span class="cx"> ASSERT(m_type == CustomValueGetter || m_type == CustomAccessorGetter || m_type == CustomValueSetter || m_type == CustomAccessorSetter);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -271,7 +271,17 @@
</span><span class="cx"> // non-clear value.
</span><span class="cx"> ASSERT(!m_state.variables().operand(node->local()).isClear());
</span><span class="cx"> break;
</span><del>-
</del><ins>+
+ case GetArgumentRegister:
+ ASSERT(!m_state.variables().operand(node->local()).isClear());
+ if (node->variableAccessData()->flushFormat() == FlushedJSValue) {
+ forNode(node).makeBytecodeTop();
+ break;
+ }
+
+ forNode(node).setType(m_graph, typeFilterFor(node->variableAccessData()->flushFormat()));
+ break;
+
</ins><span class="cx"> case LoadVarargs:
</span><span class="cx"> case ForwardVarargs: {
</span><span class="cx"> // FIXME: ForwardVarargs should check if the count becomes known, and if it does, it should turn
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -3697,11 +3697,59 @@
</span><span class="cx"> // us to track if a use of an argument may use the actual argument passed, as
</span><span class="cx"> // opposed to using a value we set explicitly.
</span><span class="cx"> if (m_currentBlock == m_graph.block(0) && !inlineCallFrame()) {
</span><del>- m_graph.m_arguments.resize(m_numArguments);
- // We will emit SetArgument nodes. They don't exit, but we're at the top of an op_enter so
- // exitOK = true.
</del><ins>+ m_graph.m_argumentsOnStack.resize(m_numArguments);
+ m_graph.m_argumentsForChecking.resize(m_numArguments);
+ // Create all GetArgumentRegister nodes first and then the corresponding MovHint nodes,
+ // followed by the corresponding SetLocal nodes and finally any SetArgument nodes for
+ // the remaining arguments.
+ // We do this to make the exit processing correct. We start with m_exitOK = true since
+ // GetArgumentRegister nodes can exit, even though they don't. The MovHint's technically could
+ // exit but won't. The SetLocals can exit and therefore we want all the MovHints
+ // before the first SetLocal so that the register state is consistent.
+ // We do all this processing before creating any SetArgument nodes since they are
+ // morally equivalent to the SetLocals for GetArgumentRegister nodes.
</ins><span class="cx"> m_exitOK = true;
</span><del>- for (unsigned argument = 0; argument < m_numArguments; ++argument) {
</del><ins>+
+ unsigned numRegisterArguments = std::min(m_numArguments, NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS);
+
+ Vector<Node*, NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS> getArgumentRegisterNodes;
+
+ // First create GetArgumentRegister nodes.
+ for (unsigned argument = 0; argument < numRegisterArguments; ++argument) {
+ getArgumentRegisterNodes.append(
+ addToGraph(GetArgumentRegister, OpInfo(0),
+ OpInfo(argumentRegisterIndexForJSFunctionArgument(argument))));
+ }
+
+ // Create all the MovHint's for the GetArgumentRegister nodes created above.
+ for (unsigned i = 0; i < getArgumentRegisterNodes.size(); ++i) {
+ Node* getArgumentRegister = getArgumentRegisterNodes[i];
+ addToGraph(MovHint, OpInfo(virtualRegisterForArgument(i).offset()), getArgumentRegister);
+ // We can't exit anymore.
+ m_exitOK = false;
+ }
+
+ // Exit is now okay, but we need to fence with an ExitOK node.
+ m_exitOK = true;
+ addToGraph(ExitOK);
+
+ // Create all the SetLocals's for the GetArgumentRegister nodes created above.
+ for (unsigned i = 0; i < getArgumentRegisterNodes.size(); ++i) {
+ Node* getArgumentRegister = getArgumentRegisterNodes[i];
+ VariableAccessData* variableAccessData = newVariableAccessData(virtualRegisterForArgument(i));
+ variableAccessData->mergeStructureCheckHoistingFailed(
+ m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache));
+ variableAccessData->mergeCheckArrayHoistingFailed(
+ m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIndexingType));
+ Node* setLocal = addToGraph(SetLocal, OpInfo(variableAccessData), getArgumentRegister);
+ m_currentBlock->variablesAtTail.argument(i) = setLocal;
+ getArgumentRegister->setVariableAccessData(setLocal->variableAccessData());
+ m_graph.m_argumentsOnStack[i] = setLocal;
+ m_graph.m_argumentsForChecking[i] = getArgumentRegister;
+ }
+
+ // Finally create any SetArgument nodes.
+ for (unsigned argument = NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS; argument < m_numArguments; ++argument) {
</ins><span class="cx"> VariableAccessData* variable = newVariableAccessData(
</span><span class="cx"> virtualRegisterForArgument(argument));
</span><span class="cx"> variable->mergeStructureCheckHoistingFailed(
</span><span class="lines">@@ -3710,7 +3758,8 @@
</span><span class="cx"> m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIndexingType));
</span><span class="cx">
</span><span class="cx"> Node* setArgument = addToGraph(SetArgument, OpInfo(variable));
</span><del>- m_graph.m_arguments[argument] = setArgument;
</del><ins>+ m_graph.m_argumentsOnStack[argument] = setArgument;
+ m_graph.m_argumentsForChecking[argument] = setArgument;
</ins><span class="cx"> m_currentBlock->variablesAtTail.setArgumentFirstTime(argument, setArgument);
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="lines">@@ -4820,8 +4869,10 @@
</span><span class="cx"> // We need to make sure that we don't unbox our arguments here since that won't be
</span><span class="cx"> // done by the arguments object creation node as that node may not exist.
</span><span class="cx"> noticeArgumentsUse();
</span><ins>+ Terminality terminality = handleVarargsCall(currentInstruction, TailCallForwardVarargs, CallMode::Tail);
+ // We need to insert flush nodes for our arguments after the TailCallForwardVarargs
+ // node so that they will be flushed to the stack and kept alive.
</ins><span class="cx"> flushForReturn();
</span><del>- Terminality terminality = handleVarargsCall(currentInstruction, TailCallForwardVarargs, CallMode::Tail);
</del><span class="cx"> ASSERT_WITH_MESSAGE(m_currentInstruction == currentInstruction, "handleVarargsCall, which may have inlined the callee, trashed m_currentInstruction");
</span><span class="cx"> // If the call is terminal then we should not parse any further bytecodes as the TailCall will exit the function.
</span><span class="cx"> // If the call is not terminal, however, then we want the subsequent op_ret/op_jump to update metadata and clean
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGCPSRethreadingPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -299,14 +299,16 @@
</span><span class="cx"> // The rules for threaded CPS form:
</span><span class="cx"> //
</span><span class="cx"> // Head variable: describes what is live at the head of the basic block.
</span><del>- // Head variable links may refer to Flush, PhantomLocal, Phi, or SetArgument.
- // SetArgument may only appear in the root block.
</del><ins>+ // Head variable links may refer to Flush, PhantomLocal, Phi, GetArgumentRegister
+ // or SetArgument.
+ // GetArgumentRegister and SetArgument may only appear in the root block.
</ins><span class="cx"> //
</span><span class="cx"> // Tail variable: the last thing that happened to the variable in the block.
</span><del>- // It may be a Flush, PhantomLocal, GetLocal, SetLocal, SetArgument, or Phi.
- // SetArgument may only appear in the root block. Note that if there ever
- // was a GetLocal to the variable, and it was followed by PhantomLocals and
- // Flushes but not SetLocals, then the tail variable will be the GetLocal.
</del><ins>+ // It may be a Flush, PhantomLocal, GetLocal, SetLocal, GetArgumentRegister,
+ // SetArgument, or Phi. GetArgumentRegister and SetArgument may only appear
+ // in the root block. Note that if there ever was a GetLocal to the variable,
+ // and it was followed by PhantomLocals and Flushes but not SetLocals, then
+ // the tail variable will be the GetLocal.
</ins><span class="cx"> // This reflects the fact that you only care that the tail variable is a
</span><span class="cx"> // Flush or PhantomLocal if nothing else interesting happened. Likewise, if
</span><span class="cx"> // there ever was a SetLocal and it was followed by Flushes, then the tail
</span><span class="lines">@@ -367,12 +369,13 @@
</span><span class="cx">
</span><span class="cx"> void specialCaseArguments()
</span><span class="cx"> {
</span><del>- // Normally, a SetArgument denotes the start of a live range for a local's value on the stack.
- // But those SetArguments used for the actual arguments to the machine CodeBlock get
- // special-cased. We could have instead used two different node types - one for the arguments
- // at the prologue case, and another for the other uses. But this seemed like IR overkill.
- for (unsigned i = m_graph.m_arguments.size(); i--;)
- m_graph.block(0)->variablesAtHead.setArgumentFirstTime(i, m_graph.m_arguments[i]);
</del><ins>+ // Normally, a SetArgument or SetLocal denotes the start of a live range for
+ // a local's value on the stack. But those SetArguments and SetLocals used
+ // for the actual arguments to the machine CodeBlock get special-cased. We could have
+ // instead used two different node types - one for the arguments at the prologue case,
+ // and another for the other uses. But this seemed like IR overkill.
+ for (unsigned i = m_graph.m_argumentsOnStack.size(); i--;)
+ m_graph.block(0)->variablesAtHead.setArgumentFirstTime(i, m_graph.m_argumentsOnStack[i]);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<OperandKind operandKind>
</span><span class="lines">@@ -480,6 +483,7 @@
</span><span class="cx"> switch (node->op()) {
</span><span class="cx"> case SetLocal:
</span><span class="cx"> case SetArgument:
</span><ins>+ case GetArgumentRegister:
</ins><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case Flush:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGClobberizeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGClobberize.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -406,6 +406,7 @@
</span><span class="cx"> case Phi:
</span><span class="cx"> case PhantomLocal:
</span><span class="cx"> case SetArgument:
</span><ins>+ case GetArgumentRegister:
</ins><span class="cx"> case Jump:
</span><span class="cx"> case Branch:
</span><span class="cx"> case Switch:
</span><span class="lines">@@ -470,7 +471,7 @@
</span><span class="cx"> case PhantomClonedArguments:
</span><span class="cx"> // DFG backend requires that the locals that this reads are flushed. FTL backend can handle those
</span><span class="cx"> // locals being promoted.
</span><del>- if (!isFTL(graph.m_plan.mode))
</del><ins>+ if (!isFTL(graph.m_plan.mode) && !node->origin.semantic.inlineCallFrame)
</ins><span class="cx"> read(Stack);
</span><span class="cx">
</span><span class="cx"> // Even though it's phantom, it still has the property that one can't be replaced with another.
</span><span class="lines">@@ -559,11 +560,18 @@
</span><span class="cx"> case TailCall:
</span><span class="cx"> case DirectTailCall:
</span><span class="cx"> case TailCallVarargs:
</span><ins>+ read(World);
+ write(SideState);
+ return;
+
</ins><span class="cx"> case TailCallForwardVarargs:
</span><ins>+ // We read all arguments after "this".
+ for (unsigned arg = 1; arg < graph.m_argumentsOnStack.size(); arg++)
+ read(AbstractHeap(Stack, virtualRegisterForArgument(arg)));
</ins><span class="cx"> read(World);
</span><span class="cx"> write(SideState);
</span><span class="cx"> return;
</span><del>-
</del><ins>+
</ins><span class="cx"> case GetGetter:
</span><span class="cx"> read(GetterSetter_getter);
</span><span class="cx"> def(HeapLocation(GetterLoc, GetterSetter_getter, node->child1()), LazyNode(node));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGCommonh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGCommon.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGCommon.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGCommon.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -152,6 +152,8 @@
</span><span class="cx">
</span><span class="cx"> enum OptimizationFixpointState { BeforeFixpoint, FixpointNotConverged, FixpointConverged };
</span><span class="cx">
</span><ins>+enum StrengthReduceArgumentFlushes { DontOptimizeArgumentFlushes, OptimizeArgumentFlushes };
+
</ins><span class="cx"> // Describes the form you can expect the entire graph to be in.
</span><span class="cx"> enum GraphForm {
</span><span class="cx"> // LoadStore form means that basic blocks may freely use GetLocal, SetLocal,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGDCEPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGDCEPhase.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGDCEPhase.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGDCEPhase.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -53,7 +53,8 @@
</span><span class="cx"> for (BasicBlock* block : m_graph.blocksInPreOrder())
</span><span class="cx"> fixupBlock(block);
</span><span class="cx">
</span><del>- cleanVariables(m_graph.m_arguments);
</del><ins>+ cleanVariables(m_graph.m_argumentsOnStack);
+ cleanVariables(m_graph.m_argumentsForChecking);
</ins><span class="cx">
</span><span class="cx"> // Just do a basic Phantom/Check clean-up.
</span><span class="cx"> for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGDoesGCcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -261,6 +261,7 @@
</span><span class="cx"> case GetStack:
</span><span class="cx"> case GetFromArguments:
</span><span class="cx"> case PutToArguments:
</span><ins>+ case GetArgumentRegister:
</ins><span class="cx"> case GetArgument:
</span><span class="cx"> case LogShadowChickenPrologue:
</span><span class="cx"> case LogShadowChickenTail:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGDrivercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGDriver.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGDriver.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGDriver.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -90,8 +90,9 @@
</span><span class="cx"> // make sure that all JIT code generation does finalization on the main thread.
</span><span class="cx"> vm.getCTIStub(osrExitGenerationThunkGenerator);
</span><span class="cx"> vm.getCTIStub(throwExceptionFromCallSlowPathGenerator);
</span><del>- vm.getCTIStub(linkCallThunkGenerator);
- vm.getCTIStub(linkPolymorphicCallThunkGenerator);
</del><ins>+ vm.getJITCallThunkEntryStub(linkCallThunkGenerator);
+ vm.getJITCallThunkEntryStub(linkDirectCallThunkGenerator);
+ vm.getJITCallThunkEntryStub(linkPolymorphicCallThunkGenerator);
</ins><span class="cx">
</span><span class="cx"> if (vm.typeProfiler())
</span><span class="cx"> vm.typeProfilerLog()->processLogEntries(ASCIILiteral("Preparing for DFG compilation."));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -1791,6 +1791,7 @@
</span><span class="cx"> case DoubleConstant:
</span><span class="cx"> case GetLocal:
</span><span class="cx"> case GetCallee:
</span><ins>+ case GetArgumentRegister:
</ins><span class="cx"> case GetArgumentCountIncludingThis:
</span><span class="cx"> case GetRestLength:
</span><span class="cx"> case GetArgument:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGenerationInfoh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGenerationInfo.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGenerationInfo.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGGenerationInfo.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -104,6 +104,19 @@
</span><span class="cx"> ASSERT(format & DataFormatJS);
</span><span class="cx"> initGPR(node, useCount, gpr, format);
</span><span class="cx"> }
</span><ins>+
+ void initArgumentRegisterValue(Node* node, uint32_t useCount, GPRReg gpr, DataFormat registerFormat = DataFormatJS)
+ {
+ m_node = node;
+ m_useCount = useCount;
+ m_registerFormat = registerFormat;
+ m_spillFormat = DataFormatNone;
+ m_canFill = false;
+ u.gpr = gpr;
+ m_bornForOSR = false;
+ m_isConstant = false;
+ ASSERT(m_useCount);
+ }
</ins><span class="cx"> #elif USE(JSVALUE32_64)
</span><span class="cx"> void initJSValue(Node* node, uint32_t useCount, GPRReg tagGPR, GPRReg payloadGPR, DataFormat format = DataFormatJS)
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -294,7 +294,6 @@
</span><span class="cx"> for (unsigned i = 0; i < data.variants.size(); ++i)
</span><span class="cx"> out.print(comma, inContext(data.variants[i], context));
</span><span class="cx"> }
</span><del>- ASSERT(node->hasVariableAccessData(*this) == node->accessesStack(*this));
</del><span class="cx"> if (node->hasVariableAccessData(*this)) {
</span><span class="cx"> VariableAccessData* variableAccessData = node->tryGetVariableAccessData();
</span><span class="cx"> if (variableAccessData) {
</span><span class="lines">@@ -373,6 +372,8 @@
</span><span class="cx"> out.print(comma, inContext(data->cases[i].value, context), ":", data->cases[i].target);
</span><span class="cx"> out.print(comma, "default:", data->fallThrough);
</span><span class="cx"> }
</span><ins>+ if (node->hasArgumentRegisterIndex())
+ out.print(comma, node->argumentRegisterIndex(), "(", GPRInfo::toArgumentRegister(node->argumentRegisterIndex()), ")");
</ins><span class="cx"> ClobberSet reads;
</span><span class="cx"> ClobberSet writes;
</span><span class="cx"> addReadsAndWrites(*this, node, reads, writes);
</span><span class="lines">@@ -396,7 +397,7 @@
</span><span class="cx"> out.print(comma, "WasHoisted");
</span><span class="cx"> out.print(")");
</span><span class="cx">
</span><del>- if (node->accessesStack(*this) && node->tryGetVariableAccessData())
</del><ins>+ if ((node->accessesStack(*this) || node->op() == GetArgumentRegister) && node->tryGetVariableAccessData())
</ins><span class="cx"> out.print(" predicting ", SpeculationDump(node->tryGetVariableAccessData()->prediction()));
</span><span class="cx"> else if (node->hasHeapPrediction())
</span><span class="cx"> out.print(" predicting ", SpeculationDump(node->getHeapPrediction()));
</span><span class="lines">@@ -506,8 +507,10 @@
</span><span class="cx"> out.print(" Fixpoint state: ", m_fixpointState, "; Form: ", m_form, "; Unification state: ", m_unificationState, "; Ref count state: ", m_refCountState, "\n");
</span><span class="cx"> if (m_form == SSA)
</span><span class="cx"> out.print(" Argument formats: ", listDump(m_argumentFormats), "\n");
</span><del>- else
- out.print(" Arguments: ", listDump(m_arguments), "\n");
</del><ins>+ else {
+ out.print(" Arguments for checking: ", listDump(m_argumentsForChecking), "\n");
+ out.print(" Arguments on stack: ", listDump(m_argumentsOnStack), "\n");
+ }
</ins><span class="cx"> out.print("\n");
</span><span class="cx">
</span><span class="cx"> Node* lastNode = nullptr;
</span><span class="lines">@@ -1620,13 +1623,13 @@
</span><span class="cx"> if (!currentNode || node->origin != currentNode->origin) {
</span><span class="cx"> CodeBlock* profiledBlock = baselineCodeBlockFor(node->origin.semantic);
</span><span class="cx">
</span><del>- if (node->accessesStack(*this)) {
</del><ins>+ if (node->accessesStack(*this) || node->op() == GetArgumentRegister) {
</ins><span class="cx"> ValueProfile* result = [&] () -> ValueProfile* {
</span><span class="cx"> if (!node->local().isArgument())
</span><span class="cx"> return nullptr;
</span><span class="cx"> int argument = node->local().toArgument();
</span><del>- Node* argumentNode = m_arguments[argument];
- if (!argumentNode)
</del><ins>+ Node* argumentNode = m_argumentsOnStack[argument];
+ if (!argumentNode || !argumentNode->accessesStack(*this))
</ins><span class="cx"> return nullptr;
</span><span class="cx"> if (node->variableAccessData() != argumentNode->variableAccessData())
</span><span class="cx"> return nullptr;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraph.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraph.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraph.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -859,7 +859,7 @@
</span><span class="cx"> bool willCatchExceptionInMachineFrame(CodeOrigin, CodeOrigin& opCatchOriginOut, HandlerInfo*& catchHandlerOut);
</span><span class="cx">
</span><span class="cx"> bool needsScopeRegister() const { return m_hasDebuggerEnabled || m_codeBlock->usesEval(); }
</span><del>- bool needsFlushedThis() const { return m_codeBlock->usesEval(); }
</del><ins>+ bool needsFlushedThis() const { return m_hasDebuggerEnabled || m_codeBlock->usesEval(); }
</ins><span class="cx">
</span><span class="cx"> VM& m_vm;
</span><span class="cx"> Plan& m_plan;
</span><span class="lines">@@ -878,9 +878,9 @@
</span><span class="cx">
</span><span class="cx"> Bag<StorageAccessData> m_storageAccessData;
</span><span class="cx">
</span><del>- // In CPS, this is all of the SetArgument nodes for the arguments in the machine code block
- // that survived DCE. All of them except maybe "this" will survive DCE, because of the Flush
- // nodes.
</del><ins>+ // In CPS, this is all of the GetArgumentRegister and SetArgument nodes for the arguments in
+ // the machine code block that survived DCE. All of them except maybe "this" will survive DCE,
+ // because of the Flush nodes.
</ins><span class="cx"> //
</span><span class="cx"> // In SSA, this is all of the GetStack nodes for the arguments in the machine code block that
</span><span class="cx"> // may have some speculation in the prologue and survived DCE. Note that to get the speculation
</span><span class="lines">@@ -903,7 +903,8 @@
</span><span class="cx"> //
</span><span class="cx"> // If we DCE the ArithAdd and we remove the int check on x, then this won't do the side
</span><span class="cx"> // effects.
</span><del>- Vector<Node*, 8> m_arguments;
</del><ins>+ Vector<Node*, 8> m_argumentsOnStack;
+ Vector<Node*, 8> m_argumentsForChecking;
</ins><span class="cx">
</span><span class="cx"> // In CPS, this is meaningless. In SSA, this is the argument speculation that we've locked in.
</span><span class="cx"> Vector<FlushFormat> m_argumentFormats;
</span><span class="lines">@@ -954,6 +955,7 @@
</span><span class="cx"> GraphForm m_form;
</span><span class="cx"> UnificationState m_unificationState;
</span><span class="cx"> PlanStage m_planStage { PlanStage::Initial };
</span><ins>+ StrengthReduceArgumentFlushes m_strengthReduceArguments = { StrengthReduceArgumentFlushes::DontOptimizeArgumentFlushes };
</ins><span class="cx"> RefCountState m_refCountState;
</span><span class="cx"> bool m_hasDebuggerEnabled;
</span><span class="cx"> bool m_hasExceptionHandlers { false };
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGInPlaceAbstractStatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -106,11 +106,11 @@
</span><span class="cx"> if (m_graph.m_form == SSA)
</span><span class="cx"> format = m_graph.m_argumentFormats[i];
</span><span class="cx"> else {
</span><del>- Node* node = m_graph.m_arguments[i];
</del><ins>+ Node* node = m_graph.m_argumentsOnStack[i];
</ins><span class="cx"> if (!node)
</span><span class="cx"> format = FlushedJSValue;
</span><span class="cx"> else {
</span><del>- ASSERT(node->op() == SetArgument);
</del><ins>+ ASSERT(node->op() == SetArgument || node->op() == SetLocal);
</ins><span class="cx"> format = node->variableAccessData()->flushFormat();
</span><span class="cx"> }
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGJITCompilercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -99,18 +99,6 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>-void JITCompiler::compileEntry()
-{
- // This code currently matches the old JIT. In the function header we need to
- // save return address and call frame via the prologue and perform a fast stack check.
- // FIXME: https://bugs.webkit.org/show_bug.cgi?id=56292
- // We'll need to convert the remaining cti_ style calls (specifically the stack
- // check) which will be dependent on stack layout. (We'd need to account for this in
- // both normal return code and when jumping to an exception handler).
- emitFunctionPrologue();
- emitPutToCallFrameHeader(m_codeBlock, CallFrameSlot::codeBlock);
-}
-
</del><span class="cx"> void JITCompiler::compileSetupRegistersForEntry()
</span><span class="cx"> {
</span><span class="cx"> emitSaveCalleeSaves();
</span><span class="lines">@@ -277,7 +265,7 @@
</span><span class="cx"> for (unsigned i = 0; i < m_jsCalls.size(); ++i) {
</span><span class="cx"> JSCallRecord& record = m_jsCalls[i];
</span><span class="cx"> CallLinkInfo& info = *record.info;
</span><del>- linkBuffer.link(record.slowCall, FunctionPtr(m_vm->getCTIStub(linkCallThunkGenerator).code().executableAddress()));
</del><ins>+ linkBuffer.link(record.slowCall, FunctionPtr(m_vm->getJITCallThunkEntryStub(linkCallThunkGenerator).entryFor(info.argumentsLocation()).executableAddress()));
</ins><span class="cx"> info.setCallLocations(
</span><span class="cx"> CodeLocationLabel(linkBuffer.locationOfNearCall(record.slowCall)),
</span><span class="cx"> CodeLocationLabel(linkBuffer.locationOf(record.targetToCheck)),
</span><span class="lines">@@ -287,6 +275,8 @@
</span><span class="cx"> for (JSDirectCallRecord& record : m_jsDirectCalls) {
</span><span class="cx"> CallLinkInfo& info = *record.info;
</span><span class="cx"> linkBuffer.link(record.call, linkBuffer.locationOf(record.slowPath));
</span><ins>+ if (record.hasSlowCall())
+ linkBuffer.link(record.slowCall, FunctionPtr(m_vm->getJITCallThunkEntryStub(linkDirectCallThunkGenerator).entryFor(info.argumentsLocation()).executableAddress()));
</ins><span class="cx"> info.setCallLocations(
</span><span class="cx"> CodeLocationLabel(),
</span><span class="cx"> linkBuffer.locationOf(record.slowPath),
</span><span class="lines">@@ -354,8 +344,14 @@
</span><span class="cx">
</span><span class="cx"> void JITCompiler::compile()
</span><span class="cx"> {
</span><ins>+ Label mainEntry(this);
+
</ins><span class="cx"> setStartOfCode();
</span><del>- compileEntry();
</del><ins>+ emitFunctionPrologue();
+
+ Label entryPoint(this);
+ emitPutToCallFrameHeader(m_codeBlock, CallFrameSlot::codeBlock);
+
</ins><span class="cx"> m_speculative = std::make_unique<SpeculativeJIT>(*this);
</span><span class="cx">
</span><span class="cx"> // Plant a check that sufficient space is available in the JSStack.
</span><span class="lines">@@ -382,6 +378,20 @@
</span><span class="cx">
</span><span class="cx"> m_speculative->callOperationWithCallFrameRollbackOnException(operationThrowStackOverflowError, m_codeBlock);
</span><span class="cx">
</span><ins>+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ m_stackArgsArityOKEntry = label();
+ emitFunctionPrologue();
+
+ // Load argument values into argument registers
+ loadPtr(addressFor(CallFrameSlot::callee), argumentRegisterForCallee());
+ load32(payloadFor(CallFrameSlot::argumentCount), argumentRegisterForArgumentCount());
+
+ for (unsigned argIndex = 0; argIndex < static_cast<unsigned>(m_codeBlock->numParameters()) && argIndex < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS; argIndex++)
+ load64(Address(GPRInfo::callFrameRegister, (CallFrameSlot::thisArgument + argIndex) * static_cast<int>(sizeof(Register))), argumentRegisterForFunctionArgument(argIndex));
+
+ jump(entryPoint);
+#endif
+
</ins><span class="cx"> // Generate slow path code.
</span><span class="cx"> m_speculative->runSlowPathGenerators(m_pcToCodeOriginMapBuilder);
</span><span class="cx"> m_pcToCodeOriginMapBuilder.appendItem(labelIgnoringWatchpoints(), PCToCodeOriginMapBuilder::defaultCodeOrigin());
</span><span class="lines">@@ -406,24 +416,87 @@
</span><span class="cx"> codeBlock()->shrinkToFit(CodeBlock::LateShrink);
</span><span class="cx">
</span><span class="cx"> disassemble(*linkBuffer);
</span><del>-
</del><ins>+
+ JITEntryPoints entrypoints;
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ entrypoints.setEntryFor(RegisterArgsArityCheckNotRequired, linkBuffer->locationOf(mainEntry));
+ entrypoints.setEntryFor(StackArgsArityCheckNotRequired, linkBuffer->locationOf(m_stackArgsArityOKEntry));
+#else
+ entrypoints.setEntryFor(StackArgsArityCheckNotRequired, linkBuffer->locationOf(mainEntry));
+#endif
+
</ins><span class="cx"> m_graph.m_plan.finalizer = std::make_unique<JITFinalizer>(
</span><del>- m_graph.m_plan, WTFMove(m_jitCode), WTFMove(linkBuffer));
</del><ins>+ m_graph.m_plan, WTFMove(m_jitCode), WTFMove(linkBuffer), entrypoints);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void JITCompiler::compileFunction()
</span><span class="cx"> {
</span><span class="cx"> setStartOfCode();
</span><del>- compileEntry();
</del><span class="cx">
</span><ins>+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ unsigned numParameters = static_cast<unsigned>(m_codeBlock->numParameters());
+ GPRReg argCountReg = argumentRegisterForArgumentCount();
+ JumpList continueRegisterEntry;
+ Label registerArgumentsEntrypoints[NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS + 1];
+
+ if (numParameters < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS) {
+ // Spill any extra register arguments passed to function onto the stack.
+ for (unsigned extraRegisterArgumentIndex = NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS - 1;
+ extraRegisterArgumentIndex >= numParameters; extraRegisterArgumentIndex--) {
+ registerArgumentsEntrypoints[extraRegisterArgumentIndex + 1] = label();
+ emitPutArgumentToCallFrameBeforePrologue(argumentRegisterForFunctionArgument(extraRegisterArgumentIndex), extraRegisterArgumentIndex);
+ }
+ }
+ incrementCounter(this, VM::RegArgsExtra);
+
+ continueRegisterEntry.append(jump());
+
+ m_registerArgsWithArityCheck = label();
+ incrementCounter(this, VM::RegArgsArity);
+
+ Label registerArgsCheckArity(this);
+
+ Jump registerCheckArity;
+
+ if (numParameters < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS)
+ registerCheckArity = branch32(NotEqual, argCountReg, TrustedImm32(numParameters));
+ else {
+ registerCheckArity = branch32(Below, argCountReg, TrustedImm32(numParameters));
+ m_registerArgsWithPossibleExtraArgs = label();
+ }
+
+ Label registerEntryNoArity(this);
+
+ if (numParameters <= NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS)
+ registerArgumentsEntrypoints[numParameters] = registerEntryNoArity;
+
+ incrementCounter(this, VM::RegArgsNoArity);
+
+ continueRegisterEntry.link(this);
+#endif // NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+
+ Label mainEntry(this);
+
+ emitFunctionPrologue();
+
</ins><span class="cx"> // === Function header code generation ===
</span><span class="cx"> // This is the main entry point, without performing an arity check.
</span><span class="cx"> // If we needed to perform an arity check we will already have moved the return address,
</span><span class="cx"> // so enter after this.
</span><span class="cx"> Label fromArityCheck(this);
</span><ins>+
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ storePtr(argumentRegisterForCallee(), addressFor(CallFrameSlot::callee));
+ store32(argCountReg, payloadFor(CallFrameSlot::argumentCount));
+
+ Label fromStackEntry(this);
+#endif
+
+ emitPutToCallFrameHeader(m_codeBlock, CallFrameSlot::codeBlock);
+
</ins><span class="cx"> // Plant a check that sufficient space is available in the JSStack.
</span><del>- addPtr(TrustedImm32(virtualRegisterForLocal(m_graph.requiredRegisterCountForExecutionAndExit() - 1).offset() * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::regT1);
- Jump stackOverflow = branchPtr(Above, AbsoluteAddress(m_vm->addressOfSoftStackLimit()), GPRInfo::regT1);
</del><ins>+ addPtr(TrustedImm32(virtualRegisterForLocal(m_graph.requiredRegisterCountForExecutionAndExit() - 1).offset() * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::nonArgGPR0);
+ Jump stackOverflow = branchPtr(Above, AbsoluteAddress(m_vm->addressOfSoftStackLimit()), GPRInfo::nonArgGPR0);
</ins><span class="cx">
</span><span class="cx"> // Move the stack pointer down to accommodate locals
</span><span class="cx"> addPtr(TrustedImm32(m_graph.stackPointerOffset() * sizeof(Register)), GPRInfo::callFrameRegister, stackPointerRegister);
</span><span class="lines">@@ -452,17 +525,73 @@
</span><span class="cx"> addPtr(TrustedImm32(-maxFrameExtentForSlowPathCall), stackPointerRegister);
</span><span class="cx">
</span><span class="cx"> m_speculative->callOperationWithCallFrameRollbackOnException(operationThrowStackOverflowError, m_codeBlock);
</span><ins>+
+ JumpList arityOK;
</ins><span class="cx">
</span><del>- // The fast entry point into a function does not check the correct number of arguments
- // have been passed to the call (we only use the fast entry point where we can statically
- // determine the correct number of arguments have been passed, or have already checked).
- // In cases where an arity check is necessary, we enter here.
- // FIXME: change this from a cti call to a DFG style operation (normal C calling conventions).
- m_arityCheck = label();
- compileEntry();
</del><ins>+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ jump(registerArgsCheckArity);
</ins><span class="cx">
</span><ins>+ JumpList registerArityNeedsFixup;
+ if (numParameters < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS) {
+ registerCheckArity.link(this);
+ registerArityNeedsFixup.append(branch32(Below, argCountReg, TrustedImm32(m_codeBlock->numParameters())));
+
+ // We have extra register arguments.
+
+ // The fast entry point into a function does not check that the correct number of arguments
+ // have been passed to the call (we only use the fast entry point where we can statically
+ // determine the correct number of arguments have been passed, or have already checked).
+ // In cases where an arity check is necessary, we enter here.
+ m_registerArgsWithPossibleExtraArgs = label();
+
+ incrementCounter(this, VM::RegArgsExtra);
+
+ // Spill extra args passed to function
+ for (unsigned argIndex = static_cast<unsigned>(m_codeBlock->numParameters()); argIndex < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS; argIndex++) {
+ branch32(MacroAssembler::BelowOrEqual, argCountReg, MacroAssembler::TrustedImm32(argIndex)).linkTo(mainEntry, this);
+ emitPutArgumentToCallFrameBeforePrologue(argumentRegisterForFunctionArgument(argIndex), argIndex);
+ }
+ jump(mainEntry);
+ }
+
+ // Fall through
+ if (numParameters > 0) {
+ // There should always be a "this" parameter.
+ unsigned registerArgumentFixupCount = std::min(numParameters - 1, NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS);
+ Label registerArgumentsNeedArityFixup = label();
+
+ for (unsigned argIndex = 1; argIndex <= registerArgumentFixupCount; argIndex++)
+ registerArgumentsEntrypoints[argIndex] = registerArgumentsNeedArityFixup;
+ }
+
+ incrementCounter(this, VM::RegArgsArity);
+
+ registerArityNeedsFixup.link(this);
+
+ if (numParameters >= NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS)
+ registerCheckArity.link(this);
+
+ spillArgumentRegistersToFrameBeforePrologue();
+
+#if ENABLE(VM_COUNTERS)
+ Jump continueToStackArityFixup = jump();
+#endif
+#endif // NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+
+ m_stackArgsWithArityCheck = label();
+ incrementCounter(this, VM::StackArgsArity);
+
+#if ENABLE(VM_COUNTERS)
+ continueToStackArityFixup.link(this);
+#endif
+
+ emitFunctionPrologue();
+
</ins><span class="cx"> load32(AssemblyHelpers::payloadFor((VirtualRegister)CallFrameSlot::argumentCount), GPRInfo::regT1);
</span><del>- branch32(AboveOrEqual, GPRInfo::regT1, TrustedImm32(m_codeBlock->numParameters())).linkTo(fromArityCheck, this);
</del><ins>+ arityOK.append(branch32(AboveOrEqual, GPRInfo::regT1, TrustedImm32(m_codeBlock->numParameters())));
+
+ incrementCounter(this, VM::ArityFixupRequired);
+
</ins><span class="cx"> emitStoreCodeOrigin(CodeOrigin(0));
</span><span class="cx"> if (maxFrameExtentForSlowPathCall)
</span><span class="cx"> addPtr(TrustedImm32(-maxFrameExtentForSlowPathCall), stackPointerRegister);
</span><span class="lines">@@ -469,11 +598,32 @@
</span><span class="cx"> m_speculative->callOperationWithCallFrameRollbackOnException(m_codeBlock->m_isConstructor ? operationConstructArityCheck : operationCallArityCheck, GPRInfo::regT0);
</span><span class="cx"> if (maxFrameExtentForSlowPathCall)
</span><span class="cx"> addPtr(TrustedImm32(maxFrameExtentForSlowPathCall), stackPointerRegister);
</span><del>- branchTest32(Zero, GPRInfo::returnValueGPR).linkTo(fromArityCheck, this);
</del><ins>+ arityOK.append(branchTest32(Zero, GPRInfo::returnValueGPR));
+
</ins><span class="cx"> emitStoreCodeOrigin(CodeOrigin(0));
</span><span class="cx"> move(GPRInfo::returnValueGPR, GPRInfo::argumentGPR0);
</span><span class="cx"> m_callArityFixup = call();
</span><ins>+
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ Jump toFillRegisters = jump();
+
+ m_stackArgsArityOKEntry = label();
+
+ incrementCounter(this, VM::StackArgsNoArity);
+ emitFunctionPrologue();
+
+ arityOK.link(this);
+ toFillRegisters.link(this);
+
+ // Load argument values into argument registers
+ for (unsigned argIndex = 0; argIndex < static_cast<unsigned>(m_codeBlock->numParameters()) && argIndex < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS; argIndex++)
+ load64(Address(GPRInfo::callFrameRegister, (CallFrameSlot::thisArgument + argIndex) * static_cast<int>(sizeof(Register))), argumentRegisterForFunctionArgument(argIndex));
+
+ jump(fromStackEntry);
+#else
+ arityOK.linkTo(fromArityCheck, this);
</ins><span class="cx"> jump(fromArityCheck);
</span><ins>+#endif
</ins><span class="cx">
</span><span class="cx"> // Generate slow path code.
</span><span class="cx"> m_speculative->runSlowPathGenerators(m_pcToCodeOriginMapBuilder);
</span><span class="lines">@@ -502,10 +652,35 @@
</span><span class="cx">
</span><span class="cx"> disassemble(*linkBuffer);
</span><span class="cx">
</span><del>- MacroAssemblerCodePtr withArityCheck = linkBuffer->locationOf(m_arityCheck);
</del><ins>+ JITEntryPoints entrypoints;
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+#if ENABLE(VM_COUNTERS)
+ MacroAssemblerCodePtr mainEntryCodePtr = linkBuffer->locationOf(registerEntryNoArity);
+#else
+ MacroAssemblerCodePtr mainEntryCodePtr = linkBuffer->locationOf(mainEntry);
+#endif
+ entrypoints.setEntryFor(RegisterArgsArityCheckNotRequired, mainEntryCodePtr);
+ entrypoints.setEntryFor(RegisterArgsPossibleExtraArgs, linkBuffer->locationOf(m_registerArgsWithPossibleExtraArgs));
+ entrypoints.setEntryFor(RegisterArgsMustCheckArity, linkBuffer->locationOf(m_registerArgsWithArityCheck));
</ins><span class="cx">
</span><ins>+ for (unsigned argCount = 1; argCount <= NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS; argCount++) {
+ MacroAssemblerCodePtr entry;
+ if (argCount == numParameters)
+ entry = mainEntryCodePtr;
+ else if (registerArgumentsEntrypoints[argCount].isSet())
+ entry = linkBuffer->locationOf(registerArgumentsEntrypoints[argCount]);
+ else
+ entry = linkBuffer->locationOf(m_registerArgsWithArityCheck);
+ entrypoints.setEntryFor(JITEntryPoints::registerEntryTypeForArgumentCount(argCount), entry);
+ }
+ entrypoints.setEntryFor(StackArgsArityCheckNotRequired, linkBuffer->locationOf(m_stackArgsArityOKEntry));
+#else
+ entrypoints.setEntryFor(StackArgsArityCheckNotRequired, linkBuffer->locationOf(mainEntry));
+#endif
+ entrypoints.setEntryFor(StackArgsMustCheckArity, linkBuffer->locationOf(m_stackArgsWithArityCheck));
+
</ins><span class="cx"> m_graph.m_plan.finalizer = std::make_unique<JITFinalizer>(
</span><del>- m_graph.m_plan, WTFMove(m_jitCode), WTFMove(linkBuffer), withArityCheck);
</del><ins>+ m_graph.m_plan, WTFMove(m_jitCode), WTFMove(linkBuffer), entrypoints);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void JITCompiler::disassemble(LinkBuffer& linkBuffer)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGJITCompilerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -217,6 +217,11 @@
</span><span class="cx"> m_jsDirectCalls.append(JSDirectCallRecord(call, slowPath, info));
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ void addJSDirectCall(Call call, Call slowCall, Label slowPath, CallLinkInfo* info)
+ {
+ m_jsDirectCalls.append(JSDirectCallRecord(call, slowCall, slowPath, info));
+ }
+
</ins><span class="cx"> void addJSDirectTailCall(PatchableJump patchableJump, Call call, Label slowPath, CallLinkInfo* info)
</span><span class="cx"> {
</span><span class="cx"> m_jsDirectTailCalls.append(JSDirectTailCallRecord(patchableJump, call, slowPath, info));
</span><span class="lines">@@ -267,7 +272,6 @@
</span><span class="cx"> friend class OSRExitJumpPlaceholder;
</span><span class="cx">
</span><span class="cx"> // Internal implementation to compile.
</span><del>- void compileEntry();
</del><span class="cx"> void compileSetupRegistersForEntry();
</span><span class="cx"> void compileEntryExecutionFlag();
</span><span class="cx"> void compileBody();
</span><span class="lines">@@ -318,7 +322,18 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ JSDirectCallRecord(Call call, Call slowCall, Label slowPath, CallLinkInfo* info)
+ : call(call)
+ , slowCall(slowCall)
+ , slowPath(slowPath)
+ , info(info)
+ {
+ }
+
+ bool hasSlowCall() { return slowCall.m_label.isSet(); }
+
</ins><span class="cx"> Call call;
</span><ins>+ Call slowCall;
</ins><span class="cx"> Label slowPath;
</span><span class="cx"> CallLinkInfo* info;
</span><span class="cx"> };
</span><span class="lines">@@ -355,7 +370,12 @@
</span><span class="cx"> Vector<ExceptionHandlingOSRExitInfo> m_exceptionHandlerOSRExitCallSites;
</span><span class="cx">
</span><span class="cx"> Call m_callArityFixup;
</span><del>- Label m_arityCheck;
</del><ins>+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ Label m_registerArgsWithPossibleExtraArgs;
+ Label m_registerArgsWithArityCheck;
+ Label m_stackArgsArityOKEntry;
+#endif
+ Label m_stackArgsWithArityCheck;
</ins><span class="cx"> std::unique_ptr<SpeculativeJIT> m_speculative;
</span><span class="cx"> PCToCodeOriginMapBuilder m_pcToCodeOriginMapBuilder;
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGJITFinalizercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGJITFinalizer.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGJITFinalizer.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGJITFinalizer.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -37,11 +37,12 @@
</span><span class="cx">
</span><span class="cx"> namespace JSC { namespace DFG {
</span><span class="cx">
</span><del>-JITFinalizer::JITFinalizer(Plan& plan, PassRefPtr<JITCode> jitCode, std::unique_ptr<LinkBuffer> linkBuffer, MacroAssemblerCodePtr withArityCheck)
</del><ins>+JITFinalizer::JITFinalizer(Plan& plan, PassRefPtr<JITCode> jitCode,
+ std::unique_ptr<LinkBuffer> linkBuffer, JITEntryPoints& entrypoints)
</ins><span class="cx"> : Finalizer(plan)
</span><span class="cx"> , m_jitCode(jitCode)
</span><span class="cx"> , m_linkBuffer(WTFMove(linkBuffer))
</span><del>- , m_withArityCheck(withArityCheck)
</del><ins>+ , m_entrypoints(entrypoints)
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -56,9 +57,8 @@
</span><span class="cx">
</span><span class="cx"> bool JITFinalizer::finalize()
</span><span class="cx"> {
</span><del>- m_jitCode->initializeCodeRef(
- FINALIZE_DFG_CODE(*m_linkBuffer, ("DFG JIT code for %s", toCString(CodeBlockWithJITType(m_plan.codeBlock, JITCode::DFGJIT)).data())),
- MacroAssemblerCodePtr());
</del><ins>+ MacroAssemblerCodeRef codeRef = FINALIZE_DFG_CODE(*m_linkBuffer, ("DFG JIT code for %s", toCString(CodeBlockWithJITType(m_plan.codeBlock, JITCode::DFGJIT)).data()));
+ m_jitCode->initializeEntryPoints(JITEntryPointsWithRef(codeRef, m_entrypoints));
</ins><span class="cx">
</span><span class="cx"> m_plan.codeBlock->setJITCode(m_jitCode);
</span><span class="cx">
</span><span class="lines">@@ -69,10 +69,11 @@
</span><span class="cx">
</span><span class="cx"> bool JITFinalizer::finalizeFunction()
</span><span class="cx"> {
</span><del>- RELEASE_ASSERT(!m_withArityCheck.isEmptyValue());
- m_jitCode->initializeCodeRef(
- FINALIZE_DFG_CODE(*m_linkBuffer, ("DFG JIT code for %s", toCString(CodeBlockWithJITType(m_plan.codeBlock, JITCode::DFGJIT)).data())),
- m_withArityCheck);
</del><ins>+ RELEASE_ASSERT(!m_entrypoints.entryFor(StackArgsMustCheckArity).isEmptyValue());
+ MacroAssemblerCodeRef codeRef = FINALIZE_DFG_CODE(*m_linkBuffer, ("DFG JIT code for %s", toCString(CodeBlockWithJITType(m_plan.codeBlock, JITCode::DFGJIT)).data()));
+
+ m_jitCode->initializeEntryPoints(JITEntryPointsWithRef(codeRef, m_entrypoints));
+
</ins><span class="cx"> m_plan.codeBlock->setJITCode(m_jitCode);
</span><span class="cx">
</span><span class="cx"> finalizeCommon();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGJITFinalizerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGJITFinalizer.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGJITFinalizer.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGJITFinalizer.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -36,7 +36,7 @@
</span><span class="cx">
</span><span class="cx"> class JITFinalizer : public Finalizer {
</span><span class="cx"> public:
</span><del>- JITFinalizer(Plan&, PassRefPtr<JITCode>, std::unique_ptr<LinkBuffer>, MacroAssemblerCodePtr withArityCheck = MacroAssemblerCodePtr(MacroAssemblerCodePtr::EmptyValue));
</del><ins>+ JITFinalizer(Plan&, PassRefPtr<JITCode>, std::unique_ptr<LinkBuffer>, JITEntryPoints&);
</ins><span class="cx"> virtual ~JITFinalizer();
</span><span class="cx">
</span><span class="cx"> size_t codeSize() override;
</span><span class="lines">@@ -48,7 +48,7 @@
</span><span class="cx">
</span><span class="cx"> RefPtr<JITCode> m_jitCode;
</span><span class="cx"> std::unique_ptr<LinkBuffer> m_linkBuffer;
</span><del>- MacroAssemblerCodePtr m_withArityCheck;
</del><ins>+ JITEntryPoints m_entrypoints;
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> } } // namespace JSC::DFG
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGLiveCatchVariablePreservationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGLiveCatchVariablePreservationPhase.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGLiveCatchVariablePreservationPhase.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGLiveCatchVariablePreservationPhase.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -101,7 +101,7 @@
</span><span class="cx"> {
</span><span class="cx"> for (unsigned i = 0; i < block->size(); i++) {
</span><span class="cx"> Node* node = block->at(i);
</span><del>- bool isPrimordialSetArgument = node->op() == SetArgument && node->local().isArgument() && node == m_graph.m_arguments[node->local().toArgument()];
</del><ins>+ bool isPrimordialSetArgument = node->op() == SetArgument && node->local().isArgument() && node == m_graph.m_argumentsOnStack[node->local().toArgument()];
</ins><span class="cx"> InlineCallFrame* inlineCallFrame = node->origin.semantic.inlineCallFrame;
</span><span class="cx"> if (inlineCallFrame)
</span><span class="cx"> seenInlineCallFrames.add(inlineCallFrame);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGMaximalFlushInsertionPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGMaximalFlushInsertionPhase.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGMaximalFlushInsertionPhase.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGMaximalFlushInsertionPhase.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -67,8 +67,8 @@
</span><span class="cx"> {
</span><span class="cx"> for (unsigned i = 0; i < block->size(); i++) {
</span><span class="cx"> Node* node = block->at(i);
</span><del>- bool isPrimordialSetArgument = node->op() == SetArgument && node->local().isArgument() && node == m_graph.m_arguments[node->local().toArgument()];
- if (node->op() == SetLocal || (node->op() == SetArgument && !isPrimordialSetArgument)) {
</del><ins>+ if ((node->op() == SetArgument || node->op() == SetLocal)
+ && (!node->local().isArgument() || node != m_graph.m_argumentsOnStack[node->local().toArgument()])) {
</ins><span class="cx"> VirtualRegister operand = node->local();
</span><span class="cx"> VariableAccessData* flushAccessData = currentBlockAccessData.operand(operand);
</span><span class="cx"> if (!flushAccessData)
</span><span class="lines">@@ -117,7 +117,6 @@
</span><span class="cx"> if (initialAccessData.operand(operand))
</span><span class="cx"> continue;
</span><span class="cx">
</span><del>- DFG_ASSERT(m_graph, node, node->op() != SetLocal); // We should have inserted a Flush before this!
</del><span class="cx"> initialAccessData.operand(operand) = node->variableAccessData();
</span><span class="cx"> initialAccessNodes.operand(operand) = node;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGMayExitcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -72,6 +72,7 @@
</span><span class="cx"> case GetStack:
</span><span class="cx"> case GetCallee:
</span><span class="cx"> case GetArgumentCountIncludingThis:
</span><ins>+ case GetArgumentRegister:
</ins><span class="cx"> case GetRestLength:
</span><span class="cx"> case GetScope:
</span><span class="cx"> case PhantomLocal:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGMinifiedNodecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGMinifiedNode.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGMinifiedNode.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGMinifiedNode.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2012-2016 Apple Inc. All rights reserved.
</ins><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="cx"> * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -41,6 +41,8 @@
</span><span class="cx"> result.m_op = node->op();
</span><span class="cx"> if (hasConstant(node->op()))
</span><span class="cx"> result.m_info = JSValue::encode(node->asJSValue());
</span><ins>+ else if (node->op() == GetArgumentRegister)
+ result.m_info = jsFunctionArgumentForArgumentRegisterIndex(node->argumentRegisterIndex());
</ins><span class="cx"> else {
</span><span class="cx"> ASSERT(node->op() == PhantomDirectArguments || node->op() == PhantomClonedArguments);
</span><span class="cx"> result.m_info = bitwise_cast<uintptr_t>(node->origin.semantic.inlineCallFrame);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGMinifiedNodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGMinifiedNode.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGMinifiedNode.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGMinifiedNode.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2012, 2014, 2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2012, 2014-2016 Apple Inc. All rights reserved.
</ins><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="cx"> * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -43,6 +43,7 @@
</span><span class="cx"> case DoubleConstant:
</span><span class="cx"> case PhantomDirectArguments:
</span><span class="cx"> case PhantomClonedArguments:
</span><ins>+ case GetArgumentRegister:
</ins><span class="cx"> return true;
</span><span class="cx"> default:
</span><span class="cx"> return false;
</span><span class="lines">@@ -71,6 +72,10 @@
</span><span class="cx"> {
</span><span class="cx"> return bitwise_cast<InlineCallFrame*>(static_cast<uintptr_t>(m_info));
</span><span class="cx"> }
</span><ins>+
+ bool hasArgumentIndex() const { return hasArgumentIndex(m_op); }
+
+ unsigned argumentIndex() const { return static_cast<unsigned>(m_info); }
</ins><span class="cx">
</span><span class="cx"> static MinifiedID getID(MinifiedNode* node) { return node->id(); }
</span><span class="cx"> static bool compareByNodeIndex(const MinifiedNode& a, const MinifiedNode& b)
</span><span class="lines">@@ -88,6 +93,11 @@
</span><span class="cx"> {
</span><span class="cx"> return type == PhantomDirectArguments || type == PhantomClonedArguments;
</span><span class="cx"> }
</span><ins>+
+ static bool hasArgumentIndex(NodeType type)
+ {
+ return type == GetArgumentRegister;
+ }
</ins><span class="cx">
</span><span class="cx"> MinifiedID m_id;
</span><span class="cx"> uint64_t m_info;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNode.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNode.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGNode.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -71,6 +71,7 @@
</span><span class="cx"> case GetLocal:
</span><span class="cx"> case SetLocal:
</span><span class="cx"> case SetArgument:
</span><ins>+ case GetArgumentRegister:
</ins><span class="cx"> case Flush:
</span><span class="cx"> case PhantomLocal:
</span><span class="cx"> return true;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNode.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNode.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGNode.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -828,6 +828,9 @@
</span><span class="cx"> bool hasVariableAccessData(Graph&);
</span><span class="cx"> bool accessesStack(Graph& graph)
</span><span class="cx"> {
</span><ins>+ if (op() == GetArgumentRegister)
+ return false;
+
</ins><span class="cx"> return hasVariableAccessData(graph);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -846,6 +849,11 @@
</span><span class="cx"> return m_opInfo.as<VariableAccessData*>()->find();
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ void setVariableAccessData(VariableAccessData* variable)
+ {
+ m_opInfo = variable;
+ }
+
</ins><span class="cx"> VirtualRegister local()
</span><span class="cx"> {
</span><span class="cx"> return variableAccessData()->local();
</span><span class="lines">@@ -1214,6 +1222,17 @@
</span><span class="cx"> return speculationFromJSType(queriedType());
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ bool hasArgumentRegisterIndex()
+ {
+ return op() == GetArgumentRegister;
+ }
+
+ unsigned argumentRegisterIndex()
+ {
+ ASSERT(hasArgumentRegisterIndex());
+ return m_opInfo2.as<unsigned>();
+ }
+
</ins><span class="cx"> bool hasResult()
</span><span class="cx"> {
</span><span class="cx"> return !!result();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeTypeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNodeType.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -53,6 +53,7 @@
</span><span class="cx"> macro(CreateThis, NodeResultJS) /* Note this is not MustGenerate since we're returning it anyway. */ \
</span><span class="cx"> macro(GetCallee, NodeResultJS) \
</span><span class="cx"> macro(GetArgumentCountIncludingThis, NodeResultInt32) \
</span><ins>+ macro(GetArgumentRegister, NodeResultJS /* | NodeMustGenerate */) \
</ins><span class="cx"> \
</span><span class="cx"> /* Nodes for local variable access. These nodes are linked together using Phi nodes. */\
</span><span class="cx"> /* Any two nodes that are part of the same Phi graph will share the same */\
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOSRAvailabilityAnalysisPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -144,6 +144,11 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ case GetArgumentRegister: {
+ m_availability.m_locals.operand(node->local()).setNode(node);
+ break;
+ }
+
</ins><span class="cx"> case MovHint: {
</span><span class="cx"> m_availability.m_locals.operand(node->unlinkedLocal()).setNode(node->child1().node());
</span><span class="cx"> break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOSREntrypointCreationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOSREntrypointCreationPhase.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOSREntrypointCreationPhase.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGOSREntrypointCreationPhase.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -112,16 +112,32 @@
</span><span class="cx"> // type checks to here.
</span><span class="cx"> origin = target->at(0)->origin;
</span><span class="cx">
</span><del>- for (int argument = 0; argument < baseline->numParameters(); ++argument) {
</del><ins>+ for (unsigned argument = 0; argument < static_cast<unsigned>(baseline->numParameters()); ++argument) {
</ins><span class="cx"> Node* oldNode = target->variablesAtHead.argument(argument);
</span><span class="cx"> if (!oldNode) {
</span><del>- // Just for sanity, always have a SetArgument even if it's not needed.
- oldNode = m_graph.m_arguments[argument];
</del><ins>+ // Just for sanity, always have an argument node even if it's not needed.
+ oldNode = m_graph.m_argumentsForChecking[argument];
</ins><span class="cx"> }
</span><del>- Node* node = newRoot->appendNode(
- m_graph, SpecNone, SetArgument, origin,
- OpInfo(oldNode->variableAccessData()));
- m_graph.m_arguments[argument] = node;
</del><ins>+ Node* node;
+ Node* stackNode;
+ if (argument < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS) {
+ node = newRoot->appendNode(
+ m_graph, SpecNone, GetArgumentRegister, origin,
+ OpInfo(oldNode->variableAccessData()),
+ OpInfo(argumentRegisterIndexForJSFunctionArgument(argument)));
+ stackNode = newRoot->appendNode(
+ m_graph, SpecNone, SetLocal, origin,
+ OpInfo(oldNode->variableAccessData()),
+ Edge(node));
+ } else {
+ node = newRoot->appendNode(
+ m_graph, SpecNone, SetArgument, origin,
+ OpInfo(oldNode->variableAccessData()));
+ stackNode = node;
+ }
+
+ m_graph.m_argumentsForChecking[argument] = node;
+ m_graph.m_argumentsOnStack[argument] = stackNode;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> for (int local = 0; local < baseline->m_numCalleeLocals; ++local) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPlancpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -314,7 +314,9 @@
</span><span class="cx"> performCFA(dfg);
</span><span class="cx"> performConstantFolding(dfg);
</span><span class="cx"> bool changed = false;
</span><ins>+ dfg.m_strengthReduceArguments = OptimizeArgumentFlushes;
</ins><span class="cx"> changed |= performCFGSimplification(dfg);
</span><ins>+ changed |= performStrengthReduction(dfg);
</ins><span class="cx"> changed |= performLocalCSE(dfg);
</span><span class="cx">
</span><span class="cx"> if (validationEnabled())
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPreciseLocalClobberizeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPreciseLocalClobberize.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPreciseLocalClobberize.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGPreciseLocalClobberize.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -197,7 +197,7 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> default: {
</span><del>- // All of the outermost arguments, except this, are definitely read.
</del><ins>+ // All of the outermost stack arguments, except this, are definitely read.
</ins><span class="cx"> for (unsigned i = m_graph.m_codeBlock->numParameters(); i-- > 1;)
</span><span class="cx"> m_read(virtualRegisterForArgument(i));
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPredictionInjectionPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPredictionInjectionPhase.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPredictionInjectionPhase.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGPredictionInjectionPhase.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -56,7 +56,7 @@
</span><span class="cx"> if (!profile)
</span><span class="cx"> continue;
</span><span class="cx">
</span><del>- m_graph.m_arguments[arg]->variableAccessData()->predict(
</del><ins>+ m_graph.m_argumentsForChecking[arg]->variableAccessData()->predict(
</ins><span class="cx"> profile->computeUpdatedPrediction(locker));
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="lines">@@ -74,7 +74,7 @@
</span><span class="cx"> Node* node = block->variablesAtHead.operand(operand);
</span><span class="cx"> if (!node)
</span><span class="cx"> continue;
</span><del>- ASSERT(node->accessesStack(m_graph));
</del><ins>+ ASSERT(node->accessesStack(m_graph) || node->op() == GetArgumentRegister);
</ins><span class="cx"> node->variableAccessData()->predict(
</span><span class="cx"> speculationFromValue(m_graph.m_plan.mustHandleValues[i]));
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -168,6 +168,16 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ case GetArgumentRegister: {
+ VariableAccessData* variable = node->variableAccessData();
+ SpeculatedType prediction = variable->prediction();
+ if (!variable->couldRepresentInt52() && (prediction & SpecInt52Only))
+ prediction = (prediction | SpecAnyIntAsDouble) & ~SpecInt52Only;
+ if (prediction)
+ changed |= mergePrediction(prediction);
+ break;
+ }
+
</ins><span class="cx"> case UInt32ToNumber: {
</span><span class="cx"> if (node->canSpeculateInt32(m_pass))
</span><span class="cx"> changed |= mergePrediction(SpecInt32Only);
</span><span class="lines">@@ -968,6 +978,7 @@
</span><span class="cx">
</span><span class="cx"> case GetLocal:
</span><span class="cx"> case SetLocal:
</span><ins>+ case GetArgumentRegister:
</ins><span class="cx"> case UInt32ToNumber:
</span><span class="cx"> case ValueAdd:
</span><span class="cx"> case ArithAdd:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPutStackSinkingPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPutStackSinkingPhase.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPutStackSinkingPhase.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGPutStackSinkingPhase.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -147,7 +147,7 @@
</span><span class="cx">
</span><span class="cx"> } while (changed);
</span><span class="cx">
</span><del>- // All of the arguments should be live at head of root. Note that we may find that some
</del><ins>+ // All of the stack arguments should be live at head of root. Note that we may find that some
</ins><span class="cx"> // locals are live at head of root. This seems wrong but isn't. This will happen for example
</span><span class="cx"> // if the function accesses closure variable #42 for some other function and we either don't
</span><span class="cx"> // have variable #42 at all or we haven't set it at root, for whatever reason. Basically this
</span><span class="lines">@@ -157,8 +157,12 @@
</span><span class="cx"> //
</span><span class="cx"> // For our purposes here, the imprecision in the aliasing is harmless. It just means that we
</span><span class="cx"> // may not do as much Phi pruning as we wanted.
</span><del>- for (size_t i = liveAtHead.atIndex(0).numberOfArguments(); i--;)
- DFG_ASSERT(m_graph, nullptr, liveAtHead.atIndex(0).argument(i));
</del><ins>+ for (size_t i = liveAtHead.atIndex(0).numberOfArguments(); i--;) {
+ if (i >= NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS) {
+ // Stack arguments are live at the head of root.
+ DFG_ASSERT(m_graph, nullptr, liveAtHead.atIndex(0).argument(i));
+ }
+ }
</ins><span class="cx">
</span><span class="cx"> // Next identify where we would want to sink PutStacks to. We say that there is a deferred
</span><span class="cx"> // flush if we had a PutStack with a given FlushFormat but it hasn't been materialized yet.
</span><span class="lines">@@ -358,7 +362,8 @@
</span><span class="cx"> for (Node* node : *block) {
</span><span class="cx"> switch (node->op()) {
</span><span class="cx"> case PutStack:
</span><del>- putStacksToSink.add(node);
</del><ins>+ if (!m_graph.m_argumentsOnStack.contains(node))
+ putStacksToSink.add(node);
</ins><span class="cx"> ssaCalculator.newDef(
</span><span class="cx"> operandToVariable.operand(node->stackAccessData()->local),
</span><span class="cx"> block, node->child1().node());
</span><span class="lines">@@ -483,11 +488,15 @@
</span><span class="cx"> return;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ Node* incoming = mapping.operand(operand);
+ // Since we don't delete argument PutStacks, no need to add one back.
+ if (m_graph.m_argumentsOnStack.contains(incoming))
+ return;
+
</ins><span class="cx"> // Gotta insert a PutStack.
</span><span class="cx"> if (verbose)
</span><span class="cx"> dataLog("Inserting a PutStack for ", operand, " at ", node, "\n");
</span><span class="cx">
</span><del>- Node* incoming = mapping.operand(operand);
</del><span class="cx"> DFG_ASSERT(m_graph, node, incoming);
</span><span class="cx">
</span><span class="cx"> insertionSet.insertNode(
</span><span class="lines">@@ -538,6 +547,8 @@
</span><span class="cx"> Node* incoming;
</span><span class="cx"> if (isConcrete(deferred.operand(operand))) {
</span><span class="cx"> incoming = mapping.operand(operand);
</span><ins>+ if (m_graph.m_argumentsOnStack.contains(incoming))
+ continue;
</ins><span class="cx"> DFG_ASSERT(m_graph, phiNode, incoming);
</span><span class="cx"> } else {
</span><span class="cx"> // Issue a GetStack to get the value. This might introduce some redundancy
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGRegisterBankh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGRegisterBank.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGRegisterBank.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGRegisterBank.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -236,6 +236,11 @@
</span><span class="cx"> return m_bank->isLockedAtIndex(m_index);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ void unlock() const
+ {
+ return m_bank->unlockAtIndex(m_index);
+ }
+
</ins><span class="cx"> void release() const
</span><span class="cx"> {
</span><span class="cx"> m_bank->releaseAtIndex(m_index);
</span><span class="lines">@@ -298,6 +303,13 @@
</span><span class="cx"> return m_data[index].lockCount;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ void unlockAtIndex(unsigned index)
+ {
+ ASSERT(index < NUM_REGS);
+ ASSERT(m_data[index].lockCount);
+ --m_data[index].lockCount;
+ }
+
</ins><span class="cx"> VirtualRegister nameAtIndex(unsigned index) const
</span><span class="cx"> {
</span><span class="cx"> ASSERT(index < NUM_REGS);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSSAConversionPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -73,7 +73,8 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // Find all SetLocals and create Defs for them. We handle SetArgument by creating a
</span><del>- // GetLocal, and recording the flush format.
</del><ins>+ // GetStack, and recording the flush format. We handle GetArgumentRegister by directly
+ // adding the node to m_argumentMapping hash map.
</ins><span class="cx"> for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
</span><span class="cx"> BasicBlock* block = m_graph.block(blockIndex);
</span><span class="cx"> if (!block)
</span><span class="lines">@@ -83,14 +84,16 @@
</span><span class="cx"> // assignment for every local.
</span><span class="cx"> for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
</span><span class="cx"> Node* node = block->at(nodeIndex);
</span><del>- if (node->op() != SetLocal && node->op() != SetArgument)
</del><ins>+ if (node->op() != SetLocal && node->op() != SetArgument && node->op() != GetArgumentRegister)
</ins><span class="cx"> continue;
</span><span class="cx">
</span><span class="cx"> VariableAccessData* variable = node->variableAccessData();
</span><span class="cx">
</span><del>- Node* childNode;
</del><ins>+ Node* childNode = nullptr;
</ins><span class="cx"> if (node->op() == SetLocal)
</span><span class="cx"> childNode = node->child1().node();
</span><ins>+ else if (node->op() == GetArgumentRegister)
+ m_argumentMapping.add(node, node);
</ins><span class="cx"> else {
</span><span class="cx"> ASSERT(node->op() == SetArgument);
</span><span class="cx"> childNode = m_insertionSet.insertNode(
</span><span class="lines">@@ -101,9 +104,11 @@
</span><span class="cx"> m_argumentGetters.add(childNode);
</span><span class="cx"> m_argumentMapping.add(node, childNode);
</span><span class="cx"> }
</span><del>-
- m_calculator.newDef(
- m_ssaVariableForVariable.get(variable), block, childNode);
</del><ins>+
+ if (childNode) {
+ m_calculator.newDef(
+ m_ssaVariableForVariable.get(variable), block, childNode);
+ }
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> m_insertionSet.execute(block);
</span><span class="lines">@@ -294,7 +299,13 @@
</span><span class="cx"> valueForOperand.operand(variable->local()) = child;
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>-
</del><ins>+
+ case GetArgumentRegister: {
+ VariableAccessData* variable = node->variableAccessData();
+ valueForOperand.operand(variable->local()) = node;
+ break;
+ }
+
</ins><span class="cx"> case GetStack: {
</span><span class="cx"> ASSERT(m_argumentGetters.contains(node));
</span><span class="cx"> valueForOperand.operand(node->stackAccessData()->local) = node;
</span><span class="lines">@@ -382,17 +393,21 @@
</span><span class="cx"> block->ssa = std::make_unique<BasicBlock::SSAData>(block);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- m_graph.m_argumentFormats.resize(m_graph.m_arguments.size());
- for (unsigned i = m_graph.m_arguments.size(); i--;) {
</del><ins>+ m_graph.m_argumentFormats.resize(m_graph.m_argumentsForChecking.size());
+ for (unsigned i = m_graph.m_argumentsForChecking.size(); i--;) {
</ins><span class="cx"> FlushFormat format = FlushedJSValue;
</span><span class="cx">
</span><del>- Node* node = m_argumentMapping.get(m_graph.m_arguments[i]);
</del><ins>+ Node* node = m_argumentMapping.get(m_graph.m_argumentsForChecking[i]);
</ins><span class="cx">
</span><span class="cx"> RELEASE_ASSERT(node);
</span><del>- format = node->stackAccessData()->format;
</del><ins>+ if (node->op() == GetArgumentRegister) {
+ VariableAccessData* variable = node->variableAccessData();
+ format = variable->flushFormat();
+ } else
+ format = node->stackAccessData()->format;
</ins><span class="cx">
</span><span class="cx"> m_graph.m_argumentFormats[i] = format;
</span><del>- m_graph.m_arguments[i] = node; // Record the load that loads the arguments for the benefit of exit profiling.
</del><ins>+ m_graph.m_argumentsForChecking[i] = node; // Record the load that loads the arguments for the benefit of exit profiling.
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> m_graph.m_form = SSA;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSafeToExecuteh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -147,6 +147,7 @@
</span><span class="cx"> case CreateThis:
</span><span class="cx"> case GetCallee:
</span><span class="cx"> case GetArgumentCountIncludingThis:
</span><ins>+ case GetArgumentRegister:
</ins><span class="cx"> case GetRestLength:
</span><span class="cx"> case GetLocal:
</span><span class="cx"> case SetLocal:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -74,6 +74,7 @@
</span><span class="cx"> , m_lastGeneratedNode(LastNodeType)
</span><span class="cx"> , m_indexInBlock(0)
</span><span class="cx"> , m_generationInfo(m_jit.graph().frameRegisterCount())
</span><ins>+ , m_argumentGenerationInfo(CallFrameSlot::callee + GPRInfo::numberOfArgumentRegisters)
</ins><span class="cx"> , m_state(m_jit.graph())
</span><span class="cx"> , m_interpreter(m_jit.graph(), m_state)
</span><span class="cx"> , m_stream(&jit.jitCode()->variableEventStream)
</span><span class="lines">@@ -407,6 +408,8 @@
</span><span class="cx"> {
</span><span class="cx"> for (unsigned i = 0; i < m_generationInfo.size(); ++i)
</span><span class="cx"> m_generationInfo[i] = GenerationInfo();
</span><ins>+ for (unsigned i = 0; i < m_argumentGenerationInfo.size(); ++i)
+ m_argumentGenerationInfo[i] = GenerationInfo();
</ins><span class="cx"> m_gprs = RegisterBank<GPRInfo>();
</span><span class="cx"> m_fprs = RegisterBank<FPRInfo>();
</span><span class="cx"> }
</span><span class="lines">@@ -1199,6 +1202,25 @@
</span><span class="cx"> return strings[format];
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+static void dumpRegisterInfo(GenerationInfo& info, unsigned index)
+{
+ if (info.alive())
+ dataLogF(" % 3d:%s%s", index, dataFormatString(info.registerFormat()), dataFormatString(info.spillFormat()));
+ else
+ dataLogF(" % 3d:[__][__]", index);
+ if (info.registerFormat() == DataFormatDouble)
+ dataLogF(":fpr%d\n", info.fpr());
+ else if (info.registerFormat() != DataFormatNone
+#if USE(JSVALUE32_64)
+ && !(info.registerFormat() & DataFormatJS)
+#endif
+ ) {
+ ASSERT(info.gpr() != InvalidGPRReg);
+ dataLogF(":%s\n", GPRInfo::debugName(info.gpr()));
+ } else
+ dataLogF("\n");
+}
+
</ins><span class="cx"> void SpeculativeJIT::dump(const char* label)
</span><span class="cx"> {
</span><span class="cx"> if (label)
</span><span class="lines">@@ -1208,25 +1230,15 @@
</span><span class="cx"> m_gprs.dump();
</span><span class="cx"> dataLogF(" fprs:\n");
</span><span class="cx"> m_fprs.dump();
</span><del>- dataLogF(" VirtualRegisters:\n");
- for (unsigned i = 0; i < m_generationInfo.size(); ++i) {
- GenerationInfo& info = m_generationInfo[i];
- if (info.alive())
- dataLogF(" % 3d:%s%s", i, dataFormatString(info.registerFormat()), dataFormatString(info.spillFormat()));
- else
- dataLogF(" % 3d:[__][__]", i);
- if (info.registerFormat() == DataFormatDouble)
- dataLogF(":fpr%d\n", info.fpr());
- else if (info.registerFormat() != DataFormatNone
-#if USE(JSVALUE32_64)
- && !(info.registerFormat() & DataFormatJS)
-#endif
- ) {
- ASSERT(info.gpr() != InvalidGPRReg);
- dataLogF(":%s\n", GPRInfo::debugName(info.gpr()));
- } else
- dataLogF("\n");
- }
</del><ins>+
+ dataLogF(" Argument VirtualRegisters:\n");
+ for (unsigned i = 0; i < m_argumentGenerationInfo.size(); ++i)
+ dumpRegisterInfo(m_argumentGenerationInfo[i], i);
+
+ dataLogF(" Local VirtualRegisters:\n");
+ for (unsigned i = 0; i < m_generationInfo.size(); ++i)
+ dumpRegisterInfo(m_generationInfo[i], i);
+
</ins><span class="cx"> if (label)
</span><span class="cx"> dataLogF("</%s>\n", label);
</span><span class="cx"> }
</span><span class="lines">@@ -1677,6 +1689,9 @@
</span><span class="cx">
</span><span class="cx"> m_jit.blockHeads()[m_block->index] = m_jit.label();
</span><span class="cx">
</span><ins>+ if (!m_block->index)
+ checkArgumentTypes();
+
</ins><span class="cx"> if (!m_block->intersectionOfCFAHasVisited) {
</span><span class="cx"> // Don't generate code for basic blocks that are unreachable according to CFA.
</span><span class="cx"> // But to be sure that nobody has generated a jump to this block, drop in a
</span><span class="lines">@@ -1687,6 +1702,9 @@
</span><span class="cx">
</span><span class="cx"> m_stream->appendAndLog(VariableEvent::reset());
</span><span class="cx">
</span><ins>+ if (!m_block->index)
+ setupArgumentRegistersForEntry();
+
</ins><span class="cx"> m_jit.jitAssertHasValidCallFrame();
</span><span class="cx"> m_jit.jitAssertTagsInPlace();
</span><span class="cx"> m_jit.jitAssertArgumentCountSane();
</span><span class="lines">@@ -1696,6 +1714,21 @@
</span><span class="cx">
</span><span class="cx"> for (size_t i = m_block->variablesAtHead.size(); i--;) {
</span><span class="cx"> int operand = m_block->variablesAtHead.operandForIndex(i);
</span><ins>+ if (!m_block->index && operandIsArgument(operand)) {
+ unsigned argument = m_block->variablesAtHead.argumentForIndex(i);
+ Node* argumentNode = m_jit.graph().m_argumentsForChecking[argument];
+
+ if (argumentNode && argumentNode->op() == GetArgumentRegister) {
+ if (!argumentNode->refCount())
+ continue; // No need to record dead GetArgumentRegisters's.
+ m_stream->appendAndLog(
+ VariableEvent::movHint(
+ MinifiedID(argumentNode),
+ argumentNode->local()));
+ continue;
+ }
+ }
+
</ins><span class="cx"> Node* node = m_block->variablesAtHead[i];
</span><span class="cx"> if (!node)
</span><span class="cx"> continue; // No need to record dead SetLocal's.
</span><span class="lines">@@ -1782,13 +1815,15 @@
</span><span class="cx"> m_origin = NodeOrigin(CodeOrigin(0), CodeOrigin(0), true);
</span><span class="cx">
</span><span class="cx"> for (int i = 0; i < m_jit.codeBlock()->numParameters(); ++i) {
</span><del>- Node* node = m_jit.graph().m_arguments[i];
</del><ins>+ Node* node = m_jit.graph().m_argumentsForChecking[i];
</ins><span class="cx"> if (!node) {
</span><span class="cx"> // The argument is dead. We don't do any checks for such arguments.
</span><span class="cx"> continue;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- ASSERT(node->op() == SetArgument);
</del><ins>+ ASSERT(node->op() == SetArgument
+ || (node->op() == SetLocal && node->child1()->op() == GetArgumentRegister)
+ || node->op() == GetArgumentRegister);
</ins><span class="cx"> ASSERT(node->shouldGenerate());
</span><span class="cx">
</span><span class="cx"> VariableAccessData* variableAccessData = node->variableAccessData();
</span><span class="lines">@@ -1799,23 +1834,44 @@
</span><span class="cx">
</span><span class="cx"> VirtualRegister virtualRegister = variableAccessData->local();
</span><span class="cx">
</span><del>- JSValueSource valueSource = JSValueSource(JITCompiler::addressFor(virtualRegister));
-
</del><ins>+ JSValueSource valueSource;
+
</ins><span class="cx"> #if USE(JSVALUE64)
</span><ins>+ GPRReg argumentRegister = InvalidGPRReg;
+
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ if (static_cast<unsigned>(i) < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS) {
+ argumentRegister = argumentRegisterForFunctionArgument(i);
+ valueSource = JSValueSource(argumentRegister);
+ } else
+#endif
+#endif
+ valueSource = JSValueSource(JITCompiler::addressFor(virtualRegister));
+
+#if USE(JSVALUE64)
</ins><span class="cx"> switch (format) {
</span><span class="cx"> case FlushedInt32: {
</span><del>- speculationCheck(BadType, valueSource, node, m_jit.branch64(MacroAssembler::Below, JITCompiler::addressFor(virtualRegister), GPRInfo::tagTypeNumberRegister));
</del><ins>+ if (argumentRegister != InvalidGPRReg)
+ speculationCheck(BadType, valueSource, node, m_jit.branch64(MacroAssembler::Below, argumentRegister, GPRInfo::tagTypeNumberRegister));
+ else
+ speculationCheck(BadType, valueSource, node, m_jit.branch64(MacroAssembler::Below, JITCompiler::addressFor(virtualRegister), GPRInfo::tagTypeNumberRegister));
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> case FlushedBoolean: {
</span><span class="cx"> GPRTemporary temp(this);
</span><del>- m_jit.load64(JITCompiler::addressFor(virtualRegister), temp.gpr());
</del><ins>+ if (argumentRegister != InvalidGPRReg)
+ m_jit.move(argumentRegister, temp.gpr());
+ else
+ m_jit.load64(JITCompiler::addressFor(virtualRegister), temp.gpr());
</ins><span class="cx"> m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), temp.gpr());
</span><span class="cx"> speculationCheck(BadType, valueSource, node, m_jit.branchTest64(MacroAssembler::NonZero, temp.gpr(), TrustedImm32(static_cast<int32_t>(~1))));
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> case FlushedCell: {
</span><del>- speculationCheck(BadType, valueSource, node, m_jit.branchTest64(MacroAssembler::NonZero, JITCompiler::addressFor(virtualRegister), GPRInfo::tagMaskRegister));
</del><ins>+ if (argumentRegister != InvalidGPRReg)
+ speculationCheck(BadType, valueSource, node, m_jit.branchTest64(MacroAssembler::NonZero, argumentRegister, GPRInfo::tagMaskRegister));
+ else
+ speculationCheck(BadType, valueSource, node, m_jit.branchTest64(MacroAssembler::NonZero, JITCompiler::addressFor(virtualRegister), GPRInfo::tagMaskRegister));
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> default:
</span><span class="lines">@@ -1846,10 +1902,38 @@
</span><span class="cx"> m_origin = NodeOrigin();
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+void SpeculativeJIT::setupArgumentRegistersForEntry()
+{
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ BasicBlock* firstBlock = m_jit.graph().block(0);
+
+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=165720
+ // We should scan m_arguemntsForChecking instead of looking for GetArgumentRegister
+ // nodes in the root block.
+ for (size_t indexInBlock = 0; indexInBlock < firstBlock->size(); ++indexInBlock) {
+ Node* node = firstBlock->at(indexInBlock);
+
+ if (node->op() == GetArgumentRegister) {
+ VirtualRegister virtualRegister = node->virtualRegister();
+ GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
+ GPRReg argumentReg = GPRInfo::toArgumentRegister(node->argumentRegisterIndex());
+
+ ASSERT(argumentReg != InvalidGPRReg);
+
+ ASSERT(!m_gprs.isLocked(argumentReg));
+ m_gprs.allocateSpecific(argumentReg);
+ m_gprs.retain(argumentReg, virtualRegister, SpillOrderJS);
+ info.initArgumentRegisterValue(node, node->refCount(), argumentReg, DataFormatJS);
+ info.noticeOSRBirth(*m_stream, node, virtualRegister);
+ // Don't leave argument registers locked.
+ m_gprs.unlock(argumentReg);
+ }
+ }
+#endif
+}
+
</ins><span class="cx"> bool SpeculativeJIT::compile()
</span><span class="cx"> {
</span><del>- checkArgumentTypes();
-
</del><span class="cx"> ASSERT(!m_currentNode);
</span><span class="cx"> for (BlockIndex blockIndex = 0; blockIndex < m_jit.graph().numBlocks(); ++blockIndex) {
</span><span class="cx"> m_jit.setForBlockIndex(blockIndex);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -128,7 +128,7 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> #if USE(JSVALUE64)
</span><del>- GPRReg fillJSValue(Edge);
</del><ins>+ GPRReg fillJSValue(Edge, GPRReg gprToUse = InvalidGPRReg);
</ins><span class="cx"> #elif USE(JSVALUE32_64)
</span><span class="cx"> bool fillJSValue(Edge, GPRReg&, GPRReg&, FPRReg&);
</span><span class="cx"> #endif
</span><span class="lines">@@ -200,6 +200,9 @@
</span><span class="cx"> #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
</span><span class="cx"> m_jit.addRegisterAllocationAtOffset(m_jit.debugOffset());
</span><span class="cx"> #endif
</span><ins>+ if (specific == InvalidGPRReg)
+ return allocate();
+
</ins><span class="cx"> VirtualRegister spillMe = m_gprs.allocateSpecific(specific);
</span><span class="cx"> if (spillMe.isValid()) {
</span><span class="cx"> #if USE(JSVALUE32_64)
</span><span class="lines">@@ -315,6 +318,8 @@
</span><span class="cx">
</span><span class="cx"> void checkArgumentTypes();
</span><span class="cx">
</span><ins>+ void setupArgumentRegistersForEntry();
+
</ins><span class="cx"> void clearGenerationInfo();
</span><span class="cx">
</span><span class="cx"> // These methods are used when generating 'unexpected'
</span><span class="lines">@@ -485,6 +490,9 @@
</span><span class="cx"> // Spill a VirtualRegister to the JSStack.
</span><span class="cx"> void spill(VirtualRegister spillMe)
</span><span class="cx"> {
</span><ins>+ if (spillMe.isArgument() && m_block->index > 0)
+ return;
+
</ins><span class="cx"> GenerationInfo& info = generationInfoFromVirtualRegister(spillMe);
</span><span class="cx">
</span><span class="cx"> #if USE(JSVALUE32_64)
</span><span class="lines">@@ -2873,7 +2881,10 @@
</span><span class="cx">
</span><span class="cx"> GenerationInfo& generationInfoFromVirtualRegister(VirtualRegister virtualRegister)
</span><span class="cx"> {
</span><del>- return m_generationInfo[virtualRegister.toLocal()];
</del><ins>+ if (virtualRegister.isLocal())
+ return m_generationInfo[virtualRegister.toLocal()];
+ ASSERT(virtualRegister.isArgument());
+ return m_argumentGenerationInfo[virtualRegister.offset()];
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> GenerationInfo& generationInfo(Node* node)
</span><span class="lines">@@ -2896,6 +2907,7 @@
</span><span class="cx"> unsigned m_indexInBlock;
</span><span class="cx"> // Virtual and physical register maps.
</span><span class="cx"> Vector<GenerationInfo, 32> m_generationInfo;
</span><ins>+ Vector<GenerationInfo, 8> m_argumentGenerationInfo;
</ins><span class="cx"> RegisterBank<GPRInfo> m_gprs;
</span><span class="cx"> RegisterBank<FPRInfo> m_fprs;
</span><span class="cx">
</span><span class="lines">@@ -2994,6 +3006,20 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+#if USE(JSVALUE64)
+ explicit JSValueOperand(SpeculativeJIT* jit, Edge edge, GPRReg regToUse)
+ : m_jit(jit)
+ , m_edge(edge)
+ , m_gprOrInvalid(InvalidGPRReg)
+ {
+ ASSERT(m_jit);
+ if (!edge)
+ return;
+ if (jit->isFilled(node()) || regToUse != InvalidGPRReg)
+ gprUseSpecific(regToUse);
+ }
+#endif
+
</ins><span class="cx"> ~JSValueOperand()
</span><span class="cx"> {
</span><span class="cx"> if (!m_edge)
</span><span class="lines">@@ -3030,6 +3056,12 @@
</span><span class="cx"> m_gprOrInvalid = m_jit->fillJSValue(m_edge);
</span><span class="cx"> return m_gprOrInvalid;
</span><span class="cx"> }
</span><ins>+ GPRReg gprUseSpecific(GPRReg regToUse)
+ {
+ if (m_gprOrInvalid == InvalidGPRReg)
+ m_gprOrInvalid = m_jit->fillJSValue(m_edge, regToUse);
+ return m_gprOrInvalid;
+ }
</ins><span class="cx"> JSValueRegs jsValueRegs()
</span><span class="cx"> {
</span><span class="cx"> return JSValueRegs(gpr());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -932,7 +932,7 @@
</span><span class="cx"> CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(dynamicOrigin, m_stream->size());
</span><span class="cx">
</span><span class="cx"> CallLinkInfo* info = m_jit.codeBlock()->addCallLinkInfo();
</span><del>- info->setUpCall(callType, node->origin.semantic, calleePayloadGPR);
</del><ins>+ info->setUpCall(callType, StackArgs, node->origin.semantic, calleePayloadGPR);
</ins><span class="cx">
</span><span class="cx"> auto setResultAndResetStack = [&] () {
</span><span class="cx"> GPRFlushedCallResult resultPayload(this);
</span><span class="lines">@@ -1081,7 +1081,7 @@
</span><span class="cx"> m_jit.emitRestoreCalleeSaves();
</span><span class="cx"> }
</span><span class="cx">
</span><del>- m_jit.move(MacroAssembler::TrustedImmPtr(info), GPRInfo::regT2);
</del><ins>+ m_jit.move(MacroAssembler::TrustedImmPtr(info), GPRInfo::nonArgGPR0);
</ins><span class="cx"> JITCompiler::Call slowCall = m_jit.nearCall();
</span><span class="cx">
</span><span class="cx"> done.link(&m_jit);
</span><span class="lines">@@ -5624,6 +5624,7 @@
</span><span class="cx"> case KillStack:
</span><span class="cx"> case GetStack:
</span><span class="cx"> case GetMyArgumentByVal:
</span><ins>+ case GetArgumentRegister:
</ins><span class="cx"> case GetMyArgumentByValOutOfBounds:
</span><span class="cx"> case PhantomCreateRest:
</span><span class="cx"> case PhantomSpread:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -80,7 +80,7 @@
</span><span class="cx"> unlock(fpr);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-GPRReg SpeculativeJIT::fillJSValue(Edge edge)
</del><ins>+GPRReg SpeculativeJIT::fillJSValue(Edge edge, GPRReg gprToUse)
</ins><span class="cx"> {
</span><span class="cx"> VirtualRegister virtualRegister = edge->virtualRegister();
</span><span class="cx"> GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
</span><span class="lines">@@ -87,7 +87,7 @@
</span><span class="cx">
</span><span class="cx"> switch (info.registerFormat()) {
</span><span class="cx"> case DataFormatNone: {
</span><del>- GPRReg gpr = allocate();
</del><ins>+ GPRReg gpr = allocate(gprToUse);
</ins><span class="cx">
</span><span class="cx"> if (edge->hasConstant()) {
</span><span class="cx"> JSValue jsValue = edge->asJSValue();
</span><span class="lines">@@ -120,10 +120,15 @@
</span><span class="cx"> // If the register has already been locked we need to take a copy.
</span><span class="cx"> // If not, we'll zero extend in place, so mark on the info that this is now type DataFormatInt32, not DataFormatJSInt32.
</span><span class="cx"> if (m_gprs.isLocked(gpr)) {
</span><del>- GPRReg result = allocate();
</del><ins>+ GPRReg result = allocate(gprToUse);
</ins><span class="cx"> m_jit.or64(GPRInfo::tagTypeNumberRegister, gpr, result);
</span><span class="cx"> return result;
</span><span class="cx"> }
</span><ins>+ if (gprToUse != InvalidGPRReg && gpr != gprToUse) {
+ GPRReg result = allocate(gprToUse);
+ m_jit.or64(GPRInfo::tagTypeNumberRegister, gpr, result);
+ return result;
+ }
</ins><span class="cx"> m_gprs.lock(gpr);
</span><span class="cx"> m_jit.or64(GPRInfo::tagTypeNumberRegister, gpr);
</span><span class="cx"> info.fillJSValue(*m_stream, gpr, DataFormatJSInt32);
</span><span class="lines">@@ -138,6 +143,11 @@
</span><span class="cx"> case DataFormatJSCell:
</span><span class="cx"> case DataFormatJSBoolean: {
</span><span class="cx"> GPRReg gpr = info.gpr();
</span><ins>+ if (gprToUse != InvalidGPRReg && gpr != gprToUse) {
+ GPRReg result = allocate(gprToUse);
+ m_jit.move(gpr, result);
+ return result;
+ }
</ins><span class="cx"> m_gprs.lock(gpr);
</span><span class="cx"> return gpr;
</span><span class="cx"> }
</span><span class="lines">@@ -632,6 +642,7 @@
</span><span class="cx"> void SpeculativeJIT::emitCall(Node* node)
</span><span class="cx"> {
</span><span class="cx"> CallLinkInfo::CallType callType;
</span><ins>+ ArgumentsLocation argumentsLocation = StackArgs;
</ins><span class="cx"> bool isVarargs = false;
</span><span class="cx"> bool isForwardVarargs = false;
</span><span class="cx"> bool isTail = false;
</span><span class="lines">@@ -714,7 +725,11 @@
</span><span class="cx">
</span><span class="cx"> GPRReg calleeGPR = InvalidGPRReg;
</span><span class="cx"> CallFrameShuffleData shuffleData;
</span><del>-
</del><ins>+ std::optional<JSValueOperand> tailCallee;
+ std::optional<GPRTemporary> calleeGPRTemporary;
+
+ incrementCounter(&m_jit, VM::DFGCaller);
+
</ins><span class="cx"> ExecutableBase* executable = nullptr;
</span><span class="cx"> FunctionExecutable* functionExecutable = nullptr;
</span><span class="cx"> if (isDirect) {
</span><span class="lines">@@ -733,6 +748,7 @@
</span><span class="cx"> GPRReg resultGPR;
</span><span class="cx"> unsigned numUsedStackSlots = m_jit.graph().m_nextMachineLocal;
</span><span class="cx">
</span><ins>+ incrementCounter(&m_jit, VM::CallVarargs);
</ins><span class="cx"> if (isForwardVarargs) {
</span><span class="cx"> flushRegisters();
</span><span class="cx"> if (node->child3())
</span><span class="lines">@@ -841,15 +857,25 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (isTail) {
</span><ins>+ incrementCounter(&m_jit, VM::TailCall);
</ins><span class="cx"> Edge calleeEdge = m_jit.graph().child(node, 0);
</span><del>- JSValueOperand callee(this, calleeEdge);
- calleeGPR = callee.gpr();
</del><ins>+ // We can't get the a specific register for the callee, since that will just move
+ // from any current register. When we silent fill in the slow path we'll fill
+ // the original register and won't have the callee in the right register.
+ // Therefore we allocate a temp register for the callee and move ourselves.
+ tailCallee.emplace(this, calleeEdge);
+ GPRReg tailCalleeGPR = tailCallee->gpr();
+ calleeGPR = argumentRegisterForCallee();
+ if (tailCalleeGPR != calleeGPR)
+ calleeGPRTemporary = GPRTemporary(this, calleeGPR);
</ins><span class="cx"> if (!isDirect)
</span><del>- callee.use();
</del><ins>+ tailCallee->use();
</ins><span class="cx">
</span><ins>+ argumentsLocation = argumentsLocationFor(numAllocatedArgs);
+ shuffleData.argumentsInRegisters = argumentsLocation != StackArgs;
</ins><span class="cx"> shuffleData.tagTypeNumber = GPRInfo::tagTypeNumberRegister;
</span><span class="cx"> shuffleData.numLocals = m_jit.graph().frameRegisterCount();
</span><del>- shuffleData.callee = ValueRecovery::inGPR(calleeGPR, DataFormatJS);
</del><ins>+ shuffleData.callee = ValueRecovery::inGPR(tailCalleeGPR, DataFormatJS);
</ins><span class="cx"> shuffleData.args.resize(numAllocatedArgs);
</span><span class="cx">
</span><span class="cx"> for (unsigned i = 0; i < numPassedArgs; ++i) {
</span><span class="lines">@@ -864,7 +890,8 @@
</span><span class="cx"> shuffleData.args[i] = ValueRecovery::constant(jsUndefined());
</span><span class="cx">
</span><span class="cx"> shuffleData.setupCalleeSaveRegisters(m_jit.codeBlock());
</span><del>- } else {
</del><ins>+ } else if (node->op() == CallEval) {
+ // CallEval is handled with the arguments in the stack
</ins><span class="cx"> m_jit.store32(MacroAssembler::TrustedImm32(numPassedArgs), JITCompiler::calleeFramePayloadSlot(CallFrameSlot::argumentCount));
</span><span class="cx">
</span><span class="cx"> for (unsigned i = 0; i < numPassedArgs; i++) {
</span><span class="lines">@@ -878,15 +905,60 @@
</span><span class="cx">
</span><span class="cx"> for (unsigned i = numPassedArgs; i < numAllocatedArgs; ++i)
</span><span class="cx"> m_jit.storeTrustedValue(jsUndefined(), JITCompiler::calleeArgumentSlot(i));
</span><ins>+
+ incrementCounter(&m_jit, VM::CallEval);
+ } else {
+ for (unsigned i = numPassedArgs; i-- > 0;) {
+ GPRReg platformArgGPR = argumentRegisterForFunctionArgument(i);
+ Edge argEdge = m_jit.graph().m_varArgChildren[node->firstChild() + 1 + i];
+ JSValueOperand arg(this, argEdge, platformArgGPR);
+ GPRReg argGPR = arg.gpr();
+ ASSERT(argGPR == platformArgGPR || platformArgGPR == InvalidGPRReg);
+
+ // Only free the non-argument registers at this point.
+ if (platformArgGPR == InvalidGPRReg) {
+ use(argEdge);
+ m_jit.store64(argGPR, JITCompiler::calleeArgumentSlot(i));
+ }
+ }
+
+ // Use the argument edges for arguments passed in registers.
+ for (unsigned i = numPassedArgs; i-- > 0;) {
+ GPRReg argGPR = argumentRegisterForFunctionArgument(i);
+ if (argGPR != InvalidGPRReg) {
+ Edge argEdge = m_jit.graph().m_varArgChildren[node->firstChild() + 1 + i];
+ use(argEdge);
+ }
+ }
+
+ GPRTemporary argCount(this, argumentRegisterForArgumentCount());
+ GPRReg argCountGPR = argCount.gpr();
+ m_jit.move(TrustedImm32(numPassedArgs), argCountGPR);
+ argumentsLocation = argumentsLocationFor(numAllocatedArgs);
+
+ for (unsigned i = numPassedArgs; i < numAllocatedArgs; ++i) {
+ GPRReg platformArgGPR = argumentRegisterForFunctionArgument(i);
+
+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=165769
+ // Eliminate filling extra stack slots with undefined JSValues for register arguments.
+ // The LLInt thunks aren't smart enough to know what register arguments to spill therefore
+ // we put undefined in both the extra argument register and stack slot.
+ if (platformArgGPR != InvalidGPRReg) {
+ GPRTemporary argumentTemp(this, platformArgGPR);
+ m_jit.move(TrustedImm64(JSValue::encode(jsUndefined())), argumentTemp.gpr());
+ }
+ m_jit.storeTrustedValue(jsUndefined(), JITCompiler::calleeArgumentSlot(i));
+ }
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (!isTail || isVarargs || isForwardVarargs) {
</span><span class="cx"> Edge calleeEdge = m_jit.graph().child(node, 0);
</span><del>- JSValueOperand callee(this, calleeEdge);
</del><ins>+ JSValueOperand callee(this, calleeEdge, argumentRegisterForCallee());
</ins><span class="cx"> calleeGPR = callee.gpr();
</span><span class="cx"> callee.use();
</span><del>- m_jit.store64(calleeGPR, JITCompiler::calleeFrameSlot(CallFrameSlot::callee));
</del><ins>+ if (argumentsLocation == StackArgs)
+ m_jit.store64(calleeGPR, JITCompiler::calleeFrameSlot(CallFrameSlot::callee));
</ins><span class="cx">
</span><span class="cx"> flushRegisters();
</span><span class="cx"> }
</span><span class="lines">@@ -913,7 +985,7 @@
</span><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> CallLinkInfo* callLinkInfo = m_jit.codeBlock()->addCallLinkInfo();
</span><del>- callLinkInfo->setUpCall(callType, m_currentNode->origin.semantic, calleeGPR);
</del><ins>+ callLinkInfo->setUpCall(callType, argumentsLocation, m_currentNode->origin.semantic, calleeGPR);
</ins><span class="cx">
</span><span class="cx"> if (node->op() == CallEval) {
</span><span class="cx"> // We want to call operationCallEval but we don't want to overwrite the parameter area in
</span><span class="lines">@@ -954,8 +1026,14 @@
</span><span class="cx"> if (isTail) {
</span><span class="cx"> RELEASE_ASSERT(node->op() == DirectTailCall);
</span><span class="cx">
</span><ins>+ if (calleeGPRTemporary != std::nullopt)
+ m_jit.move(tailCallee->gpr(), calleeGPRTemporary->gpr());
+
</ins><span class="cx"> JITCompiler::PatchableJump patchableJump = m_jit.patchableJump();
</span><span class="cx"> JITCompiler::Label mainPath = m_jit.label();
</span><ins>+
+ incrementCounter(&m_jit, VM::TailCall);
+ incrementCounter(&m_jit, VM::DirectCall);
</ins><span class="cx">
</span><span class="cx"> m_jit.emitStoreCallSiteIndex(callSite);
</span><span class="cx">
</span><span class="lines">@@ -971,6 +1049,8 @@
</span><span class="cx"> callOperation(operationLinkDirectCall, callLinkInfo, calleeGPR);
</span><span class="cx"> silentFillAllRegisters(InvalidGPRReg);
</span><span class="cx"> m_jit.exceptionCheck();
</span><ins>+ if (calleeGPRTemporary != std::nullopt)
+ m_jit.move(tailCallee->gpr(), calleeGPRTemporary->gpr());
</ins><span class="cx"> m_jit.jump().linkTo(mainPath, &m_jit);
</span><span class="cx">
</span><span class="cx"> useChildren(node);
</span><span class="lines">@@ -981,6 +1061,8 @@
</span><span class="cx">
</span><span class="cx"> JITCompiler::Label mainPath = m_jit.label();
</span><span class="cx">
</span><ins>+ incrementCounter(&m_jit, VM::DirectCall);
+
</ins><span class="cx"> m_jit.emitStoreCallSiteIndex(callSite);
</span><span class="cx">
</span><span class="cx"> JITCompiler::Call call = m_jit.nearCall();
</span><span class="lines">@@ -988,9 +1070,11 @@
</span><span class="cx">
</span><span class="cx"> JITCompiler::Label slowPath = m_jit.label();
</span><span class="cx"> if (isX86())
</span><del>- m_jit.pop(JITCompiler::selectScratchGPR(calleeGPR));
</del><ins>+ m_jit.pop(GPRInfo::nonArgGPR0);
</ins><span class="cx">
</span><del>- callOperation(operationLinkDirectCall, callLinkInfo, calleeGPR);
</del><ins>+ m_jit.move(MacroAssembler::TrustedImmPtr(callLinkInfo), GPRInfo::nonArgGPR0); // Link info needs to be in nonArgGPR0
+ JITCompiler::Call slowCall = m_jit.nearCall();
+
</ins><span class="cx"> m_jit.exceptionCheck();
</span><span class="cx"> m_jit.jump().linkTo(mainPath, &m_jit);
</span><span class="cx">
</span><span class="lines">@@ -997,11 +1081,14 @@
</span><span class="cx"> done.link(&m_jit);
</span><span class="cx">
</span><span class="cx"> setResultAndResetStack();
</span><del>-
- m_jit.addJSDirectCall(call, slowPath, callLinkInfo);
</del><ins>+
+ m_jit.addJSDirectCall(call, slowCall, slowPath, callLinkInfo);
</ins><span class="cx"> return;
</span><span class="cx"> }
</span><del>-
</del><ins>+
+ if (isTail && calleeGPRTemporary != std::nullopt)
+ m_jit.move(tailCallee->gpr(), calleeGPRTemporary->gpr());
+
</ins><span class="cx"> m_jit.emitStoreCallSiteIndex(callSite);
</span><span class="cx">
</span><span class="cx"> JITCompiler::DataLabelPtr targetToCheck;
</span><span class="lines">@@ -1025,23 +1112,22 @@
</span><span class="cx">
</span><span class="cx"> if (node->op() == TailCall) {
</span><span class="cx"> CallFrameShuffler callFrameShuffler(m_jit, shuffleData);
</span><del>- callFrameShuffler.setCalleeJSValueRegs(JSValueRegs(GPRInfo::regT0));
</del><ins>+ if (argumentsLocation == StackArgs)
+ callFrameShuffler.setCalleeJSValueRegs(JSValueRegs(argumentRegisterForCallee()));
</ins><span class="cx"> callFrameShuffler.prepareForSlowPath();
</span><del>- } else {
- m_jit.move(calleeGPR, GPRInfo::regT0); // Callee needs to be in regT0
</del><ins>+ } else if (isTail)
+ m_jit.emitRestoreCalleeSaves();
</ins><span class="cx">
</span><del>- if (isTail)
- m_jit.emitRestoreCalleeSaves(); // This needs to happen after we moved calleeGPR to regT0
- }
-
- m_jit.move(MacroAssembler::TrustedImmPtr(callLinkInfo), GPRInfo::regT2); // Link info needs to be in regT2
</del><ins>+ m_jit.move(MacroAssembler::TrustedImmPtr(callLinkInfo), GPRInfo::nonArgGPR0); // Link info needs to be in nonArgGPR0
</ins><span class="cx"> JITCompiler::Call slowCall = m_jit.nearCall();
</span><span class="cx">
</span><span class="cx"> done.link(&m_jit);
</span><span class="cx">
</span><del>- if (isTail)
</del><ins>+ if (isTail) {
+ tailCallee = std::nullopt;
+ calleeGPRTemporary = std::nullopt;
</ins><span class="cx"> m_jit.abortWithReason(JITDidReturnFromTailCall);
</span><del>- else
</del><ins>+ } else
</ins><span class="cx"> setResultAndResetStack();
</span><span class="cx">
</span><span class="cx"> m_jit.addJSCall(fastCall, slowCall, targetToCheck, callLinkInfo);
</span><span class="lines">@@ -4166,6 +4252,9 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ case GetArgumentRegister:
+ break;
+
</ins><span class="cx"> case GetRestLength: {
</span><span class="cx"> compileGetRestLength(node);
</span><span class="cx"> break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGStrengthReductionPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -276,6 +276,9 @@
</span><span class="cx"> Node* setLocal = nullptr;
</span><span class="cx"> VirtualRegister local = m_node->local();
</span><span class="cx">
</span><ins>+ if (local.isArgument() && m_graph.m_strengthReduceArguments != OptimizeArgumentFlushes)
+ break;
+
</ins><span class="cx"> for (unsigned i = m_nodeIndex; i--;) {
</span><span class="cx"> Node* node = m_block->at(i);
</span><span class="cx"> if (node->op() == SetLocal && node->local() == local) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGThunkscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGThunks.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGThunks.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGThunks.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -130,15 +130,30 @@
</span><span class="cx"> jit.store32(GPRInfo::regT3, MacroAssembler::BaseIndex(GPRInfo::callFrameRegister, GPRInfo::regT4, MacroAssembler::TimesEight, -static_cast<intptr_t>(sizeof(Register)) + static_cast<intptr_t>(sizeof(int32_t))));
</span><span class="cx"> jit.branchPtr(MacroAssembler::NotEqual, GPRInfo::regT1, MacroAssembler::TrustedImmPtr(bitwise_cast<void*>(-static_cast<intptr_t>(CallFrame::headerSizeInRegisters)))).linkTo(loop, &jit);
</span><span class="cx">
</span><del>- jit.loadPtr(MacroAssembler::Address(GPRInfo::regT0, offsetOfTargetPC), GPRInfo::regT1);
- MacroAssembler::Jump ok = jit.branchPtr(MacroAssembler::Above, GPRInfo::regT1, MacroAssembler::TrustedImmPtr(bitwise_cast<void*>(static_cast<intptr_t>(1000))));
</del><ins>+ jit.loadPtr(MacroAssembler::Address(GPRInfo::regT0, offsetOfTargetPC), GPRInfo::nonArgGPR0);
+ MacroAssembler::Jump ok = jit.branchPtr(MacroAssembler::Above, GPRInfo::nonArgGPR0, MacroAssembler::TrustedImmPtr(bitwise_cast<void*>(static_cast<intptr_t>(1000))));
</ins><span class="cx"> jit.abortWithReason(DFGUnreasonableOSREntryJumpDestination);
</span><span class="cx">
</span><span class="cx"> ok.link(&jit);
</span><ins>+
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ // Load argument values into argument registers
+ jit.loadPtr(MacroAssembler::Address(GPRInfo::callFrameRegister, CallFrameSlot::callee * static_cast<int>(sizeof(Register))), argumentRegisterForCallee());
+ GPRReg argCountReg = argumentRegisterForArgumentCount();
+ jit.load32(AssemblyHelpers::payloadFor(CallFrameSlot::argumentCount), argCountReg);
+
+ MacroAssembler::JumpList doneLoadingArgs;
+
+ for (unsigned argIndex = 0; argIndex < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS; argIndex++)
+ jit.load64(MacroAssembler::Address(GPRInfo::callFrameRegister, (CallFrameSlot::thisArgument + argIndex) * static_cast<int>(sizeof(Register))), argumentRegisterForFunctionArgument(argIndex));
+
+ doneLoadingArgs.link(&jit);
+#endif
+
</ins><span class="cx"> jit.restoreCalleeSavesFromVMEntryFrameCalleeSavesBuffer();
</span><span class="cx"> jit.emitMaterializeTagCheckRegisters();
</span><span class="cx">
</span><del>- jit.jump(GPRInfo::regT1);
</del><ins>+ jit.jump(GPRInfo::nonArgGPR0);
</ins><span class="cx">
</span><span class="cx"> LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);
</span><span class="cx"> return FINALIZE_CODE(patchBuffer, ("DFG OSR entry thunk"));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGVariableEventStreamcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -133,8 +133,13 @@
</span><span class="cx"> if (!index) {
</span><span class="cx"> valueRecoveries = Operands<ValueRecovery>(codeBlock->numParameters(), numVariables);
</span><span class="cx"> for (size_t i = 0; i < valueRecoveries.size(); ++i) {
</span><del>- valueRecoveries[i] = ValueRecovery::displacedInJSStack(
- VirtualRegister(valueRecoveries.operandForIndex(i)), DataFormatJS);
</del><ins>+ if (i < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS) {
+ valueRecoveries[i] = ValueRecovery::inGPR(
+ argumentRegisterForFunctionArgument(i), DataFormatJS);
+ } else {
+ valueRecoveries[i] = ValueRecovery::displacedInJSStack(
+ VirtualRegister(valueRecoveries.operandForIndex(i)), DataFormatJS);
+ }
</ins><span class="cx"> }
</span><span class="cx"> return;
</span><span class="cx"> }
</span><span class="lines">@@ -161,6 +166,12 @@
</span><span class="cx"> MinifiedGenerationInfo info;
</span><span class="cx"> info.update(event);
</span><span class="cx"> generationInfos.add(event.id(), info);
</span><ins>+ MinifiedNode* node = graph.at(event.id());
+ if (node && node->hasArgumentIndex()) {
+ unsigned argument = node->argumentIndex();
+ VirtualRegister argumentReg = virtualRegisterForArgument(argument);
+ operandSources.setOperand(argumentReg, ValueSource(event.id()));
+ }
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> case Fill:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGVirtualRegisterAllocationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -42,7 +42,33 @@
</span><span class="cx"> : Phase(graph, "virtual register allocation")
</span><span class="cx"> {
</span><span class="cx"> }
</span><del>-
</del><ins>+
+ void allocateRegister(ScoreBoard& scoreBoard, Node* node)
+ {
+ // First, call use on all of the current node's children, then
+ // allocate a VirtualRegister for this node. We do so in this
+ // order so that if a child is on its last use, and a
+ // VirtualRegister is freed, then it may be reused for node.
+ if (node->flags() & NodeHasVarArgs) {
+ for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); childIdx++)
+ scoreBoard.useIfHasResult(m_graph.m_varArgChildren[childIdx]);
+ } else {
+ scoreBoard.useIfHasResult(node->child1());
+ scoreBoard.useIfHasResult(node->child2());
+ scoreBoard.useIfHasResult(node->child3());
+ }
+
+ if (!node->hasResult())
+ return;
+
+ VirtualRegister virtualRegister = scoreBoard.allocate();
+ node->setVirtualRegister(virtualRegister);
+ // 'mustGenerate' nodes have their useCount artificially elevated,
+ // call use now to account for this.
+ if (node->mustGenerate())
+ scoreBoard.use(node);
+ }
+
</ins><span class="cx"> bool run()
</span><span class="cx"> {
</span><span class="cx"> DFG_ASSERT(m_graph, nullptr, m_graph.m_form == ThreadedCPS);
</span><span class="lines">@@ -59,6 +85,17 @@
</span><span class="cx"> // Force usage of highest-numbered virtual registers.
</span><span class="cx"> scoreBoard.sortFree();
</span><span class="cx"> }
</span><ins>+
+ // Handle GetArgumentRegister Nodes first as the register is alive on entry
+ // to the function and may need to be spilled before any use.
+ if (!blockIndex) {
+ for (size_t indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
+ Node* node = block->at(indexInBlock);
+ if (node->op() == GetArgumentRegister)
+ allocateRegister(scoreBoard, node);
+ }
+ }
+
</ins><span class="cx"> for (size_t indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
</span><span class="cx"> Node* node = block->at(indexInBlock);
</span><span class="cx">
</span><span class="lines">@@ -73,32 +110,14 @@
</span><span class="cx"> case GetLocal:
</span><span class="cx"> ASSERT(!node->child1()->hasResult());
</span><span class="cx"> break;
</span><ins>+ case GetArgumentRegister:
+ ASSERT(!blockIndex);
+ continue;
</ins><span class="cx"> default:
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>-
- // First, call use on all of the current node's children, then
- // allocate a VirtualRegister for this node. We do so in this
- // order so that if a child is on its last use, and a
- // VirtualRegister is freed, then it may be reused for node.
- if (node->flags() & NodeHasVarArgs) {
- for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); childIdx++)
- scoreBoard.useIfHasResult(m_graph.m_varArgChildren[childIdx]);
- } else {
- scoreBoard.useIfHasResult(node->child1());
- scoreBoard.useIfHasResult(node->child2());
- scoreBoard.useIfHasResult(node->child3());
- }
</del><span class="cx">
</span><del>- if (!node->hasResult())
- continue;
-
- VirtualRegister virtualRegister = scoreBoard.allocate();
- node->setVirtualRegister(virtualRegister);
- // 'mustGenerate' nodes have their useCount artificially elevated,
- // call use now to account for this.
- if (node->mustGenerate())
- scoreBoard.use(node);
</del><ins>+ allocateRegister(scoreBoard, node);
</ins><span class="cx"> }
</span><span class="cx"> scoreBoard.assertClear();
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -172,6 +172,7 @@
</span><span class="cx"> case GetExecutable:
</span><span class="cx"> case GetScope:
</span><span class="cx"> case GetCallee:
</span><ins>+ case GetArgumentRegister:
</ins><span class="cx"> case GetArgumentCountIncludingThis:
</span><span class="cx"> case ToNumber:
</span><span class="cx"> case ToString:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLJITCodecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLJITCode.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLJITCode.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/ftl/FTLJITCode.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -45,7 +45,8 @@
</span><span class="cx"> dataLog("Destroying FTL JIT code at ");
</span><span class="cx"> CommaPrinter comma;
</span><span class="cx"> dataLog(comma, m_b3Code);
</span><del>- dataLog(comma, m_arityCheckEntrypoint);
</del><ins>+ dataLog(comma, m_registerArgsPossibleExtraArgsEntryPoint);
+ dataLog(comma, m_registerArgsCheckArityEntryPoint);
</ins><span class="cx"> dataLog("\n");
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="lines">@@ -60,31 +61,30 @@
</span><span class="cx"> m_b3Byproducts = WTFMove(byproducts);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-void JITCode::initializeAddressForCall(CodePtr address)
</del><ins>+void JITCode::initializeEntrypointThunk(CodeRef entrypointThunk)
</ins><span class="cx"> {
</span><del>- m_addressForCall = address;
</del><ins>+ m_entrypointThunk = entrypointThunk;
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-void JITCode::initializeArityCheckEntrypoint(CodeRef entrypoint)
</del><ins>+void JITCode::setEntryFor(EntryPointType type, CodePtr entry)
</ins><span class="cx"> {
</span><del>- m_arityCheckEntrypoint = entrypoint;
</del><ins>+ m_entrypoints.setEntryFor(type, entry);
</ins><span class="cx"> }
</span><del>-
-JITCode::CodePtr JITCode::addressForCall(ArityCheckMode arityCheck)
</del><ins>+
+JITCode::CodePtr JITCode::addressForCall(EntryPointType entryType)
</ins><span class="cx"> {
</span><del>- switch (arityCheck) {
- case ArityCheckNotRequired:
- return m_addressForCall;
- case MustCheckArity:
- return m_arityCheckEntrypoint.code();
- }
- RELEASE_ASSERT_NOT_REACHED();
- return CodePtr();
</del><ins>+ CodePtr entry = m_entrypoints.entryFor(entryType);
+ RELEASE_ASSERT(entry);
+ return entry;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void* JITCode::executableAddressAtOffset(size_t offset)
</span><span class="cx"> {
</span><del>- return reinterpret_cast<char*>(m_addressForCall.executableAddress()) + offset;
</del><ins>+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ return reinterpret_cast<char*>(addressForCall(RegisterArgsArityCheckNotRequired).executableAddress()) + offset;
+#else
+ return reinterpret_cast<char*>(addressForCall(StackArgsArityCheckNotRequired).executableAddress()) + offset;
+#endif
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void* JITCode::dataAddressAtOffset(size_t)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLJITCodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLJITCode.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLJITCode.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/ftl/FTLJITCode.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -44,7 +44,7 @@
</span><span class="cx"> JITCode();
</span><span class="cx"> ~JITCode();
</span><span class="cx">
</span><del>- CodePtr addressForCall(ArityCheckMode) override;
</del><ins>+ CodePtr addressForCall(EntryPointType) override;
</ins><span class="cx"> void* executableAddressAtOffset(size_t offset) override;
</span><span class="cx"> void* dataAddressAtOffset(size_t offset) override;
</span><span class="cx"> unsigned offsetOf(void* pointerIntoCode) override;
</span><span class="lines">@@ -53,9 +53,9 @@
</span><span class="cx">
</span><span class="cx"> void initializeB3Code(CodeRef);
</span><span class="cx"> void initializeB3Byproducts(std::unique_ptr<B3::OpaqueByproducts>);
</span><del>- void initializeAddressForCall(CodePtr);
- void initializeArityCheckEntrypoint(CodeRef);
-
</del><ins>+ void initializeEntrypointThunk(CodeRef);
+ void setEntryFor(EntryPointType, CodePtr);
+
</ins><span class="cx"> void validateReferences(const TrackedReferences&) override;
</span><span class="cx">
</span><span class="cx"> RegisterSet liveRegistersToPreserveAtExceptionHandlingCallSite(CodeBlock*, CallSiteIndex) override;
</span><span class="lines">@@ -77,7 +77,12 @@
</span><span class="cx"> CodePtr m_addressForCall;
</span><span class="cx"> CodeRef m_b3Code;
</span><span class="cx"> std::unique_ptr<B3::OpaqueByproducts> m_b3Byproducts;
</span><del>- CodeRef m_arityCheckEntrypoint;
</del><ins>+ CodeRef m_entrypointThunk;
+ JITEntryPoints m_entrypoints;
+ CodePtr m_registerArgsPossibleExtraArgsEntryPoint;
+ CodePtr m_registerArgsCheckArityEntryPoint;
+ CodePtr m_stackArgsArityOKEntryPoint;
+ CodePtr m_stackArgsCheckArityEntrypoint;
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> } } // namespace JSC::FTL
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLJITFinalizercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLJITFinalizer.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLJITFinalizer.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/ftl/FTLJITFinalizer.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -76,7 +76,7 @@
</span><span class="cx"> dumpDisassembly, *b3CodeLinkBuffer,
</span><span class="cx"> ("FTL B3 code for %s", toCString(CodeBlockWithJITType(m_plan.codeBlock, JITCode::FTLJIT)).data())));
</span><span class="cx">
</span><del>- jitCode->initializeArityCheckEntrypoint(
</del><ins>+ jitCode->initializeEntrypointThunk(
</ins><span class="cx"> FINALIZE_CODE_IF(
</span><span class="cx"> dumpDisassembly, *entrypointLinkBuffer,
</span><span class="cx"> ("FTL entrypoint thunk for %s with B3 generated code at %p", toCString(CodeBlockWithJITType(m_plan.codeBlock, JITCode::FTLJIT)).data(), function)));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLinkcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLink.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLink.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/ftl/FTLLink.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -127,14 +127,110 @@
</span><span class="cx">
</span><span class="cx"> switch (graph.m_plan.mode) {
</span><span class="cx"> case FTLMode: {
</span><del>- CCallHelpers::JumpList mainPathJumps;
-
- jit.load32(
- frame.withOffset(sizeof(Register) * CallFrameSlot::argumentCount),
- GPRInfo::regT1);
- mainPathJumps.append(jit.branch32(
- CCallHelpers::AboveOrEqual, GPRInfo::regT1,
- CCallHelpers::TrustedImm32(codeBlock->numParameters())));
</del><ins>+ CCallHelpers::JumpList fillRegistersAndContinueMainPath;
+ CCallHelpers::JumpList toMainPath;
+
+ unsigned numParameters = static_cast<unsigned>(codeBlock->numParameters());
+ unsigned maxRegisterArgumentCount = std::min(numParameters, NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS);
+
+ GPRReg argCountReg = argumentRegisterForArgumentCount();
+
+ CCallHelpers::Label registerArgumentsEntrypoints[NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS + 1];
+
+ if (numParameters < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS) {
+ // Spill any extra register arguments passed to function onto the stack.
+ for (unsigned argIndex = NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS - 1; argIndex >= numParameters; argIndex--) {
+ registerArgumentsEntrypoints[argIndex + 1] = jit.label();
+ jit.emitPutArgumentToCallFrameBeforePrologue(argumentRegisterForFunctionArgument(argIndex), argIndex);
+ }
+ incrementCounter(&jit, VM::RegArgsExtra);
+ toMainPath.append(jit.jump());
+ }
+
+ CCallHelpers::JumpList continueToArityFixup;
+
+ CCallHelpers::Label stackArgsCheckArityEntry = jit.label();
+ incrementCounter(&jit, VM::StackArgsArity);
+ jit.load32(frame.withOffset(sizeof(Register) * CallFrameSlot::argumentCount), GPRInfo::regT1);
+ continueToArityFixup.append(jit.branch32(
+ CCallHelpers::Below, GPRInfo::regT1,
+ CCallHelpers::TrustedImm32(numParameters)));
+
+#if ENABLE(VM_COUNTERS)
+ CCallHelpers::Jump continueToStackArityOk = jit.jump();
+#endif
+
+ CCallHelpers::Label stackArgsArityOKEntry = jit.label();
+
+ incrementCounter(&jit, VM::StackArgsArity);
+
+#if ENABLE(VM_COUNTERS)
+ continueToStackArityOk.link(&jit);
+#endif
+
+ // Load argument values into argument registers
+
+ // FIXME: Would like to eliminate these to load, but we currently can't jump into
+ // the B3 compiled code at an arbitrary point from the slow entry where the
+ // registers are stored to the stack.
+ jit.emitGetFromCallFrameHeaderBeforePrologue(CallFrameSlot::callee, argumentRegisterForCallee());
+ jit.emitGetPayloadFromCallFrameHeaderBeforePrologue(CallFrameSlot::argumentCount, argumentRegisterForArgumentCount());
+
+ for (unsigned argIndex = 0; argIndex < maxRegisterArgumentCount; argIndex++)
+ jit.emitGetFromCallFrameArgumentBeforePrologue(argIndex, argumentRegisterForFunctionArgument(argIndex));
+
+ toMainPath.append(jit.jump());
+
+ CCallHelpers::Label registerArgsCheckArityEntry = jit.label();
+ incrementCounter(&jit, VM::RegArgsArity);
+
+ CCallHelpers::JumpList continueToRegisterArityFixup;
+ CCallHelpers::Label checkForExtraRegisterArguments;
+
+ if (numParameters < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS) {
+ toMainPath.append(jit.branch32(
+ CCallHelpers::Equal, argCountReg, CCallHelpers::TrustedImm32(numParameters)));
+ continueToRegisterArityFixup.append(jit.branch32(
+ CCallHelpers::Below, argCountReg, CCallHelpers::TrustedImm32(numParameters)));
+ // Fall through to the "extra register arity" case.
+
+ checkForExtraRegisterArguments = jit.label();
+ // Spill any extra register arguments passed to function onto the stack.
+ for (unsigned argIndex = numParameters; argIndex < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS; argIndex++) {
+ toMainPath.append(jit.branch32(CCallHelpers::BelowOrEqual, argCountReg, CCallHelpers::TrustedImm32(argIndex)));
+ jit.emitPutArgumentToCallFrameBeforePrologue(argumentRegisterForFunctionArgument(argIndex), argIndex);
+ }
+
+ incrementCounter(&jit, VM::RegArgsExtra);
+ toMainPath.append(jit.jump());
+ } else
+ toMainPath.append(jit.branch32(
+ CCallHelpers::AboveOrEqual, argCountReg, CCallHelpers::TrustedImm32(numParameters)));
+
+#if ENABLE(VM_COUNTERS)
+ continueToRegisterArityFixup.append(jit.jump());
+#endif
+
+ if (numParameters > 0) {
+ // There should always be a "this" parameter.
+ CCallHelpers::Label registerArgumentsNeedArityFixup = jit.label();
+
+ for (unsigned argIndex = 1; argIndex < numParameters && argIndex <= maxRegisterArgumentCount; argIndex++)
+ registerArgumentsEntrypoints[argIndex] = registerArgumentsNeedArityFixup;
+ }
+
+#if ENABLE(VM_COUNTERS)
+ incrementCounter(&jit, VM::RegArgsArity);
+#endif
+
+ continueToRegisterArityFixup.link(&jit);
+
+ jit.spillArgumentRegistersToFrameBeforePrologue(maxRegisterArgumentCount);
+
+ continueToArityFixup.link(&jit);
+
+ incrementCounter(&jit, VM::ArityFixupRequired);
+
</ins><span class="cx"> jit.emitFunctionPrologue();
</span><span class="cx"> jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
</span><span class="cx"> jit.storePtr(GPRInfo::callFrameRegister, &vm.topCallFrame);
</span><span class="lines">@@ -155,12 +251,21 @@
</span><span class="cx">
</span><span class="cx"> jit.move(GPRInfo::returnValueGPR, GPRInfo::argumentGPR0);
</span><span class="cx"> jit.emitFunctionEpilogue();
</span><del>- mainPathJumps.append(jit.branchTest32(CCallHelpers::Zero, GPRInfo::argumentGPR0));
</del><ins>+ fillRegistersAndContinueMainPath.append(jit.branchTest32(CCallHelpers::Zero, GPRInfo::argumentGPR0));
</ins><span class="cx"> jit.emitFunctionPrologue();
</span><span class="cx"> CCallHelpers::Call callArityFixup = jit.call();
</span><span class="cx"> jit.emitFunctionEpilogue();
</span><del>- mainPathJumps.append(jit.jump());
</del><span class="cx">
</span><ins>+ fillRegistersAndContinueMainPath.append(jit.jump());
+
+ fillRegistersAndContinueMainPath.linkTo(stackArgsArityOKEntry, &jit);
+
+#if ENABLE(VM_COUNTERS)
+ CCallHelpers::Label registerEntryNoArity = jit.label();
+ incrementCounter(&jit, VM::RegArgsNoArity);
+ toMainPath.append(jit.jump());
+#endif
+
</ins><span class="cx"> linkBuffer = std::make_unique<LinkBuffer>(vm, jit, codeBlock, JITCompilationCanFail);
</span><span class="cx"> if (linkBuffer->didFailToAllocate()) {
</span><span class="cx"> state.allocationFailed = true;
</span><span class="lines">@@ -169,9 +274,35 @@
</span><span class="cx"> linkBuffer->link(callArityCheck, codeBlock->m_isConstructor ? operationConstructArityCheck : operationCallArityCheck);
</span><span class="cx"> linkBuffer->link(callLookupExceptionHandlerFromCallerFrame, lookupExceptionHandlerFromCallerFrame);
</span><span class="cx"> linkBuffer->link(callArityFixup, FunctionPtr((vm.getCTIStub(arityFixupGenerator)).code().executableAddress()));
</span><del>- linkBuffer->link(mainPathJumps, CodeLocationLabel(bitwise_cast<void*>(state.generatedFunction)));
</del><ins>+ linkBuffer->link(toMainPath, CodeLocationLabel(bitwise_cast<void*>(state.generatedFunction)));
</ins><span class="cx">
</span><del>- state.jitCode->initializeAddressForCall(MacroAssemblerCodePtr(bitwise_cast<void*>(state.generatedFunction)));
</del><ins>+ state.jitCode->setEntryFor(StackArgsMustCheckArity, linkBuffer->locationOf(stackArgsCheckArityEntry));
+ state.jitCode->setEntryFor(StackArgsArityCheckNotRequired, linkBuffer->locationOf(stackArgsArityOKEntry));
+
+#if ENABLE(VM_COUNTERS)
+ MacroAssemblerCodePtr mainEntry = linkBuffer->locationOf(registerEntryNoArity);
+#else
+ MacroAssemblerCodePtr mainEntry = MacroAssemblerCodePtr(bitwise_cast<void*>(state.generatedFunction));
+#endif
+ state.jitCode->setEntryFor(RegisterArgsArityCheckNotRequired, mainEntry);
+
+ if (checkForExtraRegisterArguments.isSet())
+ state.jitCode->setEntryFor(RegisterArgsPossibleExtraArgs, linkBuffer->locationOf(checkForExtraRegisterArguments));
+ else
+ state.jitCode->setEntryFor(RegisterArgsPossibleExtraArgs, mainEntry);
+
+ state.jitCode->setEntryFor(RegisterArgsMustCheckArity, linkBuffer->locationOf(registerArgsCheckArityEntry));
+
+ for (unsigned argCount = 1; argCount <= NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS; argCount++) {
+ MacroAssemblerCodePtr entry;
+ if (argCount == numParameters)
+ entry = mainEntry;
+ else if (registerArgumentsEntrypoints[argCount].isSet())
+ entry = linkBuffer->locationOf(registerArgumentsEntrypoints[argCount]);
+ else
+ entry = linkBuffer->locationOf(registerArgsCheckArityEntry);
+ state.jitCode->setEntryFor(JITEntryPoints::registerEntryTypeForArgumentCount(argCount), entry);
+ }
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -181,7 +312,20 @@
</span><span class="cx"> // point we've even done the stack check. Basically we just have to make the
</span><span class="cx"> // call to the B3-generated code.
</span><span class="cx"> CCallHelpers::Label start = jit.label();
</span><ins>+
</ins><span class="cx"> jit.emitFunctionEpilogue();
</span><ins>+
+ // Load argument values into argument registers
+
+ // FIXME: Would like to eliminate these to load, but we currently can't jump into
+ // the B3 compiled code at an arbitrary point from the slow entry where the
+ // registers are stored to the stack.
+ jit.emitGetFromCallFrameHeaderBeforePrologue(CallFrameSlot::callee, argumentRegisterForCallee());
+ jit.emitGetPayloadFromCallFrameHeaderBeforePrologue(CallFrameSlot::argumentCount, argumentRegisterForArgumentCount());
+
+ for (unsigned argIndex = 0; argIndex < static_cast<unsigned>(codeBlock->numParameters()) && argIndex < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS; argIndex++)
+ jit.emitGetFromCallFrameArgumentBeforePrologue(argIndex, argumentRegisterForFunctionArgument(argIndex));
+
</ins><span class="cx"> CCallHelpers::Jump mainPathJump = jit.jump();
</span><span class="cx">
</span><span class="cx"> linkBuffer = std::make_unique<LinkBuffer>(vm, jit, codeBlock, JITCompilationCanFail);
</span><span class="lines">@@ -191,7 +335,7 @@
</span><span class="cx"> }
</span><span class="cx"> linkBuffer->link(mainPathJump, CodeLocationLabel(bitwise_cast<void*>(state.generatedFunction)));
</span><span class="cx">
</span><del>- state.jitCode->initializeAddressForCall(linkBuffer->locationOf(start));
</del><ins>+ state.jitCode->setEntryFor(RegisterArgsArityCheckNotRequired, linkBuffer->locationOf(start));
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -196,6 +196,10 @@
</span><span class="cx"> m_proc.addFastConstant(m_tagTypeNumber->key());
</span><span class="cx"> m_proc.addFastConstant(m_tagMask->key());
</span><span class="cx">
</span><ins>+ // Store out callee and argument count for possible OSR exit.
+ m_out.store64(m_out.argumentRegister(argumentRegisterForCallee()), addressFor(CallFrameSlot::callee));
+ m_out.store32(m_out.argumentRegisterInt32(argumentRegisterForArgumentCount()), payloadFor(CallFrameSlot::argumentCount));
+
</ins><span class="cx"> m_out.storePtr(m_out.constIntPtr(codeBlock()), addressFor(CallFrameSlot::codeBlock));
</span><span class="cx">
</span><span class="cx"> // Stack Overflow Check.
</span><span class="lines">@@ -247,20 +251,34 @@
</span><span class="cx"> // Check Arguments.
</span><span class="cx"> availabilityMap().clear();
</span><span class="cx"> availabilityMap().m_locals = Operands<Availability>(codeBlock()->numParameters(), 0);
</span><ins>+
+ Vector<Node*, 8> argumentNodes;
+ Vector<LValue, 8> argumentValues;
+
+ argumentNodes.resize(codeBlock()->numParameters());
+ argumentValues.resize(codeBlock()->numParameters());
+
+ m_highBlock = m_graph.block(0);
+
</ins><span class="cx"> for (unsigned i = codeBlock()->numParameters(); i--;) {
</span><del>- availabilityMap().m_locals.argument(i) =
- Availability(FlushedAt(FlushedJSValue, virtualRegisterForArgument(i)));
- }
- m_node = nullptr;
- m_origin = NodeOrigin(CodeOrigin(0), CodeOrigin(0), true);
- for (unsigned i = codeBlock()->numParameters(); i--;) {
- Node* node = m_graph.m_arguments[i];
</del><ins>+ Node* node = m_graph.m_argumentsForChecking[i];
</ins><span class="cx"> VirtualRegister operand = virtualRegisterForArgument(i);
</span><span class="cx">
</span><del>- LValue jsValue = m_out.load64(addressFor(operand));
</del><ins>+ LValue jsValue = nullptr;
+
+ if (node) {
+ if (i < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS) {
+ availabilityMap().m_locals.argument(i) = Availability(node);
+ jsValue = m_out.argumentRegister(GPRInfo::toArgumentRegister(node->argumentRegisterIndex()));
+
+ setJSValue(node, jsValue);
+ } else {
+ availabilityMap().m_locals.argument(i) =
+ Availability(FlushedAt(FlushedJSValue, operand));
+ jsValue = m_out.load64(addressFor(virtualRegisterForArgument(i)));
+ }
</ins><span class="cx">
</span><del>- if (node) {
- DFG_ASSERT(m_graph, node, operand == node->stackAccessData()->machineLocal);
</del><ins>+ DFG_ASSERT(m_graph, node, node->hasArgumentRegisterIndex() || operand == node->stackAccessData()->machineLocal);
</ins><span class="cx">
</span><span class="cx"> // This is a hack, but it's an effective one. It allows us to do CSE on the
</span><span class="cx"> // primordial load of arguments. This assumes that the GetLocal that got put in
</span><span class="lines">@@ -268,7 +286,21 @@
</span><span class="cx"> // should hold true.
</span><span class="cx"> m_loadedArgumentValues.add(node, jsValue);
</span><span class="cx"> }
</span><ins>+
+ argumentNodes[i] = node;
+ argumentValues[i] = jsValue;
+ }
+
+ m_node = nullptr;
+ m_origin = NodeOrigin(CodeOrigin(0), CodeOrigin(0), true);
+ for (unsigned i = codeBlock()->numParameters(); i--;) {
+ Node* node = argumentNodes[i];
</ins><span class="cx">
</span><ins>+ if (!node)
+ continue;
+
+ LValue jsValue = argumentValues[i];
+
</ins><span class="cx"> switch (m_graph.m_argumentFormats[i]) {
</span><span class="cx"> case FlushedInt32:
</span><span class="cx"> speculate(BadType, jsValueValue(jsValue), node, isNotInt32(jsValue));
</span><span class="lines">@@ -813,6 +845,9 @@
</span><span class="cx"> case GetArgumentCountIncludingThis:
</span><span class="cx"> compileGetArgumentCountIncludingThis();
</span><span class="cx"> break;
</span><ins>+ case GetArgumentRegister:
+ compileGetArgumentRegister();
+ break;
</ins><span class="cx"> case GetScope:
</span><span class="cx"> compileGetScope();
</span><span class="cx"> break;
</span><span class="lines">@@ -5402,6 +5437,16 @@
</span><span class="cx"> setInt32(m_out.load32(payloadFor(CallFrameSlot::argumentCount)));
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ void compileGetArgumentRegister()
+ {
+ // We might have already have a value for this node.
+ if (LValue value = m_loadedArgumentValues.get(m_node)) {
+ setJSValue(value);
+ return;
+ }
+ setJSValue(m_out.argumentRegister(GPRInfo::toArgumentRegister(m_node->argumentRegisterIndex())));
+ }
+
</ins><span class="cx"> void compileGetScope()
</span><span class="cx"> {
</span><span class="cx"> setJSValue(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSFunction_scope));
</span><span class="lines">@@ -5814,9 +5859,10 @@
</span><span class="cx"> // the call.
</span><span class="cx"> Vector<ConstrainedValue> arguments;
</span><span class="cx">
</span><del>- // Make sure that the callee goes into GPR0 because that's where the slow path thunks expect the
- // callee to be.
- arguments.append(ConstrainedValue(jsCallee, ValueRep::reg(GPRInfo::regT0)));
</del><ins>+ // Make sure that the callee goes into argumentRegisterForCallee() because that's where
+ // the slow path thunks expect the callee to be.
+ GPRReg calleeReg = argumentRegisterForCallee();
+ arguments.append(ConstrainedValue(jsCallee, ValueRep::reg(calleeReg)));
</ins><span class="cx">
</span><span class="cx"> auto addArgument = [&] (LValue value, VirtualRegister reg, int offset) {
</span><span class="cx"> intptr_t offsetFromSP =
</span><span class="lines">@@ -5824,11 +5870,17 @@
</span><span class="cx"> arguments.append(ConstrainedValue(value, ValueRep::stackArgument(offsetFromSP)));
</span><span class="cx"> };
</span><span class="cx">
</span><del>- addArgument(jsCallee, VirtualRegister(CallFrameSlot::callee), 0);
- addArgument(m_out.constInt32(numArgs), VirtualRegister(CallFrameSlot::argumentCount), PayloadOffset);
- for (unsigned i = 0; i < numArgs; ++i)
- addArgument(lowJSValue(m_graph.varArgChild(node, 1 + i)), virtualRegisterForArgument(i), 0);
</del><ins>+ ArgumentsLocation argLocation = argumentsLocationFor(numArgs);
+ arguments.append(ConstrainedValue(jsCallee, ValueRep::reg(calleeReg)));
+ arguments.append(ConstrainedValue(m_out.constInt32(numArgs), ValueRep::reg(argumentRegisterForArgumentCount())));
</ins><span class="cx">
</span><ins>+ for (unsigned i = 0; i < numArgs; ++i) {
+ if (i < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS)
+ arguments.append(ConstrainedValue(lowJSValue(m_graph.varArgChild(node, 1 + i)), ValueRep::reg(argumentRegisterForFunctionArgument(i))));
+ else
+ addArgument(lowJSValue(m_graph.varArgChild(node, 1 + i)), virtualRegisterForArgument(i), 0);
+ }
+
</ins><span class="cx"> PatchpointValue* patchpoint = m_out.patchpoint(Int64);
</span><span class="cx"> patchpoint->appendVector(arguments);
</span><span class="cx">
</span><span class="lines">@@ -5856,9 +5908,11 @@
</span><span class="cx">
</span><span class="cx"> CallLinkInfo* callLinkInfo = jit.codeBlock()->addCallLinkInfo();
</span><span class="cx">
</span><ins>+ incrementCounter(&jit, VM::FTLCaller);
+
</ins><span class="cx"> CCallHelpers::DataLabelPtr targetToCheck;
</span><span class="cx"> CCallHelpers::Jump slowPath = jit.branchPtrWithPatch(
</span><del>- CCallHelpers::NotEqual, GPRInfo::regT0, targetToCheck,
</del><ins>+ CCallHelpers::NotEqual, calleeReg, targetToCheck,
</ins><span class="cx"> CCallHelpers::TrustedImmPtr(0));
</span><span class="cx">
</span><span class="cx"> CCallHelpers::Call fastCall = jit.nearCall();
</span><span class="lines">@@ -5866,13 +5920,13 @@
</span><span class="cx">
</span><span class="cx"> slowPath.link(&jit);
</span><span class="cx">
</span><del>- jit.move(CCallHelpers::TrustedImmPtr(callLinkInfo), GPRInfo::regT2);
</del><ins>+ jit.move(CCallHelpers::TrustedImmPtr(callLinkInfo), GPRInfo::nonArgGPR0);
</ins><span class="cx"> CCallHelpers::Call slowCall = jit.nearCall();
</span><span class="cx"> done.link(&jit);
</span><span class="cx">
</span><span class="cx"> callLinkInfo->setUpCall(
</span><span class="cx"> node->op() == Construct ? CallLinkInfo::Construct : CallLinkInfo::Call,
</span><del>- node->origin.semantic, GPRInfo::regT0);
</del><ins>+ argLocation, node->origin.semantic, argumentRegisterForCallee());
</ins><span class="cx">
</span><span class="cx"> jit.addPtr(
</span><span class="cx"> CCallHelpers::TrustedImm32(-params.proc().frameSize()),
</span><span class="lines">@@ -5881,7 +5935,7 @@
</span><span class="cx"> jit.addLinkTask(
</span><span class="cx"> [=] (LinkBuffer& linkBuffer) {
</span><span class="cx"> MacroAssemblerCodePtr linkCall =
</span><del>- linkBuffer.vm().getCTIStub(linkCallThunkGenerator).code();
</del><ins>+ linkBuffer.vm().getJITCallThunkEntryStub(linkCallThunkGenerator).entryFor(callLinkInfo->argumentsLocation());
</ins><span class="cx"> linkBuffer.link(slowCall, FunctionPtr(linkCall.executableAddress()));
</span><span class="cx">
</span><span class="cx"> callLinkInfo->setCallLocations(
</span><span class="lines">@@ -5925,7 +5979,10 @@
</span><span class="cx">
</span><span class="cx"> Vector<ConstrainedValue> arguments;
</span><span class="cx">
</span><del>- arguments.append(ConstrainedValue(jsCallee, ValueRep::SomeRegister));
</del><ins>+ // Make sure that the callee goes into argumentRegisterForCallee() because that's where
+ // the slow path thunks expect the callee to be.
+ GPRReg calleeReg = argumentRegisterForCallee();
+ arguments.append(ConstrainedValue(jsCallee, ValueRep::reg(calleeReg)));
</ins><span class="cx"> if (!isTail) {
</span><span class="cx"> auto addArgument = [&] (LValue value, VirtualRegister reg, int offset) {
</span><span class="cx"> intptr_t offsetFromSP =
</span><span class="lines">@@ -5932,13 +5989,28 @@
</span><span class="cx"> (reg.offset() - CallerFrameAndPC::sizeInRegisters) * sizeof(EncodedJSValue) + offset;
</span><span class="cx"> arguments.append(ConstrainedValue(value, ValueRep::stackArgument(offsetFromSP)));
</span><span class="cx"> };
</span><del>-
</del><ins>+
+ arguments.append(ConstrainedValue(jsCallee, ValueRep::reg(calleeReg)));
+#if ENABLE(CALLER_SPILLS_CALLEE)
</ins><span class="cx"> addArgument(jsCallee, VirtualRegister(CallFrameSlot::callee), 0);
</span><ins>+#endif
+ arguments.append(ConstrainedValue(m_out.constInt32(numPassedArgs), ValueRep::reg(argumentRegisterForArgumentCount())));
+#if ENABLE(CALLER_SPILLS_ARGCOUNT)
</ins><span class="cx"> addArgument(m_out.constInt32(numPassedArgs), VirtualRegister(CallFrameSlot::argumentCount), PayloadOffset);
</span><del>- for (unsigned i = 0; i < numPassedArgs; ++i)
- addArgument(lowJSValue(m_graph.varArgChild(node, 1 + i)), virtualRegisterForArgument(i), 0);
- for (unsigned i = numPassedArgs; i < numAllocatedArgs; ++i)
- addArgument(m_out.constInt64(JSValue::encode(jsUndefined())), virtualRegisterForArgument(i), 0);
</del><ins>+#endif
+
+ for (unsigned i = 0; i < numPassedArgs; ++i) {
+ if (i < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS)
+ arguments.append(ConstrainedValue(lowJSValue(m_graph.varArgChild(node, 1 + i)), ValueRep::reg(argumentRegisterForFunctionArgument(i))));
+ else
+ addArgument(lowJSValue(m_graph.varArgChild(node, 1 + i)), virtualRegisterForArgument(i), 0);
+ }
+ for (unsigned i = numPassedArgs; i < numAllocatedArgs; ++i) {
+ if (i < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS)
+ arguments.append(ConstrainedValue(m_out.constInt64(JSValue::encode(jsUndefined())), ValueRep::reg(argumentRegisterForFunctionArgument(i))));
+ else
+ addArgument(m_out.constInt64(JSValue::encode(jsUndefined())), virtualRegisterForArgument(i), 0);
+ }
</ins><span class="cx"> } else {
</span><span class="cx"> for (unsigned i = 0; i < numPassedArgs; ++i)
</span><span class="cx"> arguments.append(ConstrainedValue(lowJSValue(m_graph.varArgChild(node, 1 + i)), ValueRep::WarmAny));
</span><span class="lines">@@ -5980,6 +6052,7 @@
</span><span class="cx"> shuffleData.numLocals = state->jitCode->common.frameRegisterCount;
</span><span class="cx">
</span><span class="cx"> RegisterSet toSave = params.unavailableRegisters();
</span><ins>+ shuffleData.argumentsInRegisters = true;
</ins><span class="cx"> shuffleData.callee = ValueRecovery::inGPR(calleeGPR, DataFormatCell);
</span><span class="cx"> toSave.set(calleeGPR);
</span><span class="cx"> for (unsigned i = 0; i < numPassedArgs; ++i) {
</span><span class="lines">@@ -5998,7 +6071,11 @@
</span><span class="cx">
</span><span class="cx"> CCallHelpers::PatchableJump patchableJump = jit.patchableJump();
</span><span class="cx"> CCallHelpers::Label mainPath = jit.label();
</span><del>-
</del><ins>+
+ incrementCounter(&jit, VM::FTLCaller);
+ incrementCounter(&jit, VM::TailCall);
+ incrementCounter(&jit, VM::DirectCall);
+
</ins><span class="cx"> jit.store32(
</span><span class="cx"> CCallHelpers::TrustedImm32(callSiteIndex.bits()),
</span><span class="cx"> CCallHelpers::tagFor(VirtualRegister(CallFrameSlot::argumentCount)));
</span><span class="lines">@@ -6019,7 +6096,7 @@
</span><span class="cx"> jit.jump().linkTo(mainPath, &jit);
</span><span class="cx">
</span><span class="cx"> callLinkInfo->setUpCall(
</span><del>- CallLinkInfo::DirectTailCall, node->origin.semantic, InvalidGPRReg);
</del><ins>+ CallLinkInfo::DirectTailCall, argumentsLocationFor(numPassedArgs), node->origin.semantic, InvalidGPRReg);
</ins><span class="cx"> callLinkInfo->setExecutableDuringCompilation(executable);
</span><span class="cx"> if (numAllocatedArgs > numPassedArgs)
</span><span class="cx"> callLinkInfo->setMaxNumArguments(numAllocatedArgs);
</span><span class="lines">@@ -6042,6 +6119,9 @@
</span><span class="cx">
</span><span class="cx"> CCallHelpers::Label mainPath = jit.label();
</span><span class="cx">
</span><ins>+ incrementCounter(&jit, VM::FTLCaller);
+ incrementCounter(&jit, VM::DirectCall);
+
</ins><span class="cx"> jit.store32(
</span><span class="cx"> CCallHelpers::TrustedImm32(callSiteIndex.bits()),
</span><span class="cx"> CCallHelpers::tagFor(VirtualRegister(CallFrameSlot::argumentCount)));
</span><span class="lines">@@ -6053,7 +6133,7 @@
</span><span class="cx">
</span><span class="cx"> callLinkInfo->setUpCall(
</span><span class="cx"> isConstruct ? CallLinkInfo::DirectConstruct : CallLinkInfo::DirectCall,
</span><del>- node->origin.semantic, InvalidGPRReg);
</del><ins>+ argumentsLocationFor(numPassedArgs), node->origin.semantic, InvalidGPRReg);
</ins><span class="cx"> callLinkInfo->setExecutableDuringCompilation(executable);
</span><span class="cx"> if (numAllocatedArgs > numPassedArgs)
</span><span class="cx"> callLinkInfo->setMaxNumArguments(numAllocatedArgs);
</span><span class="lines">@@ -6064,13 +6144,11 @@
</span><span class="cx">
</span><span class="cx"> CCallHelpers::Label slowPath = jit.label();
</span><span class="cx"> if (isX86())
</span><del>- jit.pop(CCallHelpers::selectScratchGPR(calleeGPR));
-
- callOperation(
- *state, params.unavailableRegisters(), jit,
- node->origin.semantic, exceptions.get(), operationLinkDirectCall,
- InvalidGPRReg, CCallHelpers::TrustedImmPtr(callLinkInfo),
- calleeGPR).call();
</del><ins>+ jit.pop(GPRInfo::nonArgGPR0);
+
+ jit.move(CCallHelpers::TrustedImmPtr(callLinkInfo), GPRInfo::nonArgGPR0); // Link info needs to be in nonArgGPR0
+ CCallHelpers::Call slowCall = jit.nearCall();
+ exceptions->append(jit.emitExceptionCheck(AssemblyHelpers::NormalExceptionCheck, AssemblyHelpers::FarJumpWidth));
</ins><span class="cx"> jit.jump().linkTo(mainPath, &jit);
</span><span class="cx">
</span><span class="cx"> jit.addLinkTask(
</span><span class="lines">@@ -6079,6 +6157,9 @@
</span><span class="cx"> CodeLocationLabel slowPathLocation = linkBuffer.locationOf(slowPath);
</span><span class="cx">
</span><span class="cx"> linkBuffer.link(call, slowPathLocation);
</span><ins>+ MacroAssemblerCodePtr linkCall =
+ linkBuffer.vm().getJITCallThunkEntryStub(linkDirectCallThunkGenerator).entryFor(callLinkInfo->argumentsLocation());
+ linkBuffer.link(slowCall, FunctionPtr(linkCall.executableAddress()));
</ins><span class="cx">
</span><span class="cx"> callLinkInfo->setCallLocations(
</span><span class="cx"> CodeLocationLabel(),
</span><span class="lines">@@ -6110,7 +6191,8 @@
</span><span class="cx">
</span><span class="cx"> Vector<ConstrainedValue> arguments;
</span><span class="cx">
</span><del>- arguments.append(ConstrainedValue(jsCallee, ValueRep::reg(GPRInfo::regT0)));
</del><ins>+ GPRReg calleeReg = argumentRegisterForCallee();
+ arguments.append(ConstrainedValue(jsCallee, ValueRep::reg(calleeReg)));
</ins><span class="cx">
</span><span class="cx"> for (unsigned i = 0; i < numArgs; ++i) {
</span><span class="cx"> // Note: we could let the shuffler do boxing for us, but it's not super clear that this
</span><span class="lines">@@ -6144,6 +6226,9 @@
</span><span class="cx"> AllowMacroScratchRegisterUsage allowScratch(jit);
</span><span class="cx"> CallSiteIndex callSiteIndex = state->jitCode->common.addUniqueCallSiteIndex(codeOrigin);
</span><span class="cx">
</span><ins>+ incrementCounter(&jit, VM::FTLCaller);
+ incrementCounter(&jit, VM::TailCall);
+
</ins><span class="cx"> // Yes, this is really necessary. You could throw an exception in a host call on the
</span><span class="cx"> // slow path. That'll route us to lookupExceptionHandler(), which unwinds starting
</span><span class="cx"> // with the call site index of our frame. Bad things happen if it's not set.
</span><span class="lines">@@ -6152,8 +6237,9 @@
</span><span class="cx"> CCallHelpers::tagFor(VirtualRegister(CallFrameSlot::argumentCount)));
</span><span class="cx">
</span><span class="cx"> CallFrameShuffleData shuffleData;
</span><ins>+ shuffleData.argumentsInRegisters = true;
</ins><span class="cx"> shuffleData.numLocals = state->jitCode->common.frameRegisterCount;
</span><del>- shuffleData.callee = ValueRecovery::inGPR(GPRInfo::regT0, DataFormatJS);
</del><ins>+ shuffleData.callee = ValueRecovery::inGPR(calleeReg, DataFormatJS);
</ins><span class="cx">
</span><span class="cx"> for (unsigned i = 0; i < numArgs; ++i)
</span><span class="cx"> shuffleData.args.append(params[1 + i].recoveryForJSValue());
</span><span class="lines">@@ -6164,7 +6250,7 @@
</span><span class="cx">
</span><span class="cx"> CCallHelpers::DataLabelPtr targetToCheck;
</span><span class="cx"> CCallHelpers::Jump slowPath = jit.branchPtrWithPatch(
</span><del>- CCallHelpers::NotEqual, GPRInfo::regT0, targetToCheck,
</del><ins>+ CCallHelpers::NotEqual, calleeReg, targetToCheck,
</ins><span class="cx"> CCallHelpers::TrustedImmPtr(0));
</span><span class="cx">
</span><span class="cx"> callLinkInfo->setFrameShuffleData(shuffleData);
</span><span class="lines">@@ -6175,20 +6261,19 @@
</span><span class="cx"> slowPath.link(&jit);
</span><span class="cx">
</span><span class="cx"> CallFrameShuffler slowPathShuffler(jit, shuffleData);
</span><del>- slowPathShuffler.setCalleeJSValueRegs(JSValueRegs(GPRInfo::regT0));
</del><span class="cx"> slowPathShuffler.prepareForSlowPath();
</span><span class="cx">
</span><del>- jit.move(CCallHelpers::TrustedImmPtr(callLinkInfo), GPRInfo::regT2);
</del><ins>+ jit.move(CCallHelpers::TrustedImmPtr(callLinkInfo), GPRInfo::nonArgGPR0);
</ins><span class="cx"> CCallHelpers::Call slowCall = jit.nearCall();
</span><span class="cx">
</span><span class="cx"> jit.abortWithReason(JITDidReturnFromTailCall);
</span><span class="cx">
</span><del>- callLinkInfo->setUpCall(CallLinkInfo::TailCall, codeOrigin, GPRInfo::regT0);
</del><ins>+ callLinkInfo->setUpCall(CallLinkInfo::TailCall, argumentsLocationFor(numArgs), codeOrigin, calleeReg);
</ins><span class="cx">
</span><span class="cx"> jit.addLinkTask(
</span><span class="cx"> [=] (LinkBuffer& linkBuffer) {
</span><span class="cx"> MacroAssemblerCodePtr linkCall =
</span><del>- linkBuffer.vm().getCTIStub(linkCallThunkGenerator).code();
</del><ins>+ linkBuffer.vm().getJITCallThunkEntryStub(linkCallThunkGenerator).entryFor(callLinkInfo->argumentsLocation());
</ins><span class="cx"> linkBuffer.link(slowCall, FunctionPtr(linkCall.executableAddress()));
</span><span class="cx">
</span><span class="cx"> callLinkInfo->setCallLocations(
</span><span class="lines">@@ -6278,6 +6363,7 @@
</span><span class="cx"> CCallHelpers::tagFor(VirtualRegister(CallFrameSlot::argumentCount)));
</span><span class="cx">
</span><span class="cx"> CallLinkInfo* callLinkInfo = jit.codeBlock()->addCallLinkInfo();
</span><ins>+ ArgumentsLocation argumentsLocation = StackArgs;
</ins><span class="cx">
</span><span class="cx"> RegisterSet usedRegisters = RegisterSet::allRegisters();
</span><span class="cx"> usedRegisters.exclude(RegisterSet::volatileRegistersForJSCall());
</span><span class="lines">@@ -6427,7 +6513,7 @@
</span><span class="cx"> if (isTailCall)
</span><span class="cx"> jit.emitRestoreCalleeSaves();
</span><span class="cx"> ASSERT(!usedRegisters.get(GPRInfo::regT2));
</span><del>- jit.move(CCallHelpers::TrustedImmPtr(callLinkInfo), GPRInfo::regT2);
</del><ins>+ jit.move(CCallHelpers::TrustedImmPtr(callLinkInfo), GPRInfo::nonArgGPR0);
</ins><span class="cx"> CCallHelpers::Call slowCall = jit.nearCall();
</span><span class="cx">
</span><span class="cx"> if (isTailCall)
</span><span class="lines">@@ -6435,7 +6521,7 @@
</span><span class="cx"> else
</span><span class="cx"> done.link(&jit);
</span><span class="cx">
</span><del>- callLinkInfo->setUpCall(callType, node->origin.semantic, GPRInfo::regT0);
</del><ins>+ callLinkInfo->setUpCall(callType, argumentsLocation, node->origin.semantic, GPRInfo::regT0);
</ins><span class="cx">
</span><span class="cx"> jit.addPtr(
</span><span class="cx"> CCallHelpers::TrustedImm32(-originalStackHeight),
</span><span class="lines">@@ -6444,7 +6530,7 @@
</span><span class="cx"> jit.addLinkTask(
</span><span class="cx"> [=] (LinkBuffer& linkBuffer) {
</span><span class="cx"> MacroAssemblerCodePtr linkCall =
</span><del>- linkBuffer.vm().getCTIStub(linkCallThunkGenerator).code();
</del><ins>+ linkBuffer.vm().getJITCallThunkEntryStub(linkCallThunkGenerator).entryFor(StackArgs);
</ins><span class="cx"> linkBuffer.link(slowCall, FunctionPtr(linkCall.executableAddress()));
</span><span class="cx">
</span><span class="cx"> callLinkInfo->setCallLocations(
</span><span class="lines">@@ -6545,11 +6631,15 @@
</span><span class="cx">
</span><span class="cx"> exceptionHandle->scheduleExitCreationForUnwind(params, callSiteIndex);
</span><span class="cx">
</span><ins>+ incrementCounter(&jit, VM::FTLCaller);
+ incrementCounter(&jit, VM::CallVarargs);
+
</ins><span class="cx"> jit.store32(
</span><span class="cx"> CCallHelpers::TrustedImm32(callSiteIndex.bits()),
</span><span class="cx"> CCallHelpers::tagFor(VirtualRegister(CallFrameSlot::argumentCount)));
</span><span class="cx">
</span><span class="cx"> CallLinkInfo* callLinkInfo = jit.codeBlock()->addCallLinkInfo();
</span><ins>+ ArgumentsLocation argumentsLocation = StackArgs;
</ins><span class="cx"> CallVarargsData* data = node->callVarargsData();
</span><span class="cx">
</span><span class="cx"> unsigned argIndex = 1;
</span><span class="lines">@@ -6710,7 +6800,7 @@
</span><span class="cx">
</span><span class="cx"> if (isTailCall)
</span><span class="cx"> jit.emitRestoreCalleeSaves();
</span><del>- jit.move(CCallHelpers::TrustedImmPtr(callLinkInfo), GPRInfo::regT2);
</del><ins>+ jit.move(CCallHelpers::TrustedImmPtr(callLinkInfo), GPRInfo::nonArgGPR0);
</ins><span class="cx"> CCallHelpers::Call slowCall = jit.nearCall();
</span><span class="cx">
</span><span class="cx"> if (isTailCall)
</span><span class="lines">@@ -6718,7 +6808,7 @@
</span><span class="cx"> else
</span><span class="cx"> done.link(&jit);
</span><span class="cx">
</span><del>- callLinkInfo->setUpCall(callType, node->origin.semantic, GPRInfo::regT0);
</del><ins>+ callLinkInfo->setUpCall(callType, argumentsLocation, node->origin.semantic, GPRInfo::regT0);
</ins><span class="cx">
</span><span class="cx"> jit.addPtr(
</span><span class="cx"> CCallHelpers::TrustedImm32(-originalStackHeight),
</span><span class="lines">@@ -6727,7 +6817,7 @@
</span><span class="cx"> jit.addLinkTask(
</span><span class="cx"> [=] (LinkBuffer& linkBuffer) {
</span><span class="cx"> MacroAssemblerCodePtr linkCall =
</span><del>- linkBuffer.vm().getCTIStub(linkCallThunkGenerator).code();
</del><ins>+ linkBuffer.vm().getJITCallThunkEntryStub(linkCallThunkGenerator).entryFor(StackArgs);
</ins><span class="cx"> linkBuffer.link(slowCall, FunctionPtr(linkCall.executableAddress()));
</span><span class="cx">
</span><span class="cx"> callLinkInfo->setCallLocations(
</span><span class="lines">@@ -6796,13 +6886,16 @@
</span><span class="cx"> Box<CCallHelpers::JumpList> exceptions = exceptionHandle->scheduleExitCreation(params)->jumps(jit);
</span><span class="cx">
</span><span class="cx"> exceptionHandle->scheduleExitCreationForUnwind(params, callSiteIndex);
</span><del>-
</del><ins>+
+ incrementCounter(&jit, VM::FTLCaller);
+ incrementCounter(&jit, VM::CallEval);
+
</ins><span class="cx"> jit.store32(
</span><span class="cx"> CCallHelpers::TrustedImm32(callSiteIndex.bits()),
</span><span class="cx"> CCallHelpers::tagFor(VirtualRegister(CallFrameSlot::argumentCount)));
</span><span class="cx">
</span><span class="cx"> CallLinkInfo* callLinkInfo = jit.codeBlock()->addCallLinkInfo();
</span><del>- callLinkInfo->setUpCall(CallLinkInfo::Call, node->origin.semantic, GPRInfo::regT0);
</del><ins>+ callLinkInfo->setUpCall(CallLinkInfo::Call, StackArgs, node->origin.semantic, GPRInfo::regT0);
</ins><span class="cx">
</span><span class="cx"> jit.addPtr(CCallHelpers::TrustedImm32(-static_cast<ptrdiff_t>(sizeof(CallerFrameAndPC))), CCallHelpers::stackPointerRegister, GPRInfo::regT1);
</span><span class="cx"> jit.storePtr(GPRInfo::callFrameRegister, CCallHelpers::Address(GPRInfo::regT1, CallFrame::callerFrameOffset()));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLOSREntrycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLOSREntry.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLOSREntry.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/ftl/FTLOSREntry.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -71,7 +71,11 @@
</span><span class="cx"> if (Options::verboseOSR())
</span><span class="cx"> dataLog(" Values at entry: ", values, "\n");
</span><span class="cx">
</span><del>- for (int argument = values.numberOfArguments(); argument--;) {
</del><ins>+ for (unsigned argument = values.numberOfArguments(); argument--;) {
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ if (argument < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS)
+ break;
+#endif
</ins><span class="cx"> JSValue valueOnStack = exec->r(virtualRegisterForArgument(argument).offset()).asanUnsafeJSValue();
</span><span class="cx"> JSValue reconstructedValue = values.argument(argument);
</span><span class="cx"> if (valueOnStack == reconstructedValue || !argument)
</span><span class="lines">@@ -99,8 +103,12 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> exec->setCodeBlock(entryCodeBlock);
</span><del>-
- void* result = entryCode->addressForCall(ArityCheckNotRequired).executableAddress();
</del><ins>+
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ void* result = entryCode->addressForCall(RegisterArgsArityCheckNotRequired).executableAddress();
+#else
+ void* result = entryCode->addressForCall(StackArgsArityCheckNotRequired).executableAddress();
+#endif
</ins><span class="cx"> if (Options::verboseOSR())
</span><span class="cx"> dataLog(" Entry will succeed, going to address", RawPointer(result), "\n");
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLOutputcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLOutput.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLOutput.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/ftl/FTLOutput.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -89,6 +89,16 @@
</span><span class="cx"> m_block = block;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+LValue Output::argumentRegister(Reg reg)
+{
+ return m_block->appendNew<ArgumentRegValue>(m_proc, origin(), reg);
+}
+
+LValue Output::argumentRegisterInt32(Reg reg)
+{
+ return m_block->appendNew<ArgumentRegValue>(m_proc, origin(), reg, Int32);
+}
+
</ins><span class="cx"> LValue Output::framePointer()
</span><span class="cx"> {
</span><span class="cx"> return m_block->appendNew<B3::Value>(m_proc, B3::FramePointer, origin());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLOutputh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLOutput.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLOutput.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/ftl/FTLOutput.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -98,6 +98,8 @@
</span><span class="cx"> void setOrigin(DFG::Node* node) { m_origin = node; }
</span><span class="cx"> B3::Origin origin() { return B3::Origin(m_origin); }
</span><span class="cx">
</span><ins>+ LValue argumentRegister(Reg reg);
+ LValue argumentRegisterInt32(Reg reg);
</ins><span class="cx"> LValue framePointer();
</span><span class="cx">
</span><span class="cx"> B3::SlotBaseValue* lockedStackSlot(size_t bytes);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinterpreterShadowChickencpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/interpreter/ShadowChicken.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/interpreter/ShadowChicken.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/interpreter/ShadowChicken.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -297,16 +297,24 @@
</span><span class="cx"> bool foundFrame = advanceIndexInLogTo(callFrame, callFrame->jsCallee(), callFrame->callerFrame());
</span><span class="cx"> bool isTailDeleted = false;
</span><span class="cx"> JSScope* scope = nullptr;
</span><ins>+ JSValue thisValue = jsUndefined();
</ins><span class="cx"> CodeBlock* codeBlock = callFrame->codeBlock();
</span><del>- if (codeBlock && codeBlock->wasCompiledWithDebuggingOpcodes() && codeBlock->scopeRegister().isValid()) {
- scope = callFrame->scope(codeBlock->scopeRegister().offset());
- RELEASE_ASSERT(scope->inherits(JSScope::info()));
</del><ins>+ if (codeBlock && codeBlock->wasCompiledWithDebuggingOpcodes()) {
+ if (codeBlock->scopeRegister().isValid()) {
+ scope = callFrame->scope(codeBlock->scopeRegister().offset());
+ RELEASE_ASSERT(scope->inherits(JSScope::info()));
+ }
+ thisValue = callFrame->thisValue();
</ins><span class="cx"> } else if (foundFrame) {
</span><del>- scope = m_log[indexInLog].scope;
- if (scope)
- RELEASE_ASSERT(scope->inherits(JSScope::info()));
</del><ins>+ if (!scope) {
+ scope = m_log[indexInLog].scope;
+ if (scope)
+ RELEASE_ASSERT(scope->inherits(JSScope::info()));
+ }
+ if (thisValue.isUndefined())
+ thisValue = m_log[indexInLog].thisValue;
</ins><span class="cx"> }
</span><del>- toPush.append(Frame(jsCast<JSObject*>(visitor->callee()), callFrame, isTailDeleted, callFrame->thisValue(), scope, codeBlock, callFrame->callSiteIndex()));
</del><ins>+ toPush.append(Frame(jsCast<JSObject*>(visitor->callee()), callFrame, isTailDeleted, thisValue, scope, codeBlock, callFrame->callSiteIndex()));
</ins><span class="cx">
</span><span class="cx"> if (indexInLog < logCursorIndex
</span><span class="cx"> // This condition protects us from the case where advanceIndexInLogTo didn't find
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitAssemblyHelperscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -616,13 +616,13 @@
</span><span class="cx">
</span><span class="cx"> void AssemblyHelpers::emitDumbVirtualCall(CallLinkInfo* info)
</span><span class="cx"> {
</span><del>- move(TrustedImmPtr(info), GPRInfo::regT2);
</del><ins>+ move(TrustedImmPtr(info), GPRInfo::nonArgGPR0);
</ins><span class="cx"> Call call = nearCall();
</span><span class="cx"> addLinkTask(
</span><span class="cx"> [=] (LinkBuffer& linkBuffer) {
</span><del>- MacroAssemblerCodeRef virtualThunk = virtualThunkFor(&linkBuffer.vm(), *info);
- info->setSlowStub(createJITStubRoutine(virtualThunk, linkBuffer.vm(), nullptr, true));
- linkBuffer.link(call, CodeLocationLabel(virtualThunk.code()));
</del><ins>+ JITJSCallThunkEntryPointsWithRef virtualThunk = virtualThunkFor(&linkBuffer.vm(), *info);
+ info->setSlowStub(createJITStubRoutine(virtualThunk.codeRef(), linkBuffer.vm(), nullptr, true));
+ linkBuffer.link(call, CodeLocationLabel(virtualThunk.entryFor(StackArgs)));
</ins><span class="cx"> });
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitAssemblyHelpersh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -414,6 +414,89 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ enum SpillRegisterType { SpillAll, SpillExactly };
+
+ void spillArgumentRegistersToFrameBeforePrologue(unsigned minimumArgsToSpill = 0, SpillRegisterType spillType = SpillAll)
+ {
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ JumpList doneStoringArgs;
+
+ emitPutToCallFrameHeaderBeforePrologue(argumentRegisterForCallee(), CallFrameSlot::callee);
+ GPRReg argCountReg = argumentRegisterForArgumentCount();
+ emitPutToCallFrameHeaderBeforePrologue(argCountReg, CallFrameSlot::argumentCount);
+
+ unsigned argIndex = 0;
+ // Always spill "this"
+ minimumArgsToSpill = std::max(minimumArgsToSpill, 1U);
+
+ for (; argIndex < minimumArgsToSpill && argIndex < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS; argIndex++)
+ emitPutArgumentToCallFrameBeforePrologue(argumentRegisterForFunctionArgument(argIndex), argIndex);
+
+ if (spillType == SpillAll) {
+ // Spill extra args passed to function
+ for (; argIndex < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS; argIndex++) {
+ doneStoringArgs.append(branch32(MacroAssembler::BelowOrEqual, argCountReg, MacroAssembler::TrustedImm32(argIndex)));
+ emitPutArgumentToCallFrameBeforePrologue(argumentRegisterForFunctionArgument(argIndex), argIndex);
+ }
+ }
+
+ doneStoringArgs.link(this);
+#else
+ UNUSED_PARAM(minimumArgsToSpill);
+ UNUSED_PARAM(spillType);
+#endif
+ }
+
+ void spillArgumentRegistersToFrame(unsigned minimumArgsToSpill = 0, SpillRegisterType spillType = SpillAll)
+ {
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ JumpList doneStoringArgs;
+
+ emitPutToCallFrameHeader(argumentRegisterForCallee(), CallFrameSlot::callee);
+ GPRReg argCountReg = argumentRegisterForArgumentCount();
+ emitPutToCallFrameHeader(argCountReg, CallFrameSlot::argumentCount);
+
+ unsigned argIndex = 0;
+ // Always spill "this"
+ minimumArgsToSpill = std::max(minimumArgsToSpill, 1U);
+
+ for (; argIndex < minimumArgsToSpill && argIndex < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS; argIndex++)
+ emitPutArgumentToCallFrame(argumentRegisterForFunctionArgument(argIndex), argIndex);
+
+ if (spillType == SpillAll) {
+ // Spill extra args passed to function
+ for (; argIndex < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS; argIndex++) {
+ doneStoringArgs.append(branch32(MacroAssembler::BelowOrEqual, argCountReg, MacroAssembler::TrustedImm32(argIndex)));
+ emitPutArgumentToCallFrame(argumentRegisterForFunctionArgument(argIndex), argIndex);
+ }
+ }
+
+ doneStoringArgs.link(this);
+#else
+ UNUSED_PARAM(minimumArgsToSpill);
+ UNUSED_PARAM(spillType);
+#endif
+ }
+
+ void fillArgumentRegistersFromFrameBeforePrologue()
+ {
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ JumpList doneLoadingArgs;
+
+ emitGetFromCallFrameHeaderBeforePrologue(CallFrameSlot::callee, argumentRegisterForCallee());
+ GPRReg argCountReg = argumentRegisterForArgumentCount();
+ emitGetPayloadFromCallFrameHeaderBeforePrologue(CallFrameSlot::argumentCount, argCountReg);
+
+ for (unsigned argIndex = 0; argIndex < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS; argIndex++) {
+ if (argIndex) // Always load "this"
+ doneLoadingArgs.append(branch32(MacroAssembler::BelowOrEqual, argCountReg, MacroAssembler::TrustedImm32(argIndex)));
+ emitGetFromCallFrameArgumentBeforePrologue(argIndex, argumentRegisterForFunctionArgument(argIndex));
+ }
+
+ doneLoadingArgs.link(this);
+#endif
+ }
+
</ins><span class="cx"> #if CPU(X86_64) || CPU(X86)
</span><span class="cx"> static size_t prologueStackPointerDelta()
</span><span class="cx"> {
</span><span class="lines">@@ -624,6 +707,31 @@
</span><span class="cx"> {
</span><span class="cx"> storePtr(from, Address(stackPointerRegister, entry * static_cast<ptrdiff_t>(sizeof(Register)) - prologueStackPointerDelta()));
</span><span class="cx"> }
</span><ins>+
+ void emitPutArgumentToCallFrameBeforePrologue(GPRReg from, unsigned argument)
+ {
+ storePtr(from, Address(stackPointerRegister, (CallFrameSlot::thisArgument + argument) * static_cast<ptrdiff_t>(sizeof(Register)) - prologueStackPointerDelta()));
+ }
+
+ void emitPutArgumentToCallFrame(GPRReg from, unsigned argument)
+ {
+ emitPutToCallFrameHeader(from, CallFrameSlot::thisArgument + argument);
+ }
+
+ void emitGetFromCallFrameHeaderBeforePrologue(const int entry, GPRReg to)
+ {
+ loadPtr(Address(stackPointerRegister, entry * static_cast<ptrdiff_t>(sizeof(Register)) - prologueStackPointerDelta()), to);
+ }
+
+ void emitGetFromCallFrameArgumentBeforePrologue(unsigned argument, GPRReg to)
+ {
+ loadPtr(Address(stackPointerRegister, (CallFrameSlot::thisArgument + argument) * static_cast<ptrdiff_t>(sizeof(Register)) - prologueStackPointerDelta()), to);
+ }
+
+ void emitGetPayloadFromCallFrameHeaderBeforePrologue(const int entry, GPRReg to)
+ {
+ load32(Address(stackPointerRegister, entry * static_cast<ptrdiff_t>(sizeof(Register)) - prologueStackPointerDelta() + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), to);
+ }
</ins><span class="cx"> #else
</span><span class="cx"> void emitPutPayloadToCallFrameHeaderBeforePrologue(GPRReg from, int entry)
</span><span class="cx"> {
</span><span class="lines">@@ -1660,7 +1768,14 @@
</span><span class="cx"> #if USE(JSVALUE64)
</span><span class="cx"> void wangsInt64Hash(GPRReg inputAndResult, GPRReg scratch);
</span><span class="cx"> #endif
</span><del>-
</del><ins>+
+#if ENABLE(VM_COUNTERS)
+ void incrementCounter(VM::VMCounterType counterType)
+ {
+ addPtr(TrustedImm32(1), AbsoluteAddress(vm()->addressOfCounter(counterType)));
+ }
+#endif
+
</ins><span class="cx"> protected:
</span><span class="cx"> VM* m_vm;
</span><span class="cx"> CodeBlock* m_codeBlock;
</span><span class="lines">@@ -1669,6 +1784,12 @@
</span><span class="cx"> HashMap<CodeBlock*, Vector<BytecodeAndMachineOffset>> m_decodedCodeMaps;
</span><span class="cx"> };
</span><span class="cx">
</span><ins>+#if ENABLE(VM_COUNTERS)
+#define incrementCounter(jit, counterType) (jit)->incrementCounter(counterType)
+#else
+#define incrementCounter(jit, counterType) ((void)0)
+#endif
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx">
</span><span class="cx"> #endif // ENABLE(JIT)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitCachedRecoverycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/CachedRecovery.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/CachedRecovery.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/CachedRecovery.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -30,6 +30,26 @@
</span><span class="cx">
</span><span class="cx"> namespace JSC {
</span><span class="cx">
</span><ins>+void CachedRecovery::addTargetJSValueRegs(JSValueRegs jsValueRegs)
+{
+ ASSERT(m_wantedFPR == InvalidFPRReg);
+ size_t existing = m_gprTargets.find(jsValueRegs);
+ if (existing == WTF::notFound) {
+#if USE(JSVALUE64)
+ if (m_gprTargets.size() > 0 && m_recovery.isSet() && m_recovery.isInGPR()) {
+ // If we are recovering to the same GPR, make that GPR the first target.
+ GPRReg sourceGPR = m_recovery.gpr();
+ if (jsValueRegs.gpr() == sourceGPR) {
+ // Append the current first GPR below.
+ jsValueRegs = JSValueRegs(m_gprTargets[0].gpr());
+ m_gprTargets[0] = JSValueRegs(sourceGPR);
+ }
+ }
+#endif
+ m_gprTargets.append(jsValueRegs);
+ }
+}
+
</ins><span class="cx"> // We prefer loading doubles and undetermined JSValues into FPRs
</span><span class="cx"> // because it would otherwise use up GPRs. Two in JSVALUE32_64.
</span><span class="cx"> bool CachedRecovery::loadsIntoFPR() const
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitCachedRecoveryh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/CachedRecovery.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/CachedRecovery.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/CachedRecovery.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -50,6 +50,7 @@
</span><span class="cx"> CachedRecovery& operator=(CachedRecovery&&) = delete;
</span><span class="cx">
</span><span class="cx"> const Vector<VirtualRegister, 1>& targets() const { return m_targets; }
</span><ins>+ const Vector<JSValueRegs, 1>& gprTargets() const { return m_gprTargets; }
</ins><span class="cx">
</span><span class="cx"> void addTarget(VirtualRegister reg)
</span><span class="cx"> {
</span><span class="lines">@@ -68,15 +69,11 @@
</span><span class="cx"> m_targets.clear();
</span><span class="cx"> }
</span><span class="cx">
</span><del>- void setWantedJSValueRegs(JSValueRegs jsValueRegs)
- {
- ASSERT(m_wantedFPR == InvalidFPRReg);
- m_wantedJSValueRegs = jsValueRegs;
- }
</del><ins>+ void addTargetJSValueRegs(JSValueRegs);
</ins><span class="cx">
</span><span class="cx"> void setWantedFPR(FPRReg fpr)
</span><span class="cx"> {
</span><del>- ASSERT(!m_wantedJSValueRegs);
</del><ins>+ ASSERT(m_gprTargets.isEmpty());
</ins><span class="cx"> m_wantedFPR = fpr;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -119,14 +116,20 @@
</span><span class="cx">
</span><span class="cx"> void setRecovery(ValueRecovery recovery) { m_recovery = recovery; }
</span><span class="cx">
</span><del>- JSValueRegs wantedJSValueRegs() const { return m_wantedJSValueRegs; }
</del><ins>+ JSValueRegs wantedJSValueRegs() const
+ {
+ if (m_gprTargets.isEmpty())
+ return JSValueRegs();
</ins><span class="cx">
</span><ins>+ return m_gprTargets[0];
+ }
+
</ins><span class="cx"> FPRReg wantedFPR() const { return m_wantedFPR; }
</span><span class="cx"> private:
</span><span class="cx"> ValueRecovery m_recovery;
</span><del>- JSValueRegs m_wantedJSValueRegs;
</del><span class="cx"> FPRReg m_wantedFPR { InvalidFPRReg };
</span><span class="cx"> Vector<VirtualRegister, 1> m_targets;
</span><ins>+ Vector<JSValueRegs, 1> m_gprTargets;
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitCallFrameShuffleDatah"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/CallFrameShuffleData.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/CallFrameShuffleData.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/CallFrameShuffleData.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -39,6 +39,7 @@
</span><span class="cx"> ValueRecovery callee;
</span><span class="cx"> Vector<ValueRecovery> args;
</span><span class="cx"> #if USE(JSVALUE64)
</span><ins>+ bool argumentsInRegisters { false };
</ins><span class="cx"> RegisterMap<ValueRecovery> registers;
</span><span class="cx"> GPRReg tagTypeNumber { InvalidGPRReg };
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitCallFrameShufflercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/CallFrameShuffler.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/CallFrameShuffler.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/CallFrameShuffler.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -42,6 +42,9 @@
</span><span class="cx"> + roundArgumentCountToAlignFrame(jit.codeBlock()->numParameters()))
</span><span class="cx"> , m_alignedNewFrameSize(CallFrame::headerSizeInRegisters
</span><span class="cx"> + roundArgumentCountToAlignFrame(data.args.size()))
</span><ins>+#if USE(JSVALUE64)
+ , m_argumentsInRegisters(data.argumentsInRegisters)
+#endif
</ins><span class="cx"> , m_frameDelta(m_alignedNewFrameSize - m_alignedOldFrameSize)
</span><span class="cx"> , m_lockedRegisters(RegisterSet::allRegisters())
</span><span class="cx"> {
</span><span class="lines">@@ -54,11 +57,21 @@
</span><span class="cx"> m_lockedRegisters.exclude(RegisterSet::vmCalleeSaveRegisters());
</span><span class="cx">
</span><span class="cx"> ASSERT(!data.callee.isInJSStack() || data.callee.virtualRegister().isLocal());
</span><del>- addNew(VirtualRegister(CallFrameSlot::callee), data.callee);
-
</del><ins>+#if USE(JSVALUE64)
+ if (data.argumentsInRegisters)
+ addNew(JSValueRegs(argumentRegisterForCallee()), data.callee);
+ else
+#endif
+ addNew(VirtualRegister(CallFrameSlot::callee), data.callee);
+
</ins><span class="cx"> for (size_t i = 0; i < data.args.size(); ++i) {
</span><span class="cx"> ASSERT(!data.args[i].isInJSStack() || data.args[i].virtualRegister().isLocal());
</span><del>- addNew(virtualRegisterForArgument(i), data.args[i]);
</del><ins>+#if USE(JSVALUE64)
+ if (data.argumentsInRegisters && i < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS)
+ addNew(JSValueRegs(argumentRegisterForFunctionArgument(i)), data.args[i]);
+ else
+#endif
+ addNew(virtualRegisterForArgument(i), data.args[i]);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> #if USE(JSVALUE64)
</span><span class="lines">@@ -185,8 +198,13 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx"> #else
</span><del>- if (newCachedRecovery)
</del><ins>+ if (newCachedRecovery) {
</ins><span class="cx"> out.print(" ", reg, " <- ", newCachedRecovery->recovery());
</span><ins>+ if (newCachedRecovery->gprTargets().size() > 1) {
+ for (size_t i = 1; i < newCachedRecovery->gprTargets().size(); i++)
+ out.print(", ", newCachedRecovery->gprTargets()[i].gpr(), " <- ", newCachedRecovery->recovery());
+ }
+ }
</ins><span class="cx"> #endif
</span><span class="cx"> out.print("\n");
</span><span class="cx"> }
</span><span class="lines">@@ -496,7 +514,7 @@
</span><span class="cx"> ASSERT(cachedRecovery.recovery().isInRegisters()
</span><span class="cx"> || cachedRecovery.recovery().isConstant());
</span><span class="cx">
</span><del>- if (verbose)
</del><ins>+ if (verbose && cachedRecovery.targets().size())
</ins><span class="cx"> dataLog(" * Storing ", cachedRecovery.recovery());
</span><span class="cx"> for (size_t i = 0; i < cachedRecovery.targets().size(); ++i) {
</span><span class="cx"> VirtualRegister target { cachedRecovery.targets()[i] };
</span><span class="lines">@@ -505,9 +523,9 @@
</span><span class="cx"> dataLog(!i ? " into " : ", and ", "NEW ", target);
</span><span class="cx"> emitStore(cachedRecovery, addressForNew(target));
</span><span class="cx"> setNew(target, nullptr);
</span><ins>+ if (verbose)
+ dataLog("\n");
</ins><span class="cx"> }
</span><del>- if (verbose)
- dataLog("\n");
</del><span class="cx"> cachedRecovery.clearTargets();
</span><span class="cx"> if (!cachedRecovery.wantedJSValueRegs() && cachedRecovery.wantedFPR() == InvalidFPRReg)
</span><span class="cx"> clearCachedRecovery(cachedRecovery.recovery());
</span><span class="lines">@@ -606,7 +624,7 @@
</span><span class="cx"> {
</span><span class="cx"> ASSERT(!isUndecided());
</span><span class="cx">
</span><del>- updateDangerFrontier();
</del><ins>+ initDangerFrontier();
</ins><span class="cx">
</span><span class="cx"> // First, we try to store any value that goes above the danger
</span><span class="cx"> // frontier. This will never use more registers since we are only
</span><span class="lines">@@ -702,13 +720,9 @@
</span><span class="cx"> ASSERT_UNUSED(writesOK, writesOK);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-#if USE(JSVALUE64)
- if (m_tagTypeNumber != InvalidGPRReg && m_newRegisters[m_tagTypeNumber])
- releaseGPR(m_tagTypeNumber);
-#endif
-
</del><span class="cx"> // Handle 2) by loading all registers. We don't have to do any
</span><span class="cx"> // writes, since they have been taken care of above.
</span><ins>+ // Note that we need m_tagTypeNumber to remain locked to box wanted registers.
</ins><span class="cx"> if (verbose)
</span><span class="cx"> dataLog(" Loading wanted registers into registers\n");
</span><span class="cx"> for (Reg reg = Reg::first(); reg <= Reg::last(); reg = reg.next()) {
</span><span class="lines">@@ -742,13 +756,22 @@
</span><span class="cx">
</span><span class="cx"> // We need to handle 4) first because it implies releasing
</span><span class="cx"> // m_newFrameBase, which could be a wanted register.
</span><ins>+ // Note that we delay setting the argument count register as it needs to be released in step 3.
</ins><span class="cx"> if (verbose)
</span><span class="cx"> dataLog(" * Storing the argument count into ", VirtualRegister { CallFrameSlot::argumentCount }, "\n");
</span><ins>+
</ins><span class="cx"> m_jit.store32(MacroAssembler::TrustedImm32(0),
</span><span class="cx"> addressForNew(VirtualRegister { CallFrameSlot::argumentCount }).withOffset(TagOffset));
</span><del>- m_jit.store32(MacroAssembler::TrustedImm32(argCount()),
- addressForNew(VirtualRegister { CallFrameSlot::argumentCount }).withOffset(PayloadOffset));
</del><span class="cx">
</span><ins>+#if USE(JSVALUE64)
+ if (!m_argumentsInRegisters) {
+#endif
+ m_jit.store32(MacroAssembler::TrustedImm32(argCount()),
+ addressForNew(VirtualRegister { CallFrameSlot::argumentCount }).withOffset(PayloadOffset));
+#if USE(JSVALUE64)
+ }
+#endif
+
</ins><span class="cx"> if (!isSlowPath()) {
</span><span class="cx"> ASSERT(m_newFrameBase != MacroAssembler::stackPointerRegister);
</span><span class="cx"> if (verbose)
</span><span class="lines">@@ -767,6 +790,23 @@
</span><span class="cx">
</span><span class="cx"> emitDisplace(*cachedRecovery);
</span><span class="cx"> }
</span><ins>+
+#if USE(JSVALUE64)
+ // For recoveries with multiple register targets, copy the contents of the first target to the
+ // remaining targets.
+ for (Reg reg = Reg::first(); reg <= Reg::last(); reg = reg.next()) {
+ CachedRecovery* cachedRecovery { m_newRegisters[reg] };
+ if (!cachedRecovery || cachedRecovery->gprTargets().size() < 2)
+ continue;
+
+ GPRReg sourceGPR = cachedRecovery->gprTargets()[0].gpr();
+ for (size_t i = 1; i < cachedRecovery->gprTargets().size(); i++)
+ m_jit.move(sourceGPR, cachedRecovery->gprTargets()[i].gpr());
+ }
+
+ if (m_argumentsInRegisters)
+ m_jit.move(MacroAssembler::TrustedImm32(argCount()), argumentRegisterForArgumentCount());
+#endif
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitCallFrameShufflerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/CallFrameShuffler.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/CallFrameShuffler.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/CallFrameShuffler.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -96,17 +96,57 @@
</span><span class="cx"> // contains information about where the
</span><span class="cx"> // arguments/callee/callee-save registers are by taking into
</span><span class="cx"> // account any spilling that acquireGPR() could have done.
</span><del>- CallFrameShuffleData snapshot() const
</del><ins>+ CallFrameShuffleData snapshot(ArgumentsLocation argumentsLocation) const
</ins><span class="cx"> {
</span><span class="cx"> ASSERT(isUndecided());
</span><span class="cx">
</span><span class="cx"> CallFrameShuffleData data;
</span><span class="cx"> data.numLocals = numLocals();
</span><del>- data.callee = getNew(VirtualRegister { CallFrameSlot::callee })->recovery();
</del><ins>+#if USE(JSVALUE64)
+ data.argumentsInRegisters = argumentsLocation != StackArgs;
+#endif
+ if (argumentsLocation == StackArgs)
+ data.callee = getNew(VirtualRegister { CallFrameSlot::callee })->recovery();
+ else {
+ Reg reg { argumentRegisterForCallee() };
+ CachedRecovery* cachedRecovery { m_newRegisters[reg] };
+ data.callee = cachedRecovery->recovery();
+ }
</ins><span class="cx"> data.args.resize(argCount());
</span><del>- for (size_t i = 0; i < argCount(); ++i)
- data.args[i] = getNew(virtualRegisterForArgument(i))->recovery();
</del><ins>+
+ Vector<ValueRecovery> registerArgRecoveries;
+#if USE(JSVALUE64)
+ // Find cached recoveries for all argument registers.
+ // We do this here, because a cached recovery may be the source for multiple
+ // argument registers, but it is only stored in one m_newRegister index.
+ if (data.argumentsInRegisters) {
+ unsigned maxArgumentRegister = std::min(static_cast<unsigned>(argCount()), NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS);
+ registerArgRecoveries.resize(maxArgumentRegister);
+ for (size_t i = 0; i < maxArgumentRegister; ++i) {
+ Reg reg { argumentRegisterForFunctionArgument(i) };
+ CachedRecovery* cachedRecovery { m_newRegisters[reg] };
+ if (cachedRecovery) {
+ for (auto jsValueReg : cachedRecovery->gprTargets())
+ registerArgRecoveries[jsFunctionArgumentForArgumentRegister(jsValueReg.gpr())] = cachedRecovery->recovery();
+ }
+ }
+ }
+#endif
+
+ for (size_t i = 0; i < argCount(); ++i) {
+ if (argumentsLocation == StackArgs || i >= NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS)
+ data.args[i] = getNew(virtualRegisterForArgument(i))->recovery();
+ else {
+ Reg reg { argumentRegisterForFunctionArgument(i) };
+ ASSERT(registerArgRecoveries[i]);
+ data.args[i] = registerArgRecoveries[i];
+ }
+ }
</ins><span class="cx"> for (Reg reg = Reg::first(); reg <= Reg::last(); reg = reg.next()) {
</span><ins>+ if (reg.isGPR() && argumentsLocation != StackArgs
+ && GPRInfo::toArgumentIndex(reg.gpr()) < argumentRegisterIndexForJSFunctionArgument(argCount()))
+ continue;
+
</ins><span class="cx"> CachedRecovery* cachedRecovery { m_newRegisters[reg] };
</span><span class="cx"> if (!cachedRecovery)
</span><span class="cx"> continue;
</span><span class="lines">@@ -376,6 +416,9 @@
</span><span class="cx">
</span><span class="cx"> int m_alignedOldFrameSize;
</span><span class="cx"> int m_alignedNewFrameSize;
</span><ins>+#if USE(JSVALUE64)
+ bool m_argumentsInRegisters;
+#endif
</ins><span class="cx">
</span><span class="cx"> // This is the distance, in slots, between the base of the new
</span><span class="cx"> // frame and the base of the old frame. It could be negative when
</span><span class="lines">@@ -417,15 +460,22 @@
</span><span class="cx"> bool tryAcquireTagTypeNumber();
</span><span class="cx"> #endif
</span><span class="cx">
</span><del>- // This stores, for each register, information about the recovery
- // for the value that should eventually go into that register. The
- // only registers that have a target recovery will be callee-save
- // registers, as well as possibly one JSValueRegs for holding the
- // callee.
</del><ins>+ // This stores information about the recovery for the value that
+ // should eventually go into that register. In some cases there
+ // are recoveries that have multiple targets. For those recoveries,
+ // only the first target register in the map has the recovery.
+ // We optimize the case where there are multiple targets for one
+ // recovery where one of those targets is also the source register.
+ // Restoring the first target becomes a nop and simplifies the logic
+ // of restoring the remaining targets.
</ins><span class="cx"> //
</span><span class="cx"> // Once the correct value has been put into the registers, and
</span><span class="cx"> // contrary to what we do with m_newFrame, we keep the entry in
</span><span class="cx"> // m_newRegisters to simplify spilling.
</span><ins>+ //
+ // If a recovery has multiple target registers, we copy the value
+ // from the first target register to the remaining target registers
+ // at the end of the shuffling process.
</ins><span class="cx"> RegisterMap<CachedRecovery*> m_newRegisters;
</span><span class="cx">
</span><span class="cx"> template<typename CheckFunctor>
</span><span class="lines">@@ -641,9 +691,13 @@
</span><span class="cx"> ASSERT(jsValueRegs && !getNew(jsValueRegs));
</span><span class="cx"> CachedRecovery* cachedRecovery = addCachedRecovery(recovery);
</span><span class="cx"> #if USE(JSVALUE64)
</span><del>- if (cachedRecovery->wantedJSValueRegs())
- m_newRegisters[cachedRecovery->wantedJSValueRegs().gpr()] = nullptr;
- m_newRegisters[jsValueRegs.gpr()] = cachedRecovery;
</del><ins>+ if (cachedRecovery->wantedJSValueRegs()) {
+ if (recovery.isInGPR() && jsValueRegs.gpr() == recovery.gpr()) {
+ m_newRegisters[cachedRecovery->wantedJSValueRegs().gpr()] = nullptr;
+ m_newRegisters[jsValueRegs.gpr()] = cachedRecovery;
+ }
+ } else
+ m_newRegisters[jsValueRegs.gpr()] = cachedRecovery;
</ins><span class="cx"> #else
</span><span class="cx"> if (JSValueRegs oldRegs { cachedRecovery->wantedJSValueRegs() }) {
</span><span class="cx"> if (oldRegs.payloadGPR())
</span><span class="lines">@@ -656,8 +710,7 @@
</span><span class="cx"> if (jsValueRegs.tagGPR() != InvalidGPRReg)
</span><span class="cx"> m_newRegisters[jsValueRegs.tagGPR()] = cachedRecovery;
</span><span class="cx"> #endif
</span><del>- ASSERT(!cachedRecovery->wantedJSValueRegs());
- cachedRecovery->setWantedJSValueRegs(jsValueRegs);
</del><ins>+ cachedRecovery->addTargetJSValueRegs(jsValueRegs);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void addNew(FPRReg fpr, ValueRecovery recovery)
</span><span class="lines">@@ -755,13 +808,23 @@
</span><span class="cx"> return reg <= dangerFrontier();
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ void initDangerFrontier()
+ {
+ findDangerFrontierFrom(lastNew());
+ }
+
</ins><span class="cx"> void updateDangerFrontier()
</span><span class="cx"> {
</span><ins>+ findDangerFrontierFrom(m_dangerFrontier - 1);
+ }
+
+ void findDangerFrontierFrom(VirtualRegister nextReg)
+ {
</ins><span class="cx"> ASSERT(!isUndecided());
</span><span class="cx">
</span><span class="cx"> m_dangerFrontier = firstNew() - 1;
</span><del>- for (VirtualRegister reg = lastNew(); reg >= firstNew(); reg -= 1) {
- if (!getNew(reg) || !isValidOld(newAsOld(reg)) || !getOld(newAsOld(reg)))
</del><ins>+ for (VirtualRegister reg = nextReg; reg >= firstNew(); reg -= 1) {
+ if (!isValidOld(newAsOld(reg)) || !getOld(newAsOld(reg)))
</ins><span class="cx"> continue;
</span><span class="cx">
</span><span class="cx"> m_dangerFrontier = reg;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitCallFrameShuffler64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/CallFrameShuffler64.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/CallFrameShuffler64.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/CallFrameShuffler64.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -323,7 +323,8 @@
</span><span class="cx"> m_jit.move(cachedRecovery.recovery().gpr(), wantedReg.gpr());
</span><span class="cx"> else
</span><span class="cx"> m_jit.move64ToDouble(cachedRecovery.recovery().gpr(), wantedReg.fpr());
</span><del>- RELEASE_ASSERT(cachedRecovery.recovery().dataFormat() == DataFormatJS);
</del><ins>+ DataFormat format = cachedRecovery.recovery().dataFormat();
+ RELEASE_ASSERT(format == DataFormatJS || format == DataFormatCell);
</ins><span class="cx"> updateRecovery(cachedRecovery,
</span><span class="cx"> ValueRecovery::inRegister(wantedReg, DataFormatJS));
</span><span class="cx"> } else {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitGPRInfoh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/GPRInfo.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/GPRInfo.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/GPRInfo.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -69,8 +69,8 @@
</span><span class="cx"> bool operator!() const { return m_gpr == InvalidGPRReg; }
</span><span class="cx"> explicit operator bool() const { return m_gpr != InvalidGPRReg; }
</span><span class="cx">
</span><del>- bool operator==(JSValueRegs other) { return m_gpr == other.m_gpr; }
- bool operator!=(JSValueRegs other) { return !(*this == other); }
</del><ins>+ bool operator==(JSValueRegs other) const { return m_gpr == other.m_gpr; }
+ bool operator!=(JSValueRegs other) const { return !(*this == other); }
</ins><span class="cx">
</span><span class="cx"> GPRReg gpr() const { return m_gpr; }
</span><span class="cx"> GPRReg tagGPR() const { return InvalidGPRReg; }
</span><span class="lines">@@ -331,6 +331,7 @@
</span><span class="cx">
</span><span class="cx"> #if CPU(X86)
</span><span class="cx"> #define NUMBER_OF_ARGUMENT_REGISTERS 0u
</span><ins>+#define NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS 0u
</ins><span class="cx"> #define NUMBER_OF_CALLEE_SAVES_REGISTERS 0u
</span><span class="cx">
</span><span class="cx"> class GPRInfo {
</span><span class="lines">@@ -353,6 +354,7 @@
</span><span class="cx"> static const GPRReg argumentGPR2 = X86Registers::eax; // regT0
</span><span class="cx"> static const GPRReg argumentGPR3 = X86Registers::ebx; // regT3
</span><span class="cx"> static const GPRReg nonArgGPR0 = X86Registers::esi; // regT4
</span><ins>+ static const GPRReg nonArgGPR1 = X86Registers::edi; // regT5
</ins><span class="cx"> static const GPRReg returnValueGPR = X86Registers::eax; // regT0
</span><span class="cx"> static const GPRReg returnValueGPR2 = X86Registers::edx; // regT1
</span><span class="cx"> static const GPRReg nonPreservedNonReturnGPR = X86Registers::ecx;
</span><span class="lines">@@ -379,6 +381,14 @@
</span><span class="cx"> return result;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ static unsigned toArgumentIndex(GPRReg reg)
+ {
+ ASSERT(reg != InvalidGPRReg);
+ ASSERT(static_cast<int>(reg) < 8);
+ static const unsigned indexForArgumentRegister[8] = { 2, 0, 1, 3, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex };
+ return indexForArgumentRegister[reg];
+ }
+
</ins><span class="cx"> static const char* debugName(GPRReg reg)
</span><span class="cx"> {
</span><span class="cx"> ASSERT(reg != InvalidGPRReg);
</span><span class="lines">@@ -399,9 +409,11 @@
</span><span class="cx"> #if !OS(WINDOWS)
</span><span class="cx"> #define NUMBER_OF_ARGUMENT_REGISTERS 6u
</span><span class="cx"> #define NUMBER_OF_CALLEE_SAVES_REGISTERS 5u
</span><ins>+#define NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS (NUMBER_OF_ARGUMENT_REGISTERS - 2u)
</ins><span class="cx"> #else
</span><span class="cx"> #define NUMBER_OF_ARGUMENT_REGISTERS 4u
</span><span class="cx"> #define NUMBER_OF_CALLEE_SAVES_REGISTERS 7u
</span><ins>+#define NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS 0u
</ins><span class="cx"> #endif
</span><span class="cx">
</span><span class="cx"> class GPRInfo {
</span><span class="lines">@@ -464,6 +476,7 @@
</span><span class="cx"> static const GPRReg argumentGPR3 = X86Registers::r9; // regT3
</span><span class="cx"> #endif
</span><span class="cx"> static const GPRReg nonArgGPR0 = X86Registers::r10; // regT5 (regT4 on Windows)
</span><ins>+ static const GPRReg nonArgGPR1 = X86Registers::eax; // regT0
</ins><span class="cx"> static const GPRReg returnValueGPR = X86Registers::eax; // regT0
</span><span class="cx"> static const GPRReg returnValueGPR2 = X86Registers::edx; // regT1 or regT2
</span><span class="cx"> static const GPRReg nonPreservedNonReturnGPR = X86Registers::r10; // regT5 (regT4 on Windows)
</span><span class="lines">@@ -508,6 +521,18 @@
</span><span class="cx"> return indexForRegister[reg];
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ static unsigned toArgumentIndex(GPRReg reg)
+ {
+ ASSERT(reg != InvalidGPRReg);
+ ASSERT(static_cast<int>(reg) < 16);
+#if !OS(WINDOWS)
+ static const unsigned indexForArgumentRegister[16] = { InvalidIndex, 3, 2, InvalidIndex, InvalidIndex, InvalidIndex, 1, 0, 4, 5, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex };
+#else
+ static const unsigned indexForArgumentRegister[16] = { InvalidIndex, 0, 1, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, 2, 3, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex };
+#endif
+ return indexForArgumentRegister[reg];
+ }
+
</ins><span class="cx"> static const char* debugName(GPRReg reg)
</span><span class="cx"> {
</span><span class="cx"> ASSERT(reg != InvalidGPRReg);
</span><span class="lines">@@ -538,6 +563,7 @@
</span><span class="cx">
</span><span class="cx"> #if CPU(ARM)
</span><span class="cx"> #define NUMBER_OF_ARGUMENT_REGISTERS 4u
</span><ins>+#define NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS 0u
</ins><span class="cx"> #define NUMBER_OF_CALLEE_SAVES_REGISTERS 0u
</span><span class="cx">
</span><span class="cx"> class GPRInfo {
</span><span class="lines">@@ -601,6 +627,15 @@
</span><span class="cx"> return result;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ static unsigned toArgumentIndex(GPRReg reg)
+ {
+ ASSERT(reg != InvalidGPRReg);
+ ASSERT(static_cast<int>(reg) < 16);
+ if (reg > argumentGPR3)
+ return InvalidIndex;
+ return (unsigned)reg;
+ }
+
</ins><span class="cx"> static const char* debugName(GPRReg reg)
</span><span class="cx"> {
</span><span class="cx"> ASSERT(reg != InvalidGPRReg);
</span><span class="lines">@@ -621,6 +656,7 @@
</span><span class="cx">
</span><span class="cx"> #if CPU(ARM64)
</span><span class="cx"> #define NUMBER_OF_ARGUMENT_REGISTERS 8u
</span><ins>+#define NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS (NUMBER_OF_ARGUMENT_REGISTERS - 2u)
</ins><span class="cx"> // Callee Saves includes x19..x28 and FP registers q8..q15
</span><span class="cx"> #define NUMBER_OF_CALLEE_SAVES_REGISTERS 18u
</span><span class="cx">
</span><span class="lines">@@ -698,6 +734,7 @@
</span><span class="cx"> COMPILE_ASSERT(ARM64Registers::q13 == 13, q13_is_13);
</span><span class="cx"> COMPILE_ASSERT(ARM64Registers::q14 == 14, q14_is_14);
</span><span class="cx"> COMPILE_ASSERT(ARM64Registers::q15 == 15, q15_is_15);
</span><ins>+
</ins><span class="cx"> static GPRReg toRegister(unsigned index)
</span><span class="cx"> {
</span><span class="cx"> return (GPRReg)index;
</span><span class="lines">@@ -715,6 +752,14 @@
</span><span class="cx"> return toRegister(index);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ static unsigned toArgumentIndex(GPRReg reg)
+ {
+ ASSERT(reg != InvalidGPRReg);
+ if (reg > argumentGPR7)
+ return InvalidIndex;
+ return (unsigned)reg;
+ }
+
</ins><span class="cx"> static const char* debugName(GPRReg reg)
</span><span class="cx"> {
</span><span class="cx"> ASSERT(reg != InvalidGPRReg);
</span><span class="lines">@@ -746,6 +791,7 @@
</span><span class="cx">
</span><span class="cx"> #if CPU(MIPS)
</span><span class="cx"> #define NUMBER_OF_ARGUMENT_REGISTERS 4u
</span><ins>+#define NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS 0u
</ins><span class="cx"> #define NUMBER_OF_CALLEE_SAVES_REGISTERS 0u
</span><span class="cx">
</span><span class="cx"> class GPRInfo {
</span><span class="lines">@@ -773,6 +819,7 @@
</span><span class="cx"> static const GPRReg argumentGPR2 = MIPSRegisters::a2;
</span><span class="cx"> static const GPRReg argumentGPR3 = MIPSRegisters::a3;
</span><span class="cx"> static const GPRReg nonArgGPR0 = regT4;
</span><ins>+ static const GPRReg nonArgGPR1 = regT5;
</ins><span class="cx"> static const GPRReg returnValueGPR = regT0;
</span><span class="cx"> static const GPRReg returnValueGPR2 = regT1;
</span><span class="cx"> static const GPRReg nonPreservedNonReturnGPR = regT2;
</span><span class="lines">@@ -825,6 +872,7 @@
</span><span class="cx">
</span><span class="cx"> #if CPU(SH4)
</span><span class="cx"> #define NUMBER_OF_ARGUMENT_REGISTERS 4u
</span><ins>+#define NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS 0u
</ins><span class="cx"> #define NUMBER_OF_CALLEE_SAVES_REGISTERS 0u
</span><span class="cx">
</span><span class="cx"> class GPRInfo {
</span><span class="lines">@@ -855,6 +903,7 @@
</span><span class="cx"> static const GPRReg argumentGPR2 = SH4Registers::r6; // regT2
</span><span class="cx"> static const GPRReg argumentGPR3 = SH4Registers::r7; // regT3
</span><span class="cx"> static const GPRReg nonArgGPR0 = regT4;
</span><ins>+ static const GPRReg nonArgGPR1 = regT5;
</ins><span class="cx"> static const GPRReg returnValueGPR = regT0;
</span><span class="cx"> static const GPRReg returnValueGPR2 = regT1;
</span><span class="cx"> static const GPRReg nonPreservedNonReturnGPR = regT2;
</span><span class="lines">@@ -891,6 +940,73 @@
</span><span class="cx">
</span><span class="cx"> #endif // CPU(SH4)
</span><span class="cx">
</span><ins>+inline GPRReg argumentRegisterFor(unsigned argumentIndex)
+{
+#if NUMBER_OF_ARGUMENT_REGISTERS
+ if (argumentIndex >= NUMBER_OF_ARGUMENT_REGISTERS)
+ return InvalidGPRReg;
+ return GPRInfo::toArgumentRegister(argumentIndex);
+#else
+ UNUSED_PARAM(argumentIndex);
+ RELEASE_ASSERT_NOT_REACHED();
+ return InvalidGPRReg;
+#endif
+}
+
+inline GPRReg argumentRegisterForCallee()
+{
+#if NUMBER_OF_ARGUMENT_REGISTERS
+ return argumentRegisterFor(0);
+#else
+ return GPRInfo::regT0;
+#endif
+}
+
+inline GPRReg argumentRegisterForArgumentCount()
+{
+ return argumentRegisterFor(1);
+}
+
+inline unsigned argumentRegisterIndexForJSFunctionArgument(unsigned argument)
+{
+ return argument + 2;
+}
+
+inline unsigned jsFunctionArgumentForArgumentRegisterIndex(unsigned index)
+{
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS > 0
+ ASSERT(index >= 2);
+ return index - 2;
+#else
+ UNUSED_PARAM(index);
+ RELEASE_ASSERT_NOT_REACHED();
+ return 0;
+#endif
+}
+
+inline unsigned jsFunctionArgumentForArgumentRegister(GPRReg gpr)
+{
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS > 0
+ unsigned argumentRegisterIndex = GPRInfo::toArgumentIndex(gpr);
+ ASSERT(argumentRegisterIndex != GPRInfo::InvalidIndex);
+ return jsFunctionArgumentForArgumentRegisterIndex(argumentRegisterIndex);
+#else
+ UNUSED_PARAM(gpr);
+ RELEASE_ASSERT_NOT_REACHED();
+ return 0;
+#endif
+}
+
+inline GPRReg argumentRegisterForFunctionArgument(unsigned argumentIndex)
+{
+ return argumentRegisterFor(argumentRegisterIndexForJSFunctionArgument(argumentIndex));
+}
+
+inline unsigned numberOfRegisterArgumentsFor(unsigned argumentCount)
+{
+ return std::min(argumentCount, NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS);
+}
+
</ins><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 class="lines">@@ -907,6 +1023,8 @@
</span><span class="cx"> #endif
</span><span class="cx"> inline NoResultTag extractResult(NoResultTag) { return NoResult; }
</span><span class="cx">
</span><ins>+#else // CLOOP
+#define NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS 0u
</ins><span class="cx"> #endif // ENABLE(JIT)
</span><span class="cx">
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JIT.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JIT.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/JIT.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -66,14 +66,6 @@
</span><span class="cx"> newCalleeFunction);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-JIT::CodeRef JIT::compileCTINativeCall(VM* vm, NativeFunction func)
-{
- if (!vm->canUseJIT())
- return CodeRef::createLLIntCodeRef(llint_native_call_trampoline);
- JIT jit(vm, 0);
- return jit.privateCompileCTINativeCall(vm, func);
-}
-
</del><span class="cx"> JIT::JIT(VM* vm, CodeBlock* codeBlock)
</span><span class="cx"> : JSInterfaceJIT(vm, codeBlock)
</span><span class="cx"> , m_interpreter(vm->interpreter)
</span><span class="lines">@@ -579,6 +571,20 @@
</span><span class="cx"> if (m_randomGenerator.getUint32() & 1)
</span><span class="cx"> nop();
</span><span class="cx">
</span><ins>+#if USE(JSVALUE64)
+ spillArgumentRegistersToFrameBeforePrologue(static_cast<unsigned>(m_codeBlock->numParameters()));
+ incrementCounter(this, VM::RegArgsNoArity);
+#if ENABLE(VM_COUNTERS)
+ Jump continueStackEntry = jump();
+#endif
+#endif
+ m_stackArgsArityOKEntry = label();
+ incrementCounter(this, VM::StackArgsNoArity);
+
+#if USE(JSVALUE64) && ENABLE(VM_COUNTERS)
+ continueStackEntry.link(this);
+#endif
+
</ins><span class="cx"> emitFunctionPrologue();
</span><span class="cx"> emitPutToCallFrameHeader(m_codeBlock, CallFrameSlot::codeBlock);
</span><span class="cx">
</span><span class="lines">@@ -635,7 +641,21 @@
</span><span class="cx"> callOperationWithCallFrameRollbackOnException(operationThrowStackOverflowError, m_codeBlock);
</span><span class="cx">
</span><span class="cx"> if (m_codeBlock->codeType() == FunctionCode) {
</span><del>- m_arityCheck = label();
</del><ins>+ m_registerArgsWithArityCheck = label();
+
+ incrementCounter(this, VM::RegArgsArity);
+
+ spillArgumentRegistersToFrameBeforePrologue();
+
+#if ENABLE(VM_COUNTERS)
+ Jump continueStackArityEntry = jump();
+#endif
+
+ m_stackArgsWithArityCheck = label();
+ incrementCounter(this, VM::StackArgsArity);
+#if ENABLE(VM_COUNTERS)
+ continueStackArityEntry.link(this);
+#endif
</ins><span class="cx"> store8(TrustedImm32(0), &m_codeBlock->m_shouldAlwaysBeInlined);
</span><span class="cx"> emitFunctionPrologue();
</span><span class="cx"> emitPutToCallFrameHeader(m_codeBlock, CallFrameSlot::codeBlock);
</span><span class="lines">@@ -643,6 +663,8 @@
</span><span class="cx"> load32(payloadFor(CallFrameSlot::argumentCount), regT1);
</span><span class="cx"> branch32(AboveOrEqual, regT1, TrustedImm32(m_codeBlock->m_numParameters)).linkTo(beginLabel, this);
</span><span class="cx">
</span><ins>+ incrementCounter(this, VM::ArityFixupRequired);
+
</ins><span class="cx"> m_bytecodeOffset = 0;
</span><span class="cx">
</span><span class="cx"> if (maxFrameExtentForSlowPathCall)
</span><span class="lines">@@ -778,9 +800,14 @@
</span><span class="cx"> }
</span><span class="cx"> m_codeBlock->setJITCodeMap(jitCodeMapEncoder.finish());
</span><span class="cx">
</span><del>- MacroAssemblerCodePtr withArityCheck;
- if (m_codeBlock->codeType() == FunctionCode)
- withArityCheck = patchBuffer.locationOf(m_arityCheck);
</del><ins>+ MacroAssemblerCodePtr stackEntryArityOKPtr = patchBuffer.locationOf(m_stackArgsArityOKEntry);
+
+ MacroAssemblerCodePtr registerEntryWithArityCheckPtr;
+ MacroAssemblerCodePtr stackEntryWithArityCheckPtr;
+ if (m_codeBlock->codeType() == FunctionCode) {
+ registerEntryWithArityCheckPtr = patchBuffer.locationOf(m_registerArgsWithArityCheck);
+ stackEntryWithArityCheckPtr = patchBuffer.locationOf(m_stackArgsWithArityCheck);
+ }
</ins><span class="cx">
</span><span class="cx"> if (Options::dumpDisassembly()) {
</span><span class="cx"> m_disassembler->dump(patchBuffer);
</span><span class="lines">@@ -804,8 +831,20 @@
</span><span class="cx"> static_cast<double>(m_instructions.size()));
</span><span class="cx">
</span><span class="cx"> m_codeBlock->shrinkToFit(CodeBlock::LateShrink);
</span><ins>+ JITEntryPoints entrypoints(result.code(), registerEntryWithArityCheckPtr, registerEntryWithArityCheckPtr, stackEntryArityOKPtr, stackEntryWithArityCheckPtr);
+
+ unsigned numParameters = static_cast<unsigned>(m_codeBlock->numParameters());
+ for (unsigned argCount = 1; argCount <= NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS; argCount++) {
+ MacroAssemblerCodePtr entry;
+ if (argCount == numParameters)
+ entry = result.code();
+ else
+ entry = registerEntryWithArityCheckPtr;
+ entrypoints.setEntryFor(JITEntryPoints::registerEntryTypeForArgumentCount(argCount), entry);
+ }
+
</ins><span class="cx"> m_codeBlock->setJITCode(
</span><del>- adoptRef(new DirectJITCode(result, withArityCheck, JITCode::BaselineJIT)));
</del><ins>+ adoptRef(new DirectJITCode(JITEntryPointsWithRef(result, entrypoints), JITCode::BaselineJIT)));
</ins><span class="cx">
</span><span class="cx"> #if ENABLE(JIT_VERBOSE)
</span><span class="cx"> dataLogF("JIT generated code for %p at [%p, %p).\n", m_codeBlock, result.executableMemory()->start(), result.executableMemory()->end());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JIT.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JIT.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/JIT.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -43,6 +43,7 @@
</span><span class="cx"> #include "JITInlineCacheGenerator.h"
</span><span class="cx"> #include "JITMathIC.h"
</span><span class="cx"> #include "JSInterfaceJIT.h"
</span><ins>+#include "LowLevelInterpreter.h"
</ins><span class="cx"> #include "PCToCodeOriginMap.h"
</span><span class="cx"> #include "UnusedPointer.h"
</span><span class="cx">
</span><span class="lines">@@ -246,7 +247,15 @@
</span><span class="cx"> jit.privateCompileHasIndexedProperty(byValInfo, returnAddress, arrayMode);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- static CodeRef compileCTINativeCall(VM*, NativeFunction);
</del><ins>+ static JITEntryPointsWithRef compileNativeCallEntryPoints(VM* vm, NativeFunction func)
+ {
+ if (!vm->canUseJIT()) {
+ CodeRef nativeCallRef = CodeRef::createLLIntCodeRef(llint_native_call_trampoline);
+ return JITEntryPointsWithRef(nativeCallRef, nativeCallRef.code(), nativeCallRef.code());
+ }
+ JIT jit(vm, 0);
+ return jit.privateCompileJITEntryNativeCall(vm, func);
+ }
</ins><span class="cx">
</span><span class="cx"> static unsigned frameRegisterCountFor(CodeBlock*);
</span><span class="cx"> static int stackPointerOffsetFor(CodeBlock*);
</span><span class="lines">@@ -266,8 +275,7 @@
</span><span class="cx">
</span><span class="cx"> void privateCompileHasIndexedProperty(ByValInfo*, ReturnAddressPtr, JITArrayMode);
</span><span class="cx">
</span><del>- Label privateCompileCTINativeCall(VM*, bool isConstruct = false);
- CodeRef privateCompileCTINativeCall(VM*, NativeFunction);
</del><ins>+ JITEntryPointsWithRef privateCompileJITEntryNativeCall(VM*, NativeFunction);
</ins><span class="cx"> void privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress);
</span><span class="cx">
</span><span class="cx"> // Add a call out from JIT code, without an exception check.
</span><span class="lines">@@ -949,8 +957,10 @@
</span><span class="cx"> unsigned m_putByIdIndex;
</span><span class="cx"> unsigned m_byValInstructionIndex;
</span><span class="cx"> unsigned m_callLinkInfoIndex;
</span><del>-
- Label m_arityCheck;
</del><ins>+
+ Label m_stackArgsArityOKEntry;
+ Label m_stackArgsWithArityCheck;
+ Label m_registerArgsWithArityCheck;
</ins><span class="cx"> std::unique_ptr<LinkBuffer> m_linkBuffer;
</span><span class="cx">
</span><span class="cx"> std::unique_ptr<JITDisassembler> m_disassembler;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITCallcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITCall.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITCall.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/JITCall.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -91,6 +91,8 @@
</span><span class="cx"> store64(regT0, Address(regT1, CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register))));
</span><span class="cx">
</span><span class="cx"> addPtr(TrustedImm32(sizeof(CallerFrameAndPC)), regT1, stackPointerRegister);
</span><ins>+ incrementCounter(this, VM::BaselineCaller);
+ incrementCounter(this, VM::CallVarargs);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void JIT::compileCallEval(Instruction* instruction)
</span><span class="lines">@@ -98,6 +100,9 @@
</span><span class="cx"> addPtr(TrustedImm32(-static_cast<ptrdiff_t>(sizeof(CallerFrameAndPC))), stackPointerRegister, regT1);
</span><span class="cx"> storePtr(callFrameRegister, Address(regT1, CallFrame::callerFrameOffset()));
</span><span class="cx">
</span><ins>+ incrementCounter(this, VM::BaselineCaller);
+ incrementCounter(this, VM::CallEval);
+
</ins><span class="cx"> addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock) * sizeof(Register)), callFrameRegister, stackPointerRegister);
</span><span class="cx"> checkStackPointerAlignment();
</span><span class="cx">
</span><span class="lines">@@ -113,7 +118,7 @@
</span><span class="cx"> void JIT::compileCallEvalSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter)
</span><span class="cx"> {
</span><span class="cx"> CallLinkInfo* info = m_codeBlock->addCallLinkInfo();
</span><del>- info->setUpCall(CallLinkInfo::Call, CodeOrigin(m_bytecodeOffset), regT0);
</del><ins>+ info->setUpCall(CallLinkInfo::Call, StackArgs, CodeOrigin(m_bytecodeOffset), regT0);
</ins><span class="cx">
</span><span class="cx"> linkSlowCase(iter);
</span><span class="cx"> int registerOffset = -instruction[4].u.operand;
</span><span class="lines">@@ -154,12 +159,14 @@
</span><span class="cx"> COMPILE_ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_tail_call_forward_arguments), call_and_tail_call_forward_arguments_opcodes_must_be_same_length);
</span><span class="cx">
</span><span class="cx"> CallLinkInfo* info = nullptr;
</span><ins>+ ArgumentsLocation argumentsLocation = StackArgs;
+
</ins><span class="cx"> if (opcodeID != op_call_eval)
</span><span class="cx"> info = m_codeBlock->addCallLinkInfo();
</span><span class="cx"> if (opcodeID == op_call_varargs || opcodeID == op_construct_varargs || opcodeID == op_tail_call_varargs || opcodeID == op_tail_call_forward_arguments)
</span><span class="cx"> compileSetupVarargsFrame(opcodeID, instruction, info);
</span><span class="cx"> else {
</span><del>- int argCount = instruction[3].u.operand;
</del><ins>+ unsigned argCount = instruction[3].u.unsignedValue;
</ins><span class="cx"> int registerOffset = -instruction[4].u.operand;
</span><span class="cx">
</span><span class="cx"> if (opcodeID == op_call && shouldEmitProfiling()) {
</span><span class="lines">@@ -171,16 +178,26 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> addPtr(TrustedImm32(registerOffset * sizeof(Register) + sizeof(CallerFrameAndPC)), callFrameRegister, stackPointerRegister);
</span><ins>+ if (argumentsLocation != StackArgs) {
+ move(TrustedImm32(argCount), argumentRegisterForArgumentCount());
+ unsigned registerArgs = std::min(argCount, NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS);
+ for (unsigned arg = 0; arg < registerArgs; arg++)
+ load64(Address(stackPointerRegister, (CallFrameSlot::thisArgument + arg) * static_cast<int>(sizeof(Register)) - sizeof(CallerFrameAndPC)), argumentRegisterForFunctionArgument(arg));
+ }
</ins><span class="cx"> store32(TrustedImm32(argCount), Address(stackPointerRegister, CallFrameSlot::argumentCount * static_cast<int>(sizeof(Register)) + PayloadOffset - sizeof(CallerFrameAndPC)));
</span><span class="cx"> } // SP holds newCallFrame + sizeof(CallerFrameAndPC), with ArgumentCount initialized.
</span><ins>+
+ incrementCounter(this, VM::BaselineCaller);
</ins><span class="cx">
</span><span class="cx"> uint32_t bytecodeOffset = instruction - m_codeBlock->instructions().begin();
</span><span class="cx"> uint32_t locationBits = CallSiteIndex(bytecodeOffset).bits();
</span><span class="cx"> store32(TrustedImm32(locationBits), Address(callFrameRegister, CallFrameSlot::argumentCount * static_cast<int>(sizeof(Register)) + TagOffset));
</span><span class="cx">
</span><del>- emitGetVirtualRegister(callee, regT0); // regT0 holds callee.
- store64(regT0, Address(stackPointerRegister, CallFrameSlot::callee * static_cast<int>(sizeof(Register)) - sizeof(CallerFrameAndPC)));
</del><ins>+ GPRReg calleeRegister = argumentRegisterForCallee();
</ins><span class="cx">
</span><ins>+ emitGetVirtualRegister(callee, calleeRegister);
+ store64(calleeRegister, Address(stackPointerRegister, CallFrameSlot::callee * static_cast<int>(sizeof(Register)) - sizeof(CallerFrameAndPC)));
+
</ins><span class="cx"> if (opcodeID == op_call_eval) {
</span><span class="cx"> compileCallEval(instruction);
</span><span class="cx"> return;
</span><span class="lines">@@ -187,16 +204,18 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> DataLabelPtr addressOfLinkedFunctionCheck;
</span><del>- Jump slowCase = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, TrustedImmPtr(0));
</del><ins>+ Jump slowCase = branchPtrWithPatch(NotEqual, calleeRegister, addressOfLinkedFunctionCheck, TrustedImmPtr(0));
</ins><span class="cx"> addSlowCase(slowCase);
</span><span class="cx">
</span><span class="cx"> ASSERT(m_callCompilationInfo.size() == callLinkInfoIndex);
</span><del>- info->setUpCall(CallLinkInfo::callTypeFor(opcodeID), CodeOrigin(m_bytecodeOffset), regT0);
</del><ins>+ info->setUpCall(CallLinkInfo::callTypeFor(opcodeID), argumentsLocation, CodeOrigin(m_bytecodeOffset), calleeRegister);
</ins><span class="cx"> m_callCompilationInfo.append(CallCompilationInfo());
</span><span class="cx"> m_callCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
</span><span class="cx"> m_callCompilationInfo[callLinkInfoIndex].callLinkInfo = info;
</span><span class="cx">
</span><span class="cx"> if (opcodeID == op_tail_call) {
</span><ins>+ incrementCounter(this, VM::TailCall);
+
</ins><span class="cx"> CallFrameShuffleData shuffleData;
</span><span class="cx"> shuffleData.tagTypeNumber = GPRInfo::tagTypeNumberRegister;
</span><span class="cx"> shuffleData.numLocals =
</span><span class="lines">@@ -209,7 +228,7 @@
</span><span class="cx"> DataFormatJS);
</span><span class="cx"> }
</span><span class="cx"> shuffleData.callee =
</span><del>- ValueRecovery::inGPR(regT0, DataFormatJS);
</del><ins>+ ValueRecovery::inGPR(calleeRegister, DataFormatJS);
</ins><span class="cx"> shuffleData.setupCalleeSaveRegisters(m_codeBlock);
</span><span class="cx"> info->setFrameShuffleData(shuffleData);
</span><span class="cx"> CallFrameShuffler(*this, shuffleData).prepareForTailCall();
</span><span class="lines">@@ -246,9 +265,10 @@
</span><span class="cx"> if (opcodeID == op_tail_call || opcodeID == op_tail_call_varargs || opcodeID == op_tail_call_forward_arguments)
</span><span class="cx"> emitRestoreCalleeSaves();
</span><span class="cx">
</span><del>- move(TrustedImmPtr(m_callCompilationInfo[callLinkInfoIndex].callLinkInfo), regT2);
</del><ins>+ CallLinkInfo* callLinkInfo = m_callCompilationInfo[callLinkInfoIndex].callLinkInfo;
+ move(TrustedImmPtr(callLinkInfo), nonArgGPR0);
</ins><span class="cx">
</span><del>- m_callCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_vm->getCTIStub(linkCallThunkGenerator).code());
</del><ins>+ m_callCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_vm->getJITCallThunkEntryStub(linkCallThunkGenerator).entryFor(callLinkInfo->argumentsLocation()));
</ins><span class="cx">
</span><span class="cx"> if (opcodeID == op_tail_call || opcodeID == op_tail_call_varargs) {
</span><span class="cx"> abortWithReason(JITDidReturnFromTailCall);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITCall32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITCall32_64.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITCall32_64.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/JITCall32_64.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -203,7 +203,7 @@
</span><span class="cx"> void JIT::compileCallEvalSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter)
</span><span class="cx"> {
</span><span class="cx"> CallLinkInfo* info = m_codeBlock->addCallLinkInfo();
</span><del>- info->setUpCall(CallLinkInfo::Call, CodeOrigin(m_bytecodeOffset), regT0);
</del><ins>+ info->setUpCall(CallLinkInfo::Call, StackArgs, CodeOrigin(m_bytecodeOffset), regT0);
</ins><span class="cx">
</span><span class="cx"> linkSlowCase(iter);
</span><span class="cx">
</span><span class="lines">@@ -211,12 +211,12 @@
</span><span class="cx">
</span><span class="cx"> addPtr(TrustedImm32(registerOffset * sizeof(Register) + sizeof(CallerFrameAndPC)), callFrameRegister, stackPointerRegister);
</span><span class="cx">
</span><del>- move(TrustedImmPtr(info), regT2);
</del><ins>+ move(TrustedImmPtr(info), nonArgGPR0);
</ins><span class="cx">
</span><span class="cx"> emitLoad(CallFrameSlot::callee, regT1, regT0);
</span><del>- MacroAssemblerCodeRef virtualThunk = virtualThunkFor(m_vm, *info);
- info->setSlowStub(createJITStubRoutine(virtualThunk, *m_vm, nullptr, true));
- emitNakedCall(virtualThunk.code());
</del><ins>+ JITJSCallThunkEntryPointsWithRef virtualThunk = virtualThunkFor(m_vm, *info);
+ info->setSlowStub(createJITStubRoutine(virtualThunk.codeRef(), *m_vm, nullptr, true));
+ emitNakedCall(virtualThunk.entryFor(StackArgs));
</ins><span class="cx"> addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock) * sizeof(Register)), callFrameRegister, stackPointerRegister);
</span><span class="cx"> checkStackPointerAlignment();
</span><span class="cx">
</span><span class="lines">@@ -286,7 +286,7 @@
</span><span class="cx"> addSlowCase(slowCase);
</span><span class="cx">
</span><span class="cx"> ASSERT(m_callCompilationInfo.size() == callLinkInfoIndex);
</span><del>- info->setUpCall(CallLinkInfo::callTypeFor(opcodeID), CodeOrigin(m_bytecodeOffset), regT0);
</del><ins>+ info->setUpCall(CallLinkInfo::callTypeFor(opcodeID), StackArgs, CodeOrigin(m_bytecodeOffset), regT0);
</ins><span class="cx"> m_callCompilationInfo.append(CallCompilationInfo());
</span><span class="cx"> m_callCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
</span><span class="cx"> m_callCompilationInfo[callLinkInfoIndex].callLinkInfo = info;
</span><span class="lines">@@ -317,12 +317,13 @@
</span><span class="cx"> linkSlowCase(iter);
</span><span class="cx"> linkSlowCase(iter);
</span><span class="cx">
</span><del>- move(TrustedImmPtr(m_callCompilationInfo[callLinkInfoIndex].callLinkInfo), regT2);
</del><ins>+ CallLinkInfo* callLinkInfo = m_callCompilationInfo[callLinkInfoIndex].callLinkInfo;
+ move(TrustedImmPtr(callLinkInfo), nonArgGPR0);
</ins><span class="cx">
</span><span class="cx"> if (opcodeID == op_tail_call || opcodeID == op_tail_call_varargs)
</span><span class="cx"> emitRestoreCalleeSaves();
</span><span class="cx">
</span><del>- m_callCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_vm->getCTIStub(linkCallThunkGenerator).code());
</del><ins>+ m_callCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_vm->getJITCallThunkEntryStub(linkCallThunkGenerator).entryFor(callLinkInfo->argumentsLocation()));
</ins><span class="cx">
</span><span class="cx"> if (opcodeID == op_tail_call || opcodeID == op_tail_call_varargs) {
</span><span class="cx"> abortWithReason(JITDidReturnFromTailCall);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITCodecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITCode.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITCode.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/JITCode.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -75,9 +75,9 @@
</span><span class="cx">
</span><span class="cx"> if (!function || !protoCallFrame->needArityCheck()) {
</span><span class="cx"> ASSERT(!protoCallFrame->needArityCheck());
</span><del>- entryAddress = executableAddress();
</del><ins>+ entryAddress = addressForCall(StackArgsArityCheckNotRequired).executableAddress();
</ins><span class="cx"> } else
</span><del>- entryAddress = addressForCall(MustCheckArity).executableAddress();
</del><ins>+ entryAddress = addressForCall(StackArgsMustCheckArity).executableAddress();
</ins><span class="cx"> JSValue result = JSValue::decode(vmEntryToJavaScript(entryAddress, vm, protoCallFrame));
</span><span class="cx"> return scope.exception() ? jsNull() : result;
</span><span class="cx"> }
</span><span class="lines">@@ -162,9 +162,9 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx">
</span><del>-DirectJITCode::DirectJITCode(JITCode::CodeRef ref, JITCode::CodePtr withArityCheck, JITType jitType)
- : JITCodeWithCodeRef(ref, jitType)
- , m_withArityCheck(withArityCheck)
</del><ins>+DirectJITCode::DirectJITCode(JITEntryPointsWithRef entries, JITType jitType)
+ : JITCodeWithCodeRef(entries.codeRef(), jitType)
+ , m_entryPoints(entries)
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -172,25 +172,16 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx">
</span><del>-void DirectJITCode::initializeCodeRef(JITCode::CodeRef ref, JITCode::CodePtr withArityCheck)
</del><ins>+void DirectJITCode::initializeEntryPoints(JITEntryPointsWithRef entries)
</ins><span class="cx"> {
</span><span class="cx"> RELEASE_ASSERT(!m_ref);
</span><del>- m_ref = ref;
- m_withArityCheck = withArityCheck;
</del><ins>+ m_ref = entries.codeRef();
+ m_entryPoints = entries;
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-JITCode::CodePtr DirectJITCode::addressForCall(ArityCheckMode arity)
</del><ins>+JITCode::CodePtr DirectJITCode::addressForCall(EntryPointType type)
</ins><span class="cx"> {
</span><del>- switch (arity) {
- case ArityCheckNotRequired:
- RELEASE_ASSERT(m_ref);
- return m_ref.code();
- case MustCheckArity:
- RELEASE_ASSERT(m_withArityCheck);
- return m_withArityCheck;
- }
- RELEASE_ASSERT_NOT_REACHED();
- return CodePtr();
</del><ins>+ return m_entryPoints.entryFor(type);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> NativeJITCode::NativeJITCode(JITType jitType)
</span><span class="lines">@@ -213,7 +204,7 @@
</span><span class="cx"> m_ref = ref;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-JITCode::CodePtr NativeJITCode::addressForCall(ArityCheckMode)
</del><ins>+JITCode::CodePtr NativeJITCode::addressForCall(EntryPointType)
</ins><span class="cx"> {
</span><span class="cx"> RELEASE_ASSERT(!!m_ref);
</span><span class="cx"> return m_ref.code();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITCodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITCode.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITCode.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/JITCode.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -25,10 +25,10 @@
</span><span class="cx">
</span><span class="cx"> #pragma once
</span><span class="cx">
</span><del>-#include "ArityCheckMode.h"
</del><span class="cx"> #include "CallFrame.h"
</span><span class="cx"> #include "CodeOrigin.h"
</span><span class="cx"> #include "Disassembler.h"
</span><ins>+#include "JITEntryPoints.h"
</ins><span class="cx"> #include "JSCJSValue.h"
</span><span class="cx"> #include "MacroAssemblerCodeRef.h"
</span><span class="cx"> #include "RegisterSet.h"
</span><span class="lines">@@ -173,9 +173,8 @@
</span><span class="cx"> return jitCode->jitType();
</span><span class="cx"> }
</span><span class="cx">
</span><del>- virtual CodePtr addressForCall(ArityCheckMode) = 0;
</del><ins>+ virtual CodePtr addressForCall(EntryPointType) = 0;
</ins><span class="cx"> virtual void* executableAddressAtOffset(size_t offset) = 0;
</span><del>- void* executableAddress() { return executableAddressAtOffset(0); }
</del><span class="cx"> virtual void* dataAddressAtOffset(size_t offset) = 0;
</span><span class="cx"> virtual unsigned offsetOf(void* pointerIntoCode) = 0;
</span><span class="cx">
</span><span class="lines">@@ -224,15 +223,15 @@
</span><span class="cx"> class DirectJITCode : public JITCodeWithCodeRef {
</span><span class="cx"> public:
</span><span class="cx"> DirectJITCode(JITType);
</span><del>- DirectJITCode(CodeRef, CodePtr withArityCheck, JITType);
</del><ins>+ DirectJITCode(JITEntryPointsWithRef, JITType);
</ins><span class="cx"> virtual ~DirectJITCode();
</span><span class="cx">
</span><del>- void initializeCodeRef(CodeRef, CodePtr withArityCheck);
</del><ins>+ void initializeEntryPoints(JITEntryPointsWithRef);
</ins><span class="cx">
</span><del>- CodePtr addressForCall(ArityCheckMode) override;
</del><ins>+ CodePtr addressForCall(EntryPointType) override;
</ins><span class="cx">
</span><span class="cx"> private:
</span><del>- CodePtr m_withArityCheck;
</del><ins>+ JITEntryPoints m_entryPoints;
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> class NativeJITCode : public JITCodeWithCodeRef {
</span><span class="lines">@@ -243,7 +242,7 @@
</span><span class="cx">
</span><span class="cx"> void initializeCodeRef(CodeRef);
</span><span class="cx">
</span><del>- CodePtr addressForCall(ArityCheckMode) override;
</del><ins>+ CodePtr addressForCall(EntryPointType) override;
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITEntryPointsh"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/jit/JITEntryPoints.h (0 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITEntryPoints.h         (rev 0)
+++ trunk/Source/JavaScriptCore/jit/JITEntryPoints.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -0,0 +1,359 @@
</span><ins>+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "GPRInfo.h"
+#include "MacroAssemblerCodeRef.h"
+
+namespace JSC {
+class VM;
+class MacroAssemblerCodeRef;
+
+enum ArgumentsLocation : unsigned {
+ StackArgs = 0,
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS >= 4
+ RegisterArgs1InRegisters,
+ RegisterArgs2InRegisters,
+ RegisterArgs3InRegisters,
+ RegisterArgs4InRegisters,
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS == 6
+ RegisterArgs5InRegisters,
+ RegisterArgs6InRegisters,
+#endif
+ RegisterArgsWithExtraOnStack
+#endif
+};
+
+// This enum needs to have the same enumerator ordering as ArgumentsLocation.
+enum ThunkEntryPointType : unsigned {
+ StackArgsEntry = 0,
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS >= 4
+ Register1ArgEntry,
+ Register2ArgsEntry,
+ Register3ArgsEntry,
+ Register4ArgsEntry,
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS == 6
+ Register5ArgsEntry,
+ Register6ArgsEntry,
+#endif
+#endif
+ ThunkEntryPointTypeCount
+};
+
+enum EntryPointType {
+ StackArgsArityCheckNotRequired,
+ StackArgsMustCheckArity,
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ RegisterArgsArityCheckNotRequired,
+ RegisterArgsPossibleExtraArgs,
+ RegisterArgsMustCheckArity,
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS >= 4
+ RegisterArgs1,
+ RegisterArgs2,
+ RegisterArgs3,
+ RegisterArgs4,
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS == 6
+ RegisterArgs5,
+ RegisterArgs6,
+#endif
+#endif
+#endif
+ NumberOfEntryPointTypes
+};
+
+class JITEntryPoints {
+public:
+ typedef MacroAssemblerCodePtr CodePtr;
+ static const unsigned numberOfEntryTypes = EntryPointType::NumberOfEntryPointTypes;
+
+ JITEntryPoints()
+ {
+ clearEntries();
+ }
+
+ JITEntryPoints(CodePtr registerArgsNoCheckRequiredEntry, CodePtr registerArgsPossibleExtraArgsEntry,
+ CodePtr registerArgsCheckArityEntry, CodePtr stackArgsArityCheckNotRequiredEntry,
+ CodePtr stackArgsCheckArityEntry)
+ {
+ m_entryPoints[StackArgsArityCheckNotRequired] = stackArgsArityCheckNotRequiredEntry;
+ m_entryPoints[StackArgsMustCheckArity] = stackArgsCheckArityEntry;
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ m_entryPoints[RegisterArgsArityCheckNotRequired] = registerArgsNoCheckRequiredEntry;
+ m_entryPoints[RegisterArgsPossibleExtraArgs] = registerArgsPossibleExtraArgsEntry;
+ m_entryPoints[RegisterArgsMustCheckArity] = registerArgsCheckArityEntry;
+ for (unsigned i = 1; i <= NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS; i ++)
+ m_entryPoints[registerEntryTypeForArgumentCount(i)] = registerArgsCheckArityEntry;
+#else
+ UNUSED_PARAM(registerArgsNoCheckRequiredEntry);
+ UNUSED_PARAM(registerArgsPossibleExtraArgsEntry);
+ UNUSED_PARAM(registerArgsCheckArityEntry);
+#endif
+
+ }
+
+ CodePtr entryFor(EntryPointType type)
+ {
+ return m_entryPoints[type];
+ }
+
+ void setEntryFor(EntryPointType type, CodePtr entry)
+ {
+ ASSERT(type < NumberOfEntryPointTypes);
+ m_entryPoints[type] = entry;
+ }
+
+ static ptrdiff_t offsetOfEntryFor(EntryPointType type)
+ {
+ return offsetof(JITEntryPoints, m_entryPoints[type]);
+ }
+
+ static EntryPointType registerEntryTypeForArgumentCount(unsigned argCount)
+ {
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ ASSERT(argCount);
+ unsigned registerArgCount = numberOfRegisterArgumentsFor(argCount);
+ if (!registerArgCount || registerArgCount != argCount)
+ return RegisterArgsMustCheckArity;
+
+ return static_cast<EntryPointType>(RegisterArgs1 + registerArgCount - 1);
+#else
+ UNUSED_PARAM(argCount);
+ RELEASE_ASSERT_NOT_REACHED();
+ return StackArgsMustCheckArity;
+#endif
+ }
+
+ static EntryPointType registerEntryTypeForArgumentType(ArgumentsLocation type)
+ {
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ ASSERT(type != StackArgs);
+ if (type == RegisterArgsWithExtraOnStack)
+ return RegisterArgsMustCheckArity;
+
+ return static_cast<EntryPointType>(RegisterArgs1 + type - RegisterArgs1InRegisters);
+#else
+ UNUSED_PARAM(type);
+ RELEASE_ASSERT_NOT_REACHED();
+ return StackArgsMustCheckArity;
+#endif
+ }
+
+ void clearEntries()
+ {
+ for (unsigned i = numberOfEntryTypes; i--;)
+ m_entryPoints[i] = MacroAssemblerCodePtr();
+ }
+
+ JITEntryPoints& operator=(const JITEntryPoints& other)
+ {
+ for (unsigned i = numberOfEntryTypes; i--;)
+ m_entryPoints[i] = other.m_entryPoints[i];
+
+ return *this;
+ }
+
+private:
+
+ CodePtr m_entryPoints[numberOfEntryTypes];
+};
+
+class JITEntryPointsWithRef : public JITEntryPoints {
+public:
+ typedef MacroAssemblerCodeRef CodeRef;
+
+ JITEntryPointsWithRef()
+ {
+ }
+
+ JITEntryPointsWithRef(const JITEntryPointsWithRef& other)
+ : JITEntryPoints(other)
+ , m_codeRef(other.m_codeRef)
+ {
+ }
+
+ JITEntryPointsWithRef(CodeRef codeRef, const JITEntryPoints& other)
+ : JITEntryPoints(other)
+ , m_codeRef(codeRef)
+ {
+ }
+
+ JITEntryPointsWithRef(CodeRef codeRef, CodePtr stackArgsArityCheckNotRequiredEntry,
+ CodePtr stackArgsCheckArityEntry)
+ : JITEntryPoints(CodePtr(), CodePtr(), CodePtr(), stackArgsArityCheckNotRequiredEntry, stackArgsCheckArityEntry)
+ , m_codeRef(codeRef)
+ {
+ }
+
+ JITEntryPointsWithRef(CodeRef codeRef, CodePtr registerArgsNoChecksRequiredEntry,
+ CodePtr registerArgsPossibleExtraArgsEntry, CodePtr registerArgsCheckArityEntry,
+ CodePtr stackArgsArityCheckNotRequiredEntry, CodePtr stackArgsCheckArityEntry)
+ : JITEntryPoints(registerArgsNoChecksRequiredEntry, registerArgsPossibleExtraArgsEntry,
+ registerArgsCheckArityEntry, stackArgsArityCheckNotRequiredEntry,
+ stackArgsCheckArityEntry)
+ , m_codeRef(codeRef)
+ {
+ }
+
+ CodeRef codeRef() { return m_codeRef; }
+
+private:
+ CodeRef m_codeRef;
+};
+
+inline ArgumentsLocation argumentsLocationFor(unsigned argumentCount)
+{
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ if (!argumentCount)
+ return StackArgs;
+
+ argumentCount = std::min(NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS + 1, argumentCount);
+
+ return static_cast<ArgumentsLocation>(ArgumentsLocation::RegisterArgs1InRegisters + argumentCount - 1);
+#else
+ UNUSED_PARAM(argumentCount);
+ return StackArgs;
+#endif
+}
+
+inline EntryPointType registerEntryPointTypeFor(unsigned argumentCount)
+{
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ if (!argumentCount || argumentCount > NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS)
+ return RegisterArgsMustCheckArity;
+
+ return static_cast<EntryPointType>(EntryPointType::RegisterArgs1 + argumentCount - 1);
+#else
+ RELEASE_ASSERT_NOT_REACHED();
+ UNUSED_PARAM(argumentCount);
+ return StackArgsMustCheckArity;
+#endif
+}
+
+inline EntryPointType entryPointTypeFor(ArgumentsLocation argumentLocation)
+{
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ if (argumentLocation == StackArgs)
+ return StackArgsMustCheckArity;
+
+ if (argumentLocation == RegisterArgsWithExtraOnStack)
+ return RegisterArgsMustCheckArity;
+
+ return static_cast<EntryPointType>(EntryPointType::RegisterArgs1 + static_cast<unsigned>(argumentLocation - RegisterArgs1InRegisters));
+#else
+ UNUSED_PARAM(argumentLocation);
+ return StackArgsMustCheckArity;
+#endif
+}
+
+inline ThunkEntryPointType thunkEntryPointTypeFor(ArgumentsLocation argumentLocation)
+{
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ unsigned argumentLocationIndex = std::min(RegisterArgsWithExtraOnStack - 1, static_cast<unsigned>(argumentLocation));
+ return static_cast<ThunkEntryPointType>(argumentLocationIndex);
+#else
+ UNUSED_PARAM(argumentLocation);
+ return StackArgsEntry;
+#endif
+}
+
+inline ThunkEntryPointType thunkEntryPointTypeFor(unsigned argumentCount)
+{
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ argumentCount = numberOfRegisterArgumentsFor(argumentCount);
+
+ return static_cast<ThunkEntryPointType>(ThunkEntryPointType::Register1ArgEntry + argumentCount - 1);
+#else
+ UNUSED_PARAM(argumentCount);
+ return StackArgsEntry;
+#endif
+}
+
+class JITJSCallThunkEntryPointsWithRef {
+public:
+ typedef MacroAssemblerCodePtr CodePtr;
+ typedef MacroAssemblerCodeRef CodeRef;
+ static const unsigned numberOfEntryTypes = ThunkEntryPointType::ThunkEntryPointTypeCount;
+
+ JITJSCallThunkEntryPointsWithRef()
+ {
+ }
+
+ JITJSCallThunkEntryPointsWithRef(CodeRef codeRef)
+ : m_codeRef(codeRef)
+ {
+ }
+
+ JITJSCallThunkEntryPointsWithRef(const JITJSCallThunkEntryPointsWithRef& other)
+ : m_codeRef(other.m_codeRef)
+ {
+ for (unsigned i = 0; i < numberOfEntryTypes; i++)
+ m_entryPoints[i] = other.m_entryPoints[i];
+ }
+
+ CodePtr entryFor(ThunkEntryPointType type)
+ {
+ return m_entryPoints[type];
+ }
+
+ CodePtr entryFor(ArgumentsLocation argumentsLocation)
+ {
+ return entryFor(thunkEntryPointTypeFor(argumentsLocation));
+ }
+
+ void setEntryFor(ThunkEntryPointType type, CodePtr entry)
+ {
+ m_entryPoints[type] = entry;
+ }
+
+ static ptrdiff_t offsetOfEntryFor(ThunkEntryPointType type)
+ {
+ return offsetof(JITJSCallThunkEntryPointsWithRef, m_entryPoints[type]);
+ }
+
+ void clearEntries()
+ {
+ for (unsigned i = numberOfEntryTypes; i--;)
+ m_entryPoints[i] = MacroAssemblerCodePtr();
+ }
+
+ CodeRef codeRef() { return m_codeRef; }
+
+ JITJSCallThunkEntryPointsWithRef& operator=(const JITJSCallThunkEntryPointsWithRef& other)
+ {
+ m_codeRef = other.m_codeRef;
+ for (unsigned i = numberOfEntryTypes; i--;)
+ m_entryPoints[i] = other.m_entryPoints[i];
+
+ return *this;
+ }
+
+private:
+ CodeRef m_codeRef;
+ CodePtr m_entryPoints[numberOfEntryTypes];
+};
+
+
+} // namespace JSC
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOpcodescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -49,9 +49,9 @@
</span><span class="cx">
</span><span class="cx"> #if USE(JSVALUE64)
</span><span class="cx">
</span><del>-JIT::CodeRef JIT::privateCompileCTINativeCall(VM* vm, NativeFunction)
</del><ins>+JITEntryPointsWithRef JIT::privateCompileJITEntryNativeCall(VM* vm, NativeFunction)
</ins><span class="cx"> {
</span><del>- return vm->getCTIStub(nativeCallGenerator);
</del><ins>+ return vm->getJITEntryStub(nativeCallGenerator);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void JIT::emit_op_mov(Instruction* currentInstruction)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOpcodes32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -46,7 +46,7 @@
</span><span class="cx">
</span><span class="cx"> namespace JSC {
</span><span class="cx">
</span><del>-JIT::CodeRef JIT::privateCompileCTINativeCall(VM* vm, NativeFunction func)
</del><ins>+JITEntryPointsWithRef JIT::privateCompileJITEntryNativeCall(VM* vm, NativeFunction func)
</ins><span class="cx"> {
</span><span class="cx"> // FIXME: This should be able to log ShadowChicken prologue packets.
</span><span class="cx"> // https://bugs.webkit.org/show_bug.cgi?id=155689
</span><span class="lines">@@ -129,7 +129,9 @@
</span><span class="cx"> LinkBuffer patchBuffer(*m_vm, *this, GLOBAL_THUNK_ID);
</span><span class="cx">
</span><span class="cx"> patchBuffer.link(nativeCall, FunctionPtr(func));
</span><del>- return FINALIZE_CODE(patchBuffer, ("JIT CTI native call"));
</del><ins>+ JIT::CodeRef codeRef = FINALIZE_CODE(patchBuffer, ("JIT CTI native call"));
+
+ return JITEntryPointsWithRef(codeRef, codeRef.code(), codeRef.code());
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void JIT::emit_op_mov(Instruction* currentInstruction)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOperationscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOperations.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOperations.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/JITOperations.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -890,10 +890,14 @@
</span><span class="cx"> JSScope* scope = callee->scopeUnchecked();
</span><span class="cx"> ExecutableBase* executable = callee->executable();
</span><span class="cx">
</span><del>- MacroAssemblerCodePtr codePtr;
</del><ins>+ MacroAssemblerCodePtr codePtr, codePtrForLinking;
</ins><span class="cx"> CodeBlock* codeBlock = 0;
</span><span class="cx"> if (executable->isHostFunction()) {
</span><del>- codePtr = executable->entrypointFor(kind, MustCheckArity);
</del><ins>+ codePtr = executable->entrypointFor(kind, StackArgsMustCheckArity);
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ if (callLinkInfo->argumentsInRegisters())
+ codePtrForLinking = executable->entrypointFor(kind, RegisterArgsMustCheckArity);
+#endif
</ins><span class="cx"> } else {
</span><span class="cx"> FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
</span><span class="cx">
</span><span class="lines">@@ -914,17 +918,41 @@
</span><span class="cx"> reinterpret_cast<void*>(KeepTheFrame));
</span><span class="cx"> }
</span><span class="cx"> codeBlock = *codeBlockSlot;
</span><del>- ArityCheckMode arity;
- if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters()) || callLinkInfo->isVarargs())
- arity = MustCheckArity;
- else
- arity = ArityCheckNotRequired;
- codePtr = functionExecutable->entrypointFor(kind, arity);
</del><ins>+ EntryPointType entryType;
+ size_t callerArgumentCount = execCallee->argumentCountIncludingThis();
+ size_t calleeArgumentCount = static_cast<size_t>(codeBlock->numParameters());
+ if (callerArgumentCount < calleeArgumentCount || callLinkInfo->isVarargs()) {
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ if (callLinkInfo->argumentsInRegisters()) {
+ codePtrForLinking = functionExecutable->entrypointFor(kind, JITEntryPoints::registerEntryTypeForArgumentCount(callerArgumentCount));
+ if (!codePtrForLinking)
+ codePtrForLinking = functionExecutable->entrypointFor(kind, RegisterArgsMustCheckArity);
+ }
+#endif
+ entryType = StackArgsMustCheckArity;
+ (void) functionExecutable->entrypointFor(kind, entryPointTypeFor(callLinkInfo->argumentsLocation()));
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ } else if (callLinkInfo->argumentsInRegisters()) {
+ if (callerArgumentCount == calleeArgumentCount || calleeArgumentCount >= NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS)
+ codePtrForLinking = functionExecutable->entrypointFor(kind, RegisterArgsArityCheckNotRequired);
+ else {
+ codePtrForLinking = functionExecutable->entrypointFor(kind, JITEntryPoints::registerEntryTypeForArgumentCount(callerArgumentCount));
+ if (!codePtrForLinking)
+ codePtrForLinking = functionExecutable->entrypointFor(kind, RegisterArgsPossibleExtraArgs);
+ }
+ // Prepopulate the entry points the virtual thunk might use.
+ (void) functionExecutable->entrypointFor(kind, entryPointTypeFor(callLinkInfo->argumentsLocation()));
+
+ entryType = StackArgsArityCheckNotRequired;
+#endif
+ } else
+ entryType = StackArgsArityCheckNotRequired;
+ codePtr = functionExecutable->entrypointFor(kind, entryType);
</ins><span class="cx"> }
</span><span class="cx"> if (!callLinkInfo->seenOnce())
</span><span class="cx"> callLinkInfo->setSeen();
</span><span class="cx"> else
</span><del>- linkFor(execCallee, *callLinkInfo, codeBlock, callee, codePtr);
</del><ins>+ linkFor(execCallee, *callLinkInfo, codeBlock, callee, codePtrForLinking ? codePtrForLinking : codePtr);
</ins><span class="cx">
</span><span class="cx"> return encodeResult(codePtr.executableAddress(), reinterpret_cast<void*>(callLinkInfo->callMode() == CallMode::Tail ? ReuseTheFrame : KeepTheFrame));
</span><span class="cx"> }
</span><span class="lines">@@ -959,7 +987,11 @@
</span><span class="cx"> MacroAssemblerCodePtr codePtr;
</span><span class="cx"> CodeBlock* codeBlock = nullptr;
</span><span class="cx"> if (executable->isHostFunction())
</span><del>- codePtr = executable->entrypointFor(kind, MustCheckArity);
</del><ins>+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ codePtr = executable->entrypointFor(kind, callLinkInfo->argumentsInRegisters() ? RegisterArgsMustCheckArity : StackArgsMustCheckArity);
+#else
+ codePtr = executable->entrypointFor(kind, StackArgsMustCheckArity);
+#endif
</ins><span class="cx"> else {
</span><span class="cx"> FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
</span><span class="cx">
</span><span class="lines">@@ -971,13 +1003,29 @@
</span><span class="cx"> throwException(exec, throwScope, error);
</span><span class="cx"> return;
</span><span class="cx"> }
</span><del>- ArityCheckMode arity;
</del><ins>+ EntryPointType entryType;
</ins><span class="cx"> unsigned argumentStackSlots = callLinkInfo->maxNumArguments();
</span><del>- if (argumentStackSlots < static_cast<size_t>(codeBlock->numParameters()))
- arity = MustCheckArity;
</del><ins>+ size_t codeBlockParameterCount = static_cast<size_t>(codeBlock->numParameters());
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ if (callLinkInfo->argumentsInRegisters()) {
+ // This logic could probably be simplified!
+ if (argumentStackSlots < codeBlockParameterCount)
+ entryType = entryPointTypeFor(callLinkInfo->argumentsLocation());
+ else if (argumentStackSlots > NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS) {
+ if (codeBlockParameterCount < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS)
+ entryType = RegisterArgsPossibleExtraArgs;
+ else
+ entryType = RegisterArgsArityCheckNotRequired;
+ } else
+ entryType = registerEntryPointTypeFor(argumentStackSlots);
+ } else if (argumentStackSlots < codeBlockParameterCount)
+#else
+ if (argumentStackSlots < codeBlockParameterCount)
+#endif
+ entryType = StackArgsMustCheckArity;
</ins><span class="cx"> else
</span><del>- arity = ArityCheckNotRequired;
- codePtr = functionExecutable->entrypointFor(kind, arity);
</del><ins>+ entryType = StackArgsArityCheckNotRequired;
+ codePtr = functionExecutable->entrypointFor(kind, entryType);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> linkDirectFor(exec, *callLinkInfo, codeBlock, codePtr);
</span><span class="lines">@@ -1020,8 +1068,17 @@
</span><span class="cx"> reinterpret_cast<void*>(KeepTheFrame));
</span><span class="cx"> }
</span><span class="cx"> }
</span><ins>+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ if (callLinkInfo->argumentsInRegisters()) {
+ // Pull into the cache the arity check register entry if the caller wants a register entry.
+ // This will be used by the generic virtual call thunk.
+ (void) executable->entrypointFor(kind, RegisterArgsMustCheckArity);
+ (void) executable->entrypointFor(kind, entryPointTypeFor(callLinkInfo->argumentsLocation()));
+
+ }
+#endif
</ins><span class="cx"> return encodeResult(executable->entrypointFor(
</span><del>- kind, MustCheckArity).executableAddress(),
</del><ins>+ kind, StackArgsMustCheckArity).executableAddress(),
</ins><span class="cx"> reinterpret_cast<void*>(callLinkInfo->callMode() == CallMode::Tail ? ReuseTheFrame : KeepTheFrame));
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITThunkscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITThunks.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITThunks.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/JITThunks.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -44,18 +44,22 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx">
</span><del>-MacroAssemblerCodePtr JITThunks::ctiNativeCall(VM* vm)
</del><ins>+JITEntryPointsWithRef JITThunks::jitEntryNativeCall(VM* vm)
</ins><span class="cx"> {
</span><del>- if (!vm->canUseJIT())
- return MacroAssemblerCodePtr::createLLIntCodePtr(llint_native_call_trampoline);
- return ctiStub(vm, nativeCallGenerator).code();
</del><ins>+ if (!vm->canUseJIT()) {
+ MacroAssemblerCodePtr nativeCallStub = MacroAssemblerCodePtr::createLLIntCodePtr(llint_native_call_trampoline);
+ return JITEntryPointsWithRef(MacroAssemblerCodeRef::createSelfManagedCodeRef(nativeCallStub), nativeCallStub, nativeCallStub);
+ }
+ return jitEntryStub(vm, nativeCallGenerator);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-MacroAssemblerCodePtr JITThunks::ctiNativeConstruct(VM* vm)
</del><ins>+JITEntryPointsWithRef JITThunks::jitEntryNativeConstruct(VM* vm)
</ins><span class="cx"> {
</span><del>- if (!vm->canUseJIT())
- return MacroAssemblerCodePtr::createLLIntCodePtr(llint_native_construct_trampoline);
- return ctiStub(vm, nativeConstructGenerator).code();
</del><ins>+ if (!vm->canUseJIT()) {
+ MacroAssemblerCodePtr nativeConstructStub = MacroAssemblerCodePtr::createLLIntCodePtr(llint_native_construct_trampoline);
+ return JITEntryPointsWithRef(MacroAssemblerCodeRef::createSelfManagedCodeRef(nativeConstructStub), nativeConstructStub, nativeConstructStub);
+ }
+ return jitEntryStub(vm, nativeConstructGenerator);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> MacroAssemblerCodePtr JITThunks::ctiNativeTailCall(VM* vm)
</span><span class="lines">@@ -82,6 +86,30 @@
</span><span class="cx"> return entry.iterator->value;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+JITEntryPointsWithRef JITThunks::jitEntryStub(VM* vm, JITEntryGenerator generator)
+{
+ LockHolder locker(m_lock);
+ JITEntryStubMap::AddResult entry = m_jitEntryStubMap.add(generator, JITEntryPointsWithRef());
+ if (entry.isNewEntry) {
+ // Compilation thread can only retrieve existing entries.
+ ASSERT(!isCompilationThread());
+ entry.iterator->value = generator(vm);
+ }
+ return entry.iterator->value;
+}
+
+JITJSCallThunkEntryPointsWithRef JITThunks::jitCallThunkEntryStub(VM* vm, JITCallThunkEntryGenerator generator)
+{
+ LockHolder locker(m_lock);
+ JITCallThunkEntryStubMap::AddResult entry = m_jitCallThunkEntryStubMap.add(generator, JITJSCallThunkEntryPointsWithRef());
+ if (entry.isNewEntry) {
+ // Compilation thread can only retrieve existing entries.
+ ASSERT(!isCompilationThread());
+ entry.iterator->value = generator(vm);
+ }
+ return entry.iterator->value;
+}
+
</ins><span class="cx"> void JITThunks::finalize(Handle<Unknown> handle, void*)
</span><span class="cx"> {
</span><span class="cx"> auto* nativeExecutable = jsCast<NativeExecutable*>(handle.get().asCell());
</span><span class="lines">@@ -93,7 +121,7 @@
</span><span class="cx"> return hostFunctionStub(vm, function, constructor, nullptr, NoIntrinsic, nullptr, name);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-NativeExecutable* JITThunks::hostFunctionStub(VM* vm, NativeFunction function, NativeFunction constructor, ThunkGenerator generator, Intrinsic intrinsic, const DOMJIT::Signature* signature, const String& name)
</del><ins>+NativeExecutable* JITThunks::hostFunctionStub(VM* vm, NativeFunction function, NativeFunction constructor, JITEntryGenerator generator, Intrinsic intrinsic, const DOMJIT::Signature* signature, const String& name)
</ins><span class="cx"> {
</span><span class="cx"> ASSERT(!isCompilationThread());
</span><span class="cx"> ASSERT(vm->canUseJIT());
</span><span class="lines">@@ -103,12 +131,12 @@
</span><span class="cx">
</span><span class="cx"> RefPtr<JITCode> forCall;
</span><span class="cx"> if (generator) {
</span><del>- MacroAssemblerCodeRef entry = generator(vm);
- forCall = adoptRef(new DirectJITCode(entry, entry.code(), JITCode::HostCallThunk));
</del><ins>+ JITEntryPointsWithRef entry = generator(vm);
+ forCall = adoptRef(new DirectJITCode(entry, JITCode::HostCallThunk));
</ins><span class="cx"> } else
</span><del>- forCall = adoptRef(new NativeJITCode(JIT::compileCTINativeCall(vm, function), JITCode::HostCallThunk));
</del><ins>+ forCall = adoptRef(new DirectJITCode(JIT::compileNativeCallEntryPoints(vm, function), JITCode::HostCallThunk));
</ins><span class="cx">
</span><del>- RefPtr<JITCode> forConstruct = adoptRef(new NativeJITCode(MacroAssemblerCodeRef::createSelfManagedCodeRef(ctiNativeConstruct(vm)), JITCode::HostCallThunk));
</del><ins>+ RefPtr<JITCode> forConstruct = adoptRef(new DirectJITCode(jitEntryNativeConstruct(vm), JITCode::HostCallThunk));
</ins><span class="cx">
</span><span class="cx"> NativeExecutable* nativeExecutable = NativeExecutable::create(*vm, forCall, function, forConstruct, constructor, intrinsic, signature, name);
</span><span class="cx"> weakAdd(*m_hostFunctionStubMap, std::make_tuple(function, constructor, name), Weak<NativeExecutable>(nativeExecutable, this));
</span><span class="lines">@@ -115,7 +143,7 @@
</span><span class="cx"> return nativeExecutable;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-NativeExecutable* JITThunks::hostFunctionStub(VM* vm, NativeFunction function, ThunkGenerator generator, Intrinsic intrinsic, const String& name)
</del><ins>+NativeExecutable* JITThunks::hostFunctionStub(VM* vm, NativeFunction function, JITEntryGenerator generator, Intrinsic intrinsic, const String& name)
</ins><span class="cx"> {
</span><span class="cx"> return hostFunctionStub(vm, function, callHostFunctionAsConstructor, generator, intrinsic, nullptr, name);
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITThunksh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITThunks.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITThunks.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/JITThunks.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx">
</span><span class="cx"> #include "CallData.h"
</span><span class="cx"> #include "Intrinsic.h"
</span><ins>+#include "JITEntryPoints.h"
</ins><span class="cx"> #include "MacroAssemblerCodeRef.h"
</span><span class="cx"> #include "ThunkGenerator.h"
</span><span class="cx"> #include "Weak.h"
</span><span class="lines">@@ -52,16 +53,18 @@
</span><span class="cx"> JITThunks();
</span><span class="cx"> virtual ~JITThunks();
</span><span class="cx">
</span><del>- MacroAssemblerCodePtr ctiNativeCall(VM*);
- MacroAssemblerCodePtr ctiNativeConstruct(VM*);
</del><ins>+ JITEntryPointsWithRef jitEntryNativeCall(VM*);
+ JITEntryPointsWithRef jitEntryNativeConstruct(VM*);
</ins><span class="cx"> MacroAssemblerCodePtr ctiNativeTailCall(VM*);
</span><span class="cx"> MacroAssemblerCodePtr ctiNativeTailCallWithoutSavedTags(VM*);
</span><span class="cx">
</span><span class="cx"> MacroAssemblerCodeRef ctiStub(VM*, ThunkGenerator);
</span><ins>+ JITEntryPointsWithRef jitEntryStub(VM*, JITEntryGenerator);
+ JITJSCallThunkEntryPointsWithRef jitCallThunkEntryStub(VM*, JITCallThunkEntryGenerator);
</ins><span class="cx">
</span><span class="cx"> NativeExecutable* hostFunctionStub(VM*, NativeFunction, NativeFunction constructor, const String& name);
</span><del>- NativeExecutable* hostFunctionStub(VM*, NativeFunction, NativeFunction constructor, ThunkGenerator, Intrinsic, const DOMJIT::Signature*, const String& name);
- NativeExecutable* hostFunctionStub(VM*, NativeFunction, ThunkGenerator, Intrinsic, const String& name);
</del><ins>+ NativeExecutable* hostFunctionStub(VM*, NativeFunction, NativeFunction constructor, JITEntryGenerator, Intrinsic, const DOMJIT::Signature*, const String& name);
+ NativeExecutable* hostFunctionStub(VM*, NativeFunction, JITEntryGenerator, Intrinsic, const String& name);
</ins><span class="cx">
</span><span class="cx"> void clearHostFunctionStubs();
</span><span class="cx">
</span><span class="lines">@@ -70,6 +73,10 @@
</span><span class="cx">
</span><span class="cx"> typedef HashMap<ThunkGenerator, MacroAssemblerCodeRef> CTIStubMap;
</span><span class="cx"> CTIStubMap m_ctiStubMap;
</span><ins>+ typedef HashMap<JITEntryGenerator, JITEntryPointsWithRef> JITEntryStubMap;
+ JITEntryStubMap m_jitEntryStubMap;
+ typedef HashMap<JITCallThunkEntryGenerator, JITJSCallThunkEntryPointsWithRef> JITCallThunkEntryStubMap;
+ JITCallThunkEntryStubMap m_jitCallThunkEntryStubMap;
</ins><span class="cx">
</span><span class="cx"> typedef std::tuple<NativeFunction, NativeFunction, String> HostFunctionKey;
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJSInterfaceJITh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JSInterfaceJIT.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JSInterfaceJIT.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/JSInterfaceJIT.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -63,6 +63,7 @@
</span><span class="cx"> Jump emitJumpIfNotJSCell(RegisterID);
</span><span class="cx"> Jump emitJumpIfNumber(RegisterID);
</span><span class="cx"> Jump emitJumpIfNotNumber(RegisterID);
</span><ins>+ Jump emitJumpIfNotInt32(RegisterID reg);
</ins><span class="cx"> void emitTagInt(RegisterID src, RegisterID dest);
</span><span class="cx"> #endif
</span><span class="cx">
</span><span class="lines">@@ -163,12 +164,17 @@
</span><span class="cx"> return branchTest64(NonZero, dst, tagMaskRegister);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ inline JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotInt32(RegisterID reg)
+ {
+ Jump result = branch64(Below, reg, tagTypeNumberRegister);
+ zeroExtend32ToPtr(reg, reg);
+ return result;
+ }
+
</ins><span class="cx"> inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst)
</span><span class="cx"> {
</span><span class="cx"> load64(addressFor(virtualRegisterIndex), dst);
</span><del>- Jump result = branch64(Below, dst, tagTypeNumberRegister);
- zeroExtend32ToPtr(dst, dst);
- return result;
</del><ins>+ return emitJumpIfNotInt32(dst);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitRegisterSetcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/RegisterSet.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/RegisterSet.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/RegisterSet.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -159,6 +159,20 @@
</span><span class="cx"> return result;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+RegisterSet RegisterSet::argumentRegisters()
+{
+ RegisterSet result;
+#if USE(JSVALUE64)
+ for (unsigned argumentIndex = 0; argumentIndex < NUMBER_OF_ARGUMENT_REGISTERS; argumentIndex++) {
+ GPRReg argumentReg = argumentRegisterFor(argumentIndex);
+
+ if (argumentReg != InvalidGPRReg)
+ result.set(argumentReg);
+ }
+#endif
+ return result;
+}
+
</ins><span class="cx"> RegisterSet RegisterSet::vmCalleeSaveRegisters()
</span><span class="cx"> {
</span><span class="cx"> RegisterSet result;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitRegisterSeth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/RegisterSet.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/RegisterSet.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/RegisterSet.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -49,6 +49,7 @@
</span><span class="cx"> static RegisterSet runtimeRegisters();
</span><span class="cx"> static RegisterSet specialRegisters(); // The union of stack, reserved hardware, and runtime registers.
</span><span class="cx"> JS_EXPORT_PRIVATE static RegisterSet calleeSaveRegisters();
</span><ins>+ static RegisterSet argumentRegisters(); // Registers used to pass arguments when making JS Calls
</ins><span class="cx"> static RegisterSet vmCalleeSaveRegisters(); // Callee save registers that might be saved and used by any tier.
</span><span class="cx"> static RegisterSet llintBaselineCalleeSaveRegisters(); // Registers saved and used by the LLInt.
</span><span class="cx"> static RegisterSet dfgCalleeSaveRegisters(); // Registers saved and used by the DFG JIT.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitRepatchcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/Repatch.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/Repatch.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/Repatch.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -540,21 +540,21 @@
</span><span class="cx"> ftlThunkAwareRepatchCall(exec->codeBlock(), stubInfo.slowPathCallLocation(), operationIn);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static void linkSlowFor(VM*, CallLinkInfo& callLinkInfo, MacroAssemblerCodeRef codeRef)
</del><ins>+static void linkSlowFor(VM*, CallLinkInfo& callLinkInfo, JITJSCallThunkEntryPointsWithRef thunkEntryPoints)
</ins><span class="cx"> {
</span><del>- MacroAssembler::repatchNearCall(callLinkInfo.callReturnLocation(), CodeLocationLabel(codeRef.code()));
</del><ins>+ MacroAssembler::repatchNearCall(callLinkInfo.callReturnLocation(), CodeLocationLabel(thunkEntryPoints.entryFor(callLinkInfo.argumentsLocation())));
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-static void linkSlowFor(VM* vm, CallLinkInfo& callLinkInfo, ThunkGenerator generator)
</del><ins>+static void linkSlowFor(VM* vm, CallLinkInfo& callLinkInfo, JITCallThunkEntryGenerator generator)
</ins><span class="cx"> {
</span><del>- linkSlowFor(vm, callLinkInfo, vm->getCTIStub(generator));
</del><ins>+ linkSlowFor(vm, callLinkInfo, vm->getJITCallThunkEntryStub(generator));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> static void linkSlowFor(VM* vm, CallLinkInfo& callLinkInfo)
</span><span class="cx"> {
</span><del>- MacroAssemblerCodeRef virtualThunk = virtualThunkFor(vm, callLinkInfo);
</del><ins>+ JITJSCallThunkEntryPointsWithRef virtualThunk = virtualThunkFor(vm, callLinkInfo);
</ins><span class="cx"> linkSlowFor(vm, callLinkInfo, virtualThunk);
</span><del>- callLinkInfo.setSlowStub(createJITStubRoutine(virtualThunk, *vm, nullptr, true));
</del><ins>+ callLinkInfo.setSlowStub(createJITStubRoutine(virtualThunk.codeRef(), *vm, nullptr, true));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> static bool isWebAssemblyToJSCallee(VM& vm, JSCell* callee)
</span><span class="lines">@@ -644,7 +644,7 @@
</span><span class="cx"> linkSlowFor(vm, callLinkInfo);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static void revertCall(VM* vm, CallLinkInfo& callLinkInfo, MacroAssemblerCodeRef codeRef)
</del><ins>+static void revertCall(VM* vm, CallLinkInfo& callLinkInfo, JITJSCallThunkEntryPointsWithRef codeRef)
</ins><span class="cx"> {
</span><span class="cx"> if (callLinkInfo.isDirect()) {
</span><span class="cx"> callLinkInfo.clearCodeBlock();
</span><span class="lines">@@ -671,7 +671,7 @@
</span><span class="cx"> if (Options::dumpDisassembly())
</span><span class="cx"> dataLog("Unlinking call at ", callLinkInfo.hotPathOther(), "\n");
</span><span class="cx">
</span><del>- revertCall(&vm, callLinkInfo, vm.getCTIStub(linkCallThunkGenerator));
</del><ins>+ revertCall(&vm, callLinkInfo, vm.getJITCallThunkEntryStub(linkCallThunkGenerator));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void linkVirtualFor(ExecState* exec, CallLinkInfo& callLinkInfo)
</span><span class="lines">@@ -683,9 +683,9 @@
</span><span class="cx"> if (shouldDumpDisassemblyFor(callerCodeBlock))
</span><span class="cx"> dataLog("Linking virtual call at ", *callerCodeBlock, " ", callerFrame->codeOrigin(), "\n");
</span><span class="cx">
</span><del>- MacroAssemblerCodeRef virtualThunk = virtualThunkFor(&vm, callLinkInfo);
</del><ins>+ JITJSCallThunkEntryPointsWithRef virtualThunk = virtualThunkFor(&vm, callLinkInfo);
</ins><span class="cx"> revertCall(&vm, callLinkInfo, virtualThunk);
</span><del>- callLinkInfo.setSlowStub(createJITStubRoutine(virtualThunk, vm, nullptr, true));
</del><ins>+ callLinkInfo.setSlowStub(createJITStubRoutine(virtualThunk.codeRef(), vm, nullptr, true));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> namespace {
</span><span class="lines">@@ -740,6 +740,7 @@
</span><span class="cx"> callLinkInfo.setHasSeenClosure();
</span><span class="cx">
</span><span class="cx"> Vector<PolymorphicCallCase> callCases;
</span><ins>+ size_t callerArgumentCount = exec->argumentCountIncludingThis();
</ins><span class="cx">
</span><span class="cx"> // Figure out what our cases are.
</span><span class="cx"> for (CallVariant variant : list) {
</span><span class="lines">@@ -751,7 +752,7 @@
</span><span class="cx"> codeBlock = jsCast<FunctionExecutable*>(executable)->codeBlockForCall();
</span><span class="cx"> // If we cannot handle a callee, either because we don't have a CodeBlock or because arity mismatch,
</span><span class="cx"> // assume that it's better for this whole thing to be a virtual call.
</span><del>- if (!codeBlock || exec->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters()) || callLinkInfo.isVarargs()) {
</del><ins>+ if (!codeBlock || callerArgumentCount < static_cast<size_t>(codeBlock->numParameters()) || callLinkInfo.isVarargs()) {
</ins><span class="cx"> linkVirtualFor(exec, callLinkInfo);
</span><span class="cx"> return;
</span><span class="cx"> }
</span><span class="lines">@@ -775,7 +776,10 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> GPRReg calleeGPR = static_cast<GPRReg>(callLinkInfo.calleeGPR());
</span><del>-
</del><ins>+
+ if (callLinkInfo.argumentsInRegisters())
+ ASSERT(calleeGPR == argumentRegisterForCallee());
+
</ins><span class="cx"> CCallHelpers stubJit(&vm, callerCodeBlock);
</span><span class="cx">
</span><span class="cx"> CCallHelpers::JumpList slowPath;
</span><span class="lines">@@ -797,6 +801,8 @@
</span><span class="cx"> GPRReg scratchGPR;
</span><span class="cx"> if (frameShuffler)
</span><span class="cx"> scratchGPR = frameShuffler->acquireGPR();
</span><ins>+ else if (callLinkInfo.argumentsInRegisters())
+ scratchGPR = GPRInfo::nonArgGPR0;
</ins><span class="cx"> else
</span><span class="cx"> scratchGPR = AssemblyHelpers::selectScratchGPR(calleeGPR);
</span><span class="cx"> // Verify that we have a function and stash the executable in scratchGPR.
</span><span class="lines">@@ -862,13 +868,23 @@
</span><span class="cx"> GPRReg fastCountsBaseGPR;
</span><span class="cx"> if (frameShuffler)
</span><span class="cx"> fastCountsBaseGPR = frameShuffler->acquireGPR();
</span><ins>+ else if (callLinkInfo.argumentsInRegisters())
+#if CPU(ARM64)
+ fastCountsBaseGPR = GPRInfo::nonArgGPR1;
+#else
+ fastCountsBaseGPR = GPRInfo::regT0;
+#endif
</ins><span class="cx"> else {
</span><span class="cx"> fastCountsBaseGPR =
</span><span class="cx"> AssemblyHelpers::selectScratchGPR(calleeGPR, comparisonValueGPR, GPRInfo::regT3);
</span><span class="cx"> }
</span><del>- stubJit.move(CCallHelpers::TrustedImmPtr(fastCounts.get()), fastCountsBaseGPR);
</del><ins>+ if (fastCounts)
+ stubJit.move(CCallHelpers::TrustedImmPtr(fastCounts.get()), fastCountsBaseGPR);
</ins><span class="cx"> if (!frameShuffler && callLinkInfo.isTailCall())
</span><span class="cx"> stubJit.emitRestoreCalleeSaves();
</span><ins>+
+ incrementCounter(&stubJit, VM::PolymorphicCall);
+
</ins><span class="cx"> BinarySwitch binarySwitch(comparisonValueGPR, caseValues, BinarySwitch::IntPtr);
</span><span class="cx"> CCallHelpers::JumpList done;
</span><span class="cx"> while (binarySwitch.advance(stubJit)) {
</span><span class="lines">@@ -877,8 +893,32 @@
</span><span class="cx"> CallVariant variant = callCases[caseIndex].variant();
</span><span class="cx">
</span><span class="cx"> ASSERT(variant.executable()->hasJITCodeForCall());
</span><ins>+
+ EntryPointType entryType = StackArgsArityCheckNotRequired;
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ if (callLinkInfo.argumentsInRegisters()) {
+ CodeBlock* codeBlock = callCases[caseIndex].codeBlock();
+ if (codeBlock) {
+ size_t calleeArgumentCount = static_cast<size_t>(codeBlock->numParameters());
+ if (calleeArgumentCount == callerArgumentCount || calleeArgumentCount >= NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS)
+ entryType = RegisterArgsArityCheckNotRequired;
+ else {
+ EntryPointType entryForArgCount = JITEntryPoints::registerEntryTypeForArgumentCount(callerArgumentCount);
+ MacroAssemblerCodePtr codePtr =
+ variant.executable()->generatedJITCodeForCall()->addressForCall(entryForArgCount);
+ if (codePtr)
+ entryType = entryForArgCount;
+ else
+ entryType = RegisterArgsPossibleExtraArgs;
+ }
+ } else
+ entryType = RegisterArgsPossibleExtraArgs;
+ }
+#endif
+
</ins><span class="cx"> MacroAssemblerCodePtr codePtr =
</span><del>- variant.executable()->generatedJITCodeForCall()->addressForCall(ArityCheckNotRequired);
</del><ins>+ variant.executable()->generatedJITCodeForCall()->addressForCall(entryType);
+ ASSERT(codePtr);
</ins><span class="cx">
</span><span class="cx"> if (fastCounts) {
</span><span class="cx"> stubJit.add32(
</span><span class="lines">@@ -886,7 +926,7 @@
</span><span class="cx"> CCallHelpers::Address(fastCountsBaseGPR, caseIndex * sizeof(uint32_t)));
</span><span class="cx"> }
</span><span class="cx"> if (frameShuffler) {
</span><del>- CallFrameShuffler(stubJit, frameShuffler->snapshot()).prepareForTailCall();
</del><ins>+ CallFrameShuffler(stubJit, frameShuffler->snapshot(callLinkInfo.argumentsLocation())).prepareForTailCall();
</ins><span class="cx"> calls[caseIndex].call = stubJit.nearTailCall();
</span><span class="cx"> } else if (callLinkInfo.isTailCall()) {
</span><span class="cx"> stubJit.prepareForTailCallSlow();
</span><span class="lines">@@ -907,19 +947,19 @@
</span><span class="cx"> #if USE(JSVALUE32_64)
</span><span class="cx"> frameShuffler->setCalleeJSValueRegs(JSValueRegs(GPRInfo::regT1, GPRInfo::regT0));
</span><span class="cx"> #else
</span><del>- frameShuffler->setCalleeJSValueRegs(JSValueRegs(GPRInfo::regT0));
</del><ins>+ if (callLinkInfo.argumentsLocation() == StackArgs)
+ frameShuffler->setCalleeJSValueRegs(JSValueRegs(argumentRegisterForCallee()));
</ins><span class="cx"> #endif
</span><span class="cx"> frameShuffler->prepareForSlowPath();
</span><span class="cx"> } else {
</span><del>- stubJit.move(calleeGPR, GPRInfo::regT0);
</del><span class="cx"> #if USE(JSVALUE32_64)
</span><span class="cx"> stubJit.move(CCallHelpers::TrustedImm32(JSValue::CellTag), GPRInfo::regT1);
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><del>- stubJit.move(CCallHelpers::TrustedImmPtr(&callLinkInfo), GPRInfo::regT2);
- stubJit.move(CCallHelpers::TrustedImmPtr(callLinkInfo.callReturnLocation().executableAddress()), GPRInfo::regT4);
-
- stubJit.restoreReturnAddressBeforeReturn(GPRInfo::regT4);
</del><ins>+ stubJit.move(CCallHelpers::TrustedImmPtr(callLinkInfo.callReturnLocation().executableAddress()), GPRInfo::nonArgGPR1);
+ stubJit.restoreReturnAddressBeforeReturn(GPRInfo::nonArgGPR1);
+
+ stubJit.move(CCallHelpers::TrustedImmPtr(&callLinkInfo), GPRInfo::nonArgGPR0);
</ins><span class="cx"> AssemblyHelpers::Jump slow = stubJit.jump();
</span><span class="cx">
</span><span class="cx"> LinkBuffer patchBuffer(vm, stubJit, owner, JITCompilationCanFail);
</span><span class="lines">@@ -940,7 +980,7 @@
</span><span class="cx"> patchBuffer.link(done, callLinkInfo.callReturnLocation().labelAtOffset(0));
</span><span class="cx"> else
</span><span class="cx"> patchBuffer.link(done, callLinkInfo.hotPathOther().labelAtOffset(0));
</span><del>- patchBuffer.link(slow, CodeLocationLabel(vm.getCTIStub(linkPolymorphicCallThunkGenerator).code()));
</del><ins>+ patchBuffer.link(slow, CodeLocationLabel(vm.getJITCallThunkEntryStub(linkPolymorphicCallThunkGenerator).entryFor(callLinkInfo.argumentsLocation())));
</ins><span class="cx">
</span><span class="cx"> auto stubRoutine = adoptRef(*new PolymorphicCallStubRoutine(
</span><span class="cx"> FINALIZE_CODE_FOR(
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitSpecializedThunkJITh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/SpecializedThunkJIT.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/SpecializedThunkJIT.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/SpecializedThunkJIT.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx"> #if ENABLE(JIT)
</span><span class="cx">
</span><span class="cx"> #include "JIT.h"
</span><ins>+#include "JITEntryPoints.h"
</ins><span class="cx"> #include "JITInlines.h"
</span><span class="cx"> #include "JSInterfaceJIT.h"
</span><span class="cx"> #include "LinkBuffer.h"
</span><span class="lines">@@ -37,18 +38,43 @@
</span><span class="cx"> class SpecializedThunkJIT : public JSInterfaceJIT {
</span><span class="cx"> public:
</span><span class="cx"> static const int ThisArgument = -1;
</span><del>- SpecializedThunkJIT(VM* vm, int expectedArgCount)
</del><ins>+ enum ArgLocation { OnStack, InRegisters };
+
+ SpecializedThunkJIT(VM* vm, int expectedArgCount, AssemblyHelpers::SpillRegisterType spillType = AssemblyHelpers::SpillExactly, ArgLocation argLocation = OnStack)
</ins><span class="cx"> : JSInterfaceJIT(vm)
</span><span class="cx"> {
</span><del>- emitFunctionPrologue();
- emitSaveThenMaterializeTagRegisters();
- // Check that we have the expected number of arguments
- m_failures.append(branch32(NotEqual, payloadFor(CallFrameSlot::argumentCount), TrustedImm32(expectedArgCount + 1)));
</del><ins>+#if !NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ UNUSED_PARAM(spillType);
+ UNUSED_PARAM(argLocation);
+#else
+ if (argLocation == InRegisters) {
+ m_stackArgumentsEntry = label();
+ fillArgumentRegistersFromFrameBeforePrologue();
+ m_registerArgumentsEntry = label();
+ emitFunctionPrologue();
+ emitSaveThenMaterializeTagRegisters();
+ // Check that we have the expected number of arguments
+ m_failures.append(branch32(NotEqual, argumentRegisterForArgumentCount(), TrustedImm32(expectedArgCount + 1)));
+ } else {
+ spillArgumentRegistersToFrameBeforePrologue(expectedArgCount + 1, spillType);
+ m_stackArgumentsEntry = label();
+#endif
+ emitFunctionPrologue();
+ emitSaveThenMaterializeTagRegisters();
+ // Check that we have the expected number of arguments
+ m_failures.append(branch32(NotEqual, payloadFor(CallFrameSlot::argumentCount), TrustedImm32(expectedArgCount + 1)));
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ }
+#endif
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> explicit SpecializedThunkJIT(VM* vm)
</span><span class="cx"> : JSInterfaceJIT(vm)
</span><span class="cx"> {
</span><ins>+#if USE(JSVALUE64)
+ spillArgumentRegistersToFrameBeforePrologue();
+ m_stackArgumentsEntry = Label();
+#endif
</ins><span class="cx"> emitFunctionPrologue();
</span><span class="cx"> emitSaveThenMaterializeTagRegisters();
</span><span class="cx"> }
</span><span class="lines">@@ -94,11 +120,26 @@
</span><span class="cx"> loadInt32Argument(argument, dst, conversionFailed);
</span><span class="cx"> m_failures.append(conversionFailed);
</span><span class="cx"> }
</span><ins>+
+ void checkJSStringArgument(VM& vm, RegisterID argument)
+ {
+ m_failures.append(emitJumpIfNotJSCell(argument));
+ m_failures.append(branchStructure(NotEqual,
+ Address(argument, JSCell::structureIDOffset()),
+ vm.stringStructure.get()));
+ }
</ins><span class="cx">
</span><span class="cx"> void appendFailure(const Jump& failure)
</span><span class="cx"> {
</span><span class="cx"> m_failures.append(failure);
</span><span class="cx"> }
</span><ins>+
+ void linkFailureHere()
+ {
+ m_failures.link(this);
+ m_failures.clear();
+ }
+
</ins><span class="cx"> #if USE(JSVALUE64)
</span><span class="cx"> void returnJSValue(RegisterID src)
</span><span class="cx"> {
</span><span class="lines">@@ -164,13 +205,29 @@
</span><span class="cx"> ret();
</span><span class="cx"> }
</span><span class="cx">
</span><del>- MacroAssemblerCodeRef finalize(MacroAssemblerCodePtr fallback, const char* thunkKind)
</del><ins>+ JITEntryPointsWithRef finalize(MacroAssemblerCodePtr fallback, const char* thunkKind)
</ins><span class="cx"> {
</span><span class="cx"> LinkBuffer patchBuffer(*m_vm, *this, GLOBAL_THUNK_ID);
</span><span class="cx"> patchBuffer.link(m_failures, CodeLocationLabel(fallback));
</span><span class="cx"> for (unsigned i = 0; i < m_calls.size(); i++)
</span><span class="cx"> patchBuffer.link(m_calls[i].first, m_calls[i].second);
</span><del>- return FINALIZE_CODE(patchBuffer, ("Specialized thunk for %s", thunkKind));
</del><ins>+
+ MacroAssemblerCodePtr stackEntry;
+ if (m_stackArgumentsEntry.isSet())
+ stackEntry = patchBuffer.locationOf(m_stackArgumentsEntry);
+ MacroAssemblerCodePtr registerEntry;
+ if (m_registerArgumentsEntry.isSet())
+ registerEntry = patchBuffer.locationOf(m_registerArgumentsEntry);
+
+ MacroAssemblerCodeRef entry = FINALIZE_CODE(patchBuffer, ("Specialized thunk for %s", thunkKind));
+
+ if (m_stackArgumentsEntry.isSet()) {
+ if (m_registerArgumentsEntry.isSet())
+ return JITEntryPointsWithRef(entry, registerEntry, registerEntry, registerEntry, stackEntry, stackEntry);
+ return JITEntryPointsWithRef(entry, entry.code(), entry.code(), entry.code(), stackEntry, stackEntry);
+ }
+
+ return JITEntryPointsWithRef(entry, entry.code(), entry.code());
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // Assumes that the target function uses fpRegister0 as the first argument
</span><span class="lines">@@ -207,6 +264,8 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> MacroAssembler::JumpList m_failures;
</span><ins>+ MacroAssembler::Label m_registerArgumentsEntry;
+ MacroAssembler::Label m_stackArgumentsEntry;
</ins><span class="cx"> Vector<std::pair<Call, FunctionPtr>> m_calls;
</span><span class="cx"> };
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitThunkGeneratorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/ThunkGenerator.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/ThunkGenerator.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/ThunkGenerator.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -30,8 +30,12 @@
</span><span class="cx"> namespace JSC {
</span><span class="cx"> class VM;
</span><span class="cx"> class MacroAssemblerCodeRef;
</span><ins>+class JITEntryPointsWithRef;
+class JITJSCallThunkEntryPointsWithRef;
</ins><span class="cx">
</span><span class="cx"> typedef MacroAssemblerCodeRef (*ThunkGenerator)(VM*);
</span><ins>+typedef JITEntryPointsWithRef (*JITEntryGenerator)(VM*);
+typedef JITJSCallThunkEntryPointsWithRef (*JITCallThunkEntryGenerator)(VM*);
</ins><span class="cx">
</span><span class="cx"> } // namespace JSC
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitThunkGeneratorscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/ThunkGenerators.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/ThunkGenerators.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/ThunkGenerators.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -77,6 +77,23 @@
</span><span class="cx"> return FINALIZE_CODE(patchBuffer, ("Throw exception from call slow path thunk"));
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+static void createRegisterArgumentsSpillEntry(CCallHelpers& jit, MacroAssembler::Label entryPoints[ThunkEntryPointTypeCount])
+{
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ for (unsigned argIndex = NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS; argIndex-- > 0;) {
+ entryPoints[thunkEntryPointTypeFor(argIndex + 1)] = jit.label();
+ jit.emitPutArgumentToCallFrameBeforePrologue(argumentRegisterForFunctionArgument(argIndex), argIndex);
+ }
+
+ jit.emitPutToCallFrameHeaderBeforePrologue(argumentRegisterForCallee(), CallFrameSlot::callee);
+ jit.emitPutToCallFrameHeaderBeforePrologue(argumentRegisterForArgumentCount(), CallFrameSlot::argumentCount);
+#else
+ UNUSED_PARAM(jit);
+ UNUSED_PARAM(entryPoints);
+#endif
+ entryPoints[StackArgs] = jit.label();
+}
+
</ins><span class="cx"> static void slowPathFor(
</span><span class="cx"> CCallHelpers& jit, VM* vm, Sprt_JITOperation_ECli slowPathFunction)
</span><span class="cx"> {
</span><span class="lines">@@ -88,7 +105,7 @@
</span><span class="cx"> // Moving the stack down maxFrameExtentForSlowPathCall bytes gives us room for our 3 arguments
</span><span class="cx"> // and space for the 16 byte return area.
</span><span class="cx"> jit.addPtr(CCallHelpers::TrustedImm32(-maxFrameExtentForSlowPathCall), CCallHelpers::stackPointerRegister);
</span><del>- jit.move(GPRInfo::regT2, GPRInfo::argumentGPR2);
</del><ins>+ jit.move(GPRInfo::nonArgGPR0, GPRInfo::argumentGPR2);
</ins><span class="cx"> jit.addPtr(CCallHelpers::TrustedImm32(32), CCallHelpers::stackPointerRegister, GPRInfo::argumentGPR0);
</span><span class="cx"> jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR1);
</span><span class="cx"> jit.move(CCallHelpers::TrustedImmPtr(bitwise_cast<void*>(slowPathFunction)), GPRInfo::nonArgGPR0);
</span><span class="lines">@@ -100,7 +117,7 @@
</span><span class="cx"> #else
</span><span class="cx"> if (maxFrameExtentForSlowPathCall)
</span><span class="cx"> jit.addPtr(CCallHelpers::TrustedImm32(-maxFrameExtentForSlowPathCall), CCallHelpers::stackPointerRegister);
</span><del>- jit.setupArgumentsWithExecState(GPRInfo::regT2);
</del><ins>+ jit.setupArgumentsWithExecState(GPRInfo::nonArgGPR0);
</ins><span class="cx"> jit.move(CCallHelpers::TrustedImmPtr(bitwise_cast<void*>(slowPathFunction)), GPRInfo::nonArgGPR0);
</span><span class="cx"> emitPointerValidation(jit, GPRInfo::nonArgGPR0);
</span><span class="cx"> jit.call(GPRInfo::nonArgGPR0);
</span><span class="lines">@@ -127,7 +144,7 @@
</span><span class="cx"> jit.jump(GPRInfo::returnValueGPR);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef linkCallThunkGenerator(VM* vm)
</del><ins>+JITJSCallThunkEntryPointsWithRef linkCallThunkGenerator(VM* vm)
</ins><span class="cx"> {
</span><span class="cx"> // The return address is on the stack or in the link register. We will hence
</span><span class="cx"> // save the return address to the call frame while we make a C++ function call
</span><span class="lines">@@ -135,23 +152,115 @@
</span><span class="cx"> // to be in regT0/regT1 (payload/tag), the CallFrame to have already
</span><span class="cx"> // been adjusted, and all other registers to be available for use.
</span><span class="cx"> CCallHelpers jit(vm);
</span><del>-
</del><ins>+
+ MacroAssembler::Label entryPoints[ThunkEntryPointTypeCount];
+
+ createRegisterArgumentsSpillEntry(jit, entryPoints);
</ins><span class="cx"> slowPathFor(jit, vm, operationLinkCall);
</span><span class="cx">
</span><span class="cx"> LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);
</span><del>- return FINALIZE_CODE(patchBuffer, ("Link call slow path thunk"));
</del><ins>+ MacroAssemblerCodeRef codeRef FINALIZE_CODE(patchBuffer, ("Link call slow path thunk"));
+ JITJSCallThunkEntryPointsWithRef callEntryPoints = JITJSCallThunkEntryPointsWithRef(codeRef);
+
+ for (unsigned entryIndex = StackArgs; entryIndex < ThunkEntryPointTypeCount; entryIndex++) {
+ callEntryPoints.setEntryFor(static_cast<ThunkEntryPointType>(entryIndex),
+ patchBuffer.locationOf(entryPoints[entryIndex]));
+ }
+
+ return callEntryPoints;
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+JITJSCallThunkEntryPointsWithRef linkDirectCallThunkGenerator(VM* vm)
+{
+ // The return address is on the stack or in the link register. We will hence
+ // save the return address to the call frame while we make a C++ function call
+ // to perform linking and lazy compilation if necessary. We expect the CallLinkInfo
+ // to be in GPRInfo::nonArgGPR0, the callee to be in argumentRegisterForCallee(),
+ // the CallFrame to have already been adjusted, and arguments in argument registers
+ // and/or in the stack as appropriate.
+ CCallHelpers jit(vm);
+
+ MacroAssembler::Label entryPoints[ThunkEntryPointTypeCount];
+
+ createRegisterArgumentsSpillEntry(jit, entryPoints);
+
+ jit.move(GPRInfo::callFrameRegister, GPRInfo::nonArgGPR1); // Save callee's frame pointer
+ jit.emitFunctionPrologue();
+ jit.storePtr(GPRInfo::callFrameRegister, &vm->topCallFrame);
+
+ if (maxFrameExtentForSlowPathCall)
+ jit.addPtr(CCallHelpers::TrustedImm32(-maxFrameExtentForSlowPathCall), CCallHelpers::stackPointerRegister);
+ jit.setupArguments(GPRInfo::nonArgGPR1, GPRInfo::nonArgGPR0, argumentRegisterForCallee());
+ jit.move(CCallHelpers::TrustedImmPtr(bitwise_cast<void*>(operationLinkDirectCall)), GPRInfo::nonArgGPR0);
+ emitPointerValidation(jit, GPRInfo::nonArgGPR0);
+ jit.call(GPRInfo::nonArgGPR0);
+ if (maxFrameExtentForSlowPathCall)
+ jit.addPtr(CCallHelpers::TrustedImm32(maxFrameExtentForSlowPathCall), CCallHelpers::stackPointerRegister);
+
+ jit.emitFunctionEpilogue();
+
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ jit.emitGetFromCallFrameHeaderBeforePrologue(CallFrameSlot::callee, argumentRegisterForCallee());
+ GPRReg argCountReg = argumentRegisterForArgumentCount();
+ jit.emitGetPayloadFromCallFrameHeaderBeforePrologue(CallFrameSlot::argumentCount, argCountReg);
+
+ // load "this"
+ jit.emitGetFromCallFrameArgumentBeforePrologue(0, argumentRegisterForFunctionArgument(0));
+
+ CCallHelpers::Jump fillUndefined[NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS];
+
+ for (unsigned argIndex = 1; argIndex < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS; argIndex++) {
+ fillUndefined[argIndex] = jit.branch32(MacroAssembler::BelowOrEqual, argCountReg, MacroAssembler::TrustedImm32(argIndex));
+ jit.emitGetFromCallFrameArgumentBeforePrologue(argIndex, argumentRegisterForFunctionArgument(argIndex));
+ }
+
+ CCallHelpers::Jump doneFilling = jit.jump();
+
+ for (unsigned argIndex = 1; argIndex < NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS; argIndex++) {
+ fillUndefined[argIndex].link(&jit);
+ jit.move(CCallHelpers::TrustedImm64(JSValue::encode(jsUndefined())), argumentRegisterForFunctionArgument(argIndex));
+ }
+
+ doneFilling.link(&jit);
+#endif
+
+
+ jit.ret();
+
+ LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);
+ MacroAssemblerCodeRef codeRef FINALIZE_CODE(patchBuffer, ("Link direct call thunk"));
+ JITJSCallThunkEntryPointsWithRef callEntryPoints = JITJSCallThunkEntryPointsWithRef(codeRef);
+
+ for (unsigned entryIndex = StackArgs; entryIndex < ThunkEntryPointTypeCount; entryIndex++) {
+ callEntryPoints.setEntryFor(static_cast<ThunkEntryPointType>(entryIndex),
+ patchBuffer.locationOf(entryPoints[entryIndex]));
+ }
+
+ return callEntryPoints;
+}
+
</ins><span class="cx"> // For closure optimizations, we only include calls, since if you're using closures for
</span><span class="cx"> // object construction then you're going to lose big time anyway.
</span><del>-MacroAssemblerCodeRef linkPolymorphicCallThunkGenerator(VM* vm)
</del><ins>+JITJSCallThunkEntryPointsWithRef linkPolymorphicCallThunkGenerator(VM* vm)
</ins><span class="cx"> {
</span><span class="cx"> CCallHelpers jit(vm);
</span><span class="cx">
</span><ins>+ MacroAssembler::Label entryPoints[ThunkEntryPointTypeCount];
+
+ createRegisterArgumentsSpillEntry(jit, entryPoints);
+
</ins><span class="cx"> slowPathFor(jit, vm, operationLinkPolymorphicCall);
</span><span class="cx">
</span><span class="cx"> LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);
</span><del>- return FINALIZE_CODE(patchBuffer, ("Link polymorphic call slow path thunk"));
</del><ins>+ MacroAssemblerCodeRef codeRef FINALIZE_CODE(patchBuffer, ("Link polymorphic call slow path thunk"));
+ JITJSCallThunkEntryPointsWithRef callEntryPoints = JITJSCallThunkEntryPointsWithRef(codeRef);
+
+ for (unsigned entryIndex = StackArgs; entryIndex < ThunkEntryPointTypeCount; entryIndex++) {
+ callEntryPoints.setEntryFor(static_cast<ThunkEntryPointType>(entryIndex),
+ patchBuffer.locationOf(entryPoints[entryIndex]));
+ }
+
+ return callEntryPoints;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // FIXME: We should distinguish between a megamorphic virtual call vs. a slow
</span><span class="lines">@@ -158,22 +267,38 @@
</span><span class="cx"> // path virtual call so that we can enable fast tail calls for megamorphic
</span><span class="cx"> // virtual calls by using the shuffler.
</span><span class="cx"> // https://bugs.webkit.org/show_bug.cgi?id=148831
</span><del>-MacroAssemblerCodeRef virtualThunkFor(VM* vm, CallLinkInfo& callLinkInfo)
</del><ins>+JITJSCallThunkEntryPointsWithRef virtualThunkFor(VM* vm, CallLinkInfo& callLinkInfo)
</ins><span class="cx"> {
</span><del>- // The callee is in regT0 (for JSVALUE32_64, the tag is in regT1).
- // The return address is on the stack, or in the link register. We will hence
- // jump to the callee, or save the return address to the call frame while we
- // make a C++ function call to the appropriate JIT operation.
</del><ins>+ // The callee is in argumentRegisterForCallee() (for JSVALUE32_64, it is in regT1:regT0).
+ // The CallLinkInfo is in GPRInfo::nonArgGPR0.
+ // The return address is on the stack, or in the link register.
+ /// We will hence jump to the callee, or save the return address to the call
+ // frame while we make a C++ function call to the appropriate JIT operation.
</ins><span class="cx">
</span><span class="cx"> CCallHelpers jit(vm);
</span><span class="cx">
</span><span class="cx"> CCallHelpers::JumpList slowCase;
</span><del>-
- // This is a slow path execution, and regT2 contains the CallLinkInfo. Count the
- // slow path execution for the profiler.
</del><ins>+
+ GPRReg calleeReg = argumentRegisterForCallee();
+#if USE(JSVALUE32_64)
+ GPRReg calleeTagReg = GPRInfo::regT1;
+#endif
+ GPRReg targetReg = GPRInfo::nonArgGPR1;
+ // This is the CallLinkInfo* on entry and used later as a temp.
+ GPRReg callLinkInfoAndTempReg = GPRInfo::nonArgGPR0;
+
+ jit.fillArgumentRegistersFromFrameBeforePrologue();
+
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ MacroAssembler::Label registerEntry = jit.label();
+#endif
+
+ incrementCounter(&jit, VM::VirtualCall);
+
+ // This is a slow path execution. Count the slow path execution for the profiler.
</ins><span class="cx"> jit.add32(
</span><span class="cx"> CCallHelpers::TrustedImm32(1),
</span><del>- CCallHelpers::Address(GPRInfo::regT2, CallLinkInfo::offsetOfSlowPathCount()));
</del><ins>+ CCallHelpers::Address(callLinkInfoAndTempReg, CallLinkInfo::offsetOfSlowPathCount()));
</ins><span class="cx">
</span><span class="cx"> // FIXME: we should have a story for eliminating these checks. In many cases,
</span><span class="cx"> // the DFG knows that the value is definitely a cell, or definitely a function.
</span><span class="lines">@@ -181,54 +306,72 @@
</span><span class="cx"> #if USE(JSVALUE64)
</span><span class="cx"> slowCase.append(
</span><span class="cx"> jit.branchTest64(
</span><del>- CCallHelpers::NonZero, GPRInfo::regT0, GPRInfo::tagMaskRegister));
</del><ins>+ CCallHelpers::NonZero, calleeReg, GPRInfo::tagMaskRegister));
</ins><span class="cx"> #else
</span><span class="cx"> slowCase.append(
</span><span class="cx"> jit.branch32(
</span><del>- CCallHelpers::NotEqual, GPRInfo::regT1,
</del><ins>+ CCallHelpers::NotEqual, calleeTagReg,
</ins><span class="cx"> CCallHelpers::TrustedImm32(JSValue::CellTag)));
</span><span class="cx"> #endif
</span><del>- slowCase.append(jit.branchIfNotType(GPRInfo::regT0, JSFunctionType));
</del><ins>+ slowCase.append(jit.branchIfNotType(calleeReg, JSFunctionType));
</ins><span class="cx">
</span><span class="cx"> // Now we know we have a JSFunction.
</span><span class="cx">
</span><span class="cx"> jit.loadPtr(
</span><del>- CCallHelpers::Address(GPRInfo::regT0, JSFunction::offsetOfExecutable()),
- GPRInfo::regT4);
</del><ins>+ CCallHelpers::Address(calleeReg, JSFunction::offsetOfExecutable()),
+ targetReg);
+
+ ArgumentsLocation argumentsLocation = callLinkInfo.isTailCall() ? StackArgs : callLinkInfo.argumentsLocation();
+
</ins><span class="cx"> jit.loadPtr(
</span><span class="cx"> CCallHelpers::Address(
</span><del>- GPRInfo::regT4, ExecutableBase::offsetOfJITCodeWithArityCheckFor(
- callLinkInfo.specializationKind())),
- GPRInfo::regT4);
- slowCase.append(jit.branchTestPtr(CCallHelpers::Zero, GPRInfo::regT4));
</del><ins>+ targetReg, ExecutableBase::offsetOfEntryFor(
+ callLinkInfo.specializationKind(),
+ entryPointTypeFor(argumentsLocation))),
+ targetReg);
+ slowCase.append(jit.branchTestPtr(CCallHelpers::Zero, targetReg));
</ins><span class="cx">
</span><span class="cx"> // Now we know that we have a CodeBlock, and we're committed to making a fast
</span><span class="cx"> // call.
</span><span class="cx">
</span><span class="cx"> // Make a tail call. This will return back to JIT code.
</span><del>- emitPointerValidation(jit, GPRInfo::regT4);
</del><ins>+ emitPointerValidation(jit, targetReg);
</ins><span class="cx"> if (callLinkInfo.isTailCall()) {
</span><del>- jit.preserveReturnAddressAfterCall(GPRInfo::regT0);
- jit.prepareForTailCallSlow(GPRInfo::regT4);
</del><ins>+ jit.spillArgumentRegistersToFrameBeforePrologue();
+ jit.preserveReturnAddressAfterCall(callLinkInfoAndTempReg);
+ jit.prepareForTailCallSlow(targetReg);
</ins><span class="cx"> }
</span><del>- jit.jump(GPRInfo::regT4);
</del><ins>+ jit.jump(targetReg);
+ slowCase.link(&jit);
</ins><span class="cx">
</span><del>- slowCase.link(&jit);
-
</del><ins>+ incrementCounter(&jit, VM::VirtualSlowCall);
+
</ins><span class="cx"> // Here we don't know anything, so revert to the full slow path.
</span><ins>+ jit.spillArgumentRegistersToFrameBeforePrologue();
</ins><span class="cx">
</span><span class="cx"> slowPathFor(jit, vm, operationVirtualCall);
</span><span class="cx">
</span><span class="cx"> LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);
</span><del>- return FINALIZE_CODE(
- patchBuffer,
</del><ins>+ MacroAssemblerCodeRef codeRef FINALIZE_CODE(patchBuffer,
</ins><span class="cx"> ("Virtual %s slow path thunk",
</span><span class="cx"> callLinkInfo.callMode() == CallMode::Regular ? "call" : callLinkInfo.callMode() == CallMode::Tail ? "tail call" : "construct"));
</span><ins>+ JITJSCallThunkEntryPointsWithRef callEntryPoints = JITJSCallThunkEntryPointsWithRef(codeRef);
+
+ callEntryPoints.setEntryFor(StackArgsEntry, codeRef.code());
+
+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ MacroAssemblerCodePtr registerEntryPtr = patchBuffer.locationOf(registerEntry);
+
+ for (unsigned entryIndex = Register1ArgEntry; entryIndex < ThunkEntryPointTypeCount; entryIndex++)
+ callEntryPoints.setEntryFor(static_cast<ThunkEntryPointType>(entryIndex), registerEntryPtr);
+#endif
+
+ return callEntryPoints;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> enum ThunkEntryType { EnterViaCall, EnterViaJumpWithSavedTags, EnterViaJumpWithoutSavedTags };
</span><span class="cx">
</span><del>-static MacroAssemblerCodeRef nativeForGenerator(VM* vm, CodeSpecializationKind kind, ThunkEntryType entryType = EnterViaCall)
</del><ins>+static JITEntryPointsWithRef nativeForGenerator(VM* vm, CodeSpecializationKind kind, ThunkEntryType entryType = EnterViaCall)
</ins><span class="cx"> {
</span><span class="cx"> // FIXME: This should be able to log ShadowChicken prologue packets.
</span><span class="cx"> // https://bugs.webkit.org/show_bug.cgi?id=155689
</span><span class="lines">@@ -237,8 +380,14 @@
</span><span class="cx">
</span><span class="cx"> JSInterfaceJIT jit(vm);
</span><span class="cx">
</span><ins>+ MacroAssembler::Label stackArgsEntry;
+
</ins><span class="cx"> switch (entryType) {
</span><span class="cx"> case EnterViaCall:
</span><ins>+ jit.spillArgumentRegistersToFrameBeforePrologue();
+
+ stackArgsEntry = jit.label();
+
</ins><span class="cx"> jit.emitFunctionPrologue();
</span><span class="cx"> break;
</span><span class="cx"> case EnterViaJumpWithSavedTags:
</span><span class="lines">@@ -379,10 +528,18 @@
</span><span class="cx"> jit.jumpToExceptionHandler();
</span><span class="cx">
</span><span class="cx"> LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);
</span><del>- return FINALIZE_CODE(patchBuffer, ("native %s%s trampoline", entryType == EnterViaJumpWithSavedTags ? "Tail With Saved Tags " : entryType == EnterViaJumpWithoutSavedTags ? "Tail Without Saved Tags " : "", toCString(kind).data()));
</del><ins>+ MacroAssemblerCodeRef codeRef FINALIZE_CODE(patchBuffer, ("native %s%s trampoline", entryType == EnterViaJumpWithSavedTags ? "Tail With Saved Tags " : entryType == EnterViaJumpWithoutSavedTags ? "Tail Without Saved Tags " : "", toCString(kind).data()));
+ if (entryType == EnterViaCall) {
+ MacroAssemblerCodePtr stackEntryPtr = patchBuffer.locationOf(stackArgsEntry);
+
+ return JITEntryPointsWithRef(codeRef, codeRef.code(), codeRef.code(), codeRef.code(), stackEntryPtr, stackEntryPtr);
+ }
+
+ return JITEntryPointsWithRef(codeRef, codeRef.code(), codeRef.code());
+
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef nativeCallGenerator(VM* vm)
</del><ins>+JITEntryPointsWithRef nativeCallGenerator(VM* vm)
</ins><span class="cx"> {
</span><span class="cx"> return nativeForGenerator(vm, CodeForCall);
</span><span class="cx"> }
</span><span class="lines">@@ -389,15 +546,15 @@
</span><span class="cx">
</span><span class="cx"> MacroAssemblerCodeRef nativeTailCallGenerator(VM* vm)
</span><span class="cx"> {
</span><del>- return nativeForGenerator(vm, CodeForCall, EnterViaJumpWithSavedTags);
</del><ins>+ return nativeForGenerator(vm, CodeForCall, EnterViaJumpWithSavedTags).codeRef();
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> MacroAssemblerCodeRef nativeTailCallWithoutSavedTagsGenerator(VM* vm)
</span><span class="cx"> {
</span><del>- return nativeForGenerator(vm, CodeForCall, EnterViaJumpWithoutSavedTags);
</del><ins>+ return nativeForGenerator(vm, CodeForCall, EnterViaJumpWithoutSavedTags).codeRef();
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef nativeConstructGenerator(VM* vm)
</del><ins>+JITEntryPointsWithRef nativeConstructGenerator(VM* vm)
</ins><span class="cx"> {
</span><span class="cx"> return nativeForGenerator(vm, CodeForConstruct);
</span><span class="cx"> }
</span><span class="lines">@@ -536,6 +693,43 @@
</span><span class="cx"> return FINALIZE_CODE(patchBuffer, ("unreachable thunk"));
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+static void stringCharLoadRegCall(SpecializedThunkJIT& jit, VM* vm)
+{
+ // load string
+ GPRReg thisReg = argumentRegisterForFunctionArgument(0);
+ GPRReg indexReg = argumentRegisterForFunctionArgument(2);
+ GPRReg lengthReg = argumentRegisterForFunctionArgument(3);
+ GPRReg tempReg = SpecializedThunkJIT::nonArgGPR0;
+
+ jit.checkJSStringArgument(*vm, thisReg);
+
+ // Load string length to regT2, and start the process of loading the data pointer into regT0
+ jit.load32(MacroAssembler::Address(thisReg, ThunkHelpers::jsStringLengthOffset()), lengthReg);
+ jit.loadPtr(MacroAssembler::Address(thisReg, ThunkHelpers::jsStringValueOffset()), tempReg);
+ jit.appendFailure(jit.branchTest32(MacroAssembler::Zero, tempReg));
+
+ // load index
+ jit.move(argumentRegisterForFunctionArgument(1), indexReg);
+ jit.appendFailure(jit.emitJumpIfNotInt32(indexReg));
+
+ // Do an unsigned compare to simultaneously filter negative indices as well as indices that are too large
+ jit.appendFailure(jit.branch32(MacroAssembler::AboveOrEqual, indexReg, lengthReg));
+
+ // Load the character
+ SpecializedThunkJIT::JumpList is16Bit;
+ SpecializedThunkJIT::JumpList cont8Bit;
+ // Load the string flags
+ jit.loadPtr(MacroAssembler::Address(tempReg, StringImpl::flagsOffset()), lengthReg);
+ jit.loadPtr(MacroAssembler::Address(tempReg, StringImpl::dataOffset()), tempReg);
+ is16Bit.append(jit.branchTest32(MacroAssembler::Zero, lengthReg, MacroAssembler::TrustedImm32(StringImpl::flagIs8Bit())));
+ jit.load8(MacroAssembler::BaseIndex(tempReg, indexReg, MacroAssembler::TimesOne, 0), tempReg);
+ cont8Bit.append(jit.jump());
+ is16Bit.link(&jit);
+ jit.load16(MacroAssembler::BaseIndex(tempReg, indexReg, MacroAssembler::TimesTwo, 0), tempReg);
+ cont8Bit.link(&jit);
+}
+#else
</ins><span class="cx"> static void stringCharLoad(SpecializedThunkJIT& jit, VM* vm)
</span><span class="cx"> {
</span><span class="cx"> // load string
</span><span class="lines">@@ -565,6 +759,7 @@
</span><span class="cx"> jit.load16(MacroAssembler::BaseIndex(SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1, MacroAssembler::TimesTwo, 0), SpecializedThunkJIT::regT0);
</span><span class="cx"> cont8Bit.link(&jit);
</span><span class="cx"> }
</span><ins>+#endif
</ins><span class="cx">
</span><span class="cx"> static void charToString(SpecializedThunkJIT& jit, VM* vm, MacroAssembler::RegisterID src, MacroAssembler::RegisterID dst, MacroAssembler::RegisterID scratch)
</span><span class="cx"> {
</span><span class="lines">@@ -574,34 +769,69 @@
</span><span class="cx"> jit.appendFailure(jit.branchTestPtr(MacroAssembler::Zero, dst));
</span><span class="cx"> }
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef charCodeAtThunkGenerator(VM* vm)
</del><ins>+JITEntryPointsWithRef charCodeAtThunkGenerator(VM* vm)
</ins><span class="cx"> {
</span><ins>+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ SpecializedThunkJIT jit(vm, 1, AssemblyHelpers::SpillExactly, SpecializedThunkJIT::InRegisters);
+ stringCharLoadRegCall(jit, vm);
+ jit.returnInt32(SpecializedThunkJIT::nonArgGPR0);
+ jit.linkFailureHere();
+ jit.spillArgumentRegistersToFrame(2, AssemblyHelpers::SpillExactly);
+ jit.appendFailure(jit.jump());
+ return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "charCodeAt");
+#else
</ins><span class="cx"> SpecializedThunkJIT jit(vm, 1);
</span><span class="cx"> stringCharLoad(jit, vm);
</span><span class="cx"> jit.returnInt32(SpecializedThunkJIT::regT0);
</span><span class="cx"> return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "charCodeAt");
</span><ins>+#endif
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef charAtThunkGenerator(VM* vm)
</del><ins>+JITEntryPointsWithRef charAtThunkGenerator(VM* vm)
</ins><span class="cx"> {
</span><ins>+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ SpecializedThunkJIT jit(vm, 1, AssemblyHelpers::SpillExactly, SpecializedThunkJIT::InRegisters);
+ stringCharLoadRegCall(jit, vm);
+ charToString(jit, vm, SpecializedThunkJIT::nonArgGPR0, SpecializedThunkJIT::returnValueGPR, argumentRegisterForFunctionArgument(3));
+ jit.returnJSCell(SpecializedThunkJIT::returnValueGPR);
+ jit.linkFailureHere();
+ jit.spillArgumentRegistersToFrame(2, AssemblyHelpers::SpillExactly);
+ jit.appendFailure(jit.jump());
+ return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "charAt");
+#else
</ins><span class="cx"> SpecializedThunkJIT jit(vm, 1);
</span><span class="cx"> stringCharLoad(jit, vm);
</span><span class="cx"> charToString(jit, vm, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1);
</span><span class="cx"> jit.returnJSCell(SpecializedThunkJIT::regT0);
</span><span class="cx"> return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "charAt");
</span><ins>+#endif
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef fromCharCodeThunkGenerator(VM* vm)
</del><ins>+JITEntryPointsWithRef fromCharCodeThunkGenerator(VM* vm)
</ins><span class="cx"> {
</span><del>- SpecializedThunkJIT jit(vm, 1);
</del><ins>+#if NUMBER_OF_JS_FUNCTION_ARGUMENT_REGISTERS
+ SpecializedThunkJIT jit(vm, 1, AssemblyHelpers::SpillExactly, SpecializedThunkJIT::InRegisters);
</ins><span class="cx"> // load char code
</span><ins>+ jit.move(argumentRegisterForFunctionArgument(1), SpecializedThunkJIT::nonArgGPR0);
+ jit.appendFailure(jit.emitJumpIfNotInt32(SpecializedThunkJIT::nonArgGPR0));
+
+ charToString(jit, vm, SpecializedThunkJIT::nonArgGPR0, SpecializedThunkJIT::returnValueGPR, argumentRegisterForFunctionArgument(3));
+ jit.returnJSCell(SpecializedThunkJIT::returnValueGPR);
+ jit.linkFailureHere();
+ jit.spillArgumentRegistersToFrame(2, AssemblyHelpers::SpillAll);
+ jit.appendFailure(jit.jump());
+ return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "fromCharCode");
+#else
+ SpecializedThunkJIT jit(vm, 1, AssemblyHelpers::SpillAll);
+ // load char code
</ins><span class="cx"> jit.loadInt32Argument(0, SpecializedThunkJIT::regT0);
</span><span class="cx"> charToString(jit, vm, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1);
</span><span class="cx"> jit.returnJSCell(SpecializedThunkJIT::regT0);
</span><span class="cx"> return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "fromCharCode");
</span><ins>+#endif
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef clz32ThunkGenerator(VM* vm)
</del><ins>+JITEntryPointsWithRef clz32ThunkGenerator(VM* vm)
</ins><span class="cx"> {
</span><span class="cx"> SpecializedThunkJIT jit(vm, 1);
</span><span class="cx"> MacroAssembler::Jump nonIntArgJump;
</span><span class="lines">@@ -622,11 +852,11 @@
</span><span class="cx"> return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "clz32");
</span><span class="cx"> }
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef sqrtThunkGenerator(VM* vm)
</del><ins>+JITEntryPointsWithRef sqrtThunkGenerator(VM* vm)
</ins><span class="cx"> {
</span><span class="cx"> SpecializedThunkJIT jit(vm, 1);
</span><span class="cx"> if (!jit.supportsFloatingPointSqrt())
</span><del>- return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
</del><ins>+ return vm->jitStubs->jitEntryNativeCall(vm);
</ins><span class="cx">
</span><span class="cx"> jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
</span><span class="cx"> jit.sqrtDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT0);
</span><span class="lines">@@ -782,12 +1012,12 @@
</span><span class="cx">
</span><span class="cx"> static const double halfConstant = 0.5;
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef floorThunkGenerator(VM* vm)
</del><ins>+JITEntryPointsWithRef floorThunkGenerator(VM* vm)
</ins><span class="cx"> {
</span><span class="cx"> SpecializedThunkJIT jit(vm, 1);
</span><span class="cx"> MacroAssembler::Jump nonIntJump;
</span><span class="cx"> if (!UnaryDoubleOpWrapper(floor) || !jit.supportsFloatingPoint())
</span><del>- return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
</del><ins>+ return vm->jitStubs->jitEntryNativeCall(vm);
</ins><span class="cx"> jit.loadInt32Argument(0, SpecializedThunkJIT::regT0, nonIntJump);
</span><span class="cx"> jit.returnInt32(SpecializedThunkJIT::regT0);
</span><span class="cx"> nonIntJump.link(&jit);
</span><span class="lines">@@ -825,11 +1055,11 @@
</span><span class="cx"> return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "floor");
</span><span class="cx"> }
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef ceilThunkGenerator(VM* vm)
</del><ins>+JITEntryPointsWithRef ceilThunkGenerator(VM* vm)
</ins><span class="cx"> {
</span><span class="cx"> SpecializedThunkJIT jit(vm, 1);
</span><span class="cx"> if (!UnaryDoubleOpWrapper(ceil) || !jit.supportsFloatingPoint())
</span><del>- return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
</del><ins>+ return vm->jitStubs->jitEntryNativeCall(vm);
</ins><span class="cx"> MacroAssembler::Jump nonIntJump;
</span><span class="cx"> jit.loadInt32Argument(0, SpecializedThunkJIT::regT0, nonIntJump);
</span><span class="cx"> jit.returnInt32(SpecializedThunkJIT::regT0);
</span><span class="lines">@@ -848,11 +1078,11 @@
</span><span class="cx"> return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "ceil");
</span><span class="cx"> }
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef truncThunkGenerator(VM* vm)
</del><ins>+JITEntryPointsWithRef truncThunkGenerator(VM* vm)
</ins><span class="cx"> {
</span><span class="cx"> SpecializedThunkJIT jit(vm, 1);
</span><span class="cx"> if (!UnaryDoubleOpWrapper(trunc) || !jit.supportsFloatingPoint())
</span><del>- return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
</del><ins>+ return vm->jitStubs->jitEntryNativeCall(vm);
</ins><span class="cx"> MacroAssembler::Jump nonIntJump;
</span><span class="cx"> jit.loadInt32Argument(0, SpecializedThunkJIT::regT0, nonIntJump);
</span><span class="cx"> jit.returnInt32(SpecializedThunkJIT::regT0);
</span><span class="lines">@@ -871,11 +1101,11 @@
</span><span class="cx"> return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "trunc");
</span><span class="cx"> }
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef roundThunkGenerator(VM* vm)
</del><ins>+JITEntryPointsWithRef roundThunkGenerator(VM* vm)
</ins><span class="cx"> {
</span><span class="cx"> SpecializedThunkJIT jit(vm, 1);
</span><span class="cx"> if (!UnaryDoubleOpWrapper(jsRound) || !jit.supportsFloatingPoint())
</span><del>- return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
</del><ins>+ return vm->jitStubs->jitEntryNativeCall(vm);
</ins><span class="cx"> MacroAssembler::Jump nonIntJump;
</span><span class="cx"> jit.loadInt32Argument(0, SpecializedThunkJIT::regT0, nonIntJump);
</span><span class="cx"> jit.returnInt32(SpecializedThunkJIT::regT0);
</span><span class="lines">@@ -905,13 +1135,13 @@
</span><span class="cx"> return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "round");
</span><span class="cx"> }
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef expThunkGenerator(VM* vm)
</del><ins>+JITEntryPointsWithRef expThunkGenerator(VM* vm)
</ins><span class="cx"> {
</span><span class="cx"> if (!UnaryDoubleOpWrapper(exp))
</span><del>- return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
</del><ins>+ return vm->jitStubs->jitEntryNativeCall(vm);
</ins><span class="cx"> SpecializedThunkJIT jit(vm, 1);
</span><span class="cx"> if (!jit.supportsFloatingPoint())
</span><del>- return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
</del><ins>+ return vm->jitStubs->jitEntryNativeCall(vm);
</ins><span class="cx"> jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
</span><span class="cx"> jit.callDoubleToDoublePreservingReturn(UnaryDoubleOpWrapper(exp));
</span><span class="cx"> jit.returnDouble(SpecializedThunkJIT::fpRegT0);
</span><span class="lines">@@ -918,13 +1148,13 @@
</span><span class="cx"> return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "exp");
</span><span class="cx"> }
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef logThunkGenerator(VM* vm)
</del><ins>+JITEntryPointsWithRef logThunkGenerator(VM* vm)
</ins><span class="cx"> {
</span><span class="cx"> if (!UnaryDoubleOpWrapper(log))
</span><del>- return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
</del><ins>+ return vm->jitStubs->jitEntryNativeCall(vm);
</ins><span class="cx"> SpecializedThunkJIT jit(vm, 1);
</span><span class="cx"> if (!jit.supportsFloatingPoint())
</span><del>- return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
</del><ins>+ return vm->jitStubs->jitEntryNativeCall(vm);
</ins><span class="cx"> jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
</span><span class="cx"> jit.callDoubleToDoublePreservingReturn(UnaryDoubleOpWrapper(log));
</span><span class="cx"> jit.returnDouble(SpecializedThunkJIT::fpRegT0);
</span><span class="lines">@@ -931,11 +1161,11 @@
</span><span class="cx"> return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "log");
</span><span class="cx"> }
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef absThunkGenerator(VM* vm)
</del><ins>+JITEntryPointsWithRef absThunkGenerator(VM* vm)
</ins><span class="cx"> {
</span><span class="cx"> SpecializedThunkJIT jit(vm, 1);
</span><span class="cx"> if (!jit.supportsFloatingPointAbs())
</span><del>- return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
</del><ins>+ return vm->jitStubs->jitEntryNativeCall(vm);
</ins><span class="cx">
</span><span class="cx"> #if USE(JSVALUE64)
</span><span class="cx"> unsigned virtualRegisterIndex = CallFrame::argumentOffset(0);
</span><span class="lines">@@ -988,7 +1218,7 @@
</span><span class="cx"> return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "abs");
</span><span class="cx"> }
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef imulThunkGenerator(VM* vm)
</del><ins>+JITEntryPointsWithRef imulThunkGenerator(VM* vm)
</ins><span class="cx"> {
</span><span class="cx"> SpecializedThunkJIT jit(vm, 2);
</span><span class="cx"> MacroAssembler::Jump nonIntArg0Jump;
</span><span class="lines">@@ -1019,11 +1249,11 @@
</span><span class="cx"> return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "imul");
</span><span class="cx"> }
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef randomThunkGenerator(VM* vm)
</del><ins>+JITEntryPointsWithRef randomThunkGenerator(VM* vm)
</ins><span class="cx"> {
</span><span class="cx"> SpecializedThunkJIT jit(vm, 0);
</span><span class="cx"> if (!jit.supportsFloatingPoint())
</span><del>- return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
</del><ins>+ return vm->jitStubs->jitEntryNativeCall(vm);
</ins><span class="cx">
</span><span class="cx"> #if USE(JSVALUE64)
</span><span class="cx"> jit.emitRandomThunk(SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1, SpecializedThunkJIT::regT2, SpecializedThunkJIT::regT3, SpecializedThunkJIT::fpRegT0);
</span><span class="lines">@@ -1031,16 +1261,22 @@
</span><span class="cx">
</span><span class="cx"> return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "random");
</span><span class="cx"> #else
</span><del>- return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
</del><ins>+ return vm->jitStubs->jitEntryNativeCall(vm);
</ins><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef boundThisNoArgsFunctionCallGenerator(VM* vm)
</del><ins>+JITEntryPointsWithRef boundThisNoArgsFunctionCallGenerator(VM* vm)
</ins><span class="cx"> {
</span><del>- CCallHelpers jit(vm);
</del><ins>+ JSInterfaceJIT jit(vm);
+
+ MacroAssembler::JumpList failures;
+
+ jit.spillArgumentRegistersToFrameBeforePrologue();
</ins><span class="cx">
</span><ins>+ SpecializedThunkJIT::Label stackArgsEntry(&jit);
+
</ins><span class="cx"> jit.emitFunctionPrologue();
</span><del>-
</del><ins>+
</ins><span class="cx"> // Set up our call frame.
</span><span class="cx"> jit.storePtr(CCallHelpers::TrustedImmPtr(nullptr), CCallHelpers::addressFor(CallFrameSlot::codeBlock));
</span><span class="cx"> jit.store32(CCallHelpers::TrustedImm32(0), CCallHelpers::tagFor(CallFrameSlot::argumentCount));
</span><span class="lines">@@ -1110,9 +1346,9 @@
</span><span class="cx"> GPRInfo::regT0);
</span><span class="cx"> jit.loadPtr(
</span><span class="cx"> CCallHelpers::Address(
</span><del>- GPRInfo::regT0, ExecutableBase::offsetOfJITCodeWithArityCheckFor(CodeForCall)),
</del><ins>+ GPRInfo::regT0, ExecutableBase::offsetOfEntryFor(CodeForCall, StackArgsMustCheckArity)),
</ins><span class="cx"> GPRInfo::regT0);
</span><del>- CCallHelpers::Jump noCode = jit.branchTestPtr(CCallHelpers::Zero, GPRInfo::regT0);
</del><ins>+ failures.append(jit.branchTestPtr(CCallHelpers::Zero, GPRInfo::regT0));
</ins><span class="cx">
</span><span class="cx"> emitPointerValidation(jit, GPRInfo::regT0);
</span><span class="cx"> jit.call(GPRInfo::regT0);
</span><span class="lines">@@ -1119,11 +1355,14 @@
</span><span class="cx">
</span><span class="cx"> jit.emitFunctionEpilogue();
</span><span class="cx"> jit.ret();
</span><del>-
- LinkBuffer linkBuffer(*vm, jit, GLOBAL_THUNK_ID);
- linkBuffer.link(noCode, CodeLocationLabel(vm->jitStubs->ctiNativeTailCallWithoutSavedTags(vm)));
- return FINALIZE_CODE(
- linkBuffer, ("Specialized thunk for bound function calls with no arguments"));
</del><ins>+
+ LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);
+ patchBuffer.link(failures, CodeLocationLabel(vm->jitStubs->ctiNativeTailCallWithoutSavedTags(vm)));
+
+ MacroAssemblerCodeRef codeRef FINALIZE_CODE(patchBuffer, ("Specialized thunk for bound function calls with no arguments"));
+ MacroAssemblerCodePtr stackEntryPtr = patchBuffer.locationOf(stackArgsEntry);
+
+ return JITEntryPointsWithRef(codeRef, codeRef.code(), codeRef.code(), codeRef.code(), stackEntryPtr, stackEntryPtr);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitThunkGeneratorsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/ThunkGenerators.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/ThunkGenerators.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jit/ThunkGenerators.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -26,6 +26,7 @@
</span><span class="cx"> #pragma once
</span><span class="cx">
</span><span class="cx"> #include "CodeSpecializationKind.h"
</span><ins>+#include "JITEntryPoints.h"
</ins><span class="cx"> #include "ThunkGenerator.h"
</span><span class="cx">
</span><span class="cx"> #if ENABLE(JIT)
</span><span class="lines">@@ -36,34 +37,35 @@
</span><span class="cx"> MacroAssemblerCodeRef throwExceptionFromCallSlowPathGenerator(VM*);
</span><span class="cx">
</span><span class="cx"> MacroAssemblerCodeRef linkCallThunk(VM*, CallLinkInfo&, CodeSpecializationKind);
</span><del>-MacroAssemblerCodeRef linkCallThunkGenerator(VM*);
-MacroAssemblerCodeRef linkPolymorphicCallThunkGenerator(VM*);
</del><ins>+JITJSCallThunkEntryPointsWithRef linkCallThunkGenerator(VM*);
+JITJSCallThunkEntryPointsWithRef linkDirectCallThunkGenerator(VM*);
+JITJSCallThunkEntryPointsWithRef linkPolymorphicCallThunkGenerator(VM*);
</ins><span class="cx">
</span><del>-MacroAssemblerCodeRef virtualThunkFor(VM*, CallLinkInfo&);
</del><ins>+JITJSCallThunkEntryPointsWithRef virtualThunkFor(VM*, CallLinkInfo&);
</ins><span class="cx">
</span><del>-MacroAssemblerCodeRef nativeCallGenerator(VM*);
-MacroAssemblerCodeRef nativeConstructGenerator(VM*);
</del><ins>+JITEntryPointsWithRef nativeCallGenerator(VM*);
+JITEntryPointsWithRef nativeConstructGenerator(VM*);
</ins><span class="cx"> MacroAssemblerCodeRef nativeTailCallGenerator(VM*);
</span><span class="cx"> MacroAssemblerCodeRef nativeTailCallWithoutSavedTagsGenerator(VM*);
</span><span class="cx"> MacroAssemblerCodeRef arityFixupGenerator(VM*);
</span><span class="cx"> MacroAssemblerCodeRef unreachableGenerator(VM*);
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef charCodeAtThunkGenerator(VM*);
-MacroAssemblerCodeRef charAtThunkGenerator(VM*);
-MacroAssemblerCodeRef clz32ThunkGenerator(VM*);
-MacroAssemblerCodeRef fromCharCodeThunkGenerator(VM*);
-MacroAssemblerCodeRef absThunkGenerator(VM*);
-MacroAssemblerCodeRef ceilThunkGenerator(VM*);
-MacroAssemblerCodeRef expThunkGenerator(VM*);
-MacroAssemblerCodeRef floorThunkGenerator(VM*);
-MacroAssemblerCodeRef logThunkGenerator(VM*);
-MacroAssemblerCodeRef roundThunkGenerator(VM*);
-MacroAssemblerCodeRef sqrtThunkGenerator(VM*);
-MacroAssemblerCodeRef imulThunkGenerator(VM*);
-MacroAssemblerCodeRef randomThunkGenerator(VM*);
-MacroAssemblerCodeRef truncThunkGenerator(VM*);
</del><ins>+JITEntryPointsWithRef charCodeAtThunkGenerator(VM*);
+JITEntryPointsWithRef charAtThunkGenerator(VM*);
+JITEntryPointsWithRef clz32ThunkGenerator(VM*);
+JITEntryPointsWithRef fromCharCodeThunkGenerator(VM*);
+JITEntryPointsWithRef absThunkGenerator(VM*);
+JITEntryPointsWithRef ceilThunkGenerator(VM*);
+JITEntryPointsWithRef expThunkGenerator(VM*);
+JITEntryPointsWithRef floorThunkGenerator(VM*);
+JITEntryPointsWithRef logThunkGenerator(VM*);
+JITEntryPointsWithRef roundThunkGenerator(VM*);
+JITEntryPointsWithRef sqrtThunkGenerator(VM*);
+JITEntryPointsWithRef imulThunkGenerator(VM*);
+JITEntryPointsWithRef randomThunkGenerator(VM*);
+JITEntryPointsWithRef truncThunkGenerator(VM*);
</ins><span class="cx">
</span><del>-MacroAssemblerCodeRef boundThisNoArgsFunctionCallGenerator(VM* vm);
</del><ins>+JITEntryPointsWithRef boundThisNoArgsFunctionCallGenerator(VM*);
</ins><span class="cx">
</span><span class="cx"> }
</span><span class="cx"> #endif // ENABLE(JIT)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejsccpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jsc.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jsc.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/jsc.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -3259,6 +3259,9 @@
</span><span class="cx"> int result;
</span><span class="cx"> result = runJSC(vm, options);
</span><span class="cx">
</span><ins>+#if ENABLE(VM_COUNTERS)
+ vm->dumpCounters();
+#endif
</ins><span class="cx"> if (Options::gcAtEnd()) {
</span><span class="cx"> // We need to hold the API lock to do a GC.
</span><span class="cx"> JSLockHolder locker(vm);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLLIntEntrypointcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LLIntEntrypoint.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LLIntEntrypoint.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/llint/LLIntEntrypoint.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -46,12 +46,26 @@
</span><span class="cx"> if (vm.canUseJIT()) {
</span><span class="cx"> if (kind == CodeForCall) {
</span><span class="cx"> codeBlock->setJITCode(
</span><del>- adoptRef(new DirectJITCode(vm.getCTIStub(functionForCallEntryThunkGenerator), vm.getCTIStub(functionForCallArityCheckThunkGenerator).code(), JITCode::InterpreterThunk)));
</del><ins>+ adoptRef(new DirectJITCode(
+ JITEntryPointsWithRef(vm.getCTIStub(functionForRegisterCallEntryThunkGenerator),
+ vm.getCTIStub(functionForRegisterCallEntryThunkGenerator).code(),
+ vm.getCTIStub(functionForRegisterCallEntryThunkGenerator).code(),
+ vm.getCTIStub(functionForRegisterCallArityCheckThunkGenerator).code(),
+ vm.getCTIStub(functionForStackCallEntryThunkGenerator).code(),
+ vm.getCTIStub(functionForStackCallArityCheckThunkGenerator).code()),
+ JITCode::InterpreterThunk)));
</ins><span class="cx"> return;
</span><span class="cx"> }
</span><span class="cx"> ASSERT(kind == CodeForConstruct);
</span><span class="cx"> codeBlock->setJITCode(
</span><del>- adoptRef(new DirectJITCode(vm.getCTIStub(functionForConstructEntryThunkGenerator), vm.getCTIStub(functionForConstructArityCheckThunkGenerator).code(), JITCode::InterpreterThunk)));
</del><ins>+ adoptRef(new DirectJITCode(
+ JITEntryPointsWithRef(vm.getCTIStub(functionForRegisterCallEntryThunkGenerator),
+ vm.getCTIStub(functionForRegisterConstructEntryThunkGenerator).code(),
+ vm.getCTIStub(functionForRegisterConstructEntryThunkGenerator).code(),
+ vm.getCTIStub(functionForRegisterConstructArityCheckThunkGenerator).code(),
+ vm.getCTIStub(functionForStackConstructEntryThunkGenerator).code(),
+ vm.getCTIStub(functionForStackConstructArityCheckThunkGenerator).code()),
+ JITCode::InterpreterThunk)));
</ins><span class="cx"> return;
</span><span class="cx"> }
</span><span class="cx"> #endif // ENABLE(JIT)
</span><span class="lines">@@ -59,12 +73,26 @@
</span><span class="cx"> UNUSED_PARAM(vm);
</span><span class="cx"> if (kind == CodeForCall) {
</span><span class="cx"> codeBlock->setJITCode(
</span><del>- adoptRef(new DirectJITCode(MacroAssemblerCodeRef::createLLIntCodeRef(llint_function_for_call_prologue), MacroAssemblerCodePtr::createLLIntCodePtr(llint_function_for_call_arity_check), JITCode::InterpreterThunk)));
</del><ins>+ adoptRef(new DirectJITCode(
+ JITEntryPointsWithRef(MacroAssemblerCodeRef::createLLIntCodeRef(llint_function_for_call_prologue),
+ MacroAssemblerCodePtr::createLLIntCodePtr(llint_function_for_call_prologue),
+ MacroAssemblerCodePtr::createLLIntCodePtr(llint_function_for_call_prologue),
+ MacroAssemblerCodePtr::createLLIntCodePtr(llint_function_for_call_prologue),
+ MacroAssemblerCodePtr::createLLIntCodePtr(llint_function_for_call_arity_check),
+ MacroAssemblerCodePtr::createLLIntCodePtr(llint_function_for_call_arity_check)),
+ JITCode::InterpreterThunk)));
</ins><span class="cx"> return;
</span><span class="cx"> }
</span><span class="cx"> ASSERT(kind == CodeForConstruct);
</span><span class="cx"> codeBlock->setJITCode(
</span><del>- adoptRef(new DirectJITCode(MacroAssemblerCodeRef::createLLIntCodeRef(llint_function_for_construct_prologue), MacroAssemblerCodePtr::createLLIntCodePtr(llint_function_for_construct_arity_check), JITCode::InterpreterThunk)));
</del><ins>+ adoptRef(new DirectJITCode(
+ JITEntryPointsWithRef(MacroAssemblerCodeRef::createLLIntCodeRef(llint_function_for_construct_prologue),
+ MacroAssemblerCodePtr::createLLIntCodePtr(llint_function_for_construct_prologue),
+ MacroAssemblerCodePtr::createLLIntCodePtr(llint_function_for_construct_prologue),
+ MacroAssemblerCodePtr::createLLIntCodePtr(llint_function_for_construct_prologue),
+ MacroAssemblerCodePtr::createLLIntCodePtr(llint_function_for_construct_arity_check),
+ MacroAssemblerCodePtr::createLLIntCodePtr(llint_function_for_construct_arity_check)),
+ JITCode::InterpreterThunk)));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> static void setEvalEntrypoint(VM& vm, CodeBlock* codeBlock)
</span><span class="lines">@@ -72,7 +100,14 @@
</span><span class="cx"> #if ENABLE(JIT)
</span><span class="cx"> if (vm.canUseJIT()) {
</span><span class="cx"> codeBlock->setJITCode(
</span><del>- adoptRef(new DirectJITCode(vm.getCTIStub(evalEntryThunkGenerator), MacroAssemblerCodePtr(), JITCode::InterpreterThunk)));
</del><ins>+ adoptRef(new DirectJITCode(
+ JITEntryPointsWithRef(vm.getCTIStub(evalEntryThunkGenerator),
+ MacroAssemblerCodePtr(),
+ MacroAssemblerCodePtr(),
+ MacroAssemblerCodePtr(),
+ vm.getCTIStub(evalEntryThunkGenerator).code(),
+ vm.getCTIStub(evalEntryThunkGenerator).code()),
+ JITCode::InterpreterThunk)));
</ins><span class="cx"> return;
</span><span class="cx"> }
</span><span class="cx"> #endif // ENABLE(JIT)
</span><span class="lines">@@ -79,7 +114,14 @@
</span><span class="cx">
</span><span class="cx"> UNUSED_PARAM(vm);
</span><span class="cx"> codeBlock->setJITCode(
</span><del>- adoptRef(new DirectJITCode(MacroAssemblerCodeRef::createLLIntCodeRef(llint_eval_prologue), MacroAssemblerCodePtr(), JITCode::InterpreterThunk)));
</del><ins>+ adoptRef(new DirectJITCode(
+ JITEntryPointsWithRef(MacroAssemblerCodeRef::createLLIntCodeRef(llint_eval_prologue),
+ MacroAssemblerCodePtr(),
+ MacroAssemblerCodePtr(),
+ MacroAssemblerCodePtr(),
+ MacroAssemblerCodeRef::createLLIntCodeRef(llint_eval_prologue).code(),
+ MacroAssemblerCodeRef::createLLIntCodeRef(llint_eval_prologue).code()),
+ JITCode::InterpreterThunk)));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> static void setProgramEntrypoint(VM& vm, CodeBlock* codeBlock)
</span><span class="lines">@@ -87,7 +129,14 @@
</span><span class="cx"> #if ENABLE(JIT)
</span><span class="cx"> if (vm.canUseJIT()) {
</span><span class="cx"> codeBlock->setJITCode(
</span><del>- adoptRef(new DirectJITCode(vm.getCTIStub(programEntryThunkGenerator), MacroAssemblerCodePtr(), JITCode::InterpreterThunk)));
</del><ins>+ adoptRef(new DirectJITCode(
+ JITEntryPointsWithRef(vm.getCTIStub(programEntryThunkGenerator),
+ MacroAssemblerCodePtr(),
+ MacroAssemblerCodePtr(),
+ MacroAssemblerCodePtr(),
+ vm.getCTIStub(programEntryThunkGenerator).code(),
+ vm.getCTIStub(programEntryThunkGenerator).code()),
+ JITCode::InterpreterThunk)));
</ins><span class="cx"> return;
</span><span class="cx"> }
</span><span class="cx"> #endif // ENABLE(JIT)
</span><span class="lines">@@ -94,7 +143,14 @@
</span><span class="cx">
</span><span class="cx"> UNUSED_PARAM(vm);
</span><span class="cx"> codeBlock->setJITCode(
</span><del>- adoptRef(new DirectJITCode(MacroAssemblerCodeRef::createLLIntCodeRef(llint_program_prologue), MacroAssemblerCodePtr(), JITCode::InterpreterThunk)));
</del><ins>+ adoptRef(new DirectJITCode(
+ JITEntryPointsWithRef(MacroAssemblerCodeRef::createLLIntCodeRef(llint_program_prologue),
+ MacroAssemblerCodePtr(),
+ MacroAssemblerCodePtr(),
+ MacroAssemblerCodePtr(),
+ MacroAssemblerCodePtr::createLLIntCodePtr(llint_program_prologue),
+ MacroAssemblerCodePtr::createLLIntCodePtr(llint_program_prologue)),
+ JITCode::InterpreterThunk)));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> static void setModuleProgramEntrypoint(VM& vm, CodeBlock* codeBlock)
</span><span class="lines">@@ -102,7 +158,14 @@
</span><span class="cx"> #if ENABLE(JIT)
</span><span class="cx"> if (vm.canUseJIT()) {
</span><span class="cx"> codeBlock->setJITCode(
</span><del>- adoptRef(new DirectJITCode(vm.getCTIStub(moduleProgramEntryThunkGenerator), MacroAssemblerCodePtr(), JITCode::InterpreterThunk)));
</del><ins>+ adoptRef(new DirectJITCode(
+ JITEntryPointsWithRef(vm.getCTIStub(moduleProgramEntryThunkGenerator),
+ MacroAssemblerCodePtr(),
+ MacroAssemblerCodePtr(),
+ MacroAssemblerCodePtr(),
+ vm.getCTIStub(moduleProgramEntryThunkGenerator).code(),
+ vm.getCTIStub(moduleProgramEntryThunkGenerator).code()),
+ JITCode::InterpreterThunk)));
</ins><span class="cx"> return;
</span><span class="cx"> }
</span><span class="cx"> #endif // ENABLE(JIT)
</span><span class="lines">@@ -109,7 +172,14 @@
</span><span class="cx">
</span><span class="cx"> UNUSED_PARAM(vm);
</span><span class="cx"> codeBlock->setJITCode(
</span><del>- adoptRef(new DirectJITCode(MacroAssemblerCodeRef::createLLIntCodeRef(llint_module_program_prologue), MacroAssemblerCodePtr(), JITCode::InterpreterThunk)));
</del><ins>+ adoptRef(new DirectJITCode(
+ JITEntryPointsWithRef(MacroAssemblerCodeRef::createLLIntCodeRef(llint_module_program_prologue),
+ MacroAssemblerCodePtr(),
+ MacroAssemblerCodePtr(),
+ MacroAssemblerCodePtr(),
+ MacroAssemblerCodePtr::createLLIntCodePtr(llint_module_program_prologue),
+ MacroAssemblerCodePtr::createLLIntCodePtr(llint_module_program_prologue)),
+ JITCode::InterpreterThunk)));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void setEntrypoint(VM& vm, CodeBlock* codeBlock)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLLIntSlowPathscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -373,9 +373,9 @@
</span><span class="cx"> CODEBLOCK_LOG_EVENT(codeBlock, "OSR entry", ("in prologue"));
</span><span class="cx">
</span><span class="cx"> if (kind == Prologue)
</span><del>- LLINT_RETURN_TWO(codeBlock->jitCode()->executableAddress(), 0);
</del><ins>+ LLINT_RETURN_TWO(codeBlock->jitCode()->addressForCall(StackArgsArityCheckNotRequired).executableAddress(), 0);
</ins><span class="cx"> ASSERT(kind == ArityCheck);
</span><del>- LLINT_RETURN_TWO(codeBlock->jitCode()->addressForCall(MustCheckArity).executableAddress(), 0);
</del><ins>+ LLINT_RETURN_TWO(codeBlock->jitCode()->addressForCall(StackArgsMustCheckArity).executableAddress(), 0);
</ins><span class="cx"> }
</span><span class="cx"> #else // ENABLE(JIT)
</span><span class="cx"> static SlowPathReturnType entryOSR(ExecState* exec, Instruction*, CodeBlock* codeBlock, const char*, EntryKind)
</span><span class="lines">@@ -1292,7 +1292,7 @@
</span><span class="cx"> MacroAssemblerCodePtr codePtr;
</span><span class="cx"> CodeBlock* codeBlock = 0;
</span><span class="cx"> if (executable->isHostFunction()) {
</span><del>- codePtr = executable->entrypointFor(kind, MustCheckArity);
</del><ins>+ codePtr = executable->entrypointFor(kind, StackArgsMustCheckArity);
</ins><span class="cx"> } else {
</span><span class="cx"> FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
</span><span class="cx">
</span><span class="lines">@@ -1306,12 +1306,12 @@
</span><span class="cx"> LLINT_CALL_THROW(exec, error);
</span><span class="cx"> codeBlock = *codeBlockSlot;
</span><span class="cx"> ASSERT(codeBlock);
</span><del>- ArityCheckMode arity;
</del><ins>+ EntryPointType entryType;
</ins><span class="cx"> if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters()))
</span><del>- arity = MustCheckArity;
</del><ins>+ entryType = StackArgsMustCheckArity;
</ins><span class="cx"> else
</span><del>- arity = ArityCheckNotRequired;
- codePtr = functionExecutable->entrypointFor(kind, arity);
</del><ins>+ entryType = StackArgsArityCheckNotRequired;
+ codePtr = functionExecutable->entrypointFor(kind, entryType);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> ASSERT(!!codePtr);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLLIntThunkscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LLIntThunks.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LLIntThunks.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/llint/LLIntThunks.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -51,10 +51,19 @@
</span><span class="cx">
</span><span class="cx"> namespace LLInt {
</span><span class="cx">
</span><del>-static MacroAssemblerCodeRef generateThunkWithJumpTo(VM* vm, void (*target)(), const char *thunkKind)
</del><ins>+enum ShouldCreateRegisterEntry { CreateRegisterEntry, DontCreateRegisterEntry };
+
+static MacroAssemblerCodeRef generateThunkWithJumpTo(VM* vm, void (*target)(), const char *thunkKind, ShouldCreateRegisterEntry shouldCreateRegisterEntry = DontCreateRegisterEntry)
</ins><span class="cx"> {
</span><span class="cx"> JSInterfaceJIT jit(vm);
</span><del>-
</del><ins>+
+#if USE(JSVALUE64)
+ if (shouldCreateRegisterEntry == CreateRegisterEntry)
+ jit.spillArgumentRegistersToFrameBeforePrologue();
+#else
+ UNUSED_PARAM(shouldCreateRegisterEntry);
+#endif
+
</ins><span class="cx"> // FIXME: there's probably a better way to do it on X86, but I'm not sure I care.
</span><span class="cx"> jit.move(JSInterfaceJIT::TrustedImmPtr(bitwise_cast<void*>(target)), JSInterfaceJIT::regT0);
</span><span class="cx"> jit.jump(JSInterfaceJIT::regT0);
</span><span class="lines">@@ -63,26 +72,46 @@
</span><span class="cx"> return FINALIZE_CODE(patchBuffer, ("LLInt %s prologue thunk", thunkKind));
</span><span class="cx"> }
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef functionForCallEntryThunkGenerator(VM* vm)
</del><ins>+MacroAssemblerCodeRef functionForRegisterCallEntryThunkGenerator(VM* vm)
</ins><span class="cx"> {
</span><del>- return generateThunkWithJumpTo(vm, LLInt::getCodeFunctionPtr(llint_function_for_call_prologue), "function for call");
</del><ins>+ return generateThunkWithJumpTo(vm, LLInt::getCodeFunctionPtr(llint_function_for_call_prologue), "function for register args call", CreateRegisterEntry);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef functionForConstructEntryThunkGenerator(VM* vm)
</del><ins>+MacroAssemblerCodeRef functionForStackCallEntryThunkGenerator(VM* vm)
</ins><span class="cx"> {
</span><del>- return generateThunkWithJumpTo(vm, LLInt::getCodeFunctionPtr(llint_function_for_construct_prologue), "function for construct");
</del><ins>+ return generateThunkWithJumpTo(vm, LLInt::getCodeFunctionPtr(llint_function_for_call_prologue), "function for stack args call");
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef functionForCallArityCheckThunkGenerator(VM* vm)
</del><ins>+MacroAssemblerCodeRef functionForRegisterConstructEntryThunkGenerator(VM* vm)
</ins><span class="cx"> {
</span><del>- return generateThunkWithJumpTo(vm, LLInt::getCodeFunctionPtr(llint_function_for_call_arity_check), "function for call with arity check");
</del><ins>+ return generateThunkWithJumpTo(vm, LLInt::getCodeFunctionPtr(llint_function_for_construct_prologue), "function for register args construct", CreateRegisterEntry);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef functionForConstructArityCheckThunkGenerator(VM* vm)
</del><ins>+MacroAssemblerCodeRef functionForStackConstructEntryThunkGenerator(VM* vm)
</ins><span class="cx"> {
</span><del>- return generateThunkWithJumpTo(vm, LLInt::getCodeFunctionPtr(llint_function_for_construct_arity_check), "function for construct with arity check");
</del><ins>+ return generateThunkWithJumpTo(vm, LLInt::getCodeFunctionPtr(llint_function_for_construct_prologue), "function for stack args construct");
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+MacroAssemblerCodeRef functionForRegisterCallArityCheckThunkGenerator(VM* vm)
+{
+ return generateThunkWithJumpTo(vm, LLInt::getCodeFunctionPtr(llint_function_for_call_arity_check), "function for register args call with arity check", CreateRegisterEntry);
+}
+
+MacroAssemblerCodeRef functionForStackCallArityCheckThunkGenerator(VM* vm)
+{
+ return generateThunkWithJumpTo(vm, LLInt::getCodeFunctionPtr(llint_function_for_call_arity_check), "function for stack args call with arity check");
+}
+
+MacroAssemblerCodeRef functionForRegisterConstructArityCheckThunkGenerator(VM* vm)
+{
+ return generateThunkWithJumpTo(vm, LLInt::getCodeFunctionPtr(llint_function_for_construct_arity_check), "function for register args construct with arity check", CreateRegisterEntry);
+}
+
+MacroAssemblerCodeRef functionForStackConstructArityCheckThunkGenerator(VM* vm)
+{
+ return generateThunkWithJumpTo(vm, LLInt::getCodeFunctionPtr(llint_function_for_construct_arity_check), "function for stack args construct with arity check");
+}
+
</ins><span class="cx"> MacroAssemblerCodeRef evalEntryThunkGenerator(VM* vm)
</span><span class="cx"> {
</span><span class="cx"> return generateThunkWithJumpTo(vm, LLInt::getCodeFunctionPtr(llint_eval_prologue), "eval");
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLLIntThunksh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LLIntThunks.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LLIntThunks.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/llint/LLIntThunks.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -42,10 +42,14 @@
</span><span class="cx">
</span><span class="cx"> namespace LLInt {
</span><span class="cx">
</span><del>-MacroAssemblerCodeRef functionForCallEntryThunkGenerator(VM*);
-MacroAssemblerCodeRef functionForConstructEntryThunkGenerator(VM*);
-MacroAssemblerCodeRef functionForCallArityCheckThunkGenerator(VM*);
-MacroAssemblerCodeRef functionForConstructArityCheckThunkGenerator(VM*);
</del><ins>+MacroAssemblerCodeRef functionForRegisterCallEntryThunkGenerator(VM*);
+MacroAssemblerCodeRef functionForStackCallEntryThunkGenerator(VM*);
+MacroAssemblerCodeRef functionForRegisterConstructEntryThunkGenerator(VM*);
+MacroAssemblerCodeRef functionForStackConstructEntryThunkGenerator(VM*);
+MacroAssemblerCodeRef functionForRegisterCallArityCheckThunkGenerator(VM*);
+MacroAssemblerCodeRef functionForStackCallArityCheckThunkGenerator(VM*);
+MacroAssemblerCodeRef functionForRegisterConstructArityCheckThunkGenerator(VM*);
+MacroAssemblerCodeRef functionForStackConstructArityCheckThunkGenerator(VM*);
</ins><span class="cx"> MacroAssemblerCodeRef evalEntryThunkGenerator(VM*);
</span><span class="cx"> MacroAssemblerCodeRef programEntryThunkGenerator(VM*);
</span><span class="cx"> MacroAssemblerCodeRef moduleProgramEntryThunkGenerator(VM*);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeArityCheckModeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ArityCheckMode.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ArityCheckMode.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/runtime/ArityCheckMode.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx"> namespace JSC {
</span><span class="cx">
</span><span class="cx"> enum ArityCheckMode {
</span><ins>+ RegisterEntry,
</ins><span class="cx"> ArityCheckNotRequired,
</span><span class="cx"> MustCheckArity
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeExecutableBasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ExecutableBase.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ExecutableBase.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/runtime/ExecutableBase.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -54,8 +54,8 @@
</span><span class="cx"> #if ENABLE(JIT)
</span><span class="cx"> m_jitCodeForCall = nullptr;
</span><span class="cx"> m_jitCodeForConstruct = nullptr;
</span><del>- m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr();
- m_jitCodeForConstructWithArityCheck = MacroAssemblerCodePtr();
</del><ins>+ m_jitEntriesForCall.clearEntries();
+ m_jitEntriesForConstruct.clearEntries();
</ins><span class="cx"> #endif
</span><span class="cx"> m_numParametersForCall = NUM_PARAMETERS_NOT_COMPILED;
</span><span class="cx"> m_numParametersForConstruct = NUM_PARAMETERS_NOT_COMPILED;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeExecutableBaseh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ExecutableBase.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ExecutableBase.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/runtime/ExecutableBase.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -25,7 +25,6 @@
</span><span class="cx">
</span><span class="cx"> #pragma once
</span><span class="cx">
</span><del>-#include "ArityCheckMode.h"
</del><span class="cx"> #include "CallData.h"
</span><span class="cx"> #include "CodeBlockHash.h"
</span><span class="cx"> #include "CodeSpecializationKind.h"
</span><span class="lines">@@ -34,6 +33,7 @@
</span><span class="cx"> #include "HandlerInfo.h"
</span><span class="cx"> #include "InferredValue.h"
</span><span class="cx"> #include "JITCode.h"
</span><ins>+#include "JITEntryPoints.h"
</ins><span class="cx"> #include "JSGlobalObject.h"
</span><span class="cx"> #include "SourceCode.h"
</span><span class="cx"> #include "TypeSet.h"
</span><span class="lines">@@ -145,47 +145,42 @@
</span><span class="cx"> return generatedJITCodeForConstruct();
</span><span class="cx"> }
</span><span class="cx">
</span><del>- MacroAssemblerCodePtr entrypointFor(CodeSpecializationKind kind, ArityCheckMode arity)
</del><ins>+ MacroAssemblerCodePtr entrypointFor(CodeSpecializationKind kind, EntryPointType entryType)
</ins><span class="cx"> {
</span><span class="cx"> // Check if we have a cached result. We only have it for arity check because we use the
</span><span class="cx"> // no-arity entrypoint in non-virtual calls, which will "cache" this value directly in
</span><span class="cx"> // machine code.
</span><del>- if (arity == MustCheckArity) {
- switch (kind) {
- case CodeForCall:
- if (MacroAssemblerCodePtr result = m_jitCodeForCallWithArityCheck)
- return result;
- break;
- case CodeForConstruct:
- if (MacroAssemblerCodePtr result = m_jitCodeForConstructWithArityCheck)
- return result;
- break;
- }
</del><ins>+ switch (kind) {
+ case CodeForCall:
+ if (MacroAssemblerCodePtr result = m_jitEntriesForCall.entryFor(entryType))
+ return result;
+ break;
+ case CodeForConstruct:
+ if (MacroAssemblerCodePtr result = m_jitEntriesForConstruct.entryFor(entryType))
+ return result;
+ break;
</ins><span class="cx"> }
</span><span class="cx"> MacroAssemblerCodePtr result =
</span><del>- generatedJITCodeFor(kind)->addressForCall(arity);
- if (arity == MustCheckArity) {
- // Cache the result; this is necessary for the JIT's virtual call optimizations.
- switch (kind) {
- case CodeForCall:
- m_jitCodeForCallWithArityCheck = result;
- break;
- case CodeForConstruct:
- m_jitCodeForConstructWithArityCheck = result;
- break;
- }
</del><ins>+ generatedJITCodeFor(kind)->addressForCall(entryType);
+ // Cache the result; this is necessary for the JIT's virtual call optimizations.
+ switch (kind) {
+ case CodeForCall:
+ m_jitEntriesForCall.setEntryFor(entryType, result);
+ break;
+ case CodeForConstruct:
+ m_jitEntriesForConstruct.setEntryFor(entryType, result);
+ break;
</ins><span class="cx"> }
</span><span class="cx"> return result;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- static ptrdiff_t offsetOfJITCodeWithArityCheckFor(
- CodeSpecializationKind kind)
</del><ins>+ static ptrdiff_t offsetOfEntryFor(CodeSpecializationKind kind, EntryPointType entryPointType)
</ins><span class="cx"> {
</span><span class="cx"> switch (kind) {
</span><span class="cx"> case CodeForCall:
</span><del>- return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForCallWithArityCheck);
</del><ins>+ return OBJECT_OFFSETOF(ExecutableBase, m_jitEntriesForCall) + JITEntryPoints::offsetOfEntryFor(entryPointType);
</ins><span class="cx"> case CodeForConstruct:
</span><del>- return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstructWithArityCheck);
</del><ins>+ return OBJECT_OFFSETOF(ExecutableBase, m_jitEntriesForConstruct) + JITEntryPoints::offsetOfEntryFor(entryPointType);
</ins><span class="cx"> }
</span><span class="cx"> RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx"> return 0;
</span><span class="lines">@@ -233,8 +228,8 @@
</span><span class="cx"> Intrinsic m_intrinsic;
</span><span class="cx"> RefPtr<JITCode> m_jitCodeForCall;
</span><span class="cx"> RefPtr<JITCode> m_jitCodeForConstruct;
</span><del>- MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck;
- MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck;
</del><ins>+ JITEntryPoints m_jitEntriesForCall;
+ JITEntryPoints m_jitEntriesForConstruct;
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSBoundFunctioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSBoundFunction.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSBoundFunction.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/runtime/JSBoundFunction.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -46,7 +46,7 @@
</span><span class="cx"> ExecutableBase* executable = targetFunction->executable();
</span><span class="cx"> if (executable->hasJITCodeForCall()) {
</span><span class="cx"> // Force the executable to cache its arity entrypoint.
</span><del>- executable->entrypointFor(CodeForCall, MustCheckArity);
</del><ins>+ executable->entrypointFor(CodeForCall, StackArgsMustCheckArity);
</ins><span class="cx"> }
</span><span class="cx"> CallData callData;
</span><span class="cx"> CallType callType = getCallData(targetFunction, callData);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeNativeExecutablecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/NativeExecutable.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/NativeExecutable.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/runtime/NativeExecutable.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -63,8 +63,8 @@
</span><span class="cx"> Base::finishCreation(vm);
</span><span class="cx"> m_jitCodeForCall = callThunk;
</span><span class="cx"> m_jitCodeForConstruct = constructThunk;
</span><del>- m_jitCodeForCallWithArityCheck = m_jitCodeForCall->addressForCall(MustCheckArity);
- m_jitCodeForConstructWithArityCheck = m_jitCodeForConstruct->addressForCall(MustCheckArity);
</del><ins>+ m_jitEntriesForCall.setEntryFor(StackArgsMustCheckArity, m_jitCodeForCall->addressForCall(StackArgsMustCheckArity));
+ m_jitEntriesForConstruct.setEntryFor(StackArgsMustCheckArity, m_jitCodeForConstruct->addressForCall(StackArgsMustCheckArity));
</ins><span class="cx"> m_name = name;
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeScriptExecutablecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ScriptExecutable.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ScriptExecutable.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/runtime/ScriptExecutable.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -139,12 +139,12 @@
</span><span class="cx"> switch (kind) {
</span><span class="cx"> case CodeForCall:
</span><span class="cx"> m_jitCodeForCall = genericCodeBlock ? genericCodeBlock->jitCode() : nullptr;
</span><del>- m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr();
</del><ins>+ m_jitEntriesForCall.clearEntries();
</ins><span class="cx"> m_numParametersForCall = genericCodeBlock ? genericCodeBlock->numParameters() : NUM_PARAMETERS_NOT_COMPILED;
</span><span class="cx"> break;
</span><span class="cx"> case CodeForConstruct:
</span><span class="cx"> m_jitCodeForConstruct = genericCodeBlock ? genericCodeBlock->jitCode() : nullptr;
</span><del>- m_jitCodeForConstructWithArityCheck = MacroAssemblerCodePtr();
</del><ins>+ m_jitEntriesForConstruct.clearEntries();
</ins><span class="cx"> m_numParametersForConstruct = genericCodeBlock ? genericCodeBlock->numParameters() : NUM_PARAMETERS_NOT_COMPILED;
</span><span class="cx"> break;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeVMcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/VM.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/VM.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/runtime/VM.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -210,6 +210,10 @@
</span><span class="cx"> updateSoftReservedZoneSize(Options::softReservedZoneSize());
</span><span class="cx"> setLastStackTop(stack.origin());
</span><span class="cx">
</span><ins>+#if ENABLE(VM_COUNTERS)
+ clearCounters();
+#endif
+
</ins><span class="cx"> // Need to be careful to keep everything consistent here
</span><span class="cx"> JSLockHolder lock(this);
</span><span class="cx"> AtomicStringTable* existingEntryAtomicStringTable = wtfThreadData().setCurrentAtomicStringTable(m_atomicStringTable);
</span><span class="lines">@@ -476,7 +480,7 @@
</span><span class="cx"> #endif // ENABLE(SAMPLING_PROFILER)
</span><span class="cx">
</span><span class="cx"> #if ENABLE(JIT)
</span><del>-static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic)
</del><ins>+static JITEntryGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic)
</ins><span class="cx"> {
</span><span class="cx"> switch (intrinsic) {
</span><span class="cx"> case CharCodeAtIntrinsic:
</span><span class="lines">@@ -923,4 +927,35 @@
</span><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="cx">
</span><ins>+#if ENABLE(VM_COUNTERS)
+void VM::clearCounters()
+{
+ for (unsigned i = 0; i < NumberVMCounter; i++)
+ m_counters[i] = 0;
+}
+
+void VM::dumpCounters()
+{
+ size_t totalCalls = counterFor(BaselineCaller) + counterFor(DFGCaller) + counterFor(FTLCaller);
+ dataLog("#### VM Call counters ####\n");
+ dataLogF("%10zu Total calls\n", totalCalls);
+ dataLogF("%10zu Baseline calls\n", counterFor(BaselineCaller));
+ dataLogF("%10zu DFG calls\n", counterFor(DFGCaller));
+ dataLogF("%10zu FTL calls\n", counterFor(FTLCaller));
+ dataLogF("%10zu Vararg calls\n", counterFor(CallVarargs));
+ dataLogF("%10zu Tail calls\n", counterFor(TailCall));
+ dataLogF("%10zu Eval calls\n", counterFor(CallEval));
+ dataLogF("%10zu Direct calls\n", counterFor(DirectCall));
+ dataLogF("%10zu Polymorphic calls\n", counterFor(PolymorphicCall));
+ dataLogF("%10zu Virtual calls\n", counterFor(VirtualCall));
+ dataLogF("%10zu Virtual slow calls\n", counterFor(VirtualSlowCall));
+ dataLogF("%10zu Register args no arity\n", counterFor(RegArgsNoArity));
+ dataLogF("%10zu Stack args no arity\n", counterFor(StackArgsNoArity));
+ dataLogF("%10zu Register args extra arity\n", counterFor(RegArgsExtra));
+ dataLogF("%10zu Register args arity check\n", counterFor(RegArgsArity));
+ dataLogF("%10zu Stack args arity check\n", counterFor(StackArgsArity));
+ dataLogF("%10zu Arity fixups required\n", counterFor(ArityFixupRequired));
+}
+#endif
+
</ins><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeVMh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/VM.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/VM.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/runtime/VM.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -432,6 +432,16 @@
</span><span class="cx"> {
</span><span class="cx"> return jitStubs->ctiStub(this, generator);
</span><span class="cx"> }
</span><ins>+
+ JITEntryPointsWithRef getJITEntryStub(JITEntryGenerator generator)
+ {
+ return jitStubs->jitEntryStub(this, generator);
+ }
+
+ JITJSCallThunkEntryPointsWithRef getJITCallThunkEntryStub(JITCallThunkEntryGenerator generator)
+ {
+ return jitStubs->jitCallThunkEntryStub(this, generator);
+ }
</ins><span class="cx">
</span><span class="cx"> std::unique_ptr<RegisterAtOffsetList> allCalleeSaveRegisterOffsets;
</span><span class="cx">
</span><span class="lines">@@ -574,6 +584,50 @@
</span><span class="cx"> BumpPointerAllocator m_regExpAllocator;
</span><span class="cx"> ConcurrentJSLock m_regExpAllocatorLock;
</span><span class="cx">
</span><ins>+ enum VMCounterType {
+ BaselineCaller,
+ DFGCaller,
+ FTLCaller,
+ CallVarargs,
+ TailCall,
+ CallEval,
+ DirectCall,
+ PolymorphicCall,
+ VirtualCall,
+ VirtualSlowCall,
+ RegArgsNoArity,
+ StackArgsNoArity,
+ RegArgsExtra,
+ RegArgsArity,
+ StackArgsArity,
+ ArityFixupRequired,
+ NumberVMCounter
+ };
+
+#if ENABLE(VM_COUNTERS)
+ size_t m_counters[NumberVMCounter];
+
+ void clearCounters();
+
+ size_t* addressOfCounter(VMCounterType counterType)
+ {
+ if (counterType >= NumberVMCounter)
+ return nullptr;
+
+ return &m_counters[counterType];
+ }
+
+ size_t counterFor(VMCounterType counterType)
+ {
+ if (counterType >= NumberVMCounter)
+ return 0;
+
+ return m_counters[counterType];
+ }
+
+ JS_EXPORT_PRIVATE void dumpCounters();
+#endif
+
</ins><span class="cx"> std::unique_ptr<HasOwnPropertyCache> m_hasOwnPropertyCache;
</span><span class="cx"> ALWAYS_INLINE HasOwnPropertyCache* hasOwnPropertyCache() { return m_hasOwnPropertyCache.get(); }
</span><span class="cx"> HasOwnPropertyCache* ensureHasOwnPropertyCache();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmBindingcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmBinding.cpp (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmBinding.cpp        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/JavaScriptCore/wasm/WasmBinding.cpp        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -133,7 +133,7 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>- GPRReg importJSCellGPRReg = GPRInfo::regT0; // Callee needs to be in regT0 for slow path below.
</del><ins>+ GPRReg importJSCellGPRReg = argumentRegisterForCallee();
</ins><span class="cx"> ASSERT(!wasmCC.m_calleeSaveRegisters.get(importJSCellGPRReg));
</span><span class="cx">
</span><span class="cx"> // Each JS -> wasm entry sets the WebAssembly.Instance whose export is being called. We're calling out of this Instance, and can therefore figure out the import being called.
</span><span class="lines">@@ -148,7 +148,7 @@
</span><span class="cx"> // FIXME Tail call if the wasm return type is void and no registers were spilled. https://bugs.webkit.org/show_bug.cgi?id=165488
</span><span class="cx">
</span><span class="cx"> CallLinkInfo* callLinkInfo = callLinkInfos.add();
</span><del>- callLinkInfo->setUpCall(CallLinkInfo::Call, CodeOrigin(), importJSCellGPRReg);
</del><ins>+ callLinkInfo->setUpCall(CallLinkInfo::Call, StackArgs, CodeOrigin(), importJSCellGPRReg);
</ins><span class="cx"> JIT::DataLabelPtr targetToCheck;
</span><span class="cx"> JIT::TrustedImmPtr initialRightValue(0);
</span><span class="cx"> JIT::Jump slowPath = jit.branchPtrWithPatch(MacroAssembler::NotEqual, importJSCellGPRReg, targetToCheck, initialRightValue);
</span><span class="lines">@@ -155,8 +155,7 @@
</span><span class="cx"> JIT::Call fastCall = jit.nearCall();
</span><span class="cx"> JIT::Jump done = jit.jump();
</span><span class="cx"> slowPath.link(&jit);
</span><del>- // Callee needs to be in regT0 here.
- jit.move(MacroAssembler::TrustedImmPtr(callLinkInfo), GPRInfo::regT2); // Link info needs to be in regT2.
</del><ins>+ jit.move(MacroAssembler::TrustedImmPtr(callLinkInfo), GPRInfo::nonArgGPR0); // Link info needs to be in nonArgGPR0
</ins><span class="cx"> JIT::Call slowCall = jit.nearCall();
</span><span class="cx"> done.link(&jit);
</span><span class="cx">
</span><span class="lines">@@ -224,7 +223,7 @@
</span><span class="cx"> jit.ret();
</span><span class="cx">
</span><span class="cx"> LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);
</span><del>- patchBuffer.link(slowCall, FunctionPtr(vm->getCTIStub(linkCallThunkGenerator).code().executableAddress()));
</del><ins>+ patchBuffer.link(slowCall, FunctionPtr(vm->getJITCallThunkEntryStub(linkCallThunkGenerator).entryFor(StackArgs).executableAddress()));
</ins><span class="cx"> CodeLocationLabel callReturnLocation(patchBuffer.locationOfNearCall(slowCall));
</span><span class="cx"> CodeLocationLabel hotPathBegin(patchBuffer.locationOf(targetToCheck));
</span><span class="cx"> CodeLocationNearCall hotPathOther = patchBuffer.locationOfNearCall(fastCall);
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/WTF/ChangeLog        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -1,3 +1,14 @@
</span><ins>+2016-12-12 Michael Saboff <msaboff@apple.com>
+
+ REGRESSION(r209653): speedometer crashes making virtual slow path tailcalls
+ https://bugs.webkit.org/show_bug.cgi?id=165748
+
+ Reviewed by Filip Pizlo.
+
+ Rolling back in r209653, r209654, r209663, and r209673.
+
+ * wtf/Platform.h:
+
</ins><span class="cx"> 2016-12-12 Commit Queue <commit-queue@webkit.org>
</span><span class="cx">
</span><span class="cx"> Unreviewed, rolling out r209703.
</span></span></pre></div>
<a id="trunkSourceWTFwtfPlatformh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/Platform.h (209724 => 209725)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/Platform.h        2016-12-12 21:26:23 UTC (rev 209724)
+++ trunk/Source/WTF/wtf/Platform.h        2016-12-12 21:46:45 UTC (rev 209725)
</span><span class="lines">@@ -689,6 +689,9 @@
</span><span class="cx"> #define ENABLE_JIT 1
</span><span class="cx"> #endif
</span><span class="cx">
</span><ins>+/* This enables per VM counters available for use by JIT'ed code. */
+#define ENABLE_VM_COUNTERS 0
+
</ins><span class="cx"> /* The FTL *does not* work on 32-bit platforms. Disable it even if someone asked us to enable it. */
</span><span class="cx"> #if USE(JSVALUE32_64)
</span><span class="cx"> #undef ENABLE_FTL_JIT
</span></span></pre>
</div>
</div>
</body>
</html>