Commit 5f2e70b5 authored by mhahnenberg@apple.com's avatar mhahnenberg@apple.com

op_get_callee shouldn't use value profiling

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

Reviewed by Filip Pizlo.

Source/JavaScriptCore: 

Currently it's one of the two opcodes that uses m_singletonValue, which is unnecessary. 
Our current plan is to remove m_singletonValue so that GenGC can have a simpler story 
for handling CodeBlocks/FunctionExecutables during nursery collections.

Instead of using a ValueProfile op_get_callee now has a simple inline cache of the most 
recent JSFunction that we saw.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::finalizeUnconditionally):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitCreateThis):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* jit/JIT.cpp:
(JSC::JIT::privateCompileSlowCases):
* jit/JIT.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_get_callee):
(JSC::JIT::emitSlow_op_get_callee):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_get_callee):
(JSC::JIT::emitSlow_op_get_callee):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/CommonSlowPaths.h:

LayoutTests: 

Added two tests to make sure we didn't regress the performance of op_get_callee.

* js/regress/get_callee_monomorphic-expected.txt: Added.
* js/regress/get_callee_monomorphic.html: Added.
* js/regress/get_callee_polymorphic-expected.txt: Added.
* js/regress/get_callee_polymorphic.html: Added.
* js/regress/script-tests/get_callee_monomorphic.js: Added.
* js/regress/script-tests/get_callee_polymorphic.js: Added.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@156376 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 2f39e4b9
2013-09-24 Mark Hahnenberg <mhahnenberg@apple.com>
op_get_callee shouldn't use value profiling
https://bugs.webkit.org/show_bug.cgi?id=121821
Reviewed by Filip Pizlo.
Added two tests to make sure we didn't regress the performance of op_get_callee.
* js/regress/get_callee_monomorphic-expected.txt: Added.
* js/regress/get_callee_monomorphic.html: Added.
* js/regress/get_callee_polymorphic-expected.txt: Added.
* js/regress/get_callee_polymorphic.html: Added.
* js/regress/script-tests/get_callee_monomorphic.js: Added.
* js/regress/script-tests/get_callee_polymorphic.js: Added.
2013-09-24 Bear Travis <betravis@adobe.com>
Disable CSS_SHAPES on Windows
JSRegress/get_callee_monomorphic
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS no exception thrown
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../../resources/js-test-pre.js"></script>
</head>
<body>
<script src="resources/regress-pre.js"></script>
<script src="script-tests/get_callee_monomorphic.js"></script>
<script src="resources/regress-post.js"></script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>
JSRegress/get_callee_polymorphic
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS no exception thrown
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../../resources/js-test-pre.js"></script>
</head>
<body>
<script src="resources/regress-pre.js"></script>
<script src="script-tests/get_callee_polymorphic.js"></script>
<script src="resources/regress-post.js"></script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>
function Foo() {
this.bar = function() { return 1; };
}
var sum = 0;
for (var i = 0; i < 100000; i++) {
var f = new Foo();
sum += f.bar();
}
if (sum != 100000)
throw "Error: incorrect sum. Expected 10000 but got " + sum + ".";
var Class = {
create: function() {
return function() {
this.initialize.apply(this, arguments);
};
}
};
var sum = 0;
var init = function(a, b) { sum += a + b; };
var Class1 = Class.create();
Class1.prototype = {
initialize: init
};
var Class2 = Class.create();
Class2.prototype = {
initialize: init
};
var Class3 = Class.create();
Class3.prototype = {
initialize: init
};
for (var i = 0; i < 1000; i++) {
for (var j = 0; j < 100; j++) {
var newObject;
if (j % 3 == 0)
newObject = new Class1(2, 3);
else if (j % 3 == 1)
newObject = new Class2(2, 3);
else
newObject = new Class3(2, 3);
}
}
if (sum != 5 * 100 * 1000)
throw "Error: incorrect sum. Expected " + (5 * 100 * 1000) + " but got " + sum + ".";
2013-09-24 Mark Hahnenberg <mhahnenberg@apple.com>
op_get_callee shouldn't use value profiling
https://bugs.webkit.org/show_bug.cgi?id=121821
Reviewed by Filip Pizlo.
Currently it's one of the two opcodes that uses m_singletonValue, which is unnecessary.
Our current plan is to remove m_singletonValue so that GenGC can have a simpler story
for handling CodeBlocks/FunctionExecutables during nursery collections.
Instead of using a ValueProfile op_get_callee now has a simple inline cache of the most
recent JSFunction that we saw.
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::finalizeUnconditionally):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitCreateThis):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* jit/JIT.cpp:
(JSC::JIT::privateCompileSlowCases):
* jit/JIT.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_get_callee):
(JSC::JIT::emitSlow_op_get_callee):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_get_callee):
(JSC::JIT::emitSlow_op_get_callee):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/CommonSlowPaths.h:
2013-09-24 Mark Lam <mark.lam@apple.com>
Change JSC debug hooks to pass a CallFrame* instead of a DebuggerCallFrame.
......@@ -1736,8 +1736,7 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
}
case op_to_this:
case op_get_by_id:
case op_call_varargs:
case op_get_callee: {
case op_call_varargs: {
ValueProfile* profile = &m_valueProfiles[pc[i + opLength - 1].u.operand];
ASSERT(profile->m_bytecodeOffset == -1);
profile->m_bytecodeOffset = i;
......@@ -2239,6 +2238,13 @@ void CodeBlock::finalizeUnconditionally()
break;
case op_get_array_length:
break;
case op_get_callee:
if (!curInstruction[2].u.jsCell || Heap::isMarked(curInstruction[2].u.jsCell.get()))
break;
if (Options::verboseOSR())
dataLogF("Clearing LLInt get callee with function %p.\n", curInstruction[2].u.jsCell.get());
curInstruction[2].u.jsCell.clear();
break;
case op_get_from_scope:
case op_put_to_scope: {
WriteBarrierBase<Structure>& structure = curInstruction[5].u.structure;
......
......@@ -1404,9 +1404,9 @@ RegisterID* BytecodeGenerator::emitCreateThis(RegisterID* dst)
{
RefPtr<RegisterID> func = newTemporary();
UnlinkedValueProfile profile = emitProfiledOpcode(op_get_callee);
emitOpcode(op_get_callee);
instructions().append(func->index());
instructions().append(profile);
instructions().append(0);
size_t begin = instructions().size();
m_staticPropertyAnalyzer.createThis(m_thisRegister.index(), begin + 3);
......
......@@ -2007,18 +2007,16 @@ bool ByteCodeParser::parseBlock(unsigned limit)
}
case op_get_callee: {
ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);
ValueProfile* profile = currentInstruction[2].u.profile;
profile->computeUpdatedPrediction(locker);
if (profile->m_singletonValueIsTop
|| !profile->m_singletonValue
|| !profile->m_singletonValue.isCell())
JSCell* cachedFunction = currentInstruction[2].u.jsCell.get();
if (!cachedFunction
|| m_inlineStackTop->m_profiledBlock->couldTakeSlowCase(m_currentIndex)
|| m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadFunction)) {
set(currentInstruction[1].u.operand, get(JSStack::Callee));
else {
ASSERT(profile->m_singletonValue.asCell()->inherits(JSFunction::info()));
} else {
ASSERT(cachedFunction->inherits(JSFunction::info()));
Node* actualCallee = get(JSStack::Callee);
addToGraph(CheckFunction, OpInfo(profile->m_singletonValue.asCell()), actualCallee);
set(currentInstruction[1].u.operand, addToGraph(WeakJSConstant, OpInfo(profile->m_singletonValue.asCell())));
addToGraph(CheckFunction, OpInfo(cachedFunction), actualCallee);
set(currentInstruction[1].u.operand, addToGraph(WeakJSConstant, OpInfo(cachedFunction)));
}
NEXT_OPCODE(op_get_callee);
}
......
......@@ -407,6 +407,7 @@ void JIT::privateCompileSlowCases()
DEFINE_SLOWCASE_OP(op_create_this)
DEFINE_SLOWCASE_OP(op_div)
DEFINE_SLOWCASE_OP(op_eq)
DEFINE_SLOWCASE_OP(op_get_callee)
case op_get_by_id_out_of_line:
case op_get_array_length:
DEFINE_SLOWCASE_OP(op_get_by_id)
......
......@@ -746,6 +746,7 @@ namespace JSC {
void emitSlow_op_create_this(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_div(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_eq(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_get_callee(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_get_by_id(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_get_arguments_length(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_get_by_val(Instruction*, Vector<SlowCaseEntry>::iterator&);
......
......@@ -878,11 +878,24 @@ void JIT::emit_op_to_this(Instruction* currentInstruction)
void JIT::emit_op_get_callee(Instruction* currentInstruction)
{
int result = currentInstruction[1].u.operand;
WriteBarrierBase<JSCell>* cachedFunction = &currentInstruction[2].u.jsCell;
emitGetFromCallFrameHeaderPtr(JSStack::Callee, regT0);
emitValueProfilingSite(regT4);
loadPtr(cachedFunction, regT2);
addSlowCase(branchPtr(NotEqual, regT0, regT2));
emitPutVirtualRegister(result);
}
void JIT::emitSlow_op_get_callee(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
linkSlowCase(iter);
JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_callee);
slowPathCall.call();
emitGetVirtualRegister(currentInstruction[1].u.operand, regT0);
}
void JIT::emit_op_create_this(Instruction* currentInstruction)
{
int callee = currentInstruction[2].u.operand;
......
......@@ -1129,11 +1129,24 @@ void JIT::emit_op_init_lazy_reg(Instruction* currentInstruction)
void JIT::emit_op_get_callee(Instruction* currentInstruction)
{
int dst = currentInstruction[1].u.operand;
int result = currentInstruction[1].u.operand;
WriteBarrierBase<JSCell>* cachedFunction = &currentInstruction[2].u.jsCell;
emitGetFromCallFrameHeaderPtr(JSStack::Callee, regT0);
loadPtr(cachedFunction, regT2);
addSlowCase(branchPtr(NotEqual, regT0, regT2));
move(TrustedImm32(JSValue::CellTag), regT1);
emitValueProfilingSite(regT4);
emitStore(dst, regT1, regT0);
emitStore(result, regT1, regT0);
}
void JIT::emitSlow_op_get_callee(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
linkSlowCase(iter);
JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_callee);
slowPathCall.call();
emitLoad(currentInstruction[1].u.operand, regT1, regT0);
}
void JIT::emit_op_create_this(Instruction* currentInstruction)
......
......@@ -414,11 +414,15 @@ _llint_op_get_callee:
traceExecution()
loadi 4[PC], t0
loadp PayloadOffset + Callee[cfr], t1
valueProfile(CellTag, t1, 8, t2)
loadpFromInstruction(2, t2)
bpneq t1, t2, .opGetCalleeSlow
storei CellTag, TagOffset[cfr, t0, 8]
storei t1, PayloadOffset[cfr, t0, 8]
dispatch(3)
.opGetCalleeSlow:
callSlowPath(_slow_path_get_callee)
dispatch(3)
_llint_op_to_this:
traceExecution()
......
......@@ -295,10 +295,14 @@ _llint_op_get_callee:
traceExecution()
loadisFromInstruction(1, t0)
loadp Callee[cfr], t1
valueProfile(t1, 2, t2)
loadpFromInstruction(2, t2)
bpneq t1, t2, .opGetCalleeSlow
storep t1, [cfr, t0, 8]
dispatch(3)
.opGetCalleeSlow:
callSlowPath(_slow_path_get_callee)
dispatch(3)
_llint_op_to_this:
traceExecution()
......
......@@ -193,6 +193,14 @@ SLOW_PATH_DECL(slow_path_construct_arityCheck)
RETURN_TWO(0, reinterpret_cast<ExecState*>(SlotsToAdd));
}
SLOW_PATH_DECL(slow_path_get_callee)
{
BEGIN();
JSFunction* callee = jsCast<JSFunction*>(exec->callee());
pc[2].u.jsCell.set(exec->vm(), exec->codeBlock()->ownerExecutable(), callee);
RETURN(callee);
}
SLOW_PATH_DECL(slow_path_create_arguments)
{
BEGIN();
......
......@@ -153,6 +153,7 @@ SLOW_PATH_HIDDEN_DECL(slow_path_call_arityCheck);
SLOW_PATH_HIDDEN_DECL(slow_path_construct_arityCheck);
SLOW_PATH_HIDDEN_DECL(slow_path_create_arguments);
SLOW_PATH_HIDDEN_DECL(slow_path_create_this);
SLOW_PATH_HIDDEN_DECL(slow_path_get_callee);
SLOW_PATH_HIDDEN_DECL(slow_path_to_this);
SLOW_PATH_HIDDEN_DECL(slow_path_not);
SLOW_PATH_HIDDEN_DECL(slow_path_eq);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment