diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-05-25 15:09:11 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-05-25 15:09:11 +0200 |
commit | a89b2ebb8e192c5e8cea21079bda2ee2c0c7dddd (patch) | |
tree | b7abd9f49ae1d4d2e426a5883bfccd42b8e2ee12 /Source/JavaScriptCore/bytecode | |
parent | 8d473cf9743f1d30a16a27114e93bd5af5648d23 (diff) | |
download | qtwebkit-a89b2ebb8e192c5e8cea21079bda2ee2c0c7dddd.tar.gz |
Imported WebKit commit eb5c1b8fe4d4b1b90b5137433fc58a91da0e6878 (http://svn.webkit.org/repository/webkit/trunk@118516)
Diffstat (limited to 'Source/JavaScriptCore/bytecode')
-rw-r--r-- | Source/JavaScriptCore/bytecode/CodeBlock.cpp | 446 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecode/CodeBlock.h | 106 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecode/CodeOrigin.h | 2 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecode/DFGExitProfile.h | 15 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecode/Operands.h | 10 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecode/PredictedType.cpp | 20 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecode/PredictedType.h | 44 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecode/StructureStubInfo.h | 14 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecode/ValueRecovery.h | 12 |
9 files changed, 465 insertions, 204 deletions
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp index fa663504c..6677b302b 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp @@ -43,6 +43,7 @@ #include "JSStaticScopeObject.h" #include "JSValue.h" #include "LowLevelInterpreter.h" +#include "MethodCallLinkStatus.h" #include "RepatchBuffer.h" #include "UStringConcatenate.h" #include <stdio.h> @@ -150,7 +151,7 @@ NEVER_INLINE static const char* debugHookName(int debugHookID) return ""; } -void CodeBlock::printUnaryOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) const +void CodeBlock::printUnaryOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; @@ -158,7 +159,7 @@ void CodeBlock::printUnaryOp(ExecState* exec, int location, Vector<Instruction>: 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 +void CodeBlock::printBinaryOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; @@ -166,32 +167,240 @@ void CodeBlock::printBinaryOp(ExecState* exec, int location, Vector<Instruction> 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 +void CodeBlock::printConditionalJump(ExecState* exec, const Vector<Instruction>::const_iterator&, Vector<Instruction>::const_iterator& it, int location, const char* op) { int r0 = (++it)->u.operand; int offset = (++it)->u.operand; 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 +void CodeBlock::printGetByIdOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it) { + const char* op; + switch (exec->interpreter()->getOpcodeID(it->u.opcode)) { + case op_get_by_id: + op = "get_by_id"; + break; + case op_get_by_id_self: + op = "get_by_id_self"; + break; + case op_get_by_id_proto: + op = "get_by_id_proto"; + break; + case op_get_by_id_chain: + op = "get_by_id_chain"; + break; + case op_get_by_id_getter_self: + op = "get_by_id_getter_self"; + break; + case op_get_by_id_getter_proto: + op = "get_by_id_getter_proto"; + break; + case op_get_by_id_getter_chain: + op = "get_by_id_getter_chain"; + break; + case op_get_by_id_custom_self: + op = "get_by_id_custom_self"; + break; + case op_get_by_id_custom_proto: + op = "get_by_id_custom_proto"; + break; + case op_get_by_id_custom_chain: + op = "get_by_id_custom_chain"; + break; + case op_get_by_id_generic: + op = "get_by_id_generic"; + break; + case op_get_array_length: + op = "array_length"; + break; + case op_get_string_length: + op = "string_length"; + break; + default: + ASSERT_NOT_REACHED(); + op = 0; + } int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int id0 = (++it)->u.operand; - dataLog("[%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", location, op, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data()); it += 5; } -void CodeBlock::printCallOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) const +static void dumpStructure(const char* name, ExecState* exec, Structure* structure, Identifier& ident) +{ + if (!structure) + return; + + dataLog("%s = %p", name, structure); + + size_t offset = structure->get(exec->globalData(), ident); + if (offset != notFound) + dataLog(" (offset = %lu)", static_cast<unsigned long>(offset)); +} + +static void dumpChain(ExecState* exec, StructureChain* chain, Identifier& ident) +{ + dataLog("chain = %p: [", chain); + bool first = true; + for (WriteBarrier<Structure>* currentStructure = chain->head(); + *currentStructure; + ++currentStructure) { + if (first) + first = false; + else + dataLog(", "); + dumpStructure("struct", exec, currentStructure->get(), ident); + } + dataLog("]"); +} + +void CodeBlock::printGetByIdCacheStatus(ExecState* exec, int location) +{ + Instruction* instruction = instructions().begin() + location; + + if (exec->interpreter()->getOpcodeID(instruction[0].u.opcode) == op_method_check) + instruction++; + + Identifier& ident = identifier(instruction[3].u.operand); + +#if ENABLE(LLINT) + Structure* structure = instruction[4].u.structure.get(); + dataLog(" llint("); + dumpStructure("struct", exec, structure, ident); + dataLog(")"); +#endif + +#if ENABLE(JIT) + if (numberOfStructureStubInfos()) { + dataLog(" jit("); + StructureStubInfo& stubInfo = getStubInfo(location); + if (!stubInfo.seen) + dataLog("not seen"); + else { + Structure* baseStructure = 0; + Structure* prototypeStructure = 0; + StructureChain* chain = 0; + PolymorphicAccessStructureList* structureList = 0; + int listSize = 0; + + switch (stubInfo.accessType) { + case access_get_by_id_self: + dataLog("self"); + baseStructure = stubInfo.u.getByIdSelf.baseObjectStructure.get(); + break; + case access_get_by_id_proto: + dataLog("proto"); + baseStructure = stubInfo.u.getByIdProto.baseObjectStructure.get(); + prototypeStructure = stubInfo.u.getByIdProto.prototypeStructure.get(); + break; + case access_get_by_id_chain: + dataLog("chain"); + baseStructure = stubInfo.u.getByIdChain.baseObjectStructure.get(); + chain = stubInfo.u.getByIdChain.chain.get(); + break; + case access_get_by_id_self_list: + dataLog("self_list"); + structureList = stubInfo.u.getByIdSelfList.structureList; + listSize = stubInfo.u.getByIdSelfList.listSize; + break; + case access_get_by_id_proto_list: + dataLog("proto_list"); + structureList = stubInfo.u.getByIdProtoList.structureList; + listSize = stubInfo.u.getByIdProtoList.listSize; + break; + case access_unset: + dataLog("unset"); + break; + case access_get_by_id_generic: + dataLog("generic"); + break; + case access_get_array_length: + dataLog("array_length"); + break; + case access_get_string_length: + dataLog("string_length"); + break; + default: + ASSERT_NOT_REACHED(); + break; + } + + if (baseStructure) { + dataLog(", "); + dumpStructure("struct", exec, baseStructure, ident); + } + + if (prototypeStructure) { + dataLog(", "); + dumpStructure("prototypeStruct", exec, baseStructure, ident); + } + + if (chain) { + dataLog(", "); + dumpChain(exec, chain, ident); + } + + if (structureList) { + dataLog(", list = %p: [", structureList); + for (int i = 0; i < listSize; ++i) { + if (i) + dataLog(", "); + dataLog("("); + dumpStructure("base", exec, structureList->list[i].base.get(), ident); + if (structureList->list[i].isChain) { + if (structureList->list[i].u.chain.get()) { + dataLog(", "); + dumpChain(exec, structureList->list[i].u.chain.get(), ident); + } + } else { + if (structureList->list[i].u.proto.get()) { + dataLog(", "); + dumpStructure("proto", exec, structureList->list[i].u.proto.get(), ident); + } + } + dataLog(")"); + } + dataLog("]"); + } + } + dataLog(")"); + } +#endif +} + +void CodeBlock::printCallOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op, CacheDumpMode cacheDumpMode) { int func = (++it)->u.operand; int argCount = (++it)->u.operand; int registerOffset = (++it)->u.operand; - dataLog("[%4d] %s\t %s, %d, %d\n", location, op, registerName(exec, func).data(), argCount, registerOffset); + dataLog("[%4d] %s\t %s, %d, %d", location, op, registerName(exec, func).data(), argCount, registerOffset); + if (cacheDumpMode == DumpCaches) { +#if ENABLE(LLINT) + LLIntCallLinkInfo* callLinkInfo = it[1].u.callLinkInfo; + if (callLinkInfo->lastSeenCallee) { + dataLog(" llint(%p, exec %p)", + callLinkInfo->lastSeenCallee.get(), + callLinkInfo->lastSeenCallee->executable()); + } else + dataLog(" llint(not set)"); +#endif +#if ENABLE(JIT) + if (numberOfCallLinkInfos()) { + JSFunction* target = getCallLinkInfo(location).lastSeenCallee.get(); + if (target) + dataLog(" jit(%p, exec %p)", target, target->executable()); + else + dataLog(" jit(not set)"); + } +#endif + } + dataLog("\n"); it += 2; } -void CodeBlock::printPutByIdOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) const +void CodeBlock::printPutByIdOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) { int r0 = (++it)->u.operand; int id0 = (++it)->u.operand; @@ -206,26 +415,6 @@ static bool isGlobalResolve(OpcodeID opcodeID) return opcodeID == op_resolve_global || opcodeID == op_resolve_global_dynamic; } -static bool isPropertyAccess(OpcodeID opcodeID) -{ - switch (opcodeID) { - case op_get_by_id_self: - case op_get_by_id_proto: - case op_get_by_id_chain: - case op_put_by_id_transition: - case op_put_by_id_replace: - case op_get_by_id: - case op_put_by_id: - case op_get_by_id_generic: - case op_put_by_id_generic: - case op_get_array_length: - case op_get_string_length: - return true; - default: - return false; - } -} - static unsigned instructionOffsetForNth(ExecState* exec, const RefCountedArray<Instruction>& instructions, int nth, bool (*predicate)(OpcodeID)) { size_t i = 0; @@ -246,60 +435,15 @@ static void printGlobalResolveInfo(const GlobalResolveInfo& resolveInfo, unsigne { 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: - dataLog(" [%4d] %s: %s\n", instructionOffset, "get_by_id_self", pointerToSourceString(stubInfo.u.getByIdSelf.baseObjectStructure).utf8().data()); - return; - case access_get_by_id_proto: - 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: - 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: - 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: - 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: - 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: - dataLog(" [%4d] %s: %s\n", instructionOffset, "put_by_id_replace", pointerToSourceString(stubInfo.u.putByIdReplace.baseObjectStructure).utf8().data()); - return; - case access_unset: - dataLog(" [%4d] %s\n", instructionOffset, "unset"); - return; - case access_get_by_id_generic: - dataLog(" [%4d] %s\n", instructionOffset, "op_get_by_id_generic"); - return; - case access_put_by_id_generic: - dataLog(" [%4d] %s\n", instructionOffset, "op_put_by_id_generic"); - return; - case access_get_array_length: - dataLog(" [%4d] %s\n", instructionOffset, "op_get_array_length"); - return; - case access_get_string_length: - dataLog(" [%4d] %s\n", instructionOffset, "op_get_string_length"); - return; - default: - ASSERT_NOT_REACHED(); - } -} #endif -void CodeBlock::printStructure(const char* name, const Instruction* vPC, int operand) const +void CodeBlock::printStructure(const char* name, const Instruction* vPC, int operand) { unsigned instructionOffset = vPC - instructions().begin(); dataLog(" [%4d] %s: %s\n", instructionOffset, name, pointerToSourceString(vPC[operand].u.structure).utf8().data()); } -void CodeBlock::printStructures(const Instruction* vPC) const +void CodeBlock::printStructures(const Instruction* vPC) { Interpreter* interpreter = m_globalData->interpreter; unsigned instructionOffset = vPC - instructions().begin(); @@ -345,17 +489,30 @@ void CodeBlock::printStructures(const Instruction* vPC) const ASSERT(vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_call) || vPC[0].u.opcode == interpreter->getOpcode(op_call_eval) || vPC[0].u.opcode == interpreter->getOpcode(op_construct)); } -void CodeBlock::dump(ExecState* exec) const +void CodeBlock::dump(ExecState* exec) { size_t instructionCount = 0; for (size_t i = 0; i < instructions().size(); i += opcodeLengths[exec->interpreter()->getOpcodeID(instructions()[i].u.opcode)]) ++instructionCount; - dataLog("%lu m_instructions; %lu bytes at %p; %d parameter(s); %d callee register(s); %d variable(s)\n\n", + dataLog( + "%lu m_instructions; %lu bytes at %p (%s); %d parameter(s); %d callee register(s); %d variable(s)", static_cast<unsigned long>(instructions().size()), static_cast<unsigned long>(instructions().size() * sizeof(Instruction)), - this, m_numParameters, m_numCalleeRegisters, m_numVars); + this, codeTypeToString(codeType()), m_numParameters, m_numCalleeRegisters, + m_numVars); + if (m_numCapturedVars) + dataLog("; %d captured var(s)", m_numCapturedVars); + if (usesArguments()) { + dataLog( + "; uses arguments, in r%d, r%d", + argumentsRegister(), + unmodifiedArgumentsRegister(argumentsRegister())); + } + if (needsFullScopeChain() && codeType() == FunctionCode) + dataLog("; activation in r%d", activationRegister()); + dataLog("\n\n"); Vector<Instruction>::const_iterator begin = instructions().begin(); Vector<Instruction>::const_iterator end = instructions().end(); @@ -400,13 +557,6 @@ void CodeBlock::dump(ExecState* exec) const ++i; } while (i < m_globalResolveInfos.size()); } - if (!m_structureStubInfos.isEmpty()) { - size_t i = 0; - do { - printStructureStubInfo(m_structureStubInfos[i], instructionOffsetForNth(exec, instructions(), i + 1, isPropertyAccess)); - ++i; - } while (i < m_structureStubInfos.size()); - } #endif #if ENABLE(CLASSIC_INTERPRETER) if (!m_globalResolveInstructions.isEmpty() || !m_propertyAccessInstructions.isEmpty()) @@ -489,7 +639,7 @@ void CodeBlock::dump(ExecState* exec) const dataLog("\n"); } -void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it) const +void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it) { int location = it - begin; switch (exec->interpreter()->getOpcodeID(it->u.opcode)) { @@ -813,56 +963,22 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& it++; break; } - case op_get_by_id: { - printGetByIdOp(exec, location, it, "get_by_id"); - break; - } - case op_get_by_id_self: { - printGetByIdOp(exec, location, it, "get_by_id_self"); - break; - } - case op_get_by_id_proto: { - printGetByIdOp(exec, location, it, "get_by_id_proto"); - break; - } - case op_get_by_id_chain: { - printGetByIdOp(exec, location, it, "get_by_id_chain"); - break; - } - case op_get_by_id_getter_self: { - printGetByIdOp(exec, location, it, "get_by_id_getter_self"); - break; - } - case op_get_by_id_getter_proto: { - printGetByIdOp(exec, location, it, "get_by_id_getter_proto"); - break; - } - case op_get_by_id_getter_chain: { - printGetByIdOp(exec, location, it, "get_by_id_getter_chain"); - break; - } - case op_get_by_id_custom_self: { - printGetByIdOp(exec, location, it, "get_by_id_custom_self"); - break; - } - case op_get_by_id_custom_proto: { - printGetByIdOp(exec, location, it, "get_by_id_custom_proto"); - break; - } - case op_get_by_id_custom_chain: { - printGetByIdOp(exec, location, it, "get_by_id_custom_chain"); - break; - } - case op_get_by_id_generic: { - printGetByIdOp(exec, location, it, "get_by_id_generic"); - break; - } - case op_get_array_length: { - printGetByIdOp(exec, location, it, "get_array_length"); - break; - } + case op_get_by_id: + case op_get_by_id_self: + case op_get_by_id_proto: + case op_get_by_id_chain: + case op_get_by_id_getter_self: + case op_get_by_id_getter_proto: + case op_get_by_id_getter_chain: + case op_get_by_id_custom_self: + case op_get_by_id_custom_proto: + case op_get_by_id_custom_chain: + case op_get_by_id_generic: + case op_get_array_length: case op_get_string_length: { - printGetByIdOp(exec, location, it, "get_string_length"); + printGetByIdOp(exec, location, it); + printGetByIdCacheStatus(exec, location); + dataLog("\n"); break; } case op_get_arguments_length: { @@ -903,7 +1019,37 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& break; } case op_method_check: { - dataLog("[%4d] method_check\n", location); + dataLog("[%4d] method_check", location); + if (numberOfMethodCallLinkInfos()) { + MethodCallLinkInfo& methodCall = getMethodCallLinkInfo(location); + dataLog(" jit("); + if (!methodCall.seen) + dataLog("not seen"); + else { + // Use the fact that MethodCallLinkStatus already does smart things + // for decoding seen method calls. + MethodCallLinkStatus status = MethodCallLinkStatus::computeFor(this, location); + if (!status) + dataLog("not set"); + else { + dataLog("function = %p (executable = ", status.function()); + JSCell* functionAsCell = getJSFunction(status.function()); + if (functionAsCell) + dataLog("%p", jsCast<JSFunction*>(functionAsCell)->executable()); + else + dataLog("N/A"); + dataLog("), struct = %p", status.structure()); + if (status.needsPrototypeCheck()) + dataLog(", prototype = %p, struct = %p", status.prototype(), status.prototypeStructure()); + } + } + dataLog(")"); + } + dataLog("\n"); + ++it; + printGetByIdOp(exec, location, it); + printGetByIdCacheStatus(exec, location); + dataLog("\n"); break; } case op_del_by_id: { @@ -1124,11 +1270,11 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& break; } case op_call: { - printCallOp(exec, location, it, "call"); + printCallOp(exec, location, it, "call", DumpCaches); break; } case op_call_eval: { - printCallOp(exec, location, it, "call_eval"); + printCallOp(exec, location, it, "call_eval", DontDumpCaches); break; } case op_call_varargs: { @@ -1168,7 +1314,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& break; } case op_construct: { - printCallOp(exec, location, it, "construct"); + printCallOp(exec, location, it, "construct", DumpCaches); break; } case op_strcat: { @@ -1430,7 +1576,7 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other, SymbolTable* symTab) , m_optimizationDelayCounter(0) , m_reoptimizationRetryCounter(0) #if ENABLE(JIT) - , m_canCompileWithDFGState(CompileWithDFGUnset) + , m_canCompileWithDFGState(DFG::CapabilityLevelNotSet) #endif { setNumParameters(other.numParameters()); @@ -1545,7 +1691,7 @@ void CodeBlock::addParameter() #endif } -void CodeBlock::visitStructures(SlotVisitor& visitor, Instruction* vPC) const +void CodeBlock::visitStructures(SlotVisitor& visitor, Instruction* vPC) { Interpreter* interpreter = m_globalData->interpreter; @@ -2325,17 +2471,17 @@ JSObject* FunctionCodeBlock::compileOptimized(ExecState* exec, ScopeChainNode* s return error; } -bool ProgramCodeBlock::canCompileWithDFGInternal() +DFG::CapabilityLevel ProgramCodeBlock::canCompileWithDFGInternal() { return DFG::canCompileProgram(this); } -bool EvalCodeBlock::canCompileWithDFGInternal() +DFG::CapabilityLevel EvalCodeBlock::canCompileWithDFGInternal() { return DFG::canCompileEval(this); } -bool FunctionCodeBlock::canCompileWithDFGInternal() +DFG::CapabilityLevel FunctionCodeBlock::canCompileWithDFGInternal() { if (m_isConstructor) return DFG::canCompileFunctionForConstruct(this); @@ -2363,25 +2509,25 @@ void FunctionCodeBlock::jettison() static_cast<FunctionExecutable*>(ownerExecutable())->jettisonOptimizedCodeFor(*globalData(), m_isConstructor ? CodeForConstruct : CodeForCall); } -bool ProgramCodeBlock::jitCompileImpl(JSGlobalData& globalData) +bool ProgramCodeBlock::jitCompileImpl(ExecState* exec) { ASSERT(getJITType() == JITCode::InterpreterThunk); ASSERT(this == replacement()); - return static_cast<ProgramExecutable*>(ownerExecutable())->jitCompile(globalData); + return static_cast<ProgramExecutable*>(ownerExecutable())->jitCompile(exec); } -bool EvalCodeBlock::jitCompileImpl(JSGlobalData& globalData) +bool EvalCodeBlock::jitCompileImpl(ExecState* exec) { ASSERT(getJITType() == JITCode::InterpreterThunk); ASSERT(this == replacement()); - return static_cast<EvalExecutable*>(ownerExecutable())->jitCompile(globalData); + return static_cast<EvalExecutable*>(ownerExecutable())->jitCompile(exec); } -bool FunctionCodeBlock::jitCompileImpl(JSGlobalData& globalData) +bool FunctionCodeBlock::jitCompileImpl(ExecState* exec) { ASSERT(getJITType() == JITCode::InterpreterThunk); ASSERT(this == replacement()); - return static_cast<FunctionExecutable*>(ownerExecutable())->jitCompileFor(globalData, m_isConstructor ? CodeForConstruct : CodeForCall); + return static_cast<FunctionExecutable*>(ownerExecutable())->jitCompileFor(exec, m_isConstructor ? CodeForConstruct : CodeForCall); } #endif diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h index fe69ec673..c1772c3bf 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.h +++ b/Source/JavaScriptCore/bytecode/CodeBlock.h @@ -37,6 +37,7 @@ #include "CodeType.h" #include "CompactJITCodeMap.h" #include "DFGCodeBlocks.h" +#include "DFGCommon.h" #include "DFGExitProfile.h" #include "DFGOSREntry.h" #include "DFGOSRExit.h" @@ -132,9 +133,9 @@ namespace JSC { static void dumpStatistics(); - void dump(ExecState*) const; - void printStructures(const Instruction*) const; - void printStructure(const char* name, const Instruction*, int operand) const; + void dump(ExecState*); + void printStructures(const Instruction*); + void printStructure(const char* name, const Instruction*, int operand); bool isStrictMode() const { return m_isStrictMode; } @@ -259,7 +260,17 @@ namespace JSC { DFG::OSREntryData* dfgOSREntryData(unsigned i) { return &m_dfgData->osrEntry[i]; } DFG::OSREntryData* dfgOSREntryDataForBytecodeIndex(unsigned bytecodeIndex) { - return binarySearch<DFG::OSREntryData, unsigned, DFG::getOSREntryDataBytecodeIndex>(m_dfgData->osrEntry.begin(), m_dfgData->osrEntry.size(), bytecodeIndex); + if (!m_dfgData) + return 0; + if (m_dfgData->osrEntry.isEmpty()) + return 0; + DFG::OSREntryData* result = binarySearch< + DFG::OSREntryData, unsigned, DFG::getOSREntryDataBytecodeIndex>( + m_dfgData->osrEntry.begin(), m_dfgData->osrEntry.size(), + bytecodeIndex, WTF::KeyMustNotBePresentInArray); + if (result->m_bytecodeIndex != bytecodeIndex) + return 0; + return result; } void appendOSRExit(const DFG::OSRExit& osrExit) @@ -355,37 +366,31 @@ namespace JSC { virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*) = 0; virtual void jettison() = 0; enum JITCompilationResult { AlreadyCompiled, CouldNotCompile, CompiledSuccessfully }; - JITCompilationResult jitCompile(JSGlobalData& globalData) + JITCompilationResult jitCompile(ExecState* exec) { if (getJITType() != JITCode::InterpreterThunk) { ASSERT(getJITType() == JITCode::BaselineJIT); return AlreadyCompiled; } #if ENABLE(JIT) - if (jitCompileImpl(globalData)) + if (jitCompileImpl(exec)) return CompiledSuccessfully; return CouldNotCompile; #else - UNUSED_PARAM(globalData); + UNUSED_PARAM(exec); return CouldNotCompile; #endif } virtual CodeBlock* replacement() = 0; - enum CompileWithDFGState { - CompileWithDFGFalse, - CompileWithDFGTrue, - CompileWithDFGUnset - }; - - virtual bool canCompileWithDFGInternal() = 0; - bool canCompileWithDFG() + virtual DFG::CapabilityLevel canCompileWithDFGInternal() = 0; + DFG::CapabilityLevel canCompileWithDFG() { - bool result = canCompileWithDFGInternal(); - m_canCompileWithDFGState = result ? CompileWithDFGTrue : CompileWithDFGFalse; + DFG::CapabilityLevel result = canCompileWithDFGInternal(); + m_canCompileWithDFGState = result; return result; } - CompileWithDFGState canCompileWithDFGState() { return m_canCompileWithDFGState; } + DFG::CapabilityLevel canCompileWithDFGState() { return m_canCompileWithDFGState; } bool hasOptimizedReplacement() { @@ -429,6 +434,12 @@ namespace JSC { ASSERT(usesArguments()); return m_argumentsRegister; } + int uncheckedArgumentsRegister() + { + if (!usesArguments()) + return InvalidVirtualRegister; + return argumentsRegister(); + } void setActivationRegister(int activationRegister) { m_activationRegister = activationRegister; @@ -439,6 +450,31 @@ namespace JSC { return m_activationRegister; } bool usesArguments() const { return m_argumentsRegister != -1; } + + bool needsActivation() const + { + return needsFullScopeChain() && codeType() != GlobalCode; + } + + bool argumentIsCaptured(int) const + { + return needsActivation() || usesArguments(); + } + + bool localIsCaptured(InlineCallFrame* inlineCallFrame, int operand) const + { + if (!inlineCallFrame) + return operand < m_numCapturedVars; + + return inlineCallFrame->capturedVars.get(operand); + } + + bool isCaptured(InlineCallFrame* inlineCallFrame, int operand) const + { + if (operandIsArgument(operand)) + return argumentIsCaptured(operandToArgument(operand)); + return localIsCaptured(inlineCallFrame, operand); + } CodeType codeType() const { return m_codeType; } @@ -1065,7 +1101,7 @@ namespace JSC { protected: #if ENABLE(JIT) - virtual bool jitCompileImpl(JSGlobalData&) = 0; + virtual bool jitCompileImpl(ExecState*) = 0; #endif virtual void visitWeakReferences(SlotVisitor&); virtual void finalizeUnconditionally(); @@ -1079,16 +1115,18 @@ namespace JSC { void tallyFrequentExitSites() { } #endif - void dump(ExecState*, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator&) const; + void dump(ExecState*, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator&); CString registerName(ExecState*, int r) const; - void printUnaryOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const; - void printBinaryOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const; - void printConditionalJump(ExecState*, const Vector<Instruction>::const_iterator&, Vector<Instruction>::const_iterator&, int location, const char* op) const; - void printGetByIdOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const; - void printCallOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const; - void printPutByIdOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const; - void visitStructures(SlotVisitor&, Instruction* vPC) const; + void printUnaryOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op); + void printBinaryOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op); + void printConditionalJump(ExecState*, const Vector<Instruction>::const_iterator&, Vector<Instruction>::const_iterator&, int location, const char* op); + void printGetByIdOp(ExecState*, int location, Vector<Instruction>::const_iterator&); + void printGetByIdCacheStatus(ExecState*, int location); + enum CacheDumpMode { DumpCaches, DontDumpCaches }; + void printCallOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op, CacheDumpMode); + void printPutByIdOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op); + void visitStructures(SlotVisitor&, Instruction* vPC); #if ENABLE(DFG_JIT) bool shouldImmediatelyAssumeLivenessDuringScan() @@ -1272,7 +1310,7 @@ namespace JSC { #endif OwnPtr<RareData> m_rareData; #if ENABLE(JIT) - CompileWithDFGState m_canCompileWithDFGState; + DFG::CapabilityLevel m_canCompileWithDFGState; #endif }; @@ -1312,9 +1350,9 @@ namespace JSC { protected: virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*); virtual void jettison(); - virtual bool jitCompileImpl(JSGlobalData&); + virtual bool jitCompileImpl(ExecState*); virtual CodeBlock* replacement(); - virtual bool canCompileWithDFGInternal(); + virtual DFG::CapabilityLevel canCompileWithDFGInternal(); #endif }; @@ -1347,9 +1385,9 @@ namespace JSC { protected: virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*); virtual void jettison(); - virtual bool jitCompileImpl(JSGlobalData&); + virtual bool jitCompileImpl(ExecState*); virtual CodeBlock* replacement(); - virtual bool canCompileWithDFGInternal(); + virtual DFG::CapabilityLevel canCompileWithDFGInternal(); #endif private: @@ -1385,9 +1423,9 @@ namespace JSC { protected: virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*); virtual void jettison(); - virtual bool jitCompileImpl(JSGlobalData&); + virtual bool jitCompileImpl(ExecState*); virtual CodeBlock* replacement(); - virtual bool canCompileWithDFGInternal(); + virtual DFG::CapabilityLevel canCompileWithDFGInternal(); #endif }; diff --git a/Source/JavaScriptCore/bytecode/CodeOrigin.h b/Source/JavaScriptCore/bytecode/CodeOrigin.h index eda17648b..034e48f3f 100644 --- a/Source/JavaScriptCore/bytecode/CodeOrigin.h +++ b/Source/JavaScriptCore/bytecode/CodeOrigin.h @@ -28,6 +28,7 @@ #include "ValueRecovery.h" #include "WriteBarrier.h" +#include <wtf/BitVector.h> #include <wtf/StdLibExtras.h> #include <wtf/Vector.h> @@ -92,6 +93,7 @@ struct InlineCallFrame { WriteBarrier<ExecutableBase> executable; WriteBarrier<JSFunction> callee; CodeOrigin caller; + BitVector capturedVars; // Indexed by the machine call frame's variable numbering. unsigned stackOffset : 31; bool isCall : 1; }; diff --git a/Source/JavaScriptCore/bytecode/DFGExitProfile.h b/Source/JavaScriptCore/bytecode/DFGExitProfile.h index 31db084f5..09f9ee075 100644 --- a/Source/JavaScriptCore/bytecode/DFGExitProfile.h +++ b/Source/JavaScriptCore/bytecode/DFGExitProfile.h @@ -39,6 +39,7 @@ enum ExitKind { Overflow, // We exited because of overflow. NegativeZero, // We exited because we encountered negative zero. InadequateCoverage, // We exited because we ended up in code that didn't have profiling coverage. + ArgumentsEscaped, // We exited because arguments escaped but we didn't expect them to. Uncountable, // We exited for none of the above reasons, and we should not count it. Most uses of this should be viewed as a FIXME. }; @@ -96,6 +97,15 @@ public: ASSERT(exitKindIsCountable(kind)); } + // Use this constructor if you wish for the exit site to be counted globally within its + // code block. + explicit FrequentExitSite(ExitKind kind) + : m_bytecodeOffset(0) + , m_kind(kind) + { + ASSERT(exitKindIsCountable(kind)); + } + bool operator!() const { return m_kind == ExitKindUnset; @@ -178,6 +188,11 @@ public: return m_frequentExitSites.find(site) != m_frequentExitSites.end(); } + bool hasExitSite(ExitKind kind) const + { + return hasExitSite(FrequentExitSite(kind)); + } + bool hasExitSite(unsigned bytecodeIndex, ExitKind kind) const { return hasExitSite(FrequentExitSite(bytecodeIndex, kind)); diff --git a/Source/JavaScriptCore/bytecode/Operands.h b/Source/JavaScriptCore/bytecode/Operands.h index a05159f81..05a24d0fd 100644 --- a/Source/JavaScriptCore/bytecode/Operands.h +++ b/Source/JavaScriptCore/bytecode/Operands.h @@ -126,6 +126,16 @@ public: setLocal(operand, value); } + void setOperandFirstTime(int operand, const T& value) + { + if (operandIsArgument(operand)) { + setArgumentFirstTime(operandToArgument(operand), value); + return; + } + + setLocalFirstTime(operand, value); + } + void clear() { for (size_t i = 0; i < m_arguments.size(); ++i) diff --git a/Source/JavaScriptCore/bytecode/PredictedType.cpp b/Source/JavaScriptCore/bytecode/PredictedType.cpp index e8a71772b..5258f4079 100644 --- a/Source/JavaScriptCore/bytecode/PredictedType.cpp +++ b/Source/JavaScriptCore/bytecode/PredictedType.cpp @@ -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,7 @@ #include "config.h" #include "PredictedType.h" +#include "Arguments.h" #include "JSArray.h" #include "JSFunction.h" #include "ValueProfile.h" @@ -117,6 +118,16 @@ const char* predictionToString(PredictedType value) else isTop = false; + if (value & PredictMyArguments) + ptr.strcat("Myarguments"); + else + isTop = false; + + if (value & PredictForeignArguments) + ptr.strcat("Foreignarguments"); + else + isTop = false; + if (value & PredictString) ptr.strcat("String"); else @@ -186,6 +197,10 @@ const char* predictionToAbbreviatedString(PredictedType prediction) return "<Float32array>"; if (isFloat64ArrayPrediction(prediction)) return "<Float64array>"; + if (isMyArgumentsPrediction(prediction)) + return "<Myarguments>"; + if (isArgumentsPrediction(prediction)) + return "<Arguments>"; if (isObjectPrediction(prediction)) return "<Object>"; if (isCellPrediction(prediction)) @@ -214,6 +229,9 @@ PredictedType predictionFromClassInfo(const ClassInfo* classInfo) if (classInfo == &JSString::s_info) return PredictString; + if (classInfo == &Arguments::s_info) + return PredictArguments; // Cannot distinguish between MyArguments and ForeignArguments at this stage. That happens in the flow analysis. + if (classInfo->isSubClassOf(&JSFunction::s_info)) return PredictFunction; diff --git a/Source/JavaScriptCore/bytecode/PredictedType.h b/Source/JavaScriptCore/bytecode/PredictedType.h index 54b308124..9f0964a14 100644 --- a/Source/JavaScriptCore/bytecode/PredictedType.h +++ b/Source/JavaScriptCore/bytecode/PredictedType.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 @@ -49,17 +49,20 @@ static const PredictedType PredictUint16Array = 0x00000200; // It's defini static const PredictedType PredictUint32Array = 0x00000400; // It's definitely an Uint32Array or one of its subclasses. static const PredictedType PredictFloat32Array = 0x00000800; // It's definitely an Uint16Array or one of its subclasses. static const PredictedType PredictFloat64Array = 0x00001000; // It's definitely an Uint16Array or one of its subclasses. -static const PredictedType PredictObjectOther = 0x00002000; // It's definitely an object but not JSFinalObject, JSArray, or JSFunction. -static const PredictedType PredictObjectMask = 0x00003fff; // Bitmask used for testing for any kind of object prediction. -static const PredictedType PredictString = 0x00004000; // It's definitely a JSString. -static const PredictedType PredictCellOther = 0x00008000; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString. -static const PredictedType PredictCell = 0x0000ffff; // It's definitely a JSCell. -static const PredictedType PredictInt32 = 0x00010000; // It's definitely an Int32. -static const PredictedType PredictDoubleReal = 0x00020000; // It's definitely a non-NaN double. -static const PredictedType PredictDoubleNaN = 0x00040000; // It's definitely a NaN. -static const PredictedType PredictDouble = 0x00060000; // It's either a non-NaN or a NaN double. -static const PredictedType PredictNumber = 0x00070000; // It's either an Int32 or a Double. -static const PredictedType PredictBoolean = 0x00080000; // It's definitely a Boolean. +static const PredictedType PredictMyArguments = 0x00002000; // It's definitely an Arguments object, and it's definitely the one for my current frame. +static const PredictedType PredictForeignArguments = 0x00004000; // It's definitely an Arguments object, and it's definitely not mine. +static const PredictedType PredictArguments = 0x00006000; // It's definitely an Arguments object. +static const PredictedType PredictObjectOther = 0x00008000; // It's definitely an object but not JSFinalObject, JSArray, or JSFunction. +static const PredictedType PredictObjectMask = 0x0000ffff; // Bitmask used for testing for any kind of object prediction. +static const PredictedType PredictString = 0x00010000; // It's definitely a JSString. +static const PredictedType PredictCellOther = 0x00020000; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString. +static const PredictedType PredictCell = 0x0003ffff; // It's definitely a JSCell. +static const PredictedType PredictInt32 = 0x00800000; // It's definitely an Int32. +static const PredictedType PredictDoubleReal = 0x01000000; // It's definitely a non-NaN double. +static const PredictedType PredictDoubleNaN = 0x02000000; // It's definitely a NaN. +static const PredictedType PredictDouble = 0x03000000; // It's either a non-NaN or a NaN double. +static const PredictedType PredictNumber = 0x03800000; // It's either an Int32 or a Double. +static const PredictedType PredictBoolean = 0x04000000; // It's definitely a Boolean. static const PredictedType PredictOther = 0x08000000; // It's definitely none of the above. static const PredictedType PredictTop = 0x0fffffff; // It can be any of the above. static const PredictedType PredictEmpty = 0x10000000; // It's definitely an empty value marker. @@ -68,6 +71,12 @@ static const PredictedType FixedIndexedStorageMask = PredictInt8Array | PredictI typedef bool (*PredictionChecker)(PredictedType); +// Dummy prediction checker, only useful if someone insists on requiring a prediction checker. +inline bool isAnyPrediction(PredictedType) +{ + return true; +} + inline bool isCellPrediction(PredictedType value) { return !!(value & PredictCell) && !(value & ~PredictCell); @@ -153,6 +162,11 @@ inline bool isFloat64ArrayPrediction(PredictedType value) return value == PredictFloat64Array; } +inline bool isArgumentsPrediction(PredictedType value) +{ + return !!value && (value & PredictArguments) == value; +} + inline bool isActionableIntMutableArrayPrediction(PredictedType value) { return isInt8ArrayPrediction(value) @@ -179,6 +193,7 @@ inline bool isActionableTypedMutableArrayPrediction(PredictedType value) inline bool isActionableMutableArrayPrediction(PredictedType value) { return isArrayPrediction(value) + || isArgumentsPrediction(value) || isActionableTypedMutableArrayPrediction(value); } @@ -193,6 +208,11 @@ inline bool isArrayOrOtherPrediction(PredictedType value) return !!(value & (PredictArray | PredictOther)) && !(value & ~(PredictArray | PredictOther)); } +inline bool isMyArgumentsPrediction(PredictedType value) +{ + return value == PredictMyArguments; +} + inline bool isInt32Prediction(PredictedType value) { return value == PredictInt32; diff --git a/Source/JavaScriptCore/bytecode/StructureStubInfo.h b/Source/JavaScriptCore/bytecode/StructureStubInfo.h index 03c64bf39..9aa40532a 100644 --- a/Source/JavaScriptCore/bytecode/StructureStubInfo.h +++ b/Source/JavaScriptCore/bytecode/StructureStubInfo.h @@ -200,15 +200,15 @@ namespace JSC { #endif int8_t valueGPR; int8_t scratchGPR; - int16_t deltaCallToDone; - int16_t deltaCallToStructCheck; - int16_t deltaCallToSlowCase; - int16_t deltaCheckImmToCall; + int32_t deltaCallToDone; + int32_t deltaCallToStructCheck; + int32_t deltaCallToSlowCase; + int32_t deltaCheckImmToCall; #if USE(JSVALUE64) - int16_t deltaCallToLoadOrStore; + int32_t deltaCallToLoadOrStore; #else - int16_t deltaCallToTagLoadOrStore; - int16_t deltaCallToPayloadLoadOrStore; + int32_t deltaCallToTagLoadOrStore; + int32_t deltaCallToPayloadLoadOrStore; #endif } dfg; struct { diff --git a/Source/JavaScriptCore/bytecode/ValueRecovery.h b/Source/JavaScriptCore/bytecode/ValueRecovery.h index 007c6d3b7..ebca661d0 100644 --- a/Source/JavaScriptCore/bytecode/ValueRecovery.h +++ b/Source/JavaScriptCore/bytecode/ValueRecovery.h @@ -61,6 +61,8 @@ enum ValueRecoveryTechnique { DoubleDisplacedInRegisterFile, CellDisplacedInRegisterFile, BooleanDisplacedInRegisterFile, + // It's an Arguments object. + ArgumentsThatWereNotCreated, // It's a constant. Constant, // Don't know how to recover it. @@ -190,6 +192,13 @@ public: return result; } + static ValueRecovery argumentsThatWereNotCreated() + { + ValueRecovery result; + result.m_technique = ArgumentsThatWereNotCreated; + return result; + } + ValueRecoveryTechnique technique() const { return m_technique; } bool isConstant() const { return m_technique == Constant; } @@ -315,6 +324,9 @@ public: case BooleanDisplacedInRegisterFile: fprintf(out, "*bool(%d)", virtualRegister()); break; + case ArgumentsThatWereNotCreated: + fprintf(out, "arguments"); + break; case Constant: fprintf(out, "[%s]", constant().description()); break; |