From afcf9040fa29c7e79bcf6b0401d05d6ede3482b9 Mon Sep 17 00:00:00 2001 From: "fpizlo@apple.com" Date: Fri, 20 Jan 2012 20:22:18 +0000 Subject: [PATCH] Bytecode instructions that may have value profiling should have a direct inline link to the ValueProfile instance https://bugs.webkit.org/show_bug.cgi?id=76682 Reviewed by Sam Weinig. Each opcode that gets value profiled now has a link to its ValueProfile. This required rationalizing the emission of value profiles for opcode combos, like op_method_check/op_get_by_id and op_call/op_call_put_result. It only makes sense for one of them to have a value profile link, and it makes most sense for it to be the one that actually sets the result. The previous behavior was to have op_method_check profile for op_get_by_id when they were used together, but otherwise for op_get_by_id to have its own profiles. op_call already did the right thing; all profiling was done by op_call_put_result. But rationalizing this code required breaking some of the natural boundaries that the code had; for instance the code in DFG that emits a GetById in place of both op_method_check and op_get_by_id must now know that it's the latter of those that has the value profile, while the first of those constitutes the OSR target. Hence each CodeOrigin must now have two bytecode indices - one for OSR exit and one for profiling. Finally this change required some refiddling of our optimization heuristics, because now all code blocks have "more instructions" due to the value profile slots. * bytecode/CodeBlock.cpp: (JSC::CodeBlock::printGetByIdOp): (JSC::CodeBlock::dump): * bytecode/CodeBlock.h: (JSC::CodeBlock::valueProfileForBytecodeOffset): * bytecode/CodeOrigin.h: (JSC::CodeOrigin::CodeOrigin): (JSC::CodeOrigin::bytecodeIndexForValueProfile): * bytecode/Instruction.h: (JSC::Instruction::Instruction): * bytecode/Opcode.h: * bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::emitProfiledOpcode): (JSC::BytecodeGenerator::emitResolve): (JSC::BytecodeGenerator::emitGetScopedVar): (JSC::BytecodeGenerator::emitResolveBase): (JSC::BytecodeGenerator::emitResolveBaseForPut): (JSC::BytecodeGenerator::emitResolveWithBase): (JSC::BytecodeGenerator::emitResolveWithThis): (JSC::BytecodeGenerator::emitGetById): (JSC::BytecodeGenerator::emitGetByVal): (JSC::BytecodeGenerator::emitCall): (JSC::BytecodeGenerator::emitCallVarargs): (JSC::BytecodeGenerator::emitConstruct): * bytecompiler/BytecodeGenerator.h: * dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::ByteCodeParser): (JSC::DFG::ByteCodeParser::currentCodeOrigin): (JSC::DFG::ByteCodeParser::addCall): (JSC::DFG::ByteCodeParser::getPredictionWithoutOSRExit): (JSC::DFG::ByteCodeParser::getPrediction): (JSC::DFG::ByteCodeParser::handleCall): (JSC::DFG::ByteCodeParser::handleInlining): (JSC::DFG::ByteCodeParser::parseBlock): (JSC::DFG::ByteCodeParser::parse): * dfg/DFGGraph.h: (JSC::DFG::Graph::valueProfileFor): * jit/JIT.h: (JSC::JIT::emitValueProfilingSite): * jit/JITCall.cpp: (JSC::JIT::emit_op_call_put_result): * jit/JITCall32_64.cpp: (JSC::JIT::emit_op_call_put_result): * jit/JITInlineMethods.h: (JSC::JIT::emitValueProfilingSite): * jit/JITOpcodes.cpp: (JSC::JIT::emit_op_resolve): (JSC::JIT::emit_op_resolve_base): (JSC::JIT::emit_op_resolve_skip): (JSC::JIT::emit_op_resolve_global): (JSC::JIT::emitSlow_op_resolve_global): (JSC::JIT::emit_op_resolve_with_base): (JSC::JIT::emit_op_resolve_with_this): (JSC::JIT::emitSlow_op_resolve_global_dynamic): * jit/JITOpcodes32_64.cpp: (JSC::JIT::emit_op_resolve): (JSC::JIT::emit_op_resolve_base): (JSC::JIT::emit_op_resolve_skip): (JSC::JIT::emit_op_resolve_global): (JSC::JIT::emitSlow_op_resolve_global): (JSC::JIT::emit_op_resolve_with_base): (JSC::JIT::emit_op_resolve_with_this): * jit/JITPropertyAccess.cpp: (JSC::JIT::emit_op_get_by_val): (JSC::JIT::emitSlow_op_get_by_val): (JSC::JIT::emit_op_method_check): (JSC::JIT::emitSlow_op_method_check): (JSC::JIT::emit_op_get_by_id): (JSC::JIT::emitSlow_op_get_by_id): (JSC::JIT::emit_op_get_scoped_var): (JSC::JIT::emit_op_get_global_var): * jit/JITPropertyAccess32_64.cpp: (JSC::JIT::emit_op_method_check): (JSC::JIT::emitSlow_op_method_check): (JSC::JIT::emit_op_get_by_val): (JSC::JIT::emitSlow_op_get_by_val): (JSC::JIT::emit_op_get_by_id): (JSC::JIT::emitSlow_op_get_by_id): (JSC::JIT::emit_op_get_scoped_var): (JSC::JIT::emit_op_get_global_var): * jit/JITStubCall.h: (JSC::JITStubCall::callWithValueProfiling): * runtime/Options.cpp: (JSC::Options::initializeOptions): git-svn-id: http://svn.webkit.org/repository/webkit/trunk@105533 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- Source/JavaScriptCore/ChangeLog | 114 +++++++++++++++++++++ Source/JavaScriptCore/bytecode/CodeBlock.cpp | 14 ++- Source/JavaScriptCore/bytecode/CodeBlock.h | 5 + Source/JavaScriptCore/bytecode/CodeOrigin.h | 24 +++-- Source/JavaScriptCore/bytecode/Instruction.h | 4 + Source/JavaScriptCore/bytecode/Opcode.h | 48 ++++----- .../bytecompiler/BytecodeGenerator.cpp | 64 ++++++++---- .../bytecompiler/BytecodeGenerator.h | 1 + Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp | 27 +++-- Source/JavaScriptCore/dfg/DFGGraph.h | 22 +--- Source/JavaScriptCore/jit/JIT.h | 6 +- Source/JavaScriptCore/jit/JITCall.cpp | 2 +- Source/JavaScriptCore/jit/JITCall32_64.cpp | 2 +- Source/JavaScriptCore/jit/JITInlineMethods.h | 18 ++-- Source/JavaScriptCore/jit/JITOpcodes.cpp | 16 +-- Source/JavaScriptCore/jit/JITOpcodes32_64.cpp | 14 +-- Source/JavaScriptCore/jit/JITPropertyAccess.cpp | 16 +-- .../JavaScriptCore/jit/JITPropertyAccess32_64.cpp | 16 +-- Source/JavaScriptCore/jit/JITStubCall.h | 8 +- Source/JavaScriptCore/runtime/Options.cpp | 6 +- 20 files changed, 297 insertions(+), 130 deletions(-) diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog index 09dcea5..28b15cf 100644 --- a/Source/JavaScriptCore/ChangeLog +++ b/Source/JavaScriptCore/ChangeLog @@ -1,3 +1,117 @@ +2012-01-19 Filip Pizlo + + Bytecode instructions that may have value profiling should have a direct inline + link to the ValueProfile instance + https://bugs.webkit.org/show_bug.cgi?id=76682 + + + Reviewed by Sam Weinig. + + Each opcode that gets value profiled now has a link to its ValueProfile. This + required rationalizing the emission of value profiles for opcode combos, like + op_method_check/op_get_by_id and op_call/op_call_put_result. It only makes + sense for one of them to have a value profile link, and it makes most sense + for it to be the one that actually sets the result. The previous behavior was + to have op_method_check profile for op_get_by_id when they were used together, + but otherwise for op_get_by_id to have its own profiles. op_call already did + the right thing; all profiling was done by op_call_put_result. + + But rationalizing this code required breaking some of the natural boundaries + that the code had; for instance the code in DFG that emits a GetById in place + of both op_method_check and op_get_by_id must now know that it's the latter of + those that has the value profile, while the first of those constitutes the OSR + target. Hence each CodeOrigin must now have two bytecode indices - one for + OSR exit and one for profiling. + + Finally this change required some refiddling of our optimization heuristics, + because now all code blocks have "more instructions" due to the value profile + slots. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::printGetByIdOp): + (JSC::CodeBlock::dump): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::valueProfileForBytecodeOffset): + * bytecode/CodeOrigin.h: + (JSC::CodeOrigin::CodeOrigin): + (JSC::CodeOrigin::bytecodeIndexForValueProfile): + * bytecode/Instruction.h: + (JSC::Instruction::Instruction): + * bytecode/Opcode.h: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitProfiledOpcode): + (JSC::BytecodeGenerator::emitResolve): + (JSC::BytecodeGenerator::emitGetScopedVar): + (JSC::BytecodeGenerator::emitResolveBase): + (JSC::BytecodeGenerator::emitResolveBaseForPut): + (JSC::BytecodeGenerator::emitResolveWithBase): + (JSC::BytecodeGenerator::emitResolveWithThis): + (JSC::BytecodeGenerator::emitGetById): + (JSC::BytecodeGenerator::emitGetByVal): + (JSC::BytecodeGenerator::emitCall): + (JSC::BytecodeGenerator::emitCallVarargs): + (JSC::BytecodeGenerator::emitConstruct): + * bytecompiler/BytecodeGenerator.h: + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::ByteCodeParser): + (JSC::DFG::ByteCodeParser::currentCodeOrigin): + (JSC::DFG::ByteCodeParser::addCall): + (JSC::DFG::ByteCodeParser::getPredictionWithoutOSRExit): + (JSC::DFG::ByteCodeParser::getPrediction): + (JSC::DFG::ByteCodeParser::handleCall): + (JSC::DFG::ByteCodeParser::handleInlining): + (JSC::DFG::ByteCodeParser::parseBlock): + (JSC::DFG::ByteCodeParser::parse): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::valueProfileFor): + * jit/JIT.h: + (JSC::JIT::emitValueProfilingSite): + * jit/JITCall.cpp: + (JSC::JIT::emit_op_call_put_result): + * jit/JITCall32_64.cpp: + (JSC::JIT::emit_op_call_put_result): + * jit/JITInlineMethods.h: + (JSC::JIT::emitValueProfilingSite): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_resolve): + (JSC::JIT::emit_op_resolve_base): + (JSC::JIT::emit_op_resolve_skip): + (JSC::JIT::emit_op_resolve_global): + (JSC::JIT::emitSlow_op_resolve_global): + (JSC::JIT::emit_op_resolve_with_base): + (JSC::JIT::emit_op_resolve_with_this): + (JSC::JIT::emitSlow_op_resolve_global_dynamic): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_resolve): + (JSC::JIT::emit_op_resolve_base): + (JSC::JIT::emit_op_resolve_skip): + (JSC::JIT::emit_op_resolve_global): + (JSC::JIT::emitSlow_op_resolve_global): + (JSC::JIT::emit_op_resolve_with_base): + (JSC::JIT::emit_op_resolve_with_this): + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_get_by_val): + (JSC::JIT::emitSlow_op_get_by_val): + (JSC::JIT::emit_op_method_check): + (JSC::JIT::emitSlow_op_method_check): + (JSC::JIT::emit_op_get_by_id): + (JSC::JIT::emitSlow_op_get_by_id): + (JSC::JIT::emit_op_get_scoped_var): + (JSC::JIT::emit_op_get_global_var): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emit_op_method_check): + (JSC::JIT::emitSlow_op_method_check): + (JSC::JIT::emit_op_get_by_val): + (JSC::JIT::emitSlow_op_get_by_val): + (JSC::JIT::emit_op_get_by_id): + (JSC::JIT::emitSlow_op_get_by_id): + (JSC::JIT::emit_op_get_scoped_var): + (JSC::JIT::emit_op_get_global_var): + * jit/JITStubCall.h: + (JSC::JITStubCall::callWithValueProfiling): + * runtime/Options.cpp: + (JSC::Options::initializeOptions): + 2012-01-20 ChangSeok Oh undefined reference to symbol eina_module_free diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp index 8f283d8..72ea0b4 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp @@ -180,7 +180,7 @@ void CodeBlock::printGetByIdOp(ExecState* exec, int location, Vectoru.operand; int id0 = (++it)->u.operand; printf("[%4d] %s\t %s, %s, %s\n", location, op, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data()); - it += 4; + it += 5; } void CodeBlock::printCallOp(ExecState* exec, int location, Vector::const_iterator& it, const char* op) const @@ -743,6 +743,7 @@ void CodeBlock::dump(ExecState* exec, const Vector::const_iterator& int r0 = (++it)->u.operand; int id0 = (++it)->u.operand; printf("[%4d] resolve\t\t %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data()); + it++; break; } case op_resolve_skip: { @@ -750,13 +751,14 @@ void CodeBlock::dump(ExecState* exec, const Vector::const_iterator& int id0 = (++it)->u.operand; int skipLevels = (++it)->u.operand; printf("[%4d] resolve_skip\t %s, %s, %d\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), skipLevels); + it++; break; } case op_resolve_global: { int r0 = (++it)->u.operand; int id0 = (++it)->u.operand; printf("[%4d] resolve_global\t %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data()); - it += 2; + it += 3; break; } case op_resolve_global_dynamic: { @@ -766,6 +768,7 @@ void CodeBlock::dump(ExecState* exec, const Vector::const_iterator& ++it; int depth = (++it)->u.operand; printf("[%4d] resolve_global_dynamic\t %s, %s, %s, %d\n", location, registerName(exec, r0).data(), valueToSourceString(exec, scope).utf8().data(), idName(id0, m_identifiers[id0]).data(), depth); + ++it; break; } case op_get_scoped_var: { @@ -773,6 +776,7 @@ void CodeBlock::dump(ExecState* exec, const Vector::const_iterator& int index = (++it)->u.operand; int skipLevels = (++it)->u.operand; printf("[%4d] get_scoped_var\t %s, %d, %d\n", location, registerName(exec, r0).data(), index, skipLevels); + it++; break; } case op_put_scoped_var: { @@ -786,6 +790,7 @@ void CodeBlock::dump(ExecState* exec, const Vector::const_iterator& int r0 = (++it)->u.operand; int index = (++it)->u.operand; printf("[%4d] get_global_var\t %s, %d\n", location, registerName(exec, r0).data(), index); + it++; break; } case op_put_global_var: { @@ -799,6 +804,7 @@ void CodeBlock::dump(ExecState* exec, const Vector::const_iterator& int id0 = (++it)->u.operand; int isStrict = (++it)->u.operand; printf("[%4d] resolve_base%s\t %s, %s\n", location, isStrict ? "_strict" : "", registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data()); + it++; break; } case op_ensure_property_exists: { @@ -812,6 +818,7 @@ void CodeBlock::dump(ExecState* exec, const Vector::const_iterator& int r1 = (++it)->u.operand; int id0 = (++it)->u.operand; printf("[%4d] resolve_with_base %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data()); + it++; break; } case op_resolve_with_this: { @@ -819,6 +826,7 @@ void CodeBlock::dump(ExecState* exec, const Vector::const_iterator& int r1 = (++it)->u.operand; int id0 = (++it)->u.operand; printf("[%4d] resolve_with_this %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data()); + it++; break; } case op_get_by_id: { @@ -924,6 +932,7 @@ void CodeBlock::dump(ExecState* exec, const Vector::const_iterator& int r1 = (++it)->u.operand; int r2 = (++it)->u.operand; printf("[%4d] get_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); + it++; break; } case op_get_argument_by_val: { @@ -1162,6 +1171,7 @@ void CodeBlock::dump(ExecState* exec, const Vector::const_iterator& case op_call_put_result: { int r0 = (++it)->u.operand; printf("[%4d] op_call_put_result\t\t %s\n", location, registerName(exec, r0).data()); + it++; break; } case op_ret_object_or_this: { diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h index ceb7be6..bc30050 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.h +++ b/Source/JavaScriptCore/bytecode/CodeBlock.h @@ -521,6 +521,11 @@ namespace JSC { { ValueProfile* result = WTF::genericBinarySearch(m_valueProfiles, m_valueProfiles.size(), bytecodeOffset); ASSERT(result->m_bytecodeOffset != -1); + ASSERT(!hasInstructions() + || instructions()[bytecodeOffset + opcodeLength( + m_globalData->interpreter->getOpcodeID( + instructions()[ + bytecodeOffset].u.opcode)) - 1].u.profile == result); return result; } diff --git a/Source/JavaScriptCore/bytecode/CodeOrigin.h b/Source/JavaScriptCore/bytecode/CodeOrigin.h index 7b6ce7d..25a116c 100644 --- a/Source/JavaScriptCore/bytecode/CodeOrigin.h +++ b/Source/JavaScriptCore/bytecode/CodeOrigin.h @@ -38,29 +38,37 @@ class ExecutableBase; class JSFunction; struct CodeOrigin { - uint32_t bytecodeIndex; + // Bytecode offset that you'd use to re-execute this instruction. + unsigned bytecodeIndex : 29; + // Bytecode offset corresponding to the opcode that gives the result (needed to handle + // op_call/op_call_put_result and op_method_check/op_get_by_id). + unsigned valueProfileOffset : 3; + InlineCallFrame* inlineCallFrame; CodeOrigin() : bytecodeIndex(std::numeric_limits::max()) + , valueProfileOffset(0) , inlineCallFrame(0) { } - explicit CodeOrigin(uint32_t bytecodeIndex) - : bytecodeIndex(bytecodeIndex) - , inlineCallFrame(0) - { - } - - explicit CodeOrigin(uint32_t bytecodeIndex, InlineCallFrame* inlineCallFrame) + explicit CodeOrigin(unsigned bytecodeIndex, InlineCallFrame* inlineCallFrame = 0, unsigned valueProfileOffset = 0) : bytecodeIndex(bytecodeIndex) + , valueProfileOffset(valueProfileOffset) , inlineCallFrame(inlineCallFrame) { + ASSERT(bytecodeIndex < (1u << 29)); + ASSERT(valueProfileOffset < (1u << 3)); } bool isSet() const { return bytecodeIndex != std::numeric_limits::max(); } + unsigned bytecodeIndexForValueProfile() const + { + return bytecodeIndex + valueProfileOffset; + } + // The inline depth is the depth of the inline stack, so 1 = not inlined, // 2 = inlined one deep, etc. unsigned inlineDepth() const; diff --git a/Source/JavaScriptCore/bytecode/Instruction.h b/Source/JavaScriptCore/bytecode/Instruction.h index 5e628c0..92118ee 100644 --- a/Source/JavaScriptCore/bytecode/Instruction.h +++ b/Source/JavaScriptCore/bytecode/Instruction.h @@ -48,6 +48,7 @@ namespace JSC { class JSCell; class Structure; class StructureChain; + struct ValueProfile; #if ENABLE(JIT) typedef MacroAssemblerCodeRef PolymorphicAccessStructureListStubRoutineType; @@ -180,6 +181,8 @@ namespace JSC { } Instruction(PropertySlot::GetValueFunc getterFunc) { u.getterFunc = getterFunc; } + + Instruction(ValueProfile* profile) { u.profile = profile; } union { Opcode opcode; @@ -188,6 +191,7 @@ namespace JSC { WriteBarrierBase structureChain; WriteBarrierBase jsCell; PropertySlot::GetValueFunc getterFunc; + ValueProfile* profile; } u; private: diff --git a/Source/JavaScriptCore/bytecode/Opcode.h b/Source/JavaScriptCore/bytecode/Opcode.h index 4801e4c..0f94176 100644 --- a/Source/JavaScriptCore/bytecode/Opcode.h +++ b/Source/JavaScriptCore/bytecode/Opcode.h @@ -95,38 +95,38 @@ namespace JSC { macro(op_is_function, 3) \ macro(op_in, 4) \ \ - macro(op_resolve, 3) \ - macro(op_resolve_skip, 4) \ - macro(op_resolve_global, 5) \ - macro(op_resolve_global_dynamic, 6) \ - macro(op_get_scoped_var, 4) \ + macro(op_resolve, 4) /* has value profiling */ \ + macro(op_resolve_skip, 5) /* has value profiling */ \ + macro(op_resolve_global, 6) /* has value profiling */ \ + macro(op_resolve_global_dynamic, 7) /* has value profiling */ \ + macro(op_get_scoped_var, 5) /* has value profiling */ \ macro(op_put_scoped_var, 4) \ - macro(op_get_global_var, 3) \ + macro(op_get_global_var, 4) /* has value profiling */ \ macro(op_put_global_var, 3) \ - macro(op_resolve_base, 4) \ + macro(op_resolve_base, 5) /* has value profiling */ \ macro(op_ensure_property_exists, 3) \ - macro(op_resolve_with_base, 4) \ - macro(op_resolve_with_this, 4) \ - macro(op_get_by_id, 8) \ - macro(op_get_by_id_self, 8) \ - macro(op_get_by_id_proto, 8) \ - macro(op_get_by_id_chain, 8) \ - macro(op_get_by_id_getter_self, 8) \ - macro(op_get_by_id_getter_proto, 8) \ - macro(op_get_by_id_getter_chain, 8) \ - macro(op_get_by_id_custom_self, 8) \ - macro(op_get_by_id_custom_proto, 8) \ - macro(op_get_by_id_custom_chain, 8) \ - macro(op_get_by_id_generic, 8) \ - macro(op_get_array_length, 8) \ - macro(op_get_string_length, 8) \ + macro(op_resolve_with_base, 5) /* has value profiling */ \ + macro(op_resolve_with_this, 5) /* has value profiling */ \ + macro(op_get_by_id, 9) /* has value profiling */ \ + macro(op_get_by_id_self, 9) /* has value profiling */ \ + macro(op_get_by_id_proto, 9) /* has value profiling */ \ + macro(op_get_by_id_chain, 9) /* has value profiling */ \ + macro(op_get_by_id_getter_self, 9) /* has value profiling */ \ + macro(op_get_by_id_getter_proto, 9) /* has value profiling */ \ + macro(op_get_by_id_getter_chain, 9) /* has value profiling */ \ + macro(op_get_by_id_custom_self, 9) /* has value profiling */ \ + macro(op_get_by_id_custom_proto, 9) /* has value profiling */ \ + macro(op_get_by_id_custom_chain, 9) /* has value profiling */ \ + macro(op_get_by_id_generic, 9) /* has value profiling */ \ + macro(op_get_array_length, 9) /* has value profiling */ \ + macro(op_get_string_length, 9) /* has value profiling */ \ macro(op_get_arguments_length, 4) \ macro(op_put_by_id, 9) \ macro(op_put_by_id_transition, 9) \ macro(op_put_by_id_replace, 9) \ macro(op_put_by_id_generic, 9) \ macro(op_del_by_id, 4) \ - macro(op_get_by_val, 4) \ + macro(op_get_by_val, 5) /* has value profiling */ \ macro(op_get_argument_by_val, 4) \ macro(op_get_by_pname, 7) \ macro(op_put_by_val, 4) \ @@ -170,7 +170,7 @@ namespace JSC { macro(op_tear_off_activation, 3) \ macro(op_tear_off_arguments, 2) \ macro(op_ret, 2) \ - macro(op_call_put_result, 2) \ + macro(op_call_put_result, 3) /* has value profiling */ \ macro(op_ret_object_or_this, 3) \ macro(op_method_check, 1) \ \ diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp index bfb1618..32e8b1a 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp @@ -668,6 +668,13 @@ void BytecodeGenerator::emitOpcode(OpcodeID opcodeID) m_lastOpcodeID = opcodeID; } +ValueProfile* BytecodeGenerator::emitProfiledOpcode(OpcodeID opcodeID) +{ + ValueProfile* result = m_codeBlock->addValueProfile(instructions().size()); + emitOpcode(opcodeID); + return result; +} + void BytecodeGenerator::emitLoopHint() { #if ENABLE(DFG_JIT) @@ -1245,9 +1252,10 @@ RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const Identifier& pr bool requiresDynamicChecks = false; if (!findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject) && !globalObject) { // We can't optimise at all :-( - emitOpcode(op_resolve); + ValueProfile* profile = emitProfiledOpcode(op_resolve); instructions().append(dst->index()); instructions().append(addConstant(property)); + instructions().append(profile); return dst; } if (shouldAvoidResolveGlobal()) { @@ -1267,21 +1275,23 @@ RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const Identifier& pr #if ENABLE(INTERPRETER) m_codeBlock->addGlobalResolveInstruction(instructions().size()); #endif - emitOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global); + ValueProfile* profile = emitProfiledOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global); instructions().append(dst->index()); instructions().append(addConstant(property)); instructions().append(0); instructions().append(0); if (requiresDynamicChecks) instructions().append(depth); + instructions().append(profile); return dst; } if (requiresDynamicChecks) { // If we get here we have eval nested inside a |with| just give up - emitOpcode(op_resolve); + ValueProfile* profile = emitProfiledOpcode(op_resolve); instructions().append(dst->index()); instructions().append(addConstant(property)); + instructions().append(profile); return dst; } @@ -1292,10 +1302,11 @@ RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const Identifier& pr // In this case we are at least able to drop a few scope chains from the // lookup chain, although we still need to hash from then on. - emitOpcode(op_resolve_skip); + ValueProfile* profile = emitProfiledOpcode(op_resolve_skip); instructions().append(dst->index()); instructions().append(addConstant(property)); instructions().append(depth); + instructions().append(profile); return dst; } @@ -1311,16 +1322,18 @@ RegisterID* BytecodeGenerator::emitGetScopedVar(RegisterID* dst, size_t depth, i return dst; } - emitOpcode(op_get_global_var); + ValueProfile* profile = emitProfiledOpcode(op_get_global_var); instructions().append(dst->index()); instructions().append(index); + instructions().append(profile); return dst; } - emitOpcode(op_get_scoped_var); + ValueProfile* profile = emitProfiledOpcode(op_get_scoped_var); instructions().append(dst->index()); instructions().append(index); instructions().append(depth); + instructions().append(profile); return dst; } @@ -1348,10 +1361,11 @@ RegisterID* BytecodeGenerator::emitResolveBase(RegisterID* dst, const Identifier findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject); if (!globalObject || requiresDynamicChecks) { // We can't optimise at all :-( - emitOpcode(op_resolve_base); + ValueProfile* profile = emitProfiledOpcode(op_resolve_base); instructions().append(dst->index()); instructions().append(addConstant(property)); instructions().append(false); + instructions().append(profile); return dst; } @@ -1370,10 +1384,11 @@ RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const Iden findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject); if (!globalObject || requiresDynamicChecks) { // We can't optimise at all :-( - emitOpcode(op_resolve_base); + ValueProfile* profile = emitProfiledOpcode(op_resolve_base); instructions().append(dst->index()); instructions().append(addConstant(property)); instructions().append(true); + instructions().append(profile); return dst; } @@ -1393,10 +1408,11 @@ RegisterID* BytecodeGenerator::emitResolveWithBase(RegisterID* baseDst, Register bool requiresDynamicChecks = false; if (!findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject) || !globalObject || requiresDynamicChecks) { // We can't optimise at all :-( - emitOpcode(op_resolve_with_base); + ValueProfile* profile = emitProfiledOpcode(op_resolve_with_base); instructions().append(baseDst->index()); instructions().append(propDst->index()); instructions().append(addConstant(property)); + instructions().append(profile); return baseDst; } @@ -1411,9 +1427,10 @@ RegisterID* BytecodeGenerator::emitResolveWithBase(RegisterID* baseDst, Register return baseDst; } if (shouldAvoidResolveGlobal()) { - emitOpcode(op_resolve); + ValueProfile* profile = emitProfiledOpcode(op_resolve); instructions().append(propDst->index()); instructions().append(addConstant(property)); + instructions().append(profile); return baseDst; } #if ENABLE(JIT) @@ -1422,13 +1439,14 @@ RegisterID* BytecodeGenerator::emitResolveWithBase(RegisterID* baseDst, Register #if ENABLE(INTERPRETER) m_codeBlock->addGlobalResolveInstruction(instructions().size()); #endif - emitOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global); + ValueProfile* profile = emitProfiledOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global); instructions().append(propDst->index()); instructions().append(addConstant(property)); instructions().append(0); instructions().append(0); if (requiresDynamicChecks) instructions().append(depth); + instructions().append(profile); return baseDst; } @@ -1440,10 +1458,11 @@ RegisterID* BytecodeGenerator::emitResolveWithThis(RegisterID* baseDst, Register bool requiresDynamicChecks = false; if (!findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject) || !globalObject || requiresDynamicChecks) { // We can't optimise at all :-( - emitOpcode(op_resolve_with_this); + ValueProfile* profile = emitProfiledOpcode(op_resolve_with_this); instructions().append(baseDst->index()); instructions().append(propDst->index()); instructions().append(addConstant(property)); + instructions().append(profile); return baseDst; } @@ -1458,9 +1477,10 @@ RegisterID* BytecodeGenerator::emitResolveWithThis(RegisterID* baseDst, Register return baseDst; } if (shouldAvoidResolveGlobal()) { - emitOpcode(op_resolve); + ValueProfile* profile = emitProfiledOpcode(op_resolve); instructions().append(propDst->index()); instructions().append(addConstant(property)); + instructions().append(profile); return baseDst; } #if ENABLE(JIT) @@ -1469,13 +1489,14 @@ RegisterID* BytecodeGenerator::emitResolveWithThis(RegisterID* baseDst, Register #if ENABLE(INTERPRETER) m_codeBlock->addGlobalResolveInstruction(instructions().size()); #endif - emitOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global); + ValueProfile* profile = emitProfiledOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global); instructions().append(propDst->index()); instructions().append(addConstant(property)); instructions().append(0); instructions().append(0); if (requiresDynamicChecks) instructions().append(depth); + instructions().append(profile); return baseDst; } @@ -1490,7 +1511,7 @@ RegisterID* BytecodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, co m_codeBlock->addPropertyAccessInstruction(instructions().size()); #endif - emitOpcode(op_get_by_id); + ValueProfile* profile = emitProfiledOpcode(op_get_by_id); instructions().append(dst->index()); instructions().append(base->index()); instructions().append(addConstant(property)); @@ -1498,6 +1519,7 @@ RegisterID* BytecodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, co instructions().append(0); instructions().append(0); instructions().append(0); + instructions().append(profile); return dst; } @@ -1599,10 +1621,11 @@ RegisterID* BytecodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, R return dst; } } - emitOpcode(op_get_by_val); + ValueProfile* profile = emitProfiledOpcode(op_get_by_val); instructions().append(dst->index()); instructions().append(base->index()); instructions().append(property->index()); + instructions().append(profile); return dst; } @@ -1824,8 +1847,9 @@ RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Regi instructions().append(0); instructions().append(0); if (dst != ignoredResult()) { - emitOpcode(op_call_put_result); + ValueProfile* profile = emitProfiledOpcode(op_call_put_result); instructions().append(dst->index()); // dst + instructions().append(profile); } if (m_shouldEmitProfileHooks) { @@ -1853,8 +1877,9 @@ RegisterID* BytecodeGenerator::emitCallVarargs(RegisterID* dst, RegisterID* func instructions().append(arguments->index()); instructions().append(firstFreeRegister->index()); if (dst != ignoredResult()) { - emitOpcode(op_call_put_result); + ValueProfile* profile = emitProfiledOpcode(op_call_put_result); instructions().append(dst->index()); + instructions().append(profile); } if (m_shouldEmitProfileHooks) { emitOpcode(op_profile_did_call); @@ -1926,8 +1951,9 @@ RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, instructions().append(0); instructions().append(0); if (dst != ignoredResult()) { - emitOpcode(op_call_put_result); + ValueProfile* profile = emitProfiledOpcode(op_call_put_result); instructions().append(dst->index()); // dst + instructions().append(profile); } if (m_shouldEmitProfileHooks) { diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h index ce8d8f8..59d776e 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h @@ -409,6 +409,7 @@ namespace JSC { private: void emitOpcode(OpcodeID); + ValueProfile* emitProfiledOpcode(OpcodeID); void retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index); void retrieveLastUnaryOp(int& dstIndex, int& srcIndex); ALWAYS_INLINE void rewindBinaryOp(); diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp index 21aa621..51a8a0c 100644 --- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp +++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp @@ -48,6 +48,7 @@ public: , m_graph(graph) , m_currentBlock(0) , m_currentIndex(0) + , m_currentProfilingIndex(0) , m_constantUndefined(UINT_MAX) , m_constantNull(UINT_MAX) , m_constantNaN(UINT_MAX) @@ -519,7 +520,7 @@ private: CodeOrigin currentCodeOrigin() { - return CodeOrigin(m_currentIndex, m_inlineStackTop->m_inlineCallFrame); + return CodeOrigin(m_currentIndex, m_inlineStackTop->m_inlineCallFrame, m_currentProfilingIndex - m_currentIndex); } // These methods create a node and add it to the graph. If nodes of this type are @@ -574,8 +575,10 @@ private: Instruction* putInstruction = currentInstruction + OPCODE_LENGTH(op_call); PredictedType prediction = PredictNone; - if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) - prediction = getPrediction(m_graph.size(), m_currentIndex + OPCODE_LENGTH(op_call)); + if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) { + m_currentProfilingIndex = m_currentIndex + OPCODE_LENGTH(op_call); + prediction = getPrediction(); + } addVarArgChild(get(currentInstruction[1].u.operand)); int argCount = currentInstruction[2].u.operand; @@ -622,12 +625,12 @@ private: PredictedType getPredictionWithoutOSRExit() { - return getPredictionWithoutOSRExit(m_graph.size(), m_currentIndex); + return getPredictionWithoutOSRExit(m_graph.size(), m_currentProfilingIndex); } PredictedType getPrediction() { - return getPrediction(m_graph.size(), m_currentIndex); + return getPrediction(m_graph.size(), m_currentProfilingIndex); } NodeIndex makeSafe(NodeIndex nodeIndex) @@ -750,6 +753,8 @@ private: BasicBlock* m_currentBlock; // The bytecode index of the current instruction being generated. unsigned m_currentIndex; + // The bytecode index of the value profile of the current instruction being generated. + unsigned m_currentProfilingIndex; // We use these values during code generation, and to avoid the need for // special handling we make sure they are available as constants in the @@ -945,7 +950,8 @@ void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentIn if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) { resultOperand = putInstruction[1].u.operand; usesResult = true; - prediction = getPrediction(m_graph.size(), nextOffset); + m_currentProfilingIndex = nextOffset; + prediction = getPrediction(); nextOffset += OPCODE_LENGTH(op_call_put_result); } JSFunction* expectedFunction; @@ -1067,13 +1073,16 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c // This is where the actual inlining really happens. unsigned oldIndex = m_currentIndex; + unsigned oldProfilingIndex = m_currentProfilingIndex; m_currentIndex = 0; + m_currentProfilingIndex = 0; addToGraph(InlineStart); parseCodeBlock(); m_currentIndex = oldIndex; + m_currentProfilingIndex = oldProfilingIndex; // If the inlined code created some new basic blocks, then we have linking to do. if (inlineStackEntry.m_callsiteBlockHead != m_graph.m_blocks.size() - 1) { @@ -1331,6 +1340,8 @@ bool ByteCodeParser::parseBlock(unsigned limit) } while (true) { + m_currentProfilingIndex = m_currentIndex; + // Don't extend over jump destinations. if (m_currentIndex == limit) { // Ordinarily we want to plant a jump. But refuse to do this if the block is @@ -1703,6 +1714,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) } case op_method_check: { + m_currentProfilingIndex += OPCODE_LENGTH(op_method_check); Instruction* getInstruction = currentInstruction + OPCODE_LENGTH(op_method_check); PredictedType prediction = getPrediction(); @@ -2643,6 +2655,9 @@ bool ByteCodeParser::parse() #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) printf("Processing local variable phis.\n"); #endif + + m_currentProfilingIndex = m_currentIndex; + processPhiStack(); #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) printf("Processing argument phis.\n"); diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h index fb72906..df514a5 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.h +++ b/Source/JavaScriptCore/dfg/DFGGraph.h @@ -223,8 +223,7 @@ public: Node& node = at(nodeIndex); - switch (node.op) { - case GetLocal: { + if (node.op == GetLocal) { if (!operandIsArgument(node.local())) return 0; int argument = operandToArgument(node.local()); @@ -233,21 +232,10 @@ public: return profiledBlock->valueProfileForArgument(argument); } - // Nodes derives from calls need special handling because the value profile is - // associated with the op_call_put_result instruction. - case Call: - case Construct: - case ArrayPop: - case ArrayPush: { - ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct)); - return profiledBlock->valueProfileForBytecodeOffset(node.codeOrigin.bytecodeIndex + OPCODE_LENGTH(op_call)); - } - - default: - if (node.hasHeapPrediction()) - return profiledBlock->valueProfileForBytecodeOffset(node.codeOrigin.bytecodeIndex); - return 0; - } + if (node.hasHeapPrediction()) + return profiledBlock->valueProfileForBytecodeOffset(node.codeOrigin.bytecodeIndexForValueProfile()); + + return 0; } Vector< OwnPtr , 8> m_blocks; diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h index 750b9d8..2aec542 100644 --- a/Source/JavaScriptCore/jit/JIT.h +++ b/Source/JavaScriptCore/jit/JIT.h @@ -333,14 +333,14 @@ namespace JSC { template void emitAllocateJSFinalObject(T structure, RegisterID result, RegisterID storagePtr); void emitAllocateJSFunction(FunctionExecutable*, RegisterID scopeChain, RegisterID result, RegisterID storagePtr); - enum ValueProfilingSiteKind { FirstProfilingSite, SubsequentProfilingSite }; #if ENABLE(VALUE_PROFILER) // This assumes that the value to profile is in regT0 and that regT3 is available for // scratch. void emitValueProfilingSite(ValueProfile*); - void emitValueProfilingSite(ValueProfilingSiteKind); + void emitValueProfilingSite(unsigned bytecodeOffset); + void emitValueProfilingSite(); #else - void emitValueProfilingSite(ValueProfilingSiteKind) { } + void emitValueProfilingSite() { } #endif #if USE(JSVALUE32_64) diff --git a/Source/JavaScriptCore/jit/JITCall.cpp b/Source/JavaScriptCore/jit/JITCall.cpp index 465f1ad..3aeef95 100644 --- a/Source/JavaScriptCore/jit/JITCall.cpp +++ b/Source/JavaScriptCore/jit/JITCall.cpp @@ -50,7 +50,7 @@ namespace JSC { void JIT::emit_op_call_put_result(Instruction* instruction) { int dst = instruction[1].u.operand; - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(); emitPutVirtualRegister(dst); } diff --git a/Source/JavaScriptCore/jit/JITCall32_64.cpp b/Source/JavaScriptCore/jit/JITCall32_64.cpp index 01c9db0..b84ad1a 100644 --- a/Source/JavaScriptCore/jit/JITCall32_64.cpp +++ b/Source/JavaScriptCore/jit/JITCall32_64.cpp @@ -50,7 +50,7 @@ namespace JSC { void JIT::emit_op_call_put_result(Instruction* instruction) { int dst = instruction[1].u.operand; - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(); emitStore(dst, regT1, regT0); } diff --git a/Source/JavaScriptCore/jit/JITInlineMethods.h b/Source/JavaScriptCore/jit/JITInlineMethods.h index 5540ffa..e617961 100644 --- a/Source/JavaScriptCore/jit/JITInlineMethods.h +++ b/Source/JavaScriptCore/jit/JITInlineMethods.h @@ -486,20 +486,16 @@ inline void JIT::emitValueProfilingSite(ValueProfile* valueProfile) #endif } -inline void JIT::emitValueProfilingSite(ValueProfilingSiteKind siteKind) +inline void JIT::emitValueProfilingSite(unsigned bytecodeOffset) { if (!shouldEmitProfiling()) return; - - ValueProfile* valueProfile; - if (siteKind == FirstProfilingSite) - valueProfile = m_codeBlock->addValueProfile(m_bytecodeOffset); - else { - ASSERT(siteKind == SubsequentProfilingSite); - valueProfile = m_codeBlock->valueProfileForBytecodeOffset(m_bytecodeOffset); - } - - emitValueProfilingSite(valueProfile); + emitValueProfilingSite(m_codeBlock->valueProfileForBytecodeOffset(bytecodeOffset)); +} + +inline void JIT::emitValueProfilingSite() +{ + emitValueProfilingSite(m_bytecodeOffset); } #endif diff --git a/Source/JavaScriptCore/jit/JITOpcodes.cpp b/Source/JavaScriptCore/jit/JITOpcodes.cpp index f5be279..4f57f4a 100644 --- a/Source/JavaScriptCore/jit/JITOpcodes.cpp +++ b/Source/JavaScriptCore/jit/JITOpcodes.cpp @@ -568,7 +568,7 @@ void JIT::emit_op_resolve(Instruction* currentInstruction) { JITStubCall stubCall(this, cti_op_resolve); stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); - stubCall.callWithValueProfiling(currentInstruction[1].u.operand, FirstProfilingSite); + stubCall.callWithValueProfiling(currentInstruction[1].u.operand); } void JIT::emit_op_to_primitive(Instruction* currentInstruction) @@ -599,7 +599,7 @@ void JIT::emit_op_resolve_base(Instruction* currentInstruction) { JITStubCall stubCall(this, currentInstruction[3].u.operand ? cti_op_resolve_base_strict_put : cti_op_resolve_base); stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); - stubCall.callWithValueProfiling(currentInstruction[1].u.operand, FirstProfilingSite); + stubCall.callWithValueProfiling(currentInstruction[1].u.operand); } void JIT::emit_op_ensure_property_exists(Instruction* currentInstruction) @@ -615,7 +615,7 @@ void JIT::emit_op_resolve_skip(Instruction* currentInstruction) JITStubCall stubCall(this, cti_op_resolve_skip); stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); stubCall.addArgument(Imm32(currentInstruction[3].u.operand)); - stubCall.callWithValueProfiling(currentInstruction[1].u.operand, FirstProfilingSite); + stubCall.callWithValueProfiling(currentInstruction[1].u.operand); } void JIT::emit_op_resolve_global(Instruction* currentInstruction, bool) @@ -636,7 +636,7 @@ void JIT::emit_op_resolve_global(Instruction* currentInstruction, bool) loadPtr(Address(regT0, OBJECT_OFFSETOF(JSGlobalObject, m_propertyStorage)), regT0); load32(Address(regT2, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), regT1); loadPtr(BaseIndex(regT0, regT1, ScalePtr), regT0); - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(); emitPutVirtualRegister(currentInstruction[1].u.operand); } @@ -652,7 +652,7 @@ void JIT::emitSlow_op_resolve_global(Instruction* currentInstruction, Vectoridentifier(currentInstruction[3].u.operand))); stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); - stubCall.callWithValueProfiling(currentInstruction[2].u.operand, FirstProfilingSite); + stubCall.callWithValueProfiling(currentInstruction[2].u.operand); } void JIT::emit_op_resolve_with_this(Instruction* currentInstruction) @@ -781,7 +781,7 @@ void JIT::emit_op_resolve_with_this(Instruction* currentInstruction) JITStubCall stubCall(this, cti_op_resolve_with_this); stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand))); stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); - stubCall.callWithValueProfiling(currentInstruction[2].u.operand, FirstProfilingSite); + stubCall.callWithValueProfiling(currentInstruction[2].u.operand); } void JIT::emit_op_jtrue(Instruction* currentInstruction) @@ -1563,7 +1563,7 @@ void JIT::emitSlow_op_resolve_global_dynamic(Instruction* currentInstruction, Ve stubCall.addArgument(TrustedImmPtr(ident)); stubCall.addArgument(Imm32(currentIndex)); stubCall.addArgument(regT0); - stubCall.callWithValueProfiling(dst, SubsequentProfilingSite); // The first profiling site is in emit_op_resolve_global + stubCall.callWithValueProfiling(dst); } void JIT::emit_op_new_regexp(Instruction* currentInstruction) diff --git a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp index 9d1cbce..b798965 100644 --- a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp +++ b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp @@ -660,7 +660,7 @@ void JIT::emit_op_resolve(Instruction* currentInstruction) { JITStubCall stubCall(this, cti_op_resolve); stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); - stubCall.callWithValueProfiling(currentInstruction[1].u.operand, FirstProfilingSite); + stubCall.callWithValueProfiling(currentInstruction[1].u.operand); } void JIT::emit_op_to_primitive(Instruction* currentInstruction) @@ -702,7 +702,7 @@ void JIT::emit_op_resolve_base(Instruction* currentInstruction) { JITStubCall stubCall(this, currentInstruction[3].u.operand ? cti_op_resolve_base_strict_put : cti_op_resolve_base); stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); - stubCall.callWithValueProfiling(currentInstruction[1].u.operand, FirstProfilingSite); + stubCall.callWithValueProfiling(currentInstruction[1].u.operand); } void JIT::emit_op_ensure_property_exists(Instruction* currentInstruction) @@ -718,7 +718,7 @@ void JIT::emit_op_resolve_skip(Instruction* currentInstruction) JITStubCall stubCall(this, cti_op_resolve_skip); stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); stubCall.addArgument(Imm32(currentInstruction[3].u.operand)); - stubCall.callWithValueProfiling(currentInstruction[1].u.operand, FirstProfilingSite); + stubCall.callWithValueProfiling(currentInstruction[1].u.operand); } void JIT::emit_op_resolve_global(Instruction* currentInstruction, bool dynamic) @@ -743,7 +743,7 @@ void JIT::emit_op_resolve_global(Instruction* currentInstruction, bool dynamic) load32(Address(regT3, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), regT3); load32(BaseIndex(regT2, regT3, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); // payload load32(BaseIndex(regT2, regT3, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); // tag - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(); emitStore(dst, regT1, regT0); map(m_bytecodeOffset + (dynamic ? OPCODE_LENGTH(op_resolve_global_dynamic) : OPCODE_LENGTH(op_resolve_global)), dst, regT1, regT0); } @@ -759,7 +759,7 @@ void JIT::emitSlow_op_resolve_global(Instruction* currentInstruction, Vectoridentifier(currentInstruction[3].u.operand))); stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); - stubCall.callWithValueProfiling(currentInstruction[2].u.operand, FirstProfilingSite); + stubCall.callWithValueProfiling(currentInstruction[2].u.operand); } void JIT::emit_op_resolve_with_this(Instruction* currentInstruction) @@ -1165,7 +1165,7 @@ void JIT::emit_op_resolve_with_this(Instruction* currentInstruction) JITStubCall stubCall(this, cti_op_resolve_with_this); stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand))); stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); - stubCall.callWithValueProfiling(currentInstruction[2].u.operand, FirstProfilingSite); + stubCall.callWithValueProfiling(currentInstruction[2].u.operand); } void JIT::emit_op_throw(Instruction* currentInstruction) diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp index 48951e8..1deeefd 100644 --- a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp +++ b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp @@ -116,7 +116,7 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction) loadPtr(BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), regT0); addSlowCase(branchTestPtr(Zero, regT0)); - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(); emitPutVirtualRegister(dst); } @@ -147,7 +147,7 @@ void JIT::emitSlow_op_get_by_val(Instruction* currentInstruction, Vectoridentifier(currentInstruction[3].u.operand)); compileGetByIdSlowCase(resultVReg, baseVReg, ident, iter, true); - emitValueProfilingSite(SubsequentProfilingSite); + emitValueProfilingSite(m_bytecodeOffset + OPCODE_LENGTH(op_method_check)); // We've already generated the following get_by_id, so make sure it's skipped over. m_bytecodeOffset += OPCODE_LENGTH(op_get_by_id); @@ -361,7 +361,7 @@ void JIT::emit_op_get_by_id(Instruction* currentInstruction) emitGetVirtualRegister(baseVReg, regT0); compileGetByIdHotPath(baseVReg, ident); - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(); emitPutVirtualRegister(resultVReg); } @@ -405,7 +405,7 @@ void JIT::emitSlow_op_get_by_id(Instruction* currentInstruction, Vectoridentifier(currentInstruction[3].u.operand)); compileGetByIdSlowCase(resultVReg, baseVReg, ident, iter, false); - emitValueProfilingSite(SubsequentProfilingSite); + emitValueProfilingSite(); } void JIT::compileGetByIdSlowCase(int resultVReg, int baseVReg, Identifier* ident, Vector::iterator& iter, bool isMethodCheck) @@ -994,7 +994,7 @@ void JIT::emit_op_get_scoped_var(Instruction* currentInstruction) loadPtr(Address(regT0, OBJECT_OFFSETOF(ScopeChainNode, object)), regT0); loadPtr(Address(regT0, JSVariableObject::offsetOfRegisters()), regT0); loadPtr(Address(regT0, currentInstruction[2].u.operand * sizeof(Register)), regT0); - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(); emitPutVirtualRegister(currentInstruction[1].u.operand); } @@ -1029,7 +1029,7 @@ void JIT::emit_op_get_global_var(Instruction* currentInstruction) JSVariableObject* globalObject = m_codeBlock->globalObject(); loadPtr(&globalObject->m_registers, regT0); loadPtr(Address(regT0, currentInstruction[2].u.operand * sizeof(Register)), regT0); - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(); emitPutVirtualRegister(currentInstruction[1].u.operand); } diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp index b73d7ab..bbad000 100644 --- a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp +++ b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp @@ -144,7 +144,7 @@ void JIT::emit_op_method_check(Instruction* currentInstruction) compileGetByIdHotPath(); match.link(this); - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(m_bytecodeOffset + OPCODE_LENGTH(op_method_check)); emitStore(dst, regT1, regT0); map(m_bytecodeOffset + OPCODE_LENGTH(op_method_check) + OPCODE_LENGTH(op_get_by_id), dst, regT1, regT0); @@ -161,7 +161,7 @@ void JIT::emitSlow_op_method_check(Instruction* currentInstruction, Vectoridentifier(ident)), iter, true); - emitValueProfilingSite(SubsequentProfilingSite); + emitValueProfilingSite(m_bytecodeOffset + OPCODE_LENGTH(op_method_check)); // We've already generated the following get_by_id, so make sure it's skipped over. m_bytecodeOffset += OPCODE_LENGTH(op_get_by_id); @@ -228,7 +228,7 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction) load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); // payload addSlowCase(branch32(Equal, regT1, TrustedImm32(JSValue::EmptyValueTag))); - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(); emitStore(dst, regT1, regT0); map(m_bytecodeOffset + OPCODE_LENGTH(op_get_by_val), dst, regT1, regT0); } @@ -261,7 +261,7 @@ void JIT::emitSlow_op_get_by_val(Instruction* currentInstruction, Vectoridentifier(ident)), iter); - emitValueProfilingSite(SubsequentProfilingSite); + emitValueProfilingSite(); } void JIT::compileGetByIdSlowCase(int dst, int base, Identifier* ident, Vector::iterator& iter, bool isMethodCheck) @@ -1043,7 +1043,7 @@ void JIT::emit_op_get_scoped_var(Instruction* currentInstruction) loadPtr(Address(regT2, JSVariableObject::offsetOfRegisters()), regT2); emitLoad(index, regT1, regT0, regT2); - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(); emitStore(dst, regT1, regT0); map(m_bytecodeOffset + OPCODE_LENGTH(op_get_scoped_var), dst, regT1, regT0); } @@ -1085,7 +1085,7 @@ void JIT::emit_op_get_global_var(Instruction* currentInstruction) loadPtr(&globalObject->m_registers, regT2); emitLoad(index, regT1, regT0, regT2); - emitValueProfilingSite(FirstProfilingSite); + emitValueProfilingSite(); emitStore(dst, regT1, regT0); map(m_bytecodeOffset + OPCODE_LENGTH(op_get_global_var), dst, regT1, regT0); } diff --git a/Source/JavaScriptCore/jit/JITStubCall.h b/Source/JavaScriptCore/jit/JITStubCall.h index 18441c3..51401a7 100644 --- a/Source/JavaScriptCore/jit/JITStubCall.h +++ b/Source/JavaScriptCore/jit/JITStubCall.h @@ -201,14 +201,14 @@ namespace JSC { return call; } - JIT::Call callWithValueProfiling(unsigned dst, JIT::ValueProfilingSiteKind kind) + JIT::Call callWithValueProfiling(unsigned dst) { ASSERT(m_returnType == Value || m_returnType == Cell); JIT::Call call = this->call(); ASSERT(JIT::returnValueRegister == JIT::regT0); if (m_returnType == Cell) m_jit->move(JIT::TrustedImm32(JSValue::CellTag), JIT::regT1); - m_jit->emitValueProfilingSite(kind); + m_jit->emitValueProfilingSite(); if (m_returnType == Value) m_jit->emitStore(dst, JIT::regT1, JIT::regT0); else @@ -224,12 +224,12 @@ namespace JSC { return call; } - JIT::Call callWithValueProfiling(unsigned dst, JIT::ValueProfilingSiteKind kind) + JIT::Call callWithValueProfiling(unsigned dst) { ASSERT(m_returnType == VoidPtr || m_returnType == Cell); JIT::Call call = this->call(); ASSERT(JIT::returnValueRegister == JIT::regT0); - m_jit->emitValueProfilingSite(kind); + m_jit->emitValueProfilingSite(); m_jit->emitPutVirtualRegister(dst); return call; } diff --git a/Source/JavaScriptCore/runtime/Options.cpp b/Source/JavaScriptCore/runtime/Options.cpp index f660c87..ddfba6e 100644 --- a/Source/JavaScriptCore/runtime/Options.cpp +++ b/Source/JavaScriptCore/runtime/Options.cpp @@ -130,10 +130,10 @@ void setHeuristic(T& variable, const char* name, U value) void initializeOptions() { - SET(maximumOptimizationCandidateInstructionCount, 1000); + SET(maximumOptimizationCandidateInstructionCount, 1100); - SET(maximumFunctionForCallInlineCandidateInstructionCount, 150); - SET(maximumFunctionForConstructInlineCandidateInstructionCount, 80); + SET(maximumFunctionForCallInlineCandidateInstructionCount, 180); + SET(maximumFunctionForConstructInlineCandidateInstructionCount, 100); SET(maximumInliningDepth, 5); -- 2.7.4