diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-24 16:36:50 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-24 16:36:50 +0100 |
commit | ad0d549d4cc13433f77c1ac8f0ab379c83d93f28 (patch) | |
tree | b34b0daceb7c8e7fdde4b4ec43650ab7caadb0a9 /Source/JavaScriptCore/bytecode | |
parent | 03e12282df9aa1e1fb05a8b90f1cfc2e08764cec (diff) | |
download | qtwebkit-ad0d549d4cc13433f77c1ac8f0ab379c83d93f28.tar.gz |
Imported WebKit commit bb52bf3c0119e8a128cd93afe5572413a8617de9 (http://svn.webkit.org/repository/webkit/trunk@108790)
Diffstat (limited to 'Source/JavaScriptCore/bytecode')
28 files changed, 1653 insertions, 358 deletions
diff --git a/Source/JavaScriptCore/bytecode/BytecodeConventions.h b/Source/JavaScriptCore/bytecode/BytecodeConventions.h new file mode 100644 index 000000000..f33b060f8 --- /dev/null +++ b/Source/JavaScriptCore/bytecode/BytecodeConventions.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2012 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. + */ + +#ifndef BytecodeConventions_h +#define BytecodeConventions_h + +// Register numbers used in bytecode operations have different meaning according to their ranges: +// 0x80000000-0xFFFFFFFF Negative indices from the CallFrame pointer are entries in the call frame, see RegisterFile.h. +// 0x00000000-0x3FFFFFFF Forwards indices from the CallFrame pointer are local vars and temporaries with the function's callframe. +// 0x40000000-0x7FFFFFFF Positive indices from 0x40000000 specify entries in the constant pool on the CodeBlock. +static const int FirstConstantRegisterIndex = 0x40000000; + +#endif // BytecodeConventions_h + diff --git a/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp b/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp index f3fd5bb27..7f9e9ee8a 100644 --- a/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp +++ b/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp @@ -27,17 +27,40 @@ #include "CallLinkStatus.h" #include "CodeBlock.h" +#include "LLIntCallLinkInfo.h" namespace JSC { +CallLinkStatus CallLinkStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned bytecodeIndex) +{ + UNUSED_PARAM(profiledBlock); + UNUSED_PARAM(bytecodeIndex); +#if ENABLE(LLINT) + Instruction* instruction = profiledBlock->instructions().begin() + bytecodeIndex; + LLIntCallLinkInfo* callLinkInfo = instruction[4].u.callLinkInfo; + + return CallLinkStatus(callLinkInfo->lastSeenCallee.get(), false); +#else + return CallLinkStatus(0, false); +#endif +} + CallLinkStatus CallLinkStatus::computeFor(CodeBlock* profiledBlock, unsigned bytecodeIndex) { UNUSED_PARAM(profiledBlock); UNUSED_PARAM(bytecodeIndex); #if ENABLE(JIT) && ENABLE(VALUE_PROFILER) - return CallLinkStatus( - profiledBlock->getCallLinkInfo(bytecodeIndex).lastSeenCallee.get(), - profiledBlock->couldTakeSlowCase(bytecodeIndex)); + if (!profiledBlock->numberOfCallLinkInfos()) + return computeFromLLInt(profiledBlock, bytecodeIndex); + + if (profiledBlock->couldTakeSlowCase(bytecodeIndex)) + return CallLinkStatus(0, true); + + JSFunction* target = profiledBlock->getCallLinkInfo(bytecodeIndex).lastSeenCallee.get(); + if (!target) + return computeFromLLInt(profiledBlock, bytecodeIndex); + + return CallLinkStatus(target, false); #else return CallLinkStatus(0, false); #endif diff --git a/Source/JavaScriptCore/bytecode/CallLinkStatus.h b/Source/JavaScriptCore/bytecode/CallLinkStatus.h index e1c741016..5f7201905 100644 --- a/Source/JavaScriptCore/bytecode/CallLinkStatus.h +++ b/Source/JavaScriptCore/bytecode/CallLinkStatus.h @@ -47,15 +47,17 @@ public: static CallLinkStatus computeFor(CodeBlock*, unsigned bytecodeIndex); - bool isSet() const { return !!m_callTarget; } + bool isSet() const { return !!m_callTarget || m_couldTakeSlowPath; } - bool operator!() const { return !m_callTarget; } + bool operator!() const { return !isSet(); } bool couldTakeSlowPath() const { return m_couldTakeSlowPath; } JSFunction* callTarget() const { return m_callTarget; } private: + static CallLinkStatus computeFromLLInt(CodeBlock*, unsigned bytecodeIndex); + JSFunction* m_callTarget; bool m_couldTakeSlowPath; }; diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp index 191fafd62..ab89ad965 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp @@ -42,6 +42,7 @@ #include "JSFunction.h" #include "JSStaticScopeObject.h" #include "JSValue.h" +#include "LowLevelInterpreter.h" #include "RepatchBuffer.h" #include "UStringConcatenate.h" #include <stdio.h> @@ -154,7 +155,7 @@ void CodeBlock::printUnaryOp(ExecState* exec, int location, Vector<Instruction>: int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; - printf("[%4d] %s\t\t %s, %s\n", location, op, registerName(exec, r0).data(), registerName(exec, r1).data()); + dataLog("[%4d] %s\t\t %s, %s\n", location, op, registerName(exec, r0).data(), registerName(exec, r1).data()); } void CodeBlock::printBinaryOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) const @@ -162,14 +163,14 @@ void CodeBlock::printBinaryOp(ExecState* exec, int location, Vector<Instruction> int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int r2 = (++it)->u.operand; - printf("[%4d] %s\t\t %s, %s, %s\n", location, op, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); + dataLog("[%4d] %s\t\t %s, %s, %s\n", location, op, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); } void CodeBlock::printConditionalJump(ExecState* exec, const Vector<Instruction>::const_iterator&, Vector<Instruction>::const_iterator& it, int location, const char* op) const { int r0 = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] %s\t\t %s, %d(->%d)\n", location, op, registerName(exec, r0).data(), offset, location + offset); + dataLog("[%4d] %s\t\t %s, %d(->%d)\n", location, op, registerName(exec, r0).data(), offset, location + offset); } void CodeBlock::printGetByIdOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) const @@ -177,7 +178,7 @@ void CodeBlock::printGetByIdOp(ExecState* exec, int location, Vector<Instruction int r0 = (++it)->u.operand; int r1 = (++it)->u.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()); + dataLog("[%4d] %s\t %s, %s, %s\n", location, op, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data()); it += 5; } @@ -186,7 +187,7 @@ void CodeBlock::printCallOp(ExecState* exec, int location, Vector<Instruction>:: int func = (++it)->u.operand; int argCount = (++it)->u.operand; int registerOffset = (++it)->u.operand; - printf("[%4d] %s\t %s, %d, %d\n", location, op, registerName(exec, func).data(), argCount, registerOffset); + dataLog("[%4d] %s\t %s, %d, %d\n", location, op, registerName(exec, func).data(), argCount, registerOffset); it += 2; } @@ -195,7 +196,7 @@ void CodeBlock::printPutByIdOp(ExecState* exec, int location, Vector<Instruction int r0 = (++it)->u.operand; int id0 = (++it)->u.operand; int r1 = (++it)->u.operand; - printf("[%4d] %s\t %s, %s, %s\n", location, op, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data()); + dataLog("[%4d] %s\t %s, %s, %s\n", location, op, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data()); it += 5; } @@ -243,48 +244,48 @@ static unsigned instructionOffsetForNth(ExecState* exec, const Vector<Instructio static void printGlobalResolveInfo(const GlobalResolveInfo& resolveInfo, unsigned instructionOffset) { - printf(" [%4d] %s: %s\n", instructionOffset, "resolve_global", pointerToSourceString(resolveInfo.structure).utf8().data()); + dataLog(" [%4d] %s: %s\n", instructionOffset, "resolve_global", pointerToSourceString(resolveInfo.structure).utf8().data()); } static void printStructureStubInfo(const StructureStubInfo& stubInfo, unsigned instructionOffset) { switch (stubInfo.accessType) { case access_get_by_id_self: - printf(" [%4d] %s: %s\n", instructionOffset, "get_by_id_self", pointerToSourceString(stubInfo.u.getByIdSelf.baseObjectStructure).utf8().data()); + dataLog(" [%4d] %s: %s\n", instructionOffset, "get_by_id_self", pointerToSourceString(stubInfo.u.getByIdSelf.baseObjectStructure).utf8().data()); return; case access_get_by_id_proto: - printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_proto", pointerToSourceString(stubInfo.u.getByIdProto.baseObjectStructure).utf8().data(), pointerToSourceString(stubInfo.u.getByIdProto.prototypeStructure).utf8().data()); + dataLog(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_proto", pointerToSourceString(stubInfo.u.getByIdProto.baseObjectStructure).utf8().data(), pointerToSourceString(stubInfo.u.getByIdProto.prototypeStructure).utf8().data()); return; case access_get_by_id_chain: - printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_chain", pointerToSourceString(stubInfo.u.getByIdChain.baseObjectStructure).utf8().data(), pointerToSourceString(stubInfo.u.getByIdChain.chain).utf8().data()); + dataLog(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_chain", pointerToSourceString(stubInfo.u.getByIdChain.baseObjectStructure).utf8().data(), pointerToSourceString(stubInfo.u.getByIdChain.chain).utf8().data()); return; case access_get_by_id_self_list: - printf(" [%4d] %s: %s (%d)\n", instructionOffset, "op_get_by_id_self_list", pointerToSourceString(stubInfo.u.getByIdSelfList.structureList).utf8().data(), stubInfo.u.getByIdSelfList.listSize); + dataLog(" [%4d] %s: %s (%d)\n", instructionOffset, "op_get_by_id_self_list", pointerToSourceString(stubInfo.u.getByIdSelfList.structureList).utf8().data(), stubInfo.u.getByIdSelfList.listSize); return; case access_get_by_id_proto_list: - printf(" [%4d] %s: %s (%d)\n", instructionOffset, "op_get_by_id_proto_list", pointerToSourceString(stubInfo.u.getByIdProtoList.structureList).utf8().data(), stubInfo.u.getByIdProtoList.listSize); + dataLog(" [%4d] %s: %s (%d)\n", instructionOffset, "op_get_by_id_proto_list", pointerToSourceString(stubInfo.u.getByIdProtoList.structureList).utf8().data(), stubInfo.u.getByIdProtoList.listSize); return; case access_put_by_id_transition_normal: case access_put_by_id_transition_direct: - printf(" [%4d] %s: %s, %s, %s\n", instructionOffset, "put_by_id_transition", pointerToSourceString(stubInfo.u.putByIdTransition.previousStructure).utf8().data(), pointerToSourceString(stubInfo.u.putByIdTransition.structure).utf8().data(), pointerToSourceString(stubInfo.u.putByIdTransition.chain).utf8().data()); + dataLog(" [%4d] %s: %s, %s, %s\n", instructionOffset, "put_by_id_transition", pointerToSourceString(stubInfo.u.putByIdTransition.previousStructure).utf8().data(), pointerToSourceString(stubInfo.u.putByIdTransition.structure).utf8().data(), pointerToSourceString(stubInfo.u.putByIdTransition.chain).utf8().data()); return; case access_put_by_id_replace: - printf(" [%4d] %s: %s\n", instructionOffset, "put_by_id_replace", pointerToSourceString(stubInfo.u.putByIdReplace.baseObjectStructure).utf8().data()); + dataLog(" [%4d] %s: %s\n", instructionOffset, "put_by_id_replace", pointerToSourceString(stubInfo.u.putByIdReplace.baseObjectStructure).utf8().data()); return; case access_unset: - printf(" [%4d] %s\n", instructionOffset, "unset"); + dataLog(" [%4d] %s\n", instructionOffset, "unset"); return; case access_get_by_id_generic: - printf(" [%4d] %s\n", instructionOffset, "op_get_by_id_generic"); + dataLog(" [%4d] %s\n", instructionOffset, "op_get_by_id_generic"); return; case access_put_by_id_generic: - printf(" [%4d] %s\n", instructionOffset, "op_put_by_id_generic"); + dataLog(" [%4d] %s\n", instructionOffset, "op_put_by_id_generic"); return; case access_get_array_length: - printf(" [%4d] %s\n", instructionOffset, "op_get_array_length"); + dataLog(" [%4d] %s\n", instructionOffset, "op_get_array_length"); return; case access_get_string_length: - printf(" [%4d] %s\n", instructionOffset, "op_get_string_length"); + dataLog(" [%4d] %s\n", instructionOffset, "op_get_string_length"); return; default: ASSERT_NOT_REACHED(); @@ -295,7 +296,7 @@ static void printStructureStubInfo(const StructureStubInfo& stubInfo, unsigned i void CodeBlock::printStructure(const char* name, const Instruction* vPC, int operand) const { unsigned instructionOffset = vPC - instructions().begin(); - printf(" [%4d] %s: %s\n", instructionOffset, name, pointerToSourceString(vPC[operand].u.structure).utf8().data()); + dataLog(" [%4d] %s: %s\n", instructionOffset, name, pointerToSourceString(vPC[operand].u.structure).utf8().data()); } void CodeBlock::printStructures(const Instruction* vPC) const @@ -312,15 +313,15 @@ void CodeBlock::printStructures(const Instruction* vPC) const return; } if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto)) { - printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_proto", pointerToSourceString(vPC[4].u.structure).utf8().data(), pointerToSourceString(vPC[5].u.structure).utf8().data()); + dataLog(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_proto", pointerToSourceString(vPC[4].u.structure).utf8().data(), pointerToSourceString(vPC[5].u.structure).utf8().data()); return; } if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) { - printf(" [%4d] %s: %s, %s, %s\n", instructionOffset, "put_by_id_transition", pointerToSourceString(vPC[4].u.structure).utf8().data(), pointerToSourceString(vPC[5].u.structure).utf8().data(), pointerToSourceString(vPC[6].u.structureChain).utf8().data()); + dataLog(" [%4d] %s: %s, %s, %s\n", instructionOffset, "put_by_id_transition", pointerToSourceString(vPC[4].u.structure).utf8().data(), pointerToSourceString(vPC[5].u.structure).utf8().data(), pointerToSourceString(vPC[6].u.structureChain).utf8().data()); return; } if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain)) { - printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_chain", pointerToSourceString(vPC[4].u.structure).utf8().data(), pointerToSourceString(vPC[5].u.structureChain).utf8().data()); + dataLog(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_chain", pointerToSourceString(vPC[4].u.structure).utf8().data(), pointerToSourceString(vPC[5].u.structureChain).utf8().data()); return; } if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id)) { @@ -347,7 +348,7 @@ void CodeBlock::printStructures(const Instruction* vPC) const void CodeBlock::dump(ExecState* exec) const { if (!m_instructions) { - printf("No instructions available.\n"); + dataLog("No instructions available.\n"); return; } @@ -356,10 +357,10 @@ void CodeBlock::dump(ExecState* exec) const for (size_t i = 0; i < instructions().size(); i += opcodeLengths[exec->interpreter()->getOpcodeID(instructions()[i].u.opcode)]) ++instructionCount; - printf("%lu m_instructions; %lu bytes at %p; %d parameter(s); %d callee register(s)\n\n", + dataLog("%lu m_instructions; %lu bytes at %p; %d parameter(s); %d callee register(s); %d variable(s)\n\n", static_cast<unsigned long>(instructionCount), static_cast<unsigned long>(instructions().size() * sizeof(Instruction)), - this, m_numParameters, m_numCalleeRegisters); + this, m_numParameters, m_numCalleeRegisters, m_numVars); Vector<Instruction>::const_iterator begin = instructions().begin(); Vector<Instruction>::const_iterator end = instructions().end(); @@ -367,35 +368,35 @@ void CodeBlock::dump(ExecState* exec) const dump(exec, begin, it); if (!m_identifiers.isEmpty()) { - printf("\nIdentifiers:\n"); + dataLog("\nIdentifiers:\n"); size_t i = 0; do { - printf(" id%u = %s\n", static_cast<unsigned>(i), m_identifiers[i].ustring().utf8().data()); + dataLog(" id%u = %s\n", static_cast<unsigned>(i), m_identifiers[i].ustring().utf8().data()); ++i; } while (i != m_identifiers.size()); } if (!m_constantRegisters.isEmpty()) { - printf("\nConstants:\n"); + dataLog("\nConstants:\n"); size_t i = 0; do { - printf(" k%u = %s\n", static_cast<unsigned>(i), valueToSourceString(exec, m_constantRegisters[i].get()).utf8().data()); + dataLog(" k%u = %s\n", static_cast<unsigned>(i), valueToSourceString(exec, m_constantRegisters[i].get()).utf8().data()); ++i; } while (i < m_constantRegisters.size()); } if (m_rareData && !m_rareData->m_regexps.isEmpty()) { - printf("\nm_regexps:\n"); + dataLog("\nm_regexps:\n"); size_t i = 0; do { - printf(" re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(m_rareData->m_regexps[i].get()).utf8().data()); + dataLog(" re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(m_rareData->m_regexps[i].get()).utf8().data()); ++i; } while (i < m_rareData->m_regexps.size()); } #if ENABLE(JIT) if (!m_globalResolveInfos.isEmpty() || !m_structureStubInfos.isEmpty()) - printf("\nStructures:\n"); + dataLog("\nStructures:\n"); if (!m_globalResolveInfos.isEmpty()) { size_t i = 0; @@ -412,9 +413,9 @@ void CodeBlock::dump(ExecState* exec) const } while (i < m_structureStubInfos.size()); } #endif -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) if (!m_globalResolveInstructions.isEmpty() || !m_propertyAccessInstructions.isEmpty()) - printf("\nStructures:\n"); + dataLog("\nStructures:\n"); if (!m_globalResolveInstructions.isEmpty()) { size_t i = 0; @@ -433,36 +434,36 @@ void CodeBlock::dump(ExecState* exec) const #endif if (m_rareData && !m_rareData->m_exceptionHandlers.isEmpty()) { - printf("\nException Handlers:\n"); + dataLog("\nException Handlers:\n"); unsigned i = 0; do { - printf("\t %d: { start: [%4d] end: [%4d] target: [%4d] }\n", i + 1, m_rareData->m_exceptionHandlers[i].start, m_rareData->m_exceptionHandlers[i].end, m_rareData->m_exceptionHandlers[i].target); + dataLog("\t %d: { start: [%4d] end: [%4d] target: [%4d] }\n", i + 1, m_rareData->m_exceptionHandlers[i].start, m_rareData->m_exceptionHandlers[i].end, m_rareData->m_exceptionHandlers[i].target); ++i; } while (i < m_rareData->m_exceptionHandlers.size()); } if (m_rareData && !m_rareData->m_immediateSwitchJumpTables.isEmpty()) { - printf("Immediate Switch Jump Tables:\n"); + dataLog("Immediate Switch Jump Tables:\n"); unsigned i = 0; do { - printf(" %1d = {\n", i); + dataLog(" %1d = {\n", i); int entry = 0; Vector<int32_t>::const_iterator end = m_rareData->m_immediateSwitchJumpTables[i].branchOffsets.end(); for (Vector<int32_t>::const_iterator iter = m_rareData->m_immediateSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) { if (!*iter) continue; - printf("\t\t%4d => %04d\n", entry + m_rareData->m_immediateSwitchJumpTables[i].min, *iter); + dataLog("\t\t%4d => %04d\n", entry + m_rareData->m_immediateSwitchJumpTables[i].min, *iter); } - printf(" }\n"); + dataLog(" }\n"); ++i; } while (i < m_rareData->m_immediateSwitchJumpTables.size()); } if (m_rareData && !m_rareData->m_characterSwitchJumpTables.isEmpty()) { - printf("\nCharacter Switch Jump Tables:\n"); + dataLog("\nCharacter Switch Jump Tables:\n"); unsigned i = 0; do { - printf(" %1d = {\n", i); + dataLog(" %1d = {\n", i); int entry = 0; Vector<int32_t>::const_iterator end = m_rareData->m_characterSwitchJumpTables[i].branchOffsets.end(); for (Vector<int32_t>::const_iterator iter = m_rareData->m_characterSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) { @@ -470,27 +471,27 @@ void CodeBlock::dump(ExecState* exec) const continue; ASSERT(!((i + m_rareData->m_characterSwitchJumpTables[i].min) & ~0xFFFF)); UChar ch = static_cast<UChar>(entry + m_rareData->m_characterSwitchJumpTables[i].min); - printf("\t\t\"%s\" => %04d\n", UString(&ch, 1).utf8().data(), *iter); + dataLog("\t\t\"%s\" => %04d\n", UString(&ch, 1).utf8().data(), *iter); } - printf(" }\n"); + dataLog(" }\n"); ++i; } while (i < m_rareData->m_characterSwitchJumpTables.size()); } if (m_rareData && !m_rareData->m_stringSwitchJumpTables.isEmpty()) { - printf("\nString Switch Jump Tables:\n"); + dataLog("\nString Switch Jump Tables:\n"); unsigned i = 0; do { - printf(" %1d = {\n", i); + dataLog(" %1d = {\n", i); StringJumpTable::StringOffsetTable::const_iterator end = m_rareData->m_stringSwitchJumpTables[i].offsetTable.end(); for (StringJumpTable::StringOffsetTable::const_iterator iter = m_rareData->m_stringSwitchJumpTables[i].offsetTable.begin(); iter != end; ++iter) - printf("\t\t\"%s\" => %04d\n", UString(iter->first).utf8().data(), iter->second.branchOffset); - printf(" }\n"); + dataLog("\t\t\"%s\" => %04d\n", UString(iter->first).utf8().data(), iter->second.branchOffset); + dataLog(" }\n"); ++i; } while (i < m_rareData->m_stringSwitchJumpTables.size()); } - printf("\n"); + dataLog("\n"); } void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it) const @@ -498,73 +499,73 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int location = it - begin; switch (exec->interpreter()->getOpcodeID(it->u.opcode)) { case op_enter: { - printf("[%4d] enter\n", location); + dataLog("[%4d] enter\n", location); break; } case op_create_activation: { int r0 = (++it)->u.operand; - printf("[%4d] create_activation %s\n", location, registerName(exec, r0).data()); + dataLog("[%4d] create_activation %s\n", location, registerName(exec, r0).data()); break; } case op_create_arguments: { int r0 = (++it)->u.operand; - printf("[%4d] create_arguments\t %s\n", location, registerName(exec, r0).data()); + dataLog("[%4d] create_arguments\t %s\n", location, registerName(exec, r0).data()); break; } case op_init_lazy_reg: { int r0 = (++it)->u.operand; - printf("[%4d] init_lazy_reg\t %s\n", location, registerName(exec, r0).data()); + dataLog("[%4d] init_lazy_reg\t %s\n", location, registerName(exec, r0).data()); break; } case op_get_callee: { int r0 = (++it)->u.operand; - printf("[%4d] op_get_callee %s\n", location, registerName(exec, r0).data()); + dataLog("[%4d] op_get_callee %s\n", location, registerName(exec, r0).data()); break; } case op_create_this: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; - printf("[%4d] create_this %s %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data()); + dataLog("[%4d] create_this %s %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data()); break; } case op_convert_this: { int r0 = (++it)->u.operand; - printf("[%4d] convert_this\t %s\n", location, registerName(exec, r0).data()); + dataLog("[%4d] convert_this\t %s\n", location, registerName(exec, r0).data()); break; } case op_new_object: { int r0 = (++it)->u.operand; - printf("[%4d] new_object\t %s\n", location, registerName(exec, r0).data()); + dataLog("[%4d] new_object\t %s\n", location, registerName(exec, r0).data()); break; } case op_new_array: { int dst = (++it)->u.operand; int argv = (++it)->u.operand; int argc = (++it)->u.operand; - printf("[%4d] new_array\t %s, %s, %d\n", location, registerName(exec, dst).data(), registerName(exec, argv).data(), argc); + dataLog("[%4d] new_array\t %s, %s, %d\n", location, registerName(exec, dst).data(), registerName(exec, argv).data(), argc); break; } case op_new_array_buffer: { int dst = (++it)->u.operand; int argv = (++it)->u.operand; int argc = (++it)->u.operand; - printf("[%4d] new_array_buffer %s, %d, %d\n", location, registerName(exec, dst).data(), argv, argc); + dataLog("[%4d] new_array_buffer %s, %d, %d\n", location, registerName(exec, dst).data(), argv, argc); break; } case op_new_regexp: { int r0 = (++it)->u.operand; int re0 = (++it)->u.operand; - printf("[%4d] new_regexp\t %s, ", location, registerName(exec, r0).data()); + dataLog("[%4d] new_regexp\t %s, ", location, registerName(exec, r0).data()); if (r0 >=0 && r0 < (int)numberOfRegExps()) - printf("%s\n", regexpName(re0, regexp(re0)).data()); + dataLog("%s\n", regexpName(re0, regexp(re0)).data()); else - printf("bad_regexp(%d)\n", re0); + dataLog("bad_regexp(%d)\n", re0); break; } case op_mov: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; - printf("[%4d] mov\t\t %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data()); + dataLog("[%4d] mov\t\t %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data()); break; } case op_not: { @@ -613,12 +614,12 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& } case op_pre_inc: { int r0 = (++it)->u.operand; - printf("[%4d] pre_inc\t\t %s\n", location, registerName(exec, r0).data()); + dataLog("[%4d] pre_inc\t\t %s\n", location, registerName(exec, r0).data()); break; } case op_pre_dec: { int r0 = (++it)->u.operand; - printf("[%4d] pre_dec\t\t %s\n", location, registerName(exec, r0).data()); + dataLog("[%4d] pre_dec\t\t %s\n", location, registerName(exec, r0).data()); break; } case op_post_inc: { @@ -694,7 +695,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& } case op_check_has_instance: { int base = (++it)->u.operand; - printf("[%4d] check_has_instance\t\t %s\n", location, registerName(exec, base).data()); + dataLog("[%4d] check_has_instance\t\t %s\n", location, registerName(exec, base).data()); break; } case op_instanceof: { @@ -702,7 +703,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r1 = (++it)->u.operand; int r2 = (++it)->u.operand; int r3 = (++it)->u.operand; - printf("[%4d] instanceof\t\t %s, %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data(), registerName(exec, r3).data()); + dataLog("[%4d] instanceof\t\t %s, %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data(), registerName(exec, r3).data()); break; } case op_typeof: { @@ -740,7 +741,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& case op_resolve: { 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()); + dataLog("[%4d] resolve\t\t %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data()); it++; break; } @@ -748,14 +749,14 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r0 = (++it)->u.operand; 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); + dataLog("[%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()); + dataLog("[%4d] resolve_global\t %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data()); it += 3; break; } @@ -765,7 +766,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& JSValue scope = JSValue((++it)->u.jsCell.get()); ++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); + dataLog("[%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; } @@ -773,7 +774,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r0 = (++it)->u.operand; 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); + dataLog("[%4d] get_scoped_var\t %s, %d, %d\n", location, registerName(exec, r0).data(), index, skipLevels); it++; break; } @@ -781,41 +782,41 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int index = (++it)->u.operand; int skipLevels = (++it)->u.operand; int r0 = (++it)->u.operand; - printf("[%4d] put_scoped_var\t %d, %d, %s\n", location, index, skipLevels, registerName(exec, r0).data()); + dataLog("[%4d] put_scoped_var\t %d, %d, %s\n", location, index, skipLevels, registerName(exec, r0).data()); break; } case op_get_global_var: { 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); + dataLog("[%4d] get_global_var\t %s, %d\n", location, registerName(exec, r0).data(), index); it++; break; } case op_put_global_var: { int index = (++it)->u.operand; int r0 = (++it)->u.operand; - printf("[%4d] put_global_var\t %d, %s\n", location, index, registerName(exec, r0).data()); + dataLog("[%4d] put_global_var\t %d, %s\n", location, index, registerName(exec, r0).data()); break; } case op_resolve_base: { int r0 = (++it)->u.operand; 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()); + dataLog("[%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: { int r0 = (++it)->u.operand; int id0 = (++it)->u.operand; - printf("[%4d] ensure_property_exists\t %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data()); + dataLog("[%4d] ensure_property_exists\t %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data()); break; } case op_resolve_with_base: { int r0 = (++it)->u.operand; 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()); + dataLog("[%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; } @@ -823,7 +824,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r0 = (++it)->u.operand; 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()); + dataLog("[%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; } @@ -896,6 +897,14 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& printPutByIdOp(exec, location, it, "put_by_id_transition"); break; } + case op_put_by_id_transition_direct: { + printPutByIdOp(exec, location, it, "put_by_id_transition_direct"); + break; + } + case op_put_by_id_transition_normal: { + printPutByIdOp(exec, location, it, "put_by_id_transition_normal"); + break; + } case op_put_by_id_generic: { printPutByIdOp(exec, location, it, "put_by_id_generic"); break; @@ -905,25 +914,25 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int id0 = (++it)->u.operand; int r1 = (++it)->u.operand; int r2 = (++it)->u.operand; - printf("[%4d] put_getter_setter\t %s, %s, %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); + dataLog("[%4d] put_getter_setter\t %s, %s, %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); break; } case op_method_check: { - printf("[%4d] method_check\n", location); + dataLog("[%4d] method_check\n", location); break; } case op_del_by_id: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int id0 = (++it)->u.operand; - printf("[%4d] del_by_id\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data()); + dataLog("[%4d] del_by_id\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data()); break; } case op_get_by_val: { int r0 = (++it)->u.operand; 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()); + dataLog("[%4d] get_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); it++; break; } @@ -931,7 +940,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int r2 = (++it)->u.operand; - printf("[%4d] get_argument_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); + dataLog("[%4d] get_argument_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); ++it; break; } @@ -942,38 +951,38 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r3 = (++it)->u.operand; int r4 = (++it)->u.operand; int r5 = (++it)->u.operand; - printf("[%4d] get_by_pname\t %s, %s, %s, %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data(), registerName(exec, r3).data(), registerName(exec, r4).data(), registerName(exec, r5).data()); + dataLog("[%4d] get_by_pname\t %s, %s, %s, %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data(), registerName(exec, r3).data(), registerName(exec, r4).data(), registerName(exec, r5).data()); break; } case op_put_by_val: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int r2 = (++it)->u.operand; - printf("[%4d] put_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); + dataLog("[%4d] put_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); break; } case op_del_by_val: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int r2 = (++it)->u.operand; - printf("[%4d] del_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); + dataLog("[%4d] del_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); break; } case op_put_by_index: { int r0 = (++it)->u.operand; unsigned n0 = (++it)->u.operand; int r1 = (++it)->u.operand; - printf("[%4d] put_by_index\t %s, %u, %s\n", location, registerName(exec, r0).data(), n0, registerName(exec, r1).data()); + dataLog("[%4d] put_by_index\t %s, %u, %s\n", location, registerName(exec, r0).data(), n0, registerName(exec, r1).data()); break; } case op_jmp: { int offset = (++it)->u.operand; - printf("[%4d] jmp\t\t %d(->%d)\n", location, offset, location + offset); + dataLog("[%4d] jmp\t\t %d(->%d)\n", location, offset, location + offset); break; } case op_loop: { int offset = (++it)->u.operand; - printf("[%4d] loop\t\t %d(->%d)\n", location, offset, location + offset); + dataLog("[%4d] loop\t\t %d(->%d)\n", location, offset, location + offset); break; } case op_jtrue: { @@ -1004,129 +1013,129 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] jneq_ptr\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLog("[%4d] jneq_ptr\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); break; } case op_jless: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] jless\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLog("[%4d] jless\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); break; } case op_jlesseq: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] jlesseq\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLog("[%4d] jlesseq\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); break; } case op_jgreater: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] jgreater\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLog("[%4d] jgreater\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); break; } case op_jgreatereq: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] jgreatereq\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLog("[%4d] jgreatereq\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); break; } case op_jnless: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] jnless\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLog("[%4d] jnless\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); break; } case op_jnlesseq: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] jnlesseq\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLog("[%4d] jnlesseq\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); break; } case op_jngreater: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] jngreater\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLog("[%4d] jngreater\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); break; } case op_jngreatereq: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] jngreatereq\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLog("[%4d] jngreatereq\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); break; } case op_loop_if_less: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] loop_if_less\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLog("[%4d] loop_if_less\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); break; } case op_loop_if_lesseq: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] loop_if_lesseq\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLog("[%4d] loop_if_lesseq\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); break; } case op_loop_if_greater: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] loop_if_greater\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLog("[%4d] loop_if_greater\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); break; } case op_loop_if_greatereq: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] loop_if_greatereq\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLog("[%4d] loop_if_greatereq\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); break; } case op_loop_hint: { - printf("[%4d] loop_hint\n", location); + dataLog("[%4d] loop_hint\n", location); break; } case op_switch_imm: { int tableIndex = (++it)->u.operand; int defaultTarget = (++it)->u.operand; int scrutineeRegister = (++it)->u.operand; - printf("[%4d] switch_imm\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data()); + dataLog("[%4d] switch_imm\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data()); break; } case op_switch_char: { int tableIndex = (++it)->u.operand; int defaultTarget = (++it)->u.operand; int scrutineeRegister = (++it)->u.operand; - printf("[%4d] switch_char\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data()); + dataLog("[%4d] switch_char\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data()); break; } case op_switch_string: { int tableIndex = (++it)->u.operand; int defaultTarget = (++it)->u.operand; int scrutineeRegister = (++it)->u.operand; - printf("[%4d] switch_string\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data()); + dataLog("[%4d] switch_string\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data()); break; } case op_new_func: { int r0 = (++it)->u.operand; int f0 = (++it)->u.operand; int shouldCheck = (++it)->u.operand; - printf("[%4d] new_func\t\t %s, f%d, %s\n", location, registerName(exec, r0).data(), f0, shouldCheck ? "<Checked>" : "<Unchecked>"); + dataLog("[%4d] new_func\t\t %s, f%d, %s\n", location, registerName(exec, r0).data(), f0, shouldCheck ? "<Checked>" : "<Unchecked>"); break; } case op_new_func_exp: { int r0 = (++it)->u.operand; int f0 = (++it)->u.operand; - printf("[%4d] new_func_exp\t %s, f%d\n", location, registerName(exec, r0).data(), f0); + dataLog("[%4d] new_func_exp\t %s, f%d\n", location, registerName(exec, r0).data(), f0); break; } case op_call: { @@ -1142,35 +1151,35 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int thisValue = (++it)->u.operand; int arguments = (++it)->u.operand; int firstFreeRegister = (++it)->u.operand; - printf("[%4d] call_varargs\t %s, %s, %s, %d\n", location, registerName(exec, callee).data(), registerName(exec, thisValue).data(), registerName(exec, arguments).data(), firstFreeRegister); + dataLog("[%4d] call_varargs\t %s, %s, %s, %d\n", location, registerName(exec, callee).data(), registerName(exec, thisValue).data(), registerName(exec, arguments).data(), firstFreeRegister); break; } case op_tear_off_activation: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; - printf("[%4d] tear_off_activation\t %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data()); + dataLog("[%4d] tear_off_activation\t %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data()); break; } case op_tear_off_arguments: { int r0 = (++it)->u.operand; - printf("[%4d] tear_off_arguments %s\n", location, registerName(exec, r0).data()); + dataLog("[%4d] tear_off_arguments %s\n", location, registerName(exec, r0).data()); break; } case op_ret: { int r0 = (++it)->u.operand; - printf("[%4d] ret\t\t %s\n", location, registerName(exec, r0).data()); + dataLog("[%4d] ret\t\t %s\n", location, registerName(exec, r0).data()); break; } 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()); + dataLog("[%4d] op_call_put_result\t\t %s\n", location, registerName(exec, r0).data()); it++; break; } case op_ret_object_or_this: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; - printf("[%4d] constructor_ret\t\t %s %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data()); + dataLog("[%4d] constructor_ret\t\t %s %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data()); break; } case op_construct: { @@ -1181,13 +1190,13 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int count = (++it)->u.operand; - printf("[%4d] strcat\t\t %s, %s, %d\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), count); + dataLog("[%4d] strcat\t\t %s, %s, %d\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), count); break; } case op_to_primitive: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; - printf("[%4d] to_primitive\t %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data()); + dataLog("[%4d] to_primitive\t %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data()); break; } case op_get_pnames: { @@ -1196,7 +1205,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r2 = it[3].u.operand; int r3 = it[4].u.operand; int offset = it[5].u.operand; - printf("[%4d] get_pnames\t %s, %s, %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data(), registerName(exec, r3).data(), offset, location + offset); + dataLog("[%4d] get_pnames\t %s, %s, %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data(), registerName(exec, r3).data(), offset, location + offset); it += OPCODE_LENGTH(op_get_pnames) - 1; break; } @@ -1207,78 +1216,78 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int size = it[4].u.operand; int iter = it[5].u.operand; int offset = it[6].u.operand; - printf("[%4d] next_pname\t %s, %s, %s, %s, %s, %d(->%d)\n", location, registerName(exec, dest).data(), registerName(exec, base).data(), registerName(exec, i).data(), registerName(exec, size).data(), registerName(exec, iter).data(), offset, location + offset); + dataLog("[%4d] next_pname\t %s, %s, %s, %s, %s, %d(->%d)\n", location, registerName(exec, dest).data(), registerName(exec, base).data(), registerName(exec, i).data(), registerName(exec, size).data(), registerName(exec, iter).data(), offset, location + offset); it += OPCODE_LENGTH(op_next_pname) - 1; break; } case op_push_scope: { int r0 = (++it)->u.operand; - printf("[%4d] push_scope\t %s\n", location, registerName(exec, r0).data()); + dataLog("[%4d] push_scope\t %s\n", location, registerName(exec, r0).data()); break; } case op_pop_scope: { - printf("[%4d] pop_scope\n", location); + dataLog("[%4d] pop_scope\n", location); break; } case op_push_new_scope: { int r0 = (++it)->u.operand; int id0 = (++it)->u.operand; int r1 = (++it)->u.operand; - printf("[%4d] push_new_scope \t%s, %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data()); + dataLog("[%4d] push_new_scope \t%s, %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data()); break; } case op_jmp_scopes: { int scopeDelta = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] jmp_scopes\t^%d, %d(->%d)\n", location, scopeDelta, offset, location + offset); + dataLog("[%4d] jmp_scopes\t^%d, %d(->%d)\n", location, scopeDelta, offset, location + offset); break; } case op_catch: { int r0 = (++it)->u.operand; - printf("[%4d] catch\t\t %s\n", location, registerName(exec, r0).data()); + dataLog("[%4d] catch\t\t %s\n", location, registerName(exec, r0).data()); break; } case op_throw: { int r0 = (++it)->u.operand; - printf("[%4d] throw\t\t %s\n", location, registerName(exec, r0).data()); + dataLog("[%4d] throw\t\t %s\n", location, registerName(exec, r0).data()); break; } case op_throw_reference_error: { int k0 = (++it)->u.operand; - printf("[%4d] throw_reference_error\t %s\n", location, constantName(exec, k0, getConstant(k0)).data()); + dataLog("[%4d] throw_reference_error\t %s\n", location, constantName(exec, k0, getConstant(k0)).data()); break; } case op_jsr: { int retAddrDst = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] jsr\t\t %s, %d(->%d)\n", location, registerName(exec, retAddrDst).data(), offset, location + offset); + dataLog("[%4d] jsr\t\t %s, %d(->%d)\n", location, registerName(exec, retAddrDst).data(), offset, location + offset); break; } case op_sret: { int retAddrSrc = (++it)->u.operand; - printf("[%4d] sret\t\t %s\n", location, registerName(exec, retAddrSrc).data()); + dataLog("[%4d] sret\t\t %s\n", location, registerName(exec, retAddrSrc).data()); break; } case op_debug: { int debugHookID = (++it)->u.operand; int firstLine = (++it)->u.operand; int lastLine = (++it)->u.operand; - printf("[%4d] debug\t\t %s, %d, %d\n", location, debugHookName(debugHookID), firstLine, lastLine); + dataLog("[%4d] debug\t\t %s, %d, %d\n", location, debugHookName(debugHookID), firstLine, lastLine); break; } case op_profile_will_call: { int function = (++it)->u.operand; - printf("[%4d] profile_will_call %s\n", location, registerName(exec, function).data()); + dataLog("[%4d] profile_will_call %s\n", location, registerName(exec, function).data()); break; } case op_profile_did_call: { int function = (++it)->u.operand; - printf("[%4d] profile_did_call\t %s\n", location, registerName(exec, function).data()); + dataLog("[%4d] profile_did_call\t %s\n", location, registerName(exec, function).data()); break; } case op_end: { int r0 = (++it)->u.operand; - printf("[%4d] end\t\t %s\n", location, registerName(exec, r0).data()); + dataLog("[%4d] end\t\t %s\n", location, registerName(exec, r0).data()); break; } } @@ -1382,29 +1391,29 @@ void CodeBlock::dumpStatistics() totalSize += symbolTableTotalSize; totalSize += (liveCodeBlockSet.size() * sizeof(CodeBlock)); - printf("Number of live CodeBlocks: %d\n", liveCodeBlockSet.size()); - printf("Size of a single CodeBlock [sizeof(CodeBlock)]: %zu\n", sizeof(CodeBlock)); - printf("Size of all CodeBlocks: %zu\n", totalSize); - printf("Average size of a CodeBlock: %zu\n", totalSize / liveCodeBlockSet.size()); + dataLog("Number of live CodeBlocks: %d\n", liveCodeBlockSet.size()); + dataLog("Size of a single CodeBlock [sizeof(CodeBlock)]: %zu\n", sizeof(CodeBlock)); + dataLog("Size of all CodeBlocks: %zu\n", totalSize); + dataLog("Average size of a CodeBlock: %zu\n", totalSize / liveCodeBlockSet.size()); - printf("Number of FunctionCode CodeBlocks: %zu (%.3f%%)\n", isFunctionCode, static_cast<double>(isFunctionCode) * 100.0 / liveCodeBlockSet.size()); - printf("Number of GlobalCode CodeBlocks: %zu (%.3f%%)\n", isGlobalCode, static_cast<double>(isGlobalCode) * 100.0 / liveCodeBlockSet.size()); - printf("Number of EvalCode CodeBlocks: %zu (%.3f%%)\n", isEvalCode, static_cast<double>(isEvalCode) * 100.0 / liveCodeBlockSet.size()); + dataLog("Number of FunctionCode CodeBlocks: %zu (%.3f%%)\n", isFunctionCode, static_cast<double>(isFunctionCode) * 100.0 / liveCodeBlockSet.size()); + dataLog("Number of GlobalCode CodeBlocks: %zu (%.3f%%)\n", isGlobalCode, static_cast<double>(isGlobalCode) * 100.0 / liveCodeBlockSet.size()); + dataLog("Number of EvalCode CodeBlocks: %zu (%.3f%%)\n", isEvalCode, static_cast<double>(isEvalCode) * 100.0 / liveCodeBlockSet.size()); - printf("Number of CodeBlocks with rare data: %zu (%.3f%%)\n", hasRareData, static_cast<double>(hasRareData) * 100.0 / liveCodeBlockSet.size()); + dataLog("Number of CodeBlocks with rare data: %zu (%.3f%%)\n", hasRareData, static_cast<double>(hasRareData) * 100.0 / liveCodeBlockSet.size()); - #define PRINT_STATS(name) printf("Number of CodeBlocks with " #name ": %zu\n", name##IsNotEmpty); printf("Size of all " #name ": %zu\n", name##TotalSize); + #define PRINT_STATS(name) dataLog("Number of CodeBlocks with " #name ": %zu\n", name##IsNotEmpty); dataLog("Size of all " #name ": %zu\n", name##TotalSize); FOR_EACH_MEMBER_VECTOR(PRINT_STATS) FOR_EACH_MEMBER_VECTOR_RARE_DATA(PRINT_STATS) #undef PRINT_STATS - printf("Number of CodeBlocks with evalCodeCache: %zu\n", evalCodeCacheIsNotEmpty); - printf("Number of CodeBlocks with symbolTable: %zu\n", symbolTableIsNotEmpty); + dataLog("Number of CodeBlocks with evalCodeCache: %zu\n", evalCodeCacheIsNotEmpty); + dataLog("Number of CodeBlocks with symbolTable: %zu\n", symbolTableIsNotEmpty); - printf("Size of all symbolTables: %zu\n", symbolTableTotalSize); + dataLog("Size of all symbolTables: %zu\n", symbolTableTotalSize); #else - printf("Dumping CodeBlock statistics is not enabled.\n"); + dataLog("Dumping CodeBlock statistics is not enabled.\n"); #endif } @@ -1453,6 +1462,7 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other, SymbolTable* symTab) { setNumParameters(other.numParameters()); optimizeAfterWarmUp(); + jitAfterWarmUp(); if (other.m_rareData) { createRareDataIfNecessary(); @@ -1501,6 +1511,7 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, JSGlo ASSERT(m_source); optimizeAfterWarmUp(); + jitAfterWarmUp(); #if DUMP_CODE_BLOCK_STATISTICS liveCodeBlockSet.add(this); @@ -1518,7 +1529,11 @@ CodeBlock::~CodeBlock() #if ENABLE(VERBOSE_VALUE_PROFILE) dumpValueProfiles(); #endif - + +#if ENABLE(LLINT) + while (m_incomingLLIntCalls.begin() != m_incomingLLIntCalls.end()) + m_incomingLLIntCalls.begin()->remove(); +#endif // ENABLE(LLINT) #if ENABLE(JIT) // We may be destroyed before any CodeBlocks that refer to us are destroyed. // Consider that two CodeBlocks become unreachable at the same time. There @@ -1730,13 +1745,74 @@ void CodeBlock::finalizeUnconditionally() #else static const bool verboseUnlinking = false; #endif -#endif +#endif // ENABLE(JIT) +#if ENABLE(LLINT) + Interpreter* interpreter = m_globalData->interpreter; + // interpreter->classicEnabled() returns true if the old C++ interpreter is enabled. If that's enabled + // then we're not using LLInt. + if (!interpreter->classicEnabled()) { + for (size_t size = m_propertyAccessInstructions.size(), i = 0; i < size; ++i) { + Instruction* curInstruction = &instructions()[m_propertyAccessInstructions[i]]; + switch (interpreter->getOpcodeID(curInstruction[0].u.opcode)) { + case op_get_by_id: + case op_put_by_id: + if (!curInstruction[4].u.structure || Heap::isMarked(curInstruction[4].u.structure.get())) + break; + if (verboseUnlinking) + dataLog("Clearing LLInt property access with structure %p.\n", curInstruction[4].u.structure.get()); + curInstruction[4].u.structure.clear(); + curInstruction[5].u.operand = 0; + break; + case op_put_by_id_transition_direct: + case op_put_by_id_transition_normal: + if (Heap::isMarked(curInstruction[4].u.structure.get()) + && Heap::isMarked(curInstruction[6].u.structure.get()) + && Heap::isMarked(curInstruction[7].u.structureChain.get())) + break; + if (verboseUnlinking) { + dataLog("Clearing LLInt put transition with structures %p -> %p, chain %p.\n", + curInstruction[4].u.structure.get(), + curInstruction[6].u.structure.get(), + curInstruction[7].u.structureChain.get()); + } + curInstruction[4].u.structure.clear(); + curInstruction[6].u.structure.clear(); + curInstruction[7].u.structureChain.clear(); + curInstruction[0].u.opcode = interpreter->getOpcode(op_put_by_id); + break; + default: + ASSERT_NOT_REACHED(); + } + } + for (size_t size = m_globalResolveInstructions.size(), i = 0; i < size; ++i) { + Instruction* curInstruction = &instructions()[m_globalResolveInstructions[i]]; + ASSERT(interpreter->getOpcodeID(curInstruction[0].u.opcode) == op_resolve_global + || interpreter->getOpcodeID(curInstruction[0].u.opcode) == op_resolve_global_dynamic); + if (!curInstruction[3].u.structure || Heap::isMarked(curInstruction[3].u.structure.get())) + continue; + if (verboseUnlinking) + dataLog("Clearing LLInt global resolve cache with structure %p.\n", curInstruction[3].u.structure.get()); + curInstruction[3].u.structure.clear(); + curInstruction[4].u.operand = 0; + } + for (unsigned i = 0; i < m_llintCallLinkInfos.size(); ++i) { + if (m_llintCallLinkInfos[i].isLinked() && !Heap::isMarked(m_llintCallLinkInfos[i].callee.get())) { + if (verboseUnlinking) + dataLog("Clearing LLInt call from %p.\n", this); + m_llintCallLinkInfos[i].unlink(); + } + if (!!m_llintCallLinkInfos[i].lastSeenCallee && !Heap::isMarked(m_llintCallLinkInfos[i].lastSeenCallee.get())) + m_llintCallLinkInfos[i].lastSeenCallee.clear(); + } + } +#endif // ENABLE(LLINT) + #if ENABLE(DFG_JIT) // Check if we're not live. If we are, then jettison. if (!(shouldImmediatelyAssumeLivenessDuringScan() || m_dfgData->livenessHasBeenProved)) { if (verboseUnlinking) - printf("Code block %p has dead weak references, jettisoning during GC.\n", this); + dataLog("Code block %p has dead weak references, jettisoning during GC.\n", this); // Make sure that the baseline JIT knows that it should re-warm-up before // optimizing. @@ -1754,7 +1830,7 @@ void CodeBlock::finalizeUnconditionally() for (unsigned i = 0; i < numberOfCallLinkInfos(); ++i) { if (callLinkInfo(i).isLinked() && !Heap::isMarked(callLinkInfo(i).callee.get())) { if (verboseUnlinking) - printf("Clearing call from %p.\n", this); + dataLog("Clearing call from %p to %p.\n", this, callLinkInfo(i).callee.get()); callLinkInfo(i).unlink(*m_globalData, repatchBuffer); } if (!!callLinkInfo(i).lastSeenCallee @@ -1764,7 +1840,7 @@ void CodeBlock::finalizeUnconditionally() for (size_t size = m_globalResolveInfos.size(), i = 0; i < size; ++i) { if (m_globalResolveInfos[i].structure && !Heap::isMarked(m_globalResolveInfos[i].structure.get())) { if (verboseUnlinking) - printf("Clearing resolve info in %p.\n", this); + dataLog("Clearing resolve info in %p.\n", this); m_globalResolveInfos[i].structure.clear(); } } @@ -1778,7 +1854,7 @@ void CodeBlock::finalizeUnconditionally() continue; if (verboseUnlinking) - printf("Clearing structure cache (kind %d) in %p.\n", stubInfo.accessType, this); + dataLog("Clearing structure cache (kind %d) in %p.\n", stubInfo.accessType, this); if (isGetByIdAccess(accessType)) { if (getJITCode().jitType() == JITCode::DFGJIT) @@ -1808,7 +1884,7 @@ void CodeBlock::finalizeUnconditionally() || !Heap::isMarked(m_methodCallLinkInfos[i].cachedFunction.get()) || !Heap::isMarked(m_methodCallLinkInfos[i].cachedPrototype.get())) { if (verboseUnlinking) - printf("Clearing method call in %p.\n", this); + dataLog("Clearing method call in %p.\n", this); m_methodCallLinkInfos[i].reset(repatchBuffer, getJITType()); StructureStubInfo& stubInfo = getStubInfo(m_methodCallLinkInfos[i].bytecodeIndex); @@ -1851,11 +1927,13 @@ void CodeBlock::stronglyVisitStrongReferences(SlotVisitor& visitor) visitor.append(&m_functionExprs[i]); for (size_t i = 0; i < m_functionDecls.size(); ++i) visitor.append(&m_functionDecls[i]); -#if ENABLE(INTERPRETER) - for (size_t size = m_propertyAccessInstructions.size(), i = 0; i < size; ++i) - visitStructures(visitor, &instructions()[m_propertyAccessInstructions[i]]); - for (size_t size = m_globalResolveInstructions.size(), i = 0; i < size; ++i) - visitStructures(visitor, &instructions()[m_globalResolveInstructions[i]]); +#if ENABLE(CLASSIC_INTERPRETER) + if (m_globalData->interpreter->classicEnabled()) { + for (size_t size = m_propertyAccessInstructions.size(), i = 0; i < size; ++i) + visitStructures(visitor, &instructions()[m_propertyAccessInstructions[i]]); + for (size_t size = m_globalResolveInstructions.size(), i = 0; i < size; ++i) + visitStructures(visitor, &instructions()[m_globalResolveInstructions[i]]); + } #endif #if ENABLE(DFG_JIT) @@ -1863,10 +1941,13 @@ void CodeBlock::stronglyVisitStrongReferences(SlotVisitor& visitor) // Make sure that executables that we have inlined don't die. // FIXME: If they would have otherwise died, we should probably trigger recompilation. for (size_t i = 0; i < inlineCallFrames().size(); ++i) { - visitor.append(&inlineCallFrames()[i].executable); - visitor.append(&inlineCallFrames()[i].callee); + InlineCallFrame& inlineCallFrame = inlineCallFrames()[i]; + visitor.append(&inlineCallFrame.executable); + visitor.append(&inlineCallFrame.callee); } } + + m_lazyOperandValueProfiles.computeUpdatedPredictions(); #endif #if ENABLE(VALUE_PROFILER) @@ -1976,7 +2057,7 @@ void CodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& d return; } -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) bool CodeBlock::hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset) { if (m_globalResolveInstructions.isEmpty()) @@ -2023,7 +2104,7 @@ void CodeBlock::shrinkToFit() { instructions().shrinkToFit(); -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) m_propertyAccessInstructions.shrinkToFit(); m_globalResolveInstructions.shrinkToFit(); #endif @@ -2068,12 +2149,18 @@ unsigned CodeBlock::addOrFindConstant(JSValue v) } return addConstant(v); } - + #if ENABLE(JIT) void CodeBlock::unlinkCalls() { if (!!m_alternative) m_alternative->unlinkCalls(); +#if ENABLE(LLINT) + for (size_t i = 0; i < m_llintCallLinkInfos.size(); ++i) { + if (m_llintCallLinkInfos[i].isLinked()) + m_llintCallLinkInfos[i].unlink(); + } +#endif if (!(m_callLinkInfos.size() || m_methodCallLinkInfos.size())) return; if (!m_globalData->canUseJIT()) @@ -2088,10 +2175,62 @@ void CodeBlock::unlinkCalls() void CodeBlock::unlinkIncomingCalls() { +#if ENABLE(LLINT) + while (m_incomingLLIntCalls.begin() != m_incomingLLIntCalls.end()) + m_incomingLLIntCalls.begin()->unlink(); +#endif + if (m_incomingCalls.isEmpty()) + return; RepatchBuffer repatchBuffer(this); while (m_incomingCalls.begin() != m_incomingCalls.end()) m_incomingCalls.begin()->unlink(*m_globalData, repatchBuffer); } + +unsigned CodeBlock::bytecodeOffset(ExecState* exec, ReturnAddressPtr returnAddress) +{ +#if ENABLE(LLINT) + if (returnAddress.value() >= bitwise_cast<void*>(&llint_begin) + && returnAddress.value() <= bitwise_cast<void*>(&llint_end)) { + ASSERT(exec->codeBlock()); + ASSERT(exec->codeBlock() == this); + ASSERT(JITCode::isBaselineCode(getJITType())); + Instruction* instruction = exec->currentVPC(); + ASSERT(instruction); + + // The LLInt stores the PC after the call instruction rather than the PC of + // the call instruction. This requires some correcting. We rely on the fact + // that the preceding instruction must be one of the call instructions, so + // either it's a call_varargs or it's a call, construct, or eval. + ASSERT(OPCODE_LENGTH(op_call_varargs) <= OPCODE_LENGTH(op_call)); + ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct)); + ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval)); + if (instruction[-OPCODE_LENGTH(op_call_varargs)].u.pointer == bitwise_cast<void*>(llint_op_call_varargs)) { + // We know that the preceding instruction must be op_call_varargs because there is no way that + // the pointer to the call_varargs could be an operand to the call. + instruction -= OPCODE_LENGTH(op_call_varargs); + ASSERT(instruction[-OPCODE_LENGTH(op_call)].u.pointer != bitwise_cast<void*>(llint_op_call) + && instruction[-OPCODE_LENGTH(op_call)].u.pointer != bitwise_cast<void*>(llint_op_construct) + && instruction[-OPCODE_LENGTH(op_call)].u.pointer != bitwise_cast<void*>(llint_op_call_eval)); + } else { + // Must be that the last instruction was some op_call. + ASSERT(instruction[-OPCODE_LENGTH(op_call)].u.pointer == bitwise_cast<void*>(llint_op_call) + || instruction[-OPCODE_LENGTH(op_call)].u.pointer == bitwise_cast<void*>(llint_op_construct) + || instruction[-OPCODE_LENGTH(op_call)].u.pointer == bitwise_cast<void*>(llint_op_call_eval)); + instruction -= OPCODE_LENGTH(op_call); + } + + return bytecodeOffset(instruction); + } +#else + UNUSED_PARAM(exec); +#endif + if (!m_rareData) + return 1; + Vector<CallReturnOffsetToBytecodeOffset>& callIndices = m_rareData->m_callReturnIndexVector; + if (!callIndices.size()) + return 1; + return binarySearch<CallReturnOffsetToBytecodeOffset, unsigned, getCallReturnOffset>(callIndices.begin(), callIndices.size(), getJITCode().offsetOf(returnAddress.value()))->bytecodeOffset; +} #endif void CodeBlock::clearEvalCache() @@ -2187,31 +2326,52 @@ bool FunctionCodeBlock::canCompileWithDFGInternal() void ProgramCodeBlock::jettison() { - ASSERT(getJITType() != JITCode::BaselineJIT); + ASSERT(JITCode::isOptimizingJIT(getJITType())); ASSERT(this == replacement()); static_cast<ProgramExecutable*>(ownerExecutable())->jettisonOptimizedCode(*globalData()); } void EvalCodeBlock::jettison() { - ASSERT(getJITType() != JITCode::BaselineJIT); + ASSERT(JITCode::isOptimizingJIT(getJITType())); ASSERT(this == replacement()); static_cast<EvalExecutable*>(ownerExecutable())->jettisonOptimizedCode(*globalData()); } void FunctionCodeBlock::jettison() { - ASSERT(getJITType() != JITCode::BaselineJIT); + ASSERT(JITCode::isOptimizingJIT(getJITType())); ASSERT(this == replacement()); static_cast<FunctionExecutable*>(ownerExecutable())->jettisonOptimizedCodeFor(*globalData(), m_isConstructor ? CodeForConstruct : CodeForCall); } + +void ProgramCodeBlock::jitCompileImpl(JSGlobalData& globalData) +{ + ASSERT(getJITType() == JITCode::InterpreterThunk); + ASSERT(this == replacement()); + return static_cast<ProgramExecutable*>(ownerExecutable())->jitCompile(globalData); +} + +void EvalCodeBlock::jitCompileImpl(JSGlobalData& globalData) +{ + ASSERT(getJITType() == JITCode::InterpreterThunk); + ASSERT(this == replacement()); + return static_cast<EvalExecutable*>(ownerExecutable())->jitCompile(globalData); +} + +void FunctionCodeBlock::jitCompileImpl(JSGlobalData& globalData) +{ + ASSERT(getJITType() == JITCode::InterpreterThunk); + ASSERT(this == replacement()); + return static_cast<FunctionExecutable*>(ownerExecutable())->jitCompileFor(globalData, m_isConstructor ? CodeForConstruct : CodeForCall); +} #endif #if ENABLE(VALUE_PROFILER) bool CodeBlock::shouldOptimizeNow() { #if ENABLE(JIT_VERBOSE_OSR) - printf("Considering optimizing %p...\n", this); + dataLog("Considering optimizing %p...\n", this); #endif #if ENABLE(VERBOSE_VALUE_PROFILE) @@ -2239,7 +2399,7 @@ bool CodeBlock::shouldOptimizeNow() } #if ENABLE(JIT_VERBOSE_OSR) - printf("Profile hotness: %lf, %lf\n", (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles(), (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / numberOfValueProfiles()); + dataLog("Profile hotness: %lf, %lf\n", (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles(), (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / numberOfValueProfiles()); #endif if ((!numberOfValueProfiles() || (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles() >= Options::desiredProfileLivenessRate) @@ -2270,7 +2430,7 @@ void CodeBlock::tallyFrequentExitSites() continue; #if DFG_ENABLE(DEBUG_VERBOSE) - fprintf(stderr, "OSR exit #%u (bc#%u, @%u, %s) for code block %p occurred frequently; counting as frequent exit site.\n", i, exit.m_codeOrigin.bytecodeIndex, exit.m_nodeIndex, DFG::exitKindToString(exit.m_kind), this); + dataLog("OSR exit #%u (bc#%u, @%u, %s) for code block %p occurred frequently; counting as frequent exit site.\n", i, exit.m_codeOrigin.bytecodeIndex, exit.m_nodeIndex, DFG::exitKindToString(exit.m_kind), this); #endif } } @@ -2279,30 +2439,30 @@ void CodeBlock::tallyFrequentExitSites() #if ENABLE(VERBOSE_VALUE_PROFILE) void CodeBlock::dumpValueProfiles() { - fprintf(stderr, "ValueProfile for %p:\n", this); + dataLog("ValueProfile for %p:\n", this); for (unsigned i = 0; i < totalNumberOfValueProfiles(); ++i) { ValueProfile* profile = getFromAllValueProfiles(i); if (profile->m_bytecodeOffset < 0) { ASSERT(profile->m_bytecodeOffset == -1); - fprintf(stderr, " arg = %u: ", i); + dataLog(" arg = %u: ", i); } else - fprintf(stderr, " bc = %d: ", profile->m_bytecodeOffset); + dataLog(" bc = %d: ", profile->m_bytecodeOffset); if (!profile->numberOfSamples() && profile->m_prediction == PredictNone) { - fprintf(stderr, "<empty>\n"); + dataLog("<empty>\n"); continue; } - profile->dump(stderr); - fprintf(stderr, "\n"); + profile->dump(WTF::dataFile()); + dataLog("\n"); } - fprintf(stderr, "RareCaseProfile for %p:\n", this); + dataLog("RareCaseProfile for %p:\n", this); for (unsigned i = 0; i < numberOfRareCaseProfiles(); ++i) { RareCaseProfile* profile = rareCaseProfile(i); - fprintf(stderr, " bc = %d: %u\n", profile->m_bytecodeOffset, profile->m_counter); + dataLog(" bc = %d: %u\n", profile->m_bytecodeOffset, profile->m_counter); } - fprintf(stderr, "SpecialFastCaseProfile for %p:\n", this); + dataLog("SpecialFastCaseProfile for %p:\n", this); for (unsigned i = 0; i < numberOfSpecialFastCaseProfiles(); ++i) { RareCaseProfile* profile = specialFastCaseProfile(i); - fprintf(stderr, " bc = %d: %u\n", profile->m_bytecodeOffset, profile->m_counter); + dataLog(" bc = %d: %u\n", profile->m_bytecodeOffset, profile->m_counter); } } #endif diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h index bc2feeb2a..195aa62ca 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.h +++ b/Source/JavaScriptCore/bytecode/CodeBlock.h @@ -30,6 +30,7 @@ #ifndef CodeBlock_h #define CodeBlock_h +#include "BytecodeConventions.h" #include "CallLinkInfo.h" #include "CallReturnOffsetToBytecodeOffset.h" #include "CodeOrigin.h" @@ -50,6 +51,8 @@ #include "JITWriteBarrier.h" #include "JSGlobalObject.h" #include "JumpTable.h" +#include "LLIntCallLinkInfo.h" +#include "LazyOperandValueProfile.h" #include "LineInfo.h" #include "Nodes.h" #include "PredictionTracker.h" @@ -65,16 +68,11 @@ #include <wtf/Vector.h> #include "StructureStubInfo.h" -// Register numbers used in bytecode operations have different meaning according to their ranges: -// 0x80000000-0xFFFFFFFF Negative indices from the CallFrame pointer are entries in the call frame, see RegisterFile.h. -// 0x00000000-0x3FFFFFFF Forwards indices from the CallFrame pointer are local vars and temporaries with the function's callframe. -// 0x40000000-0x7FFFFFFF Positive indices from 0x40000000 specify entries in the constant pool on the CodeBlock. -static const int FirstConstantRegisterIndex = 0x40000000; - namespace JSC { - class ExecState; class DFGCodeBlocks; + class ExecState; + class LLIntOffsetsExtractor; inline int unmodifiedArgumentsRegister(int argumentsRegister) { return argumentsRegister - 1; } @@ -83,6 +81,7 @@ namespace JSC { class CodeBlock : public UnconditionalFinalizer, public WeakReferenceHarvester { WTF_MAKE_FAST_ALLOCATED; friend class JIT; + friend class LLIntOffsetsExtractor; public: enum CopyParsedBlockTag { CopyParsedBlock }; protected: @@ -123,7 +122,7 @@ namespace JSC { while (result->alternative()) result = result->alternative(); ASSERT(result); - ASSERT(result->getJITType() == JITCode::BaselineJIT); + ASSERT(JITCode::isBaselineCode(result->getJITType())); return result; } #endif @@ -192,15 +191,7 @@ namespace JSC { return *(binarySearch<MethodCallLinkInfo, unsigned, getMethodCallLinkInfoBytecodeIndex>(m_methodCallLinkInfos.begin(), m_methodCallLinkInfos.size(), bytecodeIndex)); } - unsigned bytecodeOffset(ReturnAddressPtr returnAddress) - { - if (!m_rareData) - return 1; - Vector<CallReturnOffsetToBytecodeOffset>& callIndices = m_rareData->m_callReturnIndexVector; - if (!callIndices.size()) - return 1; - return binarySearch<CallReturnOffsetToBytecodeOffset, unsigned, getCallReturnOffset>(callIndices.begin(), callIndices.size(), getJITCode().offsetOf(returnAddress.value()))->bytecodeOffset; - } + unsigned bytecodeOffset(ExecState*, ReturnAddressPtr); unsigned bytecodeOffsetForCallAtIndex(unsigned index) { @@ -221,11 +212,17 @@ namespace JSC { { m_incomingCalls.push(incoming); } +#if ENABLE(LLINT) + void linkIncomingCall(LLIntCallLinkInfo* incoming) + { + m_incomingLLIntCalls.push(incoming); + } +#endif // ENABLE(LLINT) void unlinkIncomingCalls(); -#endif +#endif // ENABLE(JIT) -#if ENABLE(DFG_JIT) +#if ENABLE(DFG_JIT) || ENABLE(LLINT) void setJITCodeMap(PassOwnPtr<CompactJITCodeMap> jitCodeMap) { m_jitCodeMap = jitCodeMap; @@ -234,7 +231,9 @@ namespace JSC { { return m_jitCodeMap.get(); } +#endif +#if ENABLE(DFG_JIT) void createDFGDataIfNecessary() { if (!!m_dfgData) @@ -333,12 +332,11 @@ namespace JSC { } #endif -#if ENABLE(INTERPRETER) unsigned bytecodeOffset(Instruction* returnAddress) { + ASSERT(returnAddress >= instructions().begin() && returnAddress < instructions().end()); return static_cast<Instruction*>(returnAddress) - instructions().begin(); } -#endif void setIsNumericCompareFunction(bool isNumericCompareFunction) { m_isNumericCompareFunction = isNumericCompareFunction; } bool isNumericCompareFunction() { return m_isNumericCompareFunction; } @@ -376,6 +374,20 @@ namespace JSC { ExecutableMemoryHandle* executableMemory() { return getJITCode().getExecutableMemory(); } virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*) = 0; virtual void jettison() = 0; + bool jitCompile(JSGlobalData& globalData) + { + if (getJITType() != JITCode::InterpreterThunk) { + ASSERT(getJITType() == JITCode::BaselineJIT); + return false; + } +#if ENABLE(JIT) + jitCompileImpl(globalData); + return true; +#else + UNUSED_PARAM(globalData); + return false; +#endif + } virtual CodeBlock* replacement() = 0; enum CompileWithDFGState { @@ -395,13 +407,13 @@ namespace JSC { bool hasOptimizedReplacement() { - ASSERT(getJITType() == JITCode::BaselineJIT); + ASSERT(JITCode::isBaselineCode(getJITType())); bool result = replacement()->getJITType() > getJITType(); #if !ASSERT_DISABLED if (result) ASSERT(replacement()->getJITType() == JITCode::DFGJIT); else { - ASSERT(replacement()->getJITType() == JITCode::BaselineJIT); + ASSERT(JITCode::isBaselineCode(replacement()->getJITType())); ASSERT(replacement() == this); } #endif @@ -460,18 +472,21 @@ namespace JSC { void clearEvalCache(); -#if ENABLE(INTERPRETER) void addPropertyAccessInstruction(unsigned propertyAccessInstruction) { - if (!m_globalData->canUseJIT()) - m_propertyAccessInstructions.append(propertyAccessInstruction); + m_propertyAccessInstructions.append(propertyAccessInstruction); } void addGlobalResolveInstruction(unsigned globalResolveInstruction) { - if (!m_globalData->canUseJIT()) - m_globalResolveInstructions.append(globalResolveInstruction); + m_globalResolveInstructions.append(globalResolveInstruction); } bool hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset); +#if ENABLE(LLINT) + LLIntCallLinkInfo* addLLIntCallLinkInfo() + { + m_llintCallLinkInfos.append(LLIntCallLinkInfo()); + return &m_llintCallLinkInfos.last(); + } #endif #if ENABLE(JIT) void setNumberOfStructureStubInfos(size_t size) { m_structureStubInfos.grow(size); } @@ -480,8 +495,7 @@ namespace JSC { void addGlobalResolveInfo(unsigned globalResolveInstruction) { - if (m_globalData->canUseJIT()) - m_globalResolveInfos.append(GlobalResolveInfo(globalResolveInstruction)); + m_globalResolveInfos.append(GlobalResolveInfo(globalResolveInstruction)); } GlobalResolveInfo& globalResolveInfo(int index) { return m_globalResolveInfos[index]; } bool hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset); @@ -492,6 +506,7 @@ namespace JSC { void addMethodCallLinkInfos(unsigned n) { ASSERT(m_globalData->canUseJIT()); m_methodCallLinkInfos.grow(n); } MethodCallLinkInfo& methodCallLinkInfo(int index) { return m_methodCallLinkInfos[index]; } + size_t numberOfMethodCallLinkInfos() { return m_methodCallLinkInfos.size(); } #endif #if ENABLE(VALUE_PROFILER) @@ -533,6 +548,10 @@ namespace JSC { bytecodeOffset].u.opcode)) - 1].u.profile == result); return result; } + PredictedType valueProfilePredictionForBytecodeOffset(int bytecodeOffset) + { + return valueProfileForBytecodeOffset(bytecodeOffset)->computeUpdatedPrediction(); + } unsigned totalNumberOfValueProfiles() { @@ -559,12 +578,16 @@ namespace JSC { bool likelyToTakeSlowCase(int bytecodeOffset) { + if (!numberOfRareCaseProfiles()) + return false; unsigned value = rareCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter; return value >= Options::likelyToTakeSlowCaseMinimumCount && static_cast<double>(value) / m_executionEntryCount >= Options::likelyToTakeSlowCaseThreshold; } bool couldTakeSlowCase(int bytecodeOffset) { + if (!numberOfRareCaseProfiles()) + return false; unsigned value = rareCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter; return value >= Options::couldTakeSlowCaseMinimumCount && static_cast<double>(value) / m_executionEntryCount >= Options::couldTakeSlowCaseThreshold; } @@ -583,12 +606,16 @@ namespace JSC { bool likelyToTakeSpecialFastCase(int bytecodeOffset) { + if (!numberOfRareCaseProfiles()) + return false; unsigned specialFastCaseCount = specialFastCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter; return specialFastCaseCount >= Options::likelyToTakeSlowCaseMinimumCount && static_cast<double>(specialFastCaseCount) / m_executionEntryCount >= Options::likelyToTakeSlowCaseThreshold; } bool likelyToTakeDeepestSlowCase(int bytecodeOffset) { + if (!numberOfRareCaseProfiles()) + return false; unsigned slowCaseCount = rareCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter; unsigned specialFastCaseCount = specialFastCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter; unsigned value = slowCaseCount - specialFastCaseCount; @@ -597,6 +624,8 @@ namespace JSC { bool likelyToTakeAnySlowCase(int bytecodeOffset) { + if (!numberOfRareCaseProfiles()) + return false; unsigned slowCaseCount = rareCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter; unsigned specialFastCaseCount = specialFastCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter; unsigned value = slowCaseCount + specialFastCaseCount; @@ -694,11 +723,16 @@ namespace JSC { bool addFrequentExitSite(const DFG::FrequentExitSite& site) { - ASSERT(getJITType() == JITCode::BaselineJIT); + ASSERT(JITCode::isBaselineCode(getJITType())); return m_exitProfile.add(site); } DFG::ExitProfile& exitProfile() { return m_exitProfile; } + + CompressedLazyOperandValueProfileHolder& lazyOperandValueProfiles() + { + return m_lazyOperandValueProfiles; + } #endif // Constant Pool @@ -802,6 +836,29 @@ namespace JSC { void copyPostParseDataFrom(CodeBlock* alternative); void copyPostParseDataFromAlternative(); + // Functions for controlling when JITting kicks in, in a mixed mode + // execution world. + + void dontJITAnytimeSoon() + { + m_llintExecuteCounter = Options::executionCounterValueForDontJITAnytimeSoon; + } + + void jitAfterWarmUp() + { + m_llintExecuteCounter = Options::executionCounterValueForJITAfterWarmUp; + } + + void jitSoon() + { + m_llintExecuteCounter = Options::executionCounterValueForJITSoon; + } + + int32_t llintExecuteCounter() const + { + return m_llintExecuteCounter; + } + // Functions for controlling when tiered compilation kicks in. This // controls both when the optimizing compiler is invoked and when OSR // entry happens. Two triggers exist: the loop trigger and the return @@ -994,6 +1051,9 @@ namespace JSC { bool m_shouldDiscardBytecode; protected: +#if ENABLE(JIT) + virtual void jitCompileImpl(JSGlobalData&) = 0; +#endif virtual void visitWeakReferences(SlotVisitor&); virtual void finalizeUnconditionally(); @@ -1075,9 +1135,11 @@ namespace JSC { RefPtr<SourceProvider> m_source; unsigned m_sourceOffset; -#if ENABLE(INTERPRETER) Vector<unsigned> m_propertyAccessInstructions; Vector<unsigned> m_globalResolveInstructions; +#if ENABLE(LLINT) + SegmentedVector<LLIntCallLinkInfo, 8> m_llintCallLinkInfos; + SentinelLinkedList<LLIntCallLinkInfo, BasicRawSentinelNode<LLIntCallLinkInfo> > m_incomingLLIntCalls; #endif #if ENABLE(JIT) Vector<StructureStubInfo> m_structureStubInfos; @@ -1088,9 +1150,10 @@ namespace JSC { MacroAssemblerCodePtr m_jitCodeWithArityCheck; SentinelLinkedList<CallLinkInfo, BasicRawSentinelNode<CallLinkInfo> > m_incomingCalls; #endif -#if ENABLE(DFG_JIT) +#if ENABLE(DFG_JIT) || ENABLE(LLINT) OwnPtr<CompactJITCodeMap> m_jitCodeMap; - +#endif +#if ENABLE(DFG_JIT) struct WeakReferenceTransition { WeakReferenceTransition() { } @@ -1130,6 +1193,7 @@ namespace JSC { // This is relevant to non-DFG code blocks that serve as the profiled code block // for DFG code blocks. DFG::ExitProfile m_exitProfile; + CompressedLazyOperandValueProfileHolder m_lazyOperandValueProfiles; #endif #if ENABLE(VALUE_PROFILER) Vector<ValueProfile> m_argumentValueProfiles; @@ -1153,12 +1217,14 @@ namespace JSC { OwnPtr<CodeBlock> m_alternative; + int32_t m_llintExecuteCounter; + int32_t m_jitExecuteCounter; uint32_t m_speculativeSuccessCounter; uint32_t m_speculativeFailCounter; uint8_t m_optimizationDelayCounter; uint8_t m_reoptimizationRetryCounter; - + struct RareData { WTF_MAKE_FAST_ALLOCATED; public: @@ -1234,6 +1300,7 @@ namespace JSC { protected: virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*); virtual void jettison(); + virtual void jitCompileImpl(JSGlobalData&); virtual CodeBlock* replacement(); virtual bool canCompileWithDFGInternal(); #endif @@ -1268,6 +1335,7 @@ namespace JSC { protected: virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*); virtual void jettison(); + virtual void jitCompileImpl(JSGlobalData&); virtual CodeBlock* replacement(); virtual bool canCompileWithDFGInternal(); #endif @@ -1305,6 +1373,7 @@ namespace JSC { protected: virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*); virtual void jettison(); + virtual void jitCompileImpl(JSGlobalData&); virtual CodeBlock* replacement(); virtual bool canCompileWithDFGInternal(); #endif @@ -1331,6 +1400,17 @@ namespace JSC { bool m_oldValueOfShouldDiscardBytecode; }; + inline CodeBlock* baselineCodeBlockForOriginAndBaselineCodeBlock(const CodeOrigin& codeOrigin, CodeBlock* baselineCodeBlock) + { + if (codeOrigin.inlineCallFrame) { + ExecutableBase* executable = codeOrigin.inlineCallFrame->executable.get(); + ASSERT(executable->structure()->classInfo() == &FunctionExecutable::s_info); + return static_cast<FunctionExecutable*>(executable)->baselineCodeBlockFor(codeOrigin.inlineCallFrame->isCall ? CodeForCall : CodeForConstruct); + } + return baselineCodeBlock; + } + + inline Register& ExecState::r(int index) { CodeBlock* codeBlock = this->codeBlock(); diff --git a/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp b/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp index 5eff1d4a0..11aead3df 100644 --- a/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp +++ b/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp @@ -27,20 +27,49 @@ #include "GetByIdStatus.h" #include "CodeBlock.h" +#include "LowLevelInterpreter.h" namespace JSC { +GetByIdStatus GetByIdStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned bytecodeIndex, Identifier& ident) +{ + UNUSED_PARAM(profiledBlock); + UNUSED_PARAM(bytecodeIndex); + UNUSED_PARAM(ident); +#if ENABLE(LLINT) + Instruction* instruction = profiledBlock->instructions().begin() + bytecodeIndex; + + if (instruction[0].u.opcode == llint_op_method_check) + instruction++; + + Structure* structure = instruction[4].u.structure.get(); + if (!structure) + return GetByIdStatus(NoInformation, StructureSet(), notFound, false); + + size_t offset = structure->get(*profiledBlock->globalData(), ident); + if (offset == notFound) + return GetByIdStatus(NoInformation, StructureSet(), notFound, false); + + return GetByIdStatus(SimpleDirect, StructureSet(structure), offset, false); +#else + return GetByIdStatus(NoInformation, StructureSet(), notFound, false); +#endif +} + GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytecodeIndex, Identifier& ident) { UNUSED_PARAM(profiledBlock); UNUSED_PARAM(bytecodeIndex); UNUSED_PARAM(ident); #if ENABLE(JIT) && ENABLE(VALUE_PROFILER) + if (!profiledBlock->numberOfStructureStubInfos()) + return computeFromLLInt(profiledBlock, bytecodeIndex, ident); + // First check if it makes either calls, in which case we want to be super careful, or // if it's not set at all, in which case we punt. StructureStubInfo& stubInfo = profiledBlock->getStubInfo(bytecodeIndex); if (!stubInfo.seen) - return GetByIdStatus(NoInformation, StructureSet(), notFound); + return computeFromLLInt(profiledBlock, bytecodeIndex, ident); PolymorphicAccessStructureList* list; int listSize; @@ -60,18 +89,19 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec } for (int i = 0; i < listSize; ++i) { if (!list->list[i].isDirect) - return GetByIdStatus(MakesCalls, StructureSet(), notFound); + return GetByIdStatus(MakesCalls, StructureSet(), notFound, true); } // Next check if it takes slow case, in which case we want to be kind of careful. if (profiledBlock->likelyToTakeSlowCase(bytecodeIndex)) - return GetByIdStatus(TakesSlowPath, StructureSet(), notFound); + return GetByIdStatus(TakesSlowPath, StructureSet(), notFound, true); // Finally figure out if we can derive an access strategy. GetByIdStatus result; + result.m_wasSeenInJIT = true; switch (stubInfo.accessType) { case access_unset: - return GetByIdStatus(NoInformation, StructureSet(), notFound); + return computeFromLLInt(profiledBlock, bytecodeIndex, ident); case access_get_by_id_self: { Structure* structure = stubInfo.u.getByIdSelf.baseObjectStructure.get(); @@ -130,7 +160,7 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec return result; #else // ENABLE(JIT) - return GetByIdStatus(NoInformation, StructureSet(), notFound); + return GetByIdStatus(NoInformation, StructureSet(), notFound, false); #endif // ENABLE(JIT) } diff --git a/Source/JavaScriptCore/bytecode/GetByIdStatus.h b/Source/JavaScriptCore/bytecode/GetByIdStatus.h index 00e50e76d..39476c009 100644 --- a/Source/JavaScriptCore/bytecode/GetByIdStatus.h +++ b/Source/JavaScriptCore/bytecode/GetByIdStatus.h @@ -49,10 +49,11 @@ public: { } - GetByIdStatus(State state, const StructureSet& structureSet, size_t offset) + GetByIdStatus(State state, const StructureSet& structureSet, size_t offset, bool wasSeenInJIT) : m_state(state) , m_structureSet(structureSet) , m_offset(offset) + , m_wasSeenInJIT(wasSeenInJIT) { ASSERT((state == SimpleDirect) == (offset != notFound)); } @@ -70,10 +71,15 @@ public: const StructureSet& structureSet() const { return m_structureSet; } size_t offset() const { return m_offset; } + bool wasSeenInJIT() const { return m_wasSeenInJIT; } + private: + static GetByIdStatus computeFromLLInt(CodeBlock*, unsigned bytecodeIndex, Identifier&); + State m_state; StructureSet m_structureSet; size_t m_offset; + bool m_wasSeenInJIT; }; } // namespace JSC diff --git a/Source/JavaScriptCore/bytecode/Instruction.h b/Source/JavaScriptCore/bytecode/Instruction.h index 92118eeb2..c4989d2db 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 LLIntCallLinkInfo; struct ValueProfile; #if ENABLE(JIT) @@ -146,9 +147,14 @@ namespace JSC { #endif struct Instruction { + Instruction() + { + u.jsCell.clear(); + } + Instruction(Opcode opcode) { -#if !ENABLE(COMPUTED_GOTO_INTERPRETER) +#if !ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) // We have to initialize one of the pointer members to ensure that // the entire struct is initialized, when opcode is not a pointer. u.jsCell.clear(); @@ -182,6 +188,8 @@ namespace JSC { Instruction(PropertySlot::GetValueFunc getterFunc) { u.getterFunc = getterFunc; } + Instruction(LLIntCallLinkInfo* callLinkInfo) { u.callLinkInfo = callLinkInfo; } + Instruction(ValueProfile* profile) { u.profile = profile; } union { @@ -191,7 +199,9 @@ namespace JSC { WriteBarrierBase<StructureChain> structureChain; WriteBarrierBase<JSCell> jsCell; PropertySlot::GetValueFunc getterFunc; + LLIntCallLinkInfo* callLinkInfo; ValueProfile* profile; + void* pointer; } u; private: diff --git a/Source/JavaScriptCore/bytecode/LLIntCallLinkInfo.h b/Source/JavaScriptCore/bytecode/LLIntCallLinkInfo.h new file mode 100644 index 000000000..bfb951018 --- /dev/null +++ b/Source/JavaScriptCore/bytecode/LLIntCallLinkInfo.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2012 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. + */ + +#ifndef LLIntCallLinkInfo_h +#define LLIntCallLinkInfo_h + +#include "JSFunction.h" +#include "MacroAssemblerCodeRef.h" +#include <wtf/SentinelLinkedList.h> + +namespace JSC { + +struct Instruction; + +struct LLIntCallLinkInfo : public BasicRawSentinelNode<LLIntCallLinkInfo> { + LLIntCallLinkInfo() + { + } + + ~LLIntCallLinkInfo() + { + if (isOnList()) + remove(); + } + + bool isLinked() { return callee; } + + void unlink() + { + callee.clear(); + machineCodeTarget = MacroAssemblerCodePtr(); + if (isOnList()) + remove(); + } + + WriteBarrier<JSFunction> callee; + WriteBarrier<JSFunction> lastSeenCallee; + MacroAssemblerCodePtr machineCodeTarget; +}; + +} // namespace JSC + +#endif // LLIntCallLinkInfo_h + diff --git a/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.cpp b/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.cpp new file mode 100644 index 000000000..f199b6923 --- /dev/null +++ b/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2012 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. + */ + +#include "config.h" +#include "LazyOperandValueProfile.h" + +#if ENABLE(VALUE_PROFILER) + +namespace JSC { + +CompressedLazyOperandValueProfileHolder::CompressedLazyOperandValueProfileHolder() { } +CompressedLazyOperandValueProfileHolder::~CompressedLazyOperandValueProfileHolder() { } + +void CompressedLazyOperandValueProfileHolder::computeUpdatedPredictions() +{ + if (!m_data) + return; + + for (unsigned i = 0; i < m_data->size(); ++i) + m_data->at(i).computeUpdatedPrediction(); +} + +LazyOperandValueProfile* CompressedLazyOperandValueProfileHolder::add( + const LazyOperandValueProfileKey& key) +{ + if (!m_data) + m_data = adoptPtr(new LazyOperandValueProfile::List()); + else { + for (unsigned i = 0; i < m_data->size(); ++i) { + if (m_data->at(i).key() == key) + return &m_data->at(i); + } + } + + m_data->append(LazyOperandValueProfile(key)); + return &m_data->last(); +} + +LazyOperandValueProfileParser::LazyOperandValueProfileParser( + CompressedLazyOperandValueProfileHolder& holder) + : m_holder(holder) +{ + if (!m_holder.m_data) + return; + + LazyOperandValueProfile::List& data = *m_holder.m_data; + for (unsigned i = 0; i < data.size(); ++i) + m_map.add(data[i].key(), &data[i]); +} + +LazyOperandValueProfileParser::~LazyOperandValueProfileParser() { } + +LazyOperandValueProfile* LazyOperandValueProfileParser::getIfPresent( + const LazyOperandValueProfileKey& key) const +{ + HashMap<LazyOperandValueProfileKey, LazyOperandValueProfile*>::const_iterator iter = + m_map.find(key); + + if (iter == m_map.end()) + return 0; + + return iter->second; +} + +PredictedType LazyOperandValueProfileParser::prediction( + const LazyOperandValueProfileKey& key) const +{ + LazyOperandValueProfile* profile = getIfPresent(key); + if (!profile) + return PredictNone; + + return profile->computeUpdatedPrediction(); +} + +} // namespace JSC + +#endif // ENABLE(VALUE_PROFILER) + diff --git a/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.h b/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.h new file mode 100644 index 000000000..d0260f991 --- /dev/null +++ b/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.h @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2012 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. + */ + +#ifndef LazyOperandValueProfile_h +#define LazyOperandValueProfile_h + +#include <wtf/Platform.h> + +#if ENABLE(VALUE_PROFILER) + +#include "ValueProfile.h" +#include <wtf/HashMap.h> +#include <wtf/Noncopyable.h> +#include <wtf/OwnPtr.h> +#include <wtf/SegmentedVector.h> + +namespace JSC { + +class ScriptExecutable; + +class LazyOperandValueProfileKey { +public: + LazyOperandValueProfileKey() + : m_bytecodeOffset(0) // 0 = empty value + , m_operand(-1) // not a valid operand index in our current scheme + { + } + + LazyOperandValueProfileKey(WTF::HashTableDeletedValueType) + : m_bytecodeOffset(1) // 1 = deleted value + , m_operand(-1) // not a valid operand index in our current scheme + { + } + + LazyOperandValueProfileKey(unsigned bytecodeOffset, int operand) + : m_bytecodeOffset(bytecodeOffset) + , m_operand(operand) + { + ASSERT(operand != -1); + } + + bool operator!() const + { + return m_operand == -1; + } + + bool operator==(const LazyOperandValueProfileKey& other) const + { + return m_bytecodeOffset == other.m_bytecodeOffset + && m_operand == other.m_operand; + } + + unsigned hash() const + { + return WTF::intHash(m_bytecodeOffset) + m_operand; + } + + unsigned bytecodeOffset() const + { + ASSERT(!!*this); + return m_bytecodeOffset; + } + int operand() const + { + ASSERT(!!*this); + return m_operand; + } + + bool isHashTableDeletedValue() const + { + return m_operand == -1 && m_bytecodeOffset; + } +private: + unsigned m_bytecodeOffset; + int m_operand; +}; + +struct LazyOperandValueProfileKeyHash { + static unsigned hash(const LazyOperandValueProfileKey& key) { return key.hash(); } + static bool equal( + const LazyOperandValueProfileKey& a, + const LazyOperandValueProfileKey& b) { return a == b; } + static const bool safeToCompareToEmptyOrDeleted = true; +}; + +} // namespace JSC + +namespace WTF { + +template<typename T> struct DefaultHash; +template<> struct DefaultHash<JSC::LazyOperandValueProfileKey> { + typedef JSC::LazyOperandValueProfileKeyHash Hash; +}; + +template<typename T> struct HashTraits; +template<> struct HashTraits<JSC::LazyOperandValueProfileKey> : public GenericHashTraits<JSC::LazyOperandValueProfileKey> { + static void constructDeletedValue(JSC::LazyOperandValueProfileKey& slot) { new (NotNull, &slot) JSC::LazyOperandValueProfileKey(HashTableDeletedValue); } + static bool isDeletedValue(const JSC::LazyOperandValueProfileKey& value) { return value.isHashTableDeletedValue(); } +}; + +} // namespace WTF + +namespace JSC { + +struct LazyOperandValueProfile : public MinimalValueProfile { + LazyOperandValueProfile() + : MinimalValueProfile() + , m_operand(-1) + { + } + + explicit LazyOperandValueProfile(const LazyOperandValueProfileKey& key) + : MinimalValueProfile(key.bytecodeOffset()) + , m_operand(key.operand()) + { + } + + LazyOperandValueProfileKey key() const + { + return LazyOperandValueProfileKey(m_bytecodeOffset, m_operand); + } + + int m_operand; + + typedef SegmentedVector<LazyOperandValueProfile, 8> List; +}; + +class LazyOperandValueProfileParser; + +class CompressedLazyOperandValueProfileHolder { + WTF_MAKE_NONCOPYABLE(CompressedLazyOperandValueProfileHolder); +public: + CompressedLazyOperandValueProfileHolder(); + ~CompressedLazyOperandValueProfileHolder(); + + void computeUpdatedPredictions(); + + LazyOperandValueProfile* add(const LazyOperandValueProfileKey& key); + +private: + friend class LazyOperandValueProfileParser; + OwnPtr<LazyOperandValueProfile::List> m_data; +}; + +class LazyOperandValueProfileParser { + WTF_MAKE_NONCOPYABLE(LazyOperandValueProfileParser); +public: + explicit LazyOperandValueProfileParser( + CompressedLazyOperandValueProfileHolder& holder); + ~LazyOperandValueProfileParser(); + + LazyOperandValueProfile* getIfPresent( + const LazyOperandValueProfileKey& key) const; + + PredictedType prediction(const LazyOperandValueProfileKey& key) const; +private: + CompressedLazyOperandValueProfileHolder& m_holder; + HashMap<LazyOperandValueProfileKey, LazyOperandValueProfile*> m_map; +}; + +} // namespace JSC + +#endif // ENABLE(VALUE_PROFILER) + +#endif // LazyOperandValueProfile_h + + diff --git a/Source/JavaScriptCore/bytecode/MethodCallLinkStatus.cpp b/Source/JavaScriptCore/bytecode/MethodCallLinkStatus.cpp index e7d721c29..795b41b69 100644 --- a/Source/JavaScriptCore/bytecode/MethodCallLinkStatus.cpp +++ b/Source/JavaScriptCore/bytecode/MethodCallLinkStatus.cpp @@ -35,6 +35,11 @@ MethodCallLinkStatus MethodCallLinkStatus::computeFor(CodeBlock* profiledBlock, UNUSED_PARAM(profiledBlock); UNUSED_PARAM(bytecodeIndex); #if ENABLE(JIT) && ENABLE(VALUE_PROFILER) + // NOTE: This does not have an LLInt fall-back because LLInt does not do any method + // call link caching. + if (!profiledBlock->numberOfMethodCallLinkInfos()) + return MethodCallLinkStatus(); + MethodCallLinkInfo& methodCall = profiledBlock->getMethodCallLinkInfo(bytecodeIndex); if (!methodCall.seen || !methodCall.cachedStructure) diff --git a/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.cpp b/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.cpp new file mode 100644 index 000000000..857ed9c87 --- /dev/null +++ b/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2012 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. + */ + +#include "config.h" +#include "MethodOfGettingAValueProfile.h" + +#if ENABLE(DFG_JIT) + +#include "CodeBlock.h" + +namespace JSC { + +MethodOfGettingAValueProfile MethodOfGettingAValueProfile::fromLazyOperand( + CodeBlock* codeBlock, const LazyOperandValueProfileKey& key) +{ + MethodOfGettingAValueProfile result; + result.m_kind = LazyOperand; + result.u.lazyOperand.codeBlock = codeBlock; + result.u.lazyOperand.bytecodeOffset = key.bytecodeOffset(); + result.u.lazyOperand.operand = key.operand(); + return result; +} + +EncodedJSValue* MethodOfGettingAValueProfile::getSpecFailBucket(unsigned index) const +{ + switch (m_kind) { + case None: + return 0; + + case Ready: + return u.profile->specFailBucket(index); + + case LazyOperand: + return u.lazyOperand.codeBlock->lazyOperandValueProfiles().add( + LazyOperandValueProfileKey( + u.lazyOperand.bytecodeOffset, u.lazyOperand.operand))->specFailBucket(index); + + default: + ASSERT_NOT_REACHED(); + return 0; + } +} + +} // namespace JSC + +#endif // ENABLE(DFG_JIT) + diff --git a/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.h b/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.h new file mode 100644 index 000000000..0f5c2be7b --- /dev/null +++ b/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2012 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. + */ + +#ifndef MethodOfGettingAValueProfile_h +#define MethodOfGettingAValueProfile_h + +#include <wtf/Platform.h> + +// This is guarded by ENABLE_DFG_JIT only because it uses some value profiles +// that are currently only used if the DFG is enabled (i.e. they are not +// available in the profile-only configuration). Hopefully someday all of +// these #if's will disappear... +#if ENABLE(DFG_JIT) + +#include "JSValue.h" + +namespace JSC { + +class CodeBlock; +class LazyOperandValueProfileKey; +struct ValueProfile; + +class MethodOfGettingAValueProfile { +public: + MethodOfGettingAValueProfile() + : m_kind(None) + { + } + + explicit MethodOfGettingAValueProfile(ValueProfile* profile) + { + if (profile) { + m_kind = Ready; + u.profile = profile; + } else + m_kind = None; + } + + static MethodOfGettingAValueProfile fromLazyOperand( + CodeBlock*, const LazyOperandValueProfileKey&); + + bool operator!() const { return m_kind == None; } + + // This logically has a pointer to a "There exists X such that + // ValueProfileBase<X>". But since C++ does not have existential + // templates, I cannot return it. So instead, for any methods that + // users of this class would like to call, we'll just have to provide + // a method here that does it through an indirection. Or we could + // possibly just make ValueProfile less template-based. But last I + // tried that, it felt more yucky than this class. + + EncodedJSValue* getSpecFailBucket(unsigned index) const; + +private: + enum Kind { + None, + Ready, + LazyOperand + }; + + Kind m_kind; + union { + ValueProfile* profile; + struct { + CodeBlock* codeBlock; + unsigned bytecodeOffset; + int operand; + } lazyOperand; + } u; +}; + +} // namespace JSC + +#endif // ENABLE(DFG_JIT) + +#endif // MethodOfGettingAValueProfile_h + diff --git a/Source/JavaScriptCore/bytecode/Opcode.cpp b/Source/JavaScriptCore/bytecode/Opcode.cpp index 2490804cd..a27714026 100644 --- a/Source/JavaScriptCore/bytecode/Opcode.cpp +++ b/Source/JavaScriptCore/bytecode/Opcode.cpp @@ -39,16 +39,12 @@ using namespace std; namespace JSC { -#if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING) || ENABLE(CODEBLOCK_SAMPLING) || ENABLE(OPCODE_STATS) - const char* const opcodeNames[] = { #define OPCODE_NAME_ENTRY(opcode, size) #opcode, FOR_EACH_OPCODE_ID(OPCODE_NAME_ENTRY) #undef OPCODE_NAME_ENTRY }; -#endif - #if ENABLE(OPCODE_STATS) long long OpcodeStats::opcodeCounts[numOpcodeIDs]; @@ -118,19 +114,19 @@ OpcodeStats::~OpcodeStats() *(currentPairIndex++) = make_pair(i, j); qsort(sortedPairIndices, numOpcodeIDs * numOpcodeIDs, sizeof(pair<int, int>), compareOpcodePairIndices); - printf("\nExecuted opcode statistics\n"); + dataLog("\nExecuted opcode statistics\n"); - printf("Total instructions executed: %lld\n\n", totalInstructions); + dataLog("Total instructions executed: %lld\n\n", totalInstructions); - printf("All opcodes by frequency:\n\n"); + dataLog("All opcodes by frequency:\n\n"); for (int i = 0; i < numOpcodeIDs; ++i) { int index = sortedIndices[i]; - printf("%s:%s %lld - %.2f%%\n", opcodeNames[index], padOpcodeName((OpcodeID)index, 28), opcodeCounts[index], ((double) opcodeCounts[index]) / ((double) totalInstructions) * 100.0); + dataLog("%s:%s %lld - %.2f%%\n", opcodeNames[index], padOpcodeName((OpcodeID)index, 28), opcodeCounts[index], ((double) opcodeCounts[index]) / ((double) totalInstructions) * 100.0); } - printf("\n"); - printf("2-opcode sequences by frequency: %lld\n\n", totalInstructions); + dataLog("\n"); + dataLog("2-opcode sequences by frequency: %lld\n\n", totalInstructions); for (int i = 0; i < numOpcodeIDs * numOpcodeIDs; ++i) { pair<int, int> indexPair = sortedPairIndices[i]; @@ -139,11 +135,11 @@ OpcodeStats::~OpcodeStats() if (!count) break; - printf("%s%s %s:%s %lld %.2f%%\n", opcodeNames[indexPair.first], padOpcodeName((OpcodeID)indexPair.first, 28), opcodeNames[indexPair.second], padOpcodeName((OpcodeID)indexPair.second, 28), count, ((double) count) / ((double) totalInstructionPairs) * 100.0); + dataLog("%s%s %s:%s %lld %.2f%%\n", opcodeNames[indexPair.first], padOpcodeName((OpcodeID)indexPair.first, 28), opcodeNames[indexPair.second], padOpcodeName((OpcodeID)indexPair.second, 28), count, ((double) count) / ((double) totalInstructionPairs) * 100.0); } - printf("\n"); - printf("Most common opcodes and sequences:\n"); + dataLog("\n"); + dataLog("Most common opcodes and sequences:\n"); for (int i = 0; i < numOpcodeIDs; ++i) { int index = sortedIndices[i]; @@ -151,7 +147,7 @@ OpcodeStats::~OpcodeStats() double opcodeProportion = ((double) opcodeCount) / ((double) totalInstructions); if (opcodeProportion < 0.0001) break; - printf("\n%s:%s %lld - %.2f%%\n", opcodeNames[index], padOpcodeName((OpcodeID)index, 28), opcodeCount, opcodeProportion * 100.0); + dataLog("\n%s:%s %lld - %.2f%%\n", opcodeNames[index], padOpcodeName((OpcodeID)index, 28), opcodeCount, opcodeProportion * 100.0); for (int j = 0; j < numOpcodeIDs * numOpcodeIDs; ++j) { pair<int, int> indexPair = sortedPairIndices[j]; @@ -164,11 +160,11 @@ OpcodeStats::~OpcodeStats() if (indexPair.first != index && indexPair.second != index) continue; - printf(" %s%s %s:%s %lld - %.2f%%\n", opcodeNames[indexPair.first], padOpcodeName((OpcodeID)indexPair.first, 28), opcodeNames[indexPair.second], padOpcodeName((OpcodeID)indexPair.second, 28), pairCount, pairProportion * 100.0); + dataLog(" %s%s %s:%s %lld - %.2f%%\n", opcodeNames[indexPair.first], padOpcodeName((OpcodeID)indexPair.first, 28), opcodeNames[indexPair.second], padOpcodeName((OpcodeID)indexPair.second, 28), pairCount, pairProportion * 100.0); } } - printf("\n"); + dataLog("\n"); } void OpcodeStats::recordInstruction(int opcode) diff --git a/Source/JavaScriptCore/bytecode/Opcode.h b/Source/JavaScriptCore/bytecode/Opcode.h index 57633a338..a47fa5e9b 100644 --- a/Source/JavaScriptCore/bytecode/Opcode.h +++ b/Source/JavaScriptCore/bytecode/Opcode.h @@ -123,6 +123,8 @@ namespace JSC { macro(op_get_arguments_length, 4) \ macro(op_put_by_id, 9) \ macro(op_put_by_id_transition, 9) \ + macro(op_put_by_id_transition_direct, 9) \ + macro(op_put_by_id_transition_normal, 9) \ macro(op_put_by_id_replace, 9) \ macro(op_put_by_id_generic, 9) \ macro(op_del_by_id, 4) \ @@ -201,6 +203,7 @@ namespace JSC { typedef enum { FOR_EACH_OPCODE_ID(OPCODE_ID_ENUM) } OpcodeID; #undef OPCODE_ID_ENUM + const int maxOpcodeLength = 9; const int numOpcodeIDs = op_end + 1; #define OPCODE_ID_LENGTHS(id, length) const int id##_length = length; @@ -217,7 +220,7 @@ namespace JSC { FOR_EACH_OPCODE_ID(VERIFY_OPCODE_ID); #undef VERIFY_OPCODE_ID -#if ENABLE(COMPUTED_GOTO_INTERPRETER) +#if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) || ENABLE(LLINT) #if COMPILER(RVCT) || COMPILER(INTEL) typedef void* Opcode; #else @@ -227,8 +230,6 @@ namespace JSC { typedef OpcodeID Opcode; #endif -#if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING) || ENABLE(CODEBLOCK_SAMPLING) || ENABLE(OPCODE_STATS) - #define PADDING_STRING " " #define PADDING_STRING_LENGTH static_cast<unsigned>(strlen(PADDING_STRING)) @@ -244,8 +245,6 @@ namespace JSC { #undef PADDING_STRING_LENGTH #undef PADDING_STRING -#endif - #if ENABLE(OPCODE_STATS) struct OpcodeStats { diff --git a/Source/JavaScriptCore/bytecode/PolymorphicPutByIdList.cpp b/Source/JavaScriptCore/bytecode/PolymorphicPutByIdList.cpp new file mode 100644 index 000000000..170615b73 --- /dev/null +++ b/Source/JavaScriptCore/bytecode/PolymorphicPutByIdList.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2012 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. + */ + +#include "config.h" +#include "PolymorphicPutByIdList.h" + +#if ENABLE(JIT) + +#include "StructureStubInfo.h" + +namespace JSC { + +PutByIdAccess PutByIdAccess::fromStructureStubInfo( + StructureStubInfo& stubInfo, + MacroAssemblerCodePtr initialSlowPath) +{ + PutByIdAccess result; + + switch (stubInfo.accessType) { + case access_put_by_id_replace: + result.m_type = Replace; + result.m_oldStructure.copyFrom(stubInfo.u.putByIdReplace.baseObjectStructure); + result.m_stubRoutine = MacroAssemblerCodeRef::createSelfManagedCodeRef(initialSlowPath); + break; + + case access_put_by_id_transition_direct: + case access_put_by_id_transition_normal: + result.m_type = Transition; + result.m_oldStructure.copyFrom(stubInfo.u.putByIdTransition.previousStructure); + result.m_newStructure.copyFrom(stubInfo.u.putByIdTransition.structure); + result.m_chain.copyFrom(stubInfo.u.putByIdTransition.chain); + result.m_stubRoutine = stubInfo.stubRoutine; + break; + + default: + ASSERT_NOT_REACHED(); + } + + return result; +} + +bool PutByIdAccess::visitWeak() const +{ + switch (m_type) { + case Replace: + if (!Heap::isMarked(m_oldStructure.get())) + return false; + break; + case Transition: + if (!Heap::isMarked(m_oldStructure.get())) + return false; + if (!Heap::isMarked(m_newStructure.get())) + return false; + if (!Heap::isMarked(m_chain.get())) + return false; + break; + default: + ASSERT_NOT_REACHED(); + return false; + } + return true; +} + +PolymorphicPutByIdList::PolymorphicPutByIdList( + PutKind putKind, + StructureStubInfo& stubInfo, + MacroAssemblerCodePtr initialSlowPath) + : m_kind(putKind) +{ + m_list.append(PutByIdAccess::fromStructureStubInfo(stubInfo, initialSlowPath)); +} + +PolymorphicPutByIdList* PolymorphicPutByIdList::from( + PutKind putKind, + StructureStubInfo& stubInfo, + MacroAssemblerCodePtr initialSlowPath) +{ + if (stubInfo.accessType == access_put_by_id_list) + return stubInfo.u.putByIdList.list; + + ASSERT(stubInfo.accessType == access_put_by_id_replace + || stubInfo.accessType == access_put_by_id_transition_normal + || stubInfo.accessType == access_put_by_id_transition_direct); + + PolymorphicPutByIdList* result = + new PolymorphicPutByIdList(putKind, stubInfo, initialSlowPath); + + stubInfo.initPutByIdList(result); + + return result; +} + +PolymorphicPutByIdList::~PolymorphicPutByIdList() { } + +bool PolymorphicPutByIdList::isFull() const +{ + ASSERT(size() <= POLYMORPHIC_LIST_CACHE_SIZE); + return size() == POLYMORPHIC_LIST_CACHE_SIZE; +} + +bool PolymorphicPutByIdList::isAlmostFull() const +{ + ASSERT(size() <= POLYMORPHIC_LIST_CACHE_SIZE); + return size() >= POLYMORPHIC_LIST_CACHE_SIZE - 1; +} + +void PolymorphicPutByIdList::addAccess(const PutByIdAccess& putByIdAccess) +{ + ASSERT(!isFull()); + // Make sure that the resizing optimizes for space, not time. + m_list.resize(m_list.size() + 1); + m_list.last() = putByIdAccess; +} + +bool PolymorphicPutByIdList::visitWeak() const +{ + for (unsigned i = 0; i < size(); ++i) { + if (!at(i).visitWeak()) + return false; + } + return true; +} + +} // namespace JSC + +#endif // ENABLE(JIT) diff --git a/Source/JavaScriptCore/bytecode/PolymorphicPutByIdList.h b/Source/JavaScriptCore/bytecode/PolymorphicPutByIdList.h new file mode 100644 index 000000000..60b632d52 --- /dev/null +++ b/Source/JavaScriptCore/bytecode/PolymorphicPutByIdList.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2012 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. + */ + +#ifndef PolymorphicPutByIdList_h +#define PolymorphicPutByIdList_h + +#include <wtf/Platform.h> + +#if ENABLE(JIT) + +#include "CodeOrigin.h" +#include "MacroAssembler.h" +#include "Opcode.h" +#include "PutKind.h" +#include "Structure.h" +#include <wtf/Vector.h> + +namespace JSC { + +struct StructureStubInfo; + +class PutByIdAccess { +public: + enum AccessType { + Invalid, + Transition, + Replace + }; + + PutByIdAccess() + : m_type(Invalid) + { + } + + static PutByIdAccess transition( + JSGlobalData& globalData, + JSCell* owner, + Structure* oldStructure, + Structure* newStructure, + StructureChain* chain, + MacroAssemblerCodeRef stubRoutine) + { + PutByIdAccess result; + result.m_type = Transition; + result.m_oldStructure.set(globalData, owner, oldStructure); + result.m_newStructure.set(globalData, owner, newStructure); + result.m_chain.set(globalData, owner, chain); + result.m_stubRoutine = stubRoutine; + return result; + } + + static PutByIdAccess replace( + JSGlobalData& globalData, + JSCell* owner, + Structure* structure, + MacroAssemblerCodeRef stubRoutine) + { + PutByIdAccess result; + result.m_type = Replace; + result.m_oldStructure.set(globalData, owner, structure); + result.m_stubRoutine = stubRoutine; + return result; + } + + static PutByIdAccess fromStructureStubInfo( + StructureStubInfo&, + MacroAssemblerCodePtr initialSlowPath); + + bool isSet() const { return m_type != Invalid; } + bool operator!() const { return !isSet(); } + + AccessType type() const { return m_type; } + + bool isTransition() const { return m_type == Transition; } + bool isReplace() const { return m_type == Replace; } + + Structure* oldStructure() const + { + // Using this instead of isSet() to make this assertion robust against the possibility + // of additional access types being added. + ASSERT(isTransition() || isReplace()); + + return m_oldStructure.get(); + } + + Structure* structure() const + { + ASSERT(isReplace()); + return m_oldStructure.get(); + } + + Structure* newStructure() const + { + ASSERT(isTransition()); + return m_newStructure.get(); + } + + StructureChain* chain() const + { + ASSERT(isTransition()); + return m_chain.get(); + } + + MacroAssemblerCodeRef stubRoutine() const + { + ASSERT(isTransition() || isReplace()); + return m_stubRoutine; + } + + bool visitWeak() const; + +private: + AccessType m_type; + WriteBarrier<Structure> m_oldStructure; + WriteBarrier<Structure> m_newStructure; + WriteBarrier<StructureChain> m_chain; + MacroAssemblerCodeRef m_stubRoutine; +}; + +class PolymorphicPutByIdList { + WTF_MAKE_FAST_ALLOCATED; +public: + // Initialize from a stub info; this will place one element in the list and it will + // be created by converting the stub info's put by id access information into our + // PutByIdAccess. + PolymorphicPutByIdList( + PutKind, + StructureStubInfo&, + MacroAssemblerCodePtr initialSlowPath); + + // Either creates a new polymorphic put list, or returns the one that is already + // in place. + static PolymorphicPutByIdList* from( + PutKind, + StructureStubInfo&, + MacroAssemblerCodePtr initialSlowPath); + + ~PolymorphicPutByIdList(); + + MacroAssemblerCodePtr currentSlowPathTarget() const + { + return m_list.last().stubRoutine().code(); + } + + void addAccess(const PutByIdAccess&); + + bool isEmpty() const { return m_list.isEmpty(); } + unsigned size() const { return m_list.size(); } + bool isFull() const; + bool isAlmostFull() const; // True if adding an element would make isFull() true. + const PutByIdAccess& at(unsigned i) const { return m_list[i]; } + const PutByIdAccess& operator[](unsigned i) const { return m_list[i]; } + + PutKind kind() const { return m_kind; } + + bool visitWeak() const; + +private: + Vector<PutByIdAccess, 2> m_list; + PutKind m_kind; +}; + +} // namespace JSC + +#endif // ENABLE(JIT) + +#endif // PolymorphicPutByIdList_h + diff --git a/Source/JavaScriptCore/bytecode/PredictedType.cpp b/Source/JavaScriptCore/bytecode/PredictedType.cpp index a8118adf9..2b490c24e 100644 --- a/Source/JavaScriptCore/bytecode/PredictedType.cpp +++ b/Source/JavaScriptCore/bytecode/PredictedType.cpp @@ -29,6 +29,7 @@ #include "config.h" #include "PredictedType.h" +#include "JSArray.h" #include "JSByteArray.h" #include "JSFunction.h" #include "ValueProfile.h" diff --git a/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp b/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp index 45a5e614c..209d4cd5e 100644 --- a/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp +++ b/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp @@ -27,27 +27,69 @@ #include "PutByIdStatus.h" #include "CodeBlock.h" +#include "LowLevelInterpreter.h" #include "Structure.h" #include "StructureChain.h" namespace JSC { +PutByIdStatus PutByIdStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned bytecodeIndex, Identifier& ident) +{ + UNUSED_PARAM(profiledBlock); + UNUSED_PARAM(bytecodeIndex); + UNUSED_PARAM(ident); +#if ENABLE(LLINT) + Instruction* instruction = profiledBlock->instructions().begin() + bytecodeIndex; + + Structure* structure = instruction[4].u.structure.get(); + if (!structure) + return PutByIdStatus(NoInformation, 0, 0, 0, notFound); + + if (instruction[0].u.opcode == llint_op_put_by_id) { + size_t offset = structure->get(*profiledBlock->globalData(), ident); + if (offset == notFound) + return PutByIdStatus(NoInformation, 0, 0, 0, notFound); + + return PutByIdStatus(SimpleReplace, structure, 0, 0, offset); + } + + ASSERT(instruction[0].u.opcode == llint_op_put_by_id_transition_direct + || instruction[0].u.opcode == llint_op_put_by_id_transition_normal); + + Structure* newStructure = instruction[6].u.structure.get(); + StructureChain* chain = instruction[7].u.structureChain.get(); + ASSERT(newStructure); + ASSERT(chain); + + size_t offset = newStructure->get(*profiledBlock->globalData(), ident); + if (offset == notFound) + return PutByIdStatus(NoInformation, 0, 0, 0, notFound); + + return PutByIdStatus(SimpleTransition, structure, newStructure, chain, offset); +#else + return PutByIdStatus(NoInformation, 0, 0, 0, notFound); +#endif +} + PutByIdStatus PutByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytecodeIndex, Identifier& ident) { UNUSED_PARAM(profiledBlock); UNUSED_PARAM(bytecodeIndex); UNUSED_PARAM(ident); #if ENABLE(JIT) && ENABLE(VALUE_PROFILER) + if (!profiledBlock->numberOfStructureStubInfos()) + return computeFromLLInt(profiledBlock, bytecodeIndex, ident); + if (profiledBlock->likelyToTakeSlowCase(bytecodeIndex)) return PutByIdStatus(TakesSlowPath, 0, 0, 0, notFound); StructureStubInfo& stubInfo = profiledBlock->getStubInfo(bytecodeIndex); if (!stubInfo.seen) - return PutByIdStatus(NoInformation, 0, 0, 0, notFound); + return computeFromLLInt(profiledBlock, bytecodeIndex, ident); switch (stubInfo.accessType) { case access_unset: - return PutByIdStatus(NoInformation, 0, 0, 0, notFound); + return computeFromLLInt(profiledBlock, bytecodeIndex, ident); case access_put_by_id_replace: { size_t offset = stubInfo.u.putByIdReplace.baseObjectStructure->get( diff --git a/Source/JavaScriptCore/bytecode/PutByIdStatus.h b/Source/JavaScriptCore/bytecode/PutByIdStatus.h index b33f4d09c..a6d95a449 100644 --- a/Source/JavaScriptCore/bytecode/PutByIdStatus.h +++ b/Source/JavaScriptCore/bytecode/PutByIdStatus.h @@ -93,6 +93,8 @@ public: size_t offset() const { return m_offset; } private: + static PutByIdStatus computeFromLLInt(CodeBlock*, unsigned bytecodeIndex, Identifier&); + State m_state; Structure* m_oldStructure; Structure* m_newStructure; diff --git a/Source/JavaScriptCore/bytecode/PutKind.h b/Source/JavaScriptCore/bytecode/PutKind.h new file mode 100644 index 000000000..7a1dd642e --- /dev/null +++ b/Source/JavaScriptCore/bytecode/PutKind.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2012 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. + */ + +#ifndef PutKind_h +#define PutKind_h + +namespace JSC { + +enum PutKind { Direct, NotDirect }; + +} // namespace JSC + +#endif // PutKind_h + diff --git a/Source/JavaScriptCore/bytecode/SamplingTool.cpp b/Source/JavaScriptCore/bytecode/SamplingTool.cpp index 0dec25fb7..077f041f4 100644 --- a/Source/JavaScriptCore/bytecode/SamplingTool.cpp +++ b/Source/JavaScriptCore/bytecode/SamplingTool.cpp @@ -67,14 +67,14 @@ void SamplingFlags::stop() total += s_flagCounts[i]; if (total) { - printf("\nSamplingFlags: sample counts with flags set: (%lld total)\n", total); + dataLog("\nSamplingFlags: sample counts with flags set: (%lld total)\n", total); for (unsigned i = 0; i <= 32; ++i) { if (s_flagCounts[i]) - printf(" [ %02d ] : %lld\t\t(%03.2f%%)\n", i, s_flagCounts[i], (100.0 * s_flagCounts[i]) / total); + dataLog(" [ %02d ] : %lld\t\t(%03.2f%%)\n", i, s_flagCounts[i], (100.0 * s_flagCounts[i]) / total); } - printf("\n"); + dataLog("\n"); } else - printf("\nSamplingFlags: no samples.\n\n"); + dataLog("\nSamplingFlags: no samples.\n\n"); } uint64_t SamplingFlags::s_flagCounts[33]; @@ -151,7 +151,7 @@ void SamplingRegion::dump() void SamplingRegion::dumpInternal() { if (!s_spectrum) { - printf("\nSamplingRegion: was never sampled.\n\n"); + dataLog("\nSamplingRegion: was never sampled.\n\n"); return; } @@ -161,10 +161,10 @@ void SamplingRegion::dumpInternal() for (unsigned i = list.size(); i--;) total += list[i].count; - printf("\nSamplingRegion: sample counts for regions: (%lu samples)\n", total); + dataLog("\nSamplingRegion: sample counts for regions: (%lu samples)\n", total); for (unsigned i = list.size(); i--;) - printf(" %3.2lf%% %s\n", (100.0 * list[i].count) / total, list[i].key); + dataLog(" %3.2lf%% %s\n", (100.0 * list[i].count) / total, list[i].key); } #else // ENABLE(SAMPLING_REGIONS) void SamplingRegion::dump() { } @@ -210,7 +210,7 @@ bool SamplingThread::s_running = false; unsigned SamplingThread::s_hertz = 10000; ThreadIdentifier SamplingThread::s_samplingThread; -void* SamplingThread::threadStartFunc(void*) +void SamplingThread::threadStartFunc(void*) { while (s_running) { sleepForMicroseconds(hertz2us(s_hertz)); @@ -225,8 +225,6 @@ void* SamplingThread::threadStartFunc(void*) SamplingTool::sample(); #endif } - - return 0; } @@ -243,7 +241,7 @@ void SamplingThread::stop() { ASSERT(s_running); s_running = false; - waitForThreadCompletion(s_samplingThread, 0); + waitForThreadCompletion(s_samplingThread); } @@ -373,10 +371,10 @@ void SamplingTool::dump(ExecState* exec) // (2) Print Opcode sampling results. - printf("\nBytecode samples [*]\n"); - printf(" sample %% of %% of | cti cti %%\n"); - printf("opcode count VM total | count of self\n"); - printf("------------------------------------------------------- | ----------------\n"); + dataLog("\nBytecode samples [*]\n"); + dataLog(" sample %% of %% of | cti cti %%\n"); + dataLog("opcode count VM total | count of self\n"); + dataLog("------------------------------------------------------- | ----------------\n"); for (int i = 0; i < numOpcodeIDs; ++i) { long long count = opcodeSampleInfo[i].count; @@ -391,18 +389,18 @@ void SamplingTool::dump(ExecState* exec) double percentOfTotal = (static_cast<double>(count) * 100) / m_sampleCount; long long countInCTIFunctions = opcodeSampleInfo[i].countInCTIFunctions; double percentInCTIFunctions = (static_cast<double>(countInCTIFunctions) * 100) / count; - fprintf(stdout, "%s:%s%-6lld %.3f%%\t%.3f%%\t | %-6lld %.3f%%\n", opcodeName, opcodePadding, count, percentOfVM, percentOfTotal, countInCTIFunctions, percentInCTIFunctions); + debugDebugPrintf("%s:%s%-6lld %.3f%%\t%.3f%%\t | %-6lld %.3f%%\n", opcodeName, opcodePadding, count, percentOfVM, percentOfTotal, countInCTIFunctions, percentInCTIFunctions); } - printf("\n[*] Samples inside host code are not charged to any Bytecode.\n\n"); - printf("\tSamples inside VM:\t\t%lld / %lld (%.3f%%)\n", m_opcodeSampleCount, m_sampleCount, (static_cast<double>(m_opcodeSampleCount) * 100) / m_sampleCount); - printf("\tSamples inside host code:\t%lld / %lld (%.3f%%)\n\n", m_sampleCount - m_opcodeSampleCount, m_sampleCount, (static_cast<double>(m_sampleCount - m_opcodeSampleCount) * 100) / m_sampleCount); - printf("\tsample count:\tsamples inside this opcode\n"); - printf("\t%% of VM:\tsample count / all opcode samples\n"); - printf("\t%% of total:\tsample count / all samples\n"); - printf("\t--------------\n"); - printf("\tcti count:\tsamples inside a CTI function called by this opcode\n"); - printf("\tcti %% of self:\tcti count / sample count\n"); + dataLog("\n[*] Samples inside host code are not charged to any Bytecode.\n\n"); + dataLog("\tSamples inside VM:\t\t%lld / %lld (%.3f%%)\n", m_opcodeSampleCount, m_sampleCount, (static_cast<double>(m_opcodeSampleCount) * 100) / m_sampleCount); + dataLog("\tSamples inside host code:\t%lld / %lld (%.3f%%)\n\n", m_sampleCount - m_opcodeSampleCount, m_sampleCount, (static_cast<double>(m_sampleCount - m_opcodeSampleCount) * 100) / m_sampleCount); + dataLog("\tsample count:\tsamples inside this opcode\n"); + dataLog("\t%% of VM:\tsample count / all opcode samples\n"); + dataLog("\t%% of total:\tsample count / all samples\n"); + dataLog("\t--------------\n"); + dataLog("\tcti count:\tsamples inside a CTI function called by this opcode\n"); + dataLog("\tcti %% of self:\tcti count / sample count\n"); #if ENABLE(CODEBLOCK_SAMPLING) @@ -418,7 +416,7 @@ void SamplingTool::dump(ExecState* exec) // (4) Print data from 'codeBlockSamples' array. - printf("\nCodeBlock samples\n\n"); + dataLog("\nCodeBlock samples\n\n"); for (int i = 0; i < scopeCount; ++i) { ScriptSampleRecord* record = codeBlockSamples[i]; @@ -428,21 +426,21 @@ void SamplingTool::dump(ExecState* exec) if (blockPercent >= 1) { //Instruction* code = codeBlock->instructions().begin(); - printf("#%d: %s:%d: %d / %lld (%.3f%%)\n", i + 1, record->m_executable->sourceURL().utf8().data(), codeBlock->lineNumberForBytecodeOffset(0), record->m_sampleCount, m_sampleCount, blockPercent); + dataLog("#%d: %s:%d: %d / %lld (%.3f%%)\n", i + 1, record->m_executable->sourceURL().utf8().data(), codeBlock->lineNumberForBytecodeOffset(0), record->m_sampleCount, m_sampleCount, blockPercent); if (i < 10) { HashMap<unsigned,unsigned> lineCounts; codeBlock->dump(exec); - printf(" Opcode and line number samples [*]\n\n"); + dataLog(" Opcode and line number samples [*]\n\n"); for (unsigned op = 0; op < record->m_size; ++op) { int count = record->m_samples[op]; if (count) { - printf(" [% 4d] has sample count: % 4d\n", op, count); + dataLog(" [% 4d] has sample count: % 4d\n", op, count); unsigned line = codeBlock->lineNumberForBytecodeOffset(op); lineCounts.set(line, (lineCounts.contains(line) ? lineCounts.get(line) : 0) + count); } } - printf("\n"); + dataLog("\n"); int linesCount = lineCounts.size(); Vector<LineCountInfo> lineCountInfo(linesCount); @@ -455,12 +453,12 @@ void SamplingTool::dump(ExecState* exec) qsort(lineCountInfo.begin(), linesCount, sizeof(LineCountInfo), compareLineCountInfoSampling); for (lineno = 0; lineno < linesCount; ++lineno) { - printf(" Line #%d has sample count %d.\n", lineCountInfo[lineno].line, lineCountInfo[lineno].count); + dataLog(" Line #%d has sample count %d.\n", lineCountInfo[lineno].line, lineCountInfo[lineno].count); } - printf("\n"); - printf(" [*] Samples inside host code are charged to the calling Bytecode.\n"); - printf(" Samples on a call / return boundary are not charged to a specific opcode or line.\n\n"); - printf(" Samples on a call / return boundary: %d / %d (%.3f%%)\n\n", record->m_sampleCount - record->m_opcodeSampleCount, record->m_sampleCount, (static_cast<double>(record->m_sampleCount - record->m_opcodeSampleCount) * 100) / record->m_sampleCount); + dataLog("\n"); + dataLog(" [*] Samples inside host code are charged to the calling Bytecode.\n"); + dataLog(" Samples on a call / return boundary are not charged to a specific opcode or line.\n\n"); + dataLog(" Samples on a call / return boundary: %d / %d (%.3f%%)\n\n", record->m_sampleCount - record->m_opcodeSampleCount, record->m_sampleCount, (static_cast<double>(record->m_sampleCount - record->m_opcodeSampleCount) * 100) / record->m_sampleCount); } } } diff --git a/Source/JavaScriptCore/bytecode/SamplingTool.h b/Source/JavaScriptCore/bytecode/SamplingTool.h index 32a44ad69..28fd528d0 100644 --- a/Source/JavaScriptCore/bytecode/SamplingTool.h +++ b/Source/JavaScriptCore/bytecode/SamplingTool.h @@ -223,7 +223,7 @@ namespace JSC { JS_EXPORT_PRIVATE static void start(unsigned hertz=10000); JS_EXPORT_PRIVATE static void stop(); - static void* threadStartFunc(void*); + static void threadStartFunc(void*); }; class SamplingTool { diff --git a/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp b/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp index ec18782d5..f2657b785 100644 --- a/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp +++ b/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp @@ -27,6 +27,7 @@ #include "StructureStubInfo.h" #include "JSObject.h" +#include "PolymorphicPutByIdList.h" #include "ScopeChain.h" namespace JSC { @@ -45,6 +46,9 @@ void StructureStubInfo::deref() delete polymorphicStructures; return; } + case access_put_by_id_list: + delete u.putByIdList.list; + return; case access_get_by_id_self: case access_get_by_id_proto: case access_get_by_id_chain: @@ -82,18 +86,14 @@ bool StructureStubInfo::visitWeakReferences() break; case access_get_by_id_self_list: { PolymorphicAccessStructureList* polymorphicStructures = u.getByIdSelfList.structureList; - if (!polymorphicStructures->visitWeak(u.getByIdSelfList.listSize)) { - delete polymorphicStructures; + if (!polymorphicStructures->visitWeak(u.getByIdSelfList.listSize)) return false; - } break; } case access_get_by_id_proto_list: { PolymorphicAccessStructureList* polymorphicStructures = u.getByIdProtoList.structureList; - if (!polymorphicStructures->visitWeak(u.getByIdSelfList.listSize)) { - delete polymorphicStructures; + if (!polymorphicStructures->visitWeak(u.getByIdSelfList.listSize)) return false; - } break; } case access_put_by_id_transition_normal: @@ -107,6 +107,10 @@ bool StructureStubInfo::visitWeakReferences() if (!Heap::isMarked(u.putByIdReplace.baseObjectStructure.get())) return false; break; + case access_put_by_id_list: + if (!u.putByIdList.list->visitWeak()) + return false; + break; default: // The rest of the instructions don't require references, so there is no need to // do anything. diff --git a/Source/JavaScriptCore/bytecode/StructureStubInfo.h b/Source/JavaScriptCore/bytecode/StructureStubInfo.h index d6b6092d0..8fad5c0cc 100644 --- a/Source/JavaScriptCore/bytecode/StructureStubInfo.h +++ b/Source/JavaScriptCore/bytecode/StructureStubInfo.h @@ -26,6 +26,8 @@ #ifndef StructureStubInfo_h #define StructureStubInfo_h +#include <wtf/Platform.h> + #if ENABLE(JIT) #include "CodeOrigin.h" @@ -36,6 +38,8 @@ namespace JSC { + class PolymorphicPutByIdList; + enum AccessType { access_get_by_id_self, access_get_by_id_proto, @@ -45,6 +49,7 @@ namespace JSC { access_put_by_id_transition_normal, access_put_by_id_transition_direct, access_put_by_id_replace, + access_put_by_id_list, access_unset, access_get_by_id_generic, access_put_by_id_generic, @@ -75,6 +80,7 @@ namespace JSC { case access_put_by_id_transition_normal: case access_put_by_id_transition_direct: case access_put_by_id_replace: + case access_put_by_id_list: case access_put_by_id_generic: return true; default: @@ -149,10 +155,16 @@ namespace JSC { u.putByIdReplace.baseObjectStructure.set(globalData, owner, baseObjectStructure); } + void initPutByIdList(PolymorphicPutByIdList* list) + { + accessType = access_put_by_id_list; + u.putByIdList.list = list; + } + void reset() { accessType = access_unset; - + deref(); stubRoutine = MacroAssemblerCodeRef(); } @@ -227,6 +239,9 @@ namespace JSC { struct { WriteBarrierBase<Structure> baseObjectStructure; } putByIdReplace; + struct { + PolymorphicPutByIdList* list; + } putByIdList; } u; MacroAssemblerCodeRef stubRoutine; diff --git a/Source/JavaScriptCore/bytecode/ValueProfile.cpp b/Source/JavaScriptCore/bytecode/ValueProfile.cpp deleted file mode 100644 index 2d7770aed..000000000 --- a/Source/JavaScriptCore/bytecode/ValueProfile.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2011 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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. - */ - -#include "config.h" -#include "ValueProfile.h" - -namespace JSC { - -#if ENABLE(VALUE_PROFILER) -PredictedType ValueProfile::computeUpdatedPrediction() -{ - for (unsigned i = 0; i < totalNumberOfBuckets; ++i) { - JSValue value = JSValue::decode(m_buckets[i]); - if (!value) - continue; - - m_numberOfSamplesInPrediction++; - mergePrediction(m_prediction, predictionFromValue(value)); - - m_buckets[i] = JSValue::encode(JSValue()); - } - - return m_prediction; -} -#endif // ENABLE(VALUE_PROFILER) - -} // namespace JSC diff --git a/Source/JavaScriptCore/bytecode/ValueProfile.h b/Source/JavaScriptCore/bytecode/ValueProfile.h index 02a1d6bf9..73e363a8b 100644 --- a/Source/JavaScriptCore/bytecode/ValueProfile.h +++ b/Source/JavaScriptCore/bytecode/ValueProfile.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2012 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,6 +29,10 @@ #ifndef ValueProfile_h #define ValueProfile_h +#include <wtf/Platform.h> + +#if ENABLE(VALUE_PROFILER) + #include "JSArray.h" #include "PredictedType.h" #include "Structure.h" @@ -36,15 +40,14 @@ namespace JSC { -#if ENABLE(VALUE_PROFILER) -struct ValueProfile { - static const unsigned logNumberOfBuckets = 0; // 1 bucket - static const unsigned numberOfBuckets = 1 << logNumberOfBuckets; +template<unsigned numberOfBucketsArgument> +struct ValueProfileBase { + static const unsigned numberOfBuckets = numberOfBucketsArgument; static const unsigned numberOfSpecFailBuckets = 1; static const unsigned bucketIndexMask = numberOfBuckets - 1; static const unsigned totalNumberOfBuckets = numberOfBuckets + numberOfSpecFailBuckets; - ValueProfile() + ValueProfileBase() : m_bytecodeOffset(-1) , m_prediction(PredictNone) , m_numberOfSamplesInPrediction(0) @@ -53,7 +56,7 @@ struct ValueProfile { m_buckets[i] = JSValue::encode(JSValue()); } - ValueProfile(int bytecodeOffset) + ValueProfileBase(int bytecodeOffset) : m_bytecodeOffset(bytecodeOffset) , m_prediction(PredictNone) , m_numberOfSamplesInPrediction(0) @@ -103,7 +106,6 @@ struct ValueProfile { return false; } -#ifndef NDEBUG void dump(FILE* out) { fprintf(out, @@ -123,10 +125,23 @@ struct ValueProfile { } } } -#endif // Updates the prediction and returns the new one. - PredictedType computeUpdatedPrediction(); + PredictedType computeUpdatedPrediction() + { + for (unsigned i = 0; i < totalNumberOfBuckets; ++i) { + JSValue value = JSValue::decode(m_buckets[i]); + if (!value) + continue; + + m_numberOfSamplesInPrediction++; + mergePrediction(m_prediction, predictionFromValue(value)); + + m_buckets[i] = JSValue::encode(JSValue()); + } + + return m_prediction; + } int m_bytecodeOffset; // -1 for prologue @@ -136,7 +151,32 @@ struct ValueProfile { EncodedJSValue m_buckets[totalNumberOfBuckets]; }; -inline int getValueProfileBytecodeOffset(ValueProfile* valueProfile) +struct MinimalValueProfile : public ValueProfileBase<0> { + MinimalValueProfile(): ValueProfileBase<0>() { } + MinimalValueProfile(int bytecodeOffset): ValueProfileBase<0>(bytecodeOffset) { } +}; + +template<unsigned logNumberOfBucketsArgument> +struct ValueProfileWithLogNumberOfBuckets : public ValueProfileBase<1 << logNumberOfBucketsArgument> { + static const unsigned logNumberOfBuckets = logNumberOfBucketsArgument; + + ValueProfileWithLogNumberOfBuckets() + : ValueProfileBase<1 << logNumberOfBucketsArgument>() + { + } + ValueProfileWithLogNumberOfBuckets(int bytecodeOffset) + : ValueProfileBase<1 << logNumberOfBucketsArgument>(bytecodeOffset) + { + } +}; + +struct ValueProfile : public ValueProfileWithLogNumberOfBuckets<0> { + ValueProfile(): ValueProfileWithLogNumberOfBuckets<0>() { } + ValueProfile(int bytecodeOffset): ValueProfileWithLogNumberOfBuckets<0>(bytecodeOffset) { } +}; + +template<typename T> +inline int getValueProfileBytecodeOffset(T* valueProfile) { return valueProfile->m_bytecodeOffset; } @@ -158,9 +198,10 @@ inline int getRareCaseProfileBytecodeOffset(RareCaseProfile* rareCaseProfile) { return rareCaseProfile->m_bytecodeOffset; } -#endif -} +} // namespace JSC + +#endif // ENABLE(VALUE_PROFILER) -#endif +#endif // ValueProfile_h |