diff options
Diffstat (limited to 'Source/JavaScriptCore/bytecode')
23 files changed, 801 insertions, 312 deletions
diff --git a/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp b/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp new file mode 100644 index 000000000..aa682da86 --- /dev/null +++ b/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp @@ -0,0 +1,40 @@ +/* + * 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 "ArrayAllocationProfile.h" + +namespace JSC { + +void ArrayAllocationProfile::updateIndexingType() +{ + if (!m_lastArray) + return; + m_currentIndexingType = leastUpperBoundOfIndexingTypes(m_currentIndexingType, m_lastArray->structure()->indexingType()); + m_lastArray = 0; +} + +} // namespace JSC + diff --git a/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h b/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h new file mode 100644 index 000000000..a1647fad4 --- /dev/null +++ b/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h @@ -0,0 +1,80 @@ +/* + * 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 ArrayAllocationProfile_h +#define ArrayAllocationProfile_h + +#include "IndexingType.h" +#include "JSArray.h" + +namespace JSC { + +class ArrayAllocationProfile { +public: + ArrayAllocationProfile() + : m_currentIndexingType(ArrayWithUndecided) + , m_lastArray(0) + { + } + + IndexingType selectIndexingType() + { + if (m_lastArray && UNLIKELY(m_lastArray->structure()->indexingType() != m_currentIndexingType)) + updateIndexingType(); + return m_currentIndexingType; + } + + JSArray* updateLastAllocation(JSArray* lastArray) + { + m_lastArray = lastArray; + return lastArray; + } + + JS_EXPORT_PRIVATE void updateIndexingType(); + + static IndexingType selectIndexingTypeFor(ArrayAllocationProfile* profile) + { + if (!profile) + return ArrayWithUndecided; + return profile->selectIndexingType(); + } + + static JSArray* updateLastAllocationFor(ArrayAllocationProfile* profile, JSArray* lastArray) + { + if (profile) + profile->updateLastAllocation(lastArray); + return lastArray; + } + +private: + + IndexingType m_currentIndexingType; + JSArray* m_lastArray; +}; + +} // namespace JSC + +#endif // ArrayAllocationProfile_h + diff --git a/Source/JavaScriptCore/bytecode/ArrayProfile.cpp b/Source/JavaScriptCore/bytecode/ArrayProfile.cpp index 5a87380fd..51baf332f 100644 --- a/Source/JavaScriptCore/bytecode/ArrayProfile.cpp +++ b/Source/JavaScriptCore/bytecode/ArrayProfile.cpp @@ -65,6 +65,13 @@ const char* arrayModesToString(ArrayModes arrayModes) return result; } +ArrayModes ArrayProfile::updatedObservedArrayModes() const +{ + if (m_lastSeenStructure) + return m_observedArrayModes | arrayModeFromStructure(m_lastSeenStructure); + return m_observedArrayModes; +} + void ArrayProfile::computeUpdatedPrediction(CodeBlock* codeBlock, OperationInProgress operation) { if (m_lastSeenStructure) { diff --git a/Source/JavaScriptCore/bytecode/ArrayProfile.h b/Source/JavaScriptCore/bytecode/ArrayProfile.h index 376684fc1..5116cd36f 100644 --- a/Source/JavaScriptCore/bytecode/ArrayProfile.h +++ b/Source/JavaScriptCore/bytecode/ArrayProfile.h @@ -45,15 +45,20 @@ typedef unsigned ArrayModes; #define ALL_NON_ARRAY_ARRAY_MODES \ (asArrayModes(NonArray) \ - | asArrayModes(NonArrayWithContiguous) \ - | asArrayModes(NonArrayWithArrayStorage) \ - | asArrayModes(NonArrayWithSlowPutArrayStorage)) + | asArrayModes(NonArrayWithInt32) \ + | asArrayModes(NonArrayWithDouble) \ + | asArrayModes(NonArrayWithContiguous) \ + | asArrayModes(NonArrayWithArrayStorage) \ + | asArrayModes(NonArrayWithSlowPutArrayStorage)) #define ALL_ARRAY_ARRAY_MODES \ (asArrayModes(ArrayClass) \ - | asArrayModes(ArrayWithContiguous) \ - | asArrayModes(ArrayWithArrayStorage) \ - | asArrayModes(ArrayWithSlowPutArrayStorage)) + | asArrayModes(ArrayWithUndecided) \ + | asArrayModes(ArrayWithInt32) \ + | asArrayModes(ArrayWithDouble) \ + | asArrayModes(ArrayWithContiguous) \ + | asArrayModes(ArrayWithArrayStorage) \ + | asArrayModes(ArrayWithSlowPutArrayStorage)) #define ALL_ARRAY_MODES (ALL_NON_ARRAY_ARRAY_MODES | ALL_ARRAY_ARRAY_MODES) @@ -79,6 +84,36 @@ inline bool arrayModesAlreadyChecked(ArrayModes proven, ArrayModes expected) return (expected | proven) == expected; } +inline bool arrayModesInclude(ArrayModes arrayModes, IndexingType shape) +{ + return !!(arrayModes & (asArrayModes(NonArray | shape) | asArrayModes(ArrayClass | shape))); +} + +inline bool shouldUseSlowPutArrayStorage(ArrayModes arrayModes) +{ + return arrayModesInclude(arrayModes, SlowPutArrayStorageShape); +} + +inline bool shouldUseFastArrayStorage(ArrayModes arrayModes) +{ + return arrayModesInclude(arrayModes, ArrayStorageShape); +} + +inline bool shouldUseContiguous(ArrayModes arrayModes) +{ + return arrayModesInclude(arrayModes, ContiguousShape); +} + +inline bool shouldUseDouble(ArrayModes arrayModes) +{ + return arrayModesInclude(arrayModes, DoubleShape); +} + +inline bool shouldUseInt32(ArrayModes arrayModes) +{ + return arrayModesInclude(arrayModes, Int32Shape); +} + class ArrayProfile { public: ArrayProfile() @@ -128,6 +163,7 @@ public: return !structureIsPolymorphic() && m_expectedStructure; } ArrayModes observedArrayModes() const { return m_observedArrayModes; } + ArrayModes updatedObservedArrayModes() const; // Computes the observed array modes without updating the profile. bool mayInterceptIndexedAccesses() const { return m_mayInterceptIndexedAccesses; } bool mayStoreToHole() const { return m_mayStoreToHole; } diff --git a/Source/JavaScriptCore/bytecode/ByValInfo.h b/Source/JavaScriptCore/bytecode/ByValInfo.h index 8cba4463d..3f79967df 100644 --- a/Source/JavaScriptCore/bytecode/ByValInfo.h +++ b/Source/JavaScriptCore/bytecode/ByValInfo.h @@ -39,6 +39,8 @@ namespace JSC { enum JITArrayMode { + JITInt32, + JITDouble, JITContiguous, JITArrayStorage, JITInt8Array, @@ -55,6 +57,8 @@ enum JITArrayMode { inline bool isOptimizableIndexingType(IndexingType indexingType) { switch (indexingType) { + case ALL_INT32_INDEXING_TYPES: + case ALL_DOUBLE_INDEXING_TYPES: case ALL_CONTIGUOUS_INDEXING_TYPES: case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: return true; @@ -77,6 +81,10 @@ inline bool hasOptimizableIndexing(Structure* structure) inline JITArrayMode jitArrayModeForIndexingType(IndexingType indexingType) { switch (indexingType) { + case ALL_INT32_INDEXING_TYPES: + return JITInt32; + case ALL_DOUBLE_INDEXING_TYPES: + return JITDouble; case ALL_CONTIGUOUS_INDEXING_TYPES: return JITContiguous; case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: diff --git a/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp b/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp index 4933a494c..762dca12a 100644 --- a/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp +++ b/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp @@ -37,6 +37,7 @@ void CallLinkInfo::unlink(JSGlobalData& globalData, RepatchBuffer& repatchBuffer { ASSERT(isLinked()); + repatchBuffer.revertJumpReplacementToBranchPtrWithPatch(RepatchBuffer::startOfBranchPtrWithPatchOnRegister(hotPathBegin), static_cast<MacroAssembler::RegisterID>(calleeGPR), 0); if (isDFG) { #if ENABLE(DFG_JIT) repatchBuffer.relink(callReturnLocation, (callType == Construct ? globalData.getCTIStub(DFG::linkConstructThunkGenerator) : globalData.getCTIStub(DFG::linkCallThunkGenerator)).code()); @@ -47,6 +48,7 @@ void CallLinkInfo::unlink(JSGlobalData& globalData, RepatchBuffer& repatchBuffer repatchBuffer.relink(callReturnLocation, callType == Construct ? globalData.jitStubs->ctiVirtualConstructLink() : globalData.jitStubs->ctiVirtualCallLink()); hasSeenShouldRepatch = false; callee.clear(); + stub.clear(); // It will be on a list if the callee has a code block. if (isOnList()) diff --git a/Source/JavaScriptCore/bytecode/CallLinkInfo.h b/Source/JavaScriptCore/bytecode/CallLinkInfo.h index 4a78e5d02..89403b0ca 100644 --- a/Source/JavaScriptCore/bytecode/CallLinkInfo.h +++ b/Source/JavaScriptCore/bytecode/CallLinkInfo.h @@ -26,6 +26,7 @@ #ifndef CallLinkInfo_h #define CallLinkInfo_h +#include "ClosureCallStubRoutine.h" #include "CodeLocation.h" #include "JITWriteBarrier.h" #include "JSFunction.h" @@ -70,12 +71,14 @@ struct CallLinkInfo : public BasicRawSentinelNode<CallLinkInfo> { CodeLocationNearCall hotPathOther; JITWriteBarrier<JSFunction> callee; WriteBarrier<JSFunction> lastSeenCallee; + RefPtr<ClosureCallStubRoutine> stub; bool hasSeenShouldRepatch : 1; bool isDFG : 1; CallType callType : 6; - unsigned bytecodeIndex; + unsigned calleeGPR : 8; + CodeOrigin codeOrigin; - bool isLinked() { return callee; } + bool isLinked() { return stub || callee; } void unlink(JSGlobalData&, RepatchBuffer&); bool seenOnce() @@ -96,7 +99,7 @@ inline void* getCallLinkInfoReturnLocation(CallLinkInfo* callLinkInfo) inline unsigned getCallLinkInfoBytecodeIndex(CallLinkInfo* callLinkInfo) { - return callLinkInfo->bytecodeIndex; + return callLinkInfo->codeOrigin.bytecodeIndex; } #endif // ENABLE(JIT) diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp index 5686d5d2c..206d281a2 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp @@ -32,6 +32,7 @@ #include "BytecodeGenerator.h" #include "DFGCapabilities.h" +#include "DFGCommon.h" #include "DFGNode.h" #include "DFGRepatch.h" #include "Debugger.h" @@ -44,7 +45,7 @@ #include "JSValue.h" #include "LowLevelInterpreter.h" #include "RepatchBuffer.h" -#include "SlotVisitorInlineMethods.h" +#include "SlotVisitorInlines.h" #include <stdio.h> #include <wtf/StringExtras.h> #include <wtf/UnusedParam.h> @@ -98,11 +99,11 @@ void CodeBlock::dumpBytecodeCommentAndNewLine(int location) #if ENABLE(BYTECODE_COMMENTS) const char* comment = commentForBytecodeOffset(location); if (comment) - dataLog("\t\t ; %s", comment); + dataLogF("\t\t ; %s", comment); #else UNUSED_PARAM(location); #endif - dataLog("\n"); + dataLogF("\n"); } CString CodeBlock::registerName(ExecState* exec, int r) const @@ -163,33 +164,33 @@ NEVER_INLINE static const char* debugHookName(int debugHookID) return ""; } -void CodeBlock::printUnaryOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) +void CodeBlock::printUnaryOp(ExecState* exec, int location, const Instruction*& it, const char* op) { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; - dataLog("[%4d] %s\t\t %s, %s", location, op, registerName(exec, r0).data(), registerName(exec, r1).data()); + dataLogF("[%4d] %s\t\t %s, %s", location, op, registerName(exec, r0).data(), registerName(exec, r1).data()); dumpBytecodeCommentAndNewLine(location); } -void CodeBlock::printBinaryOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) +void CodeBlock::printBinaryOp(ExecState* exec, int location, const Instruction*& it, const char* op) { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int r2 = (++it)->u.operand; - dataLog("[%4d] %s\t\t %s, %s, %s", location, op, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); + dataLogF("[%4d] %s\t\t %s, %s, %s", location, op, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); dumpBytecodeCommentAndNewLine(location); } -void CodeBlock::printConditionalJump(ExecState* exec, const Vector<Instruction>::const_iterator&, Vector<Instruction>::const_iterator& it, int location, const char* op) +void CodeBlock::printConditionalJump(ExecState* exec, const Instruction*, const Instruction*& it, int location, const char* op) { int r0 = (++it)->u.operand; int offset = (++it)->u.operand; - dataLog("[%4d] %s\t\t %s, %d(->%d)", location, op, registerName(exec, r0).data(), offset, location + offset); + dataLogF("[%4d] %s\t\t %s, %d(->%d)", location, op, registerName(exec, r0).data(), offset, location + offset); dumpBytecodeCommentAndNewLine(location); } -void CodeBlock::printGetByIdOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it) +void CodeBlock::printGetByIdOp(ExecState* exec, int location, const Instruction*& it) { const char* op; switch (exec->interpreter()->getOpcodeID(it->u.opcode)) { @@ -242,7 +243,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; - dataLog("[%4d] %s\t %s, %s, %s", location, op, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data()); + dataLogF("[%4d] %s\t %s, %s, %s", location, op, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data()); it += 5; } @@ -252,18 +253,18 @@ static void dumpStructure(const char* name, ExecState* exec, Structure* structur if (!structure) return; - dataLog("%s = %p", name, structure); + dataLogF("%s = %p", name, structure); PropertyOffset offset = structure->get(exec->globalData(), ident); if (offset != invalidOffset) - dataLog(" (offset = %d)", offset); + dataLogF(" (offset = %d)", offset); } #endif #if ENABLE(JIT) // unused when not ENABLE(JIT), leading to silly warnings static void dumpChain(ExecState* exec, StructureChain* chain, Identifier& ident) { - dataLog("chain = %p: [", chain); + dataLogF("chain = %p: [", chain); bool first = true; for (WriteBarrier<Structure>* currentStructure = chain->head(); *currentStructure; @@ -271,10 +272,10 @@ static void dumpChain(ExecState* exec, StructureChain* chain, Identifier& ident) if (first) first = false; else - dataLog(", "); + dataLogF(", "); dumpStructure("struct", exec, currentStructure->get(), ident); } - dataLog("]"); + dataLogF("]"); } #endif @@ -288,21 +289,21 @@ void CodeBlock::printGetByIdCacheStatus(ExecState* exec, int location) #if ENABLE(LLINT) if (exec->interpreter()->getOpcodeID(instruction[0].u.opcode) == op_get_array_length) - dataLog(" llint(array_length)"); + dataLogF(" llint(array_length)"); else { Structure* structure = instruction[4].u.structure.get(); - dataLog(" llint("); + dataLogF(" llint("); dumpStructure("struct", exec, structure, ident); - dataLog(")"); + dataLogF(")"); } #endif #if ENABLE(JIT) if (numberOfStructureStubInfos()) { - dataLog(" jit("); + dataLogF(" jit("); StructureStubInfo& stubInfo = getStubInfo(location); if (!stubInfo.seen) - dataLog("not seen"); + dataLogF("not seen"); else { Structure* baseStructure = 0; Structure* prototypeStructure = 0; @@ -312,40 +313,40 @@ void CodeBlock::printGetByIdCacheStatus(ExecState* exec, int location) switch (stubInfo.accessType) { case access_get_by_id_self: - dataLog("self"); + dataLogF("self"); baseStructure = stubInfo.u.getByIdSelf.baseObjectStructure.get(); break; case access_get_by_id_proto: - dataLog("proto"); + dataLogF("proto"); baseStructure = stubInfo.u.getByIdProto.baseObjectStructure.get(); prototypeStructure = stubInfo.u.getByIdProto.prototypeStructure.get(); break; case access_get_by_id_chain: - dataLog("chain"); + dataLogF("chain"); baseStructure = stubInfo.u.getByIdChain.baseObjectStructure.get(); chain = stubInfo.u.getByIdChain.chain.get(); break; case access_get_by_id_self_list: - dataLog("self_list"); + dataLogF("self_list"); structureList = stubInfo.u.getByIdSelfList.structureList; listSize = stubInfo.u.getByIdSelfList.listSize; break; case access_get_by_id_proto_list: - dataLog("proto_list"); + dataLogF("proto_list"); structureList = stubInfo.u.getByIdProtoList.structureList; listSize = stubInfo.u.getByIdProtoList.listSize; break; case access_unset: - dataLog("unset"); + dataLogF("unset"); break; case access_get_by_id_generic: - dataLog("generic"); + dataLogF("generic"); break; case access_get_array_length: - dataLog("array_length"); + dataLogF("array_length"); break; case access_get_string_length: - dataLog("string_length"); + dataLogF("string_length"); break; default: ASSERT_NOT_REACHED(); @@ -353,71 +354,71 @@ void CodeBlock::printGetByIdCacheStatus(ExecState* exec, int location) } if (baseStructure) { - dataLog(", "); + dataLogF(", "); dumpStructure("struct", exec, baseStructure, ident); } if (prototypeStructure) { - dataLog(", "); + dataLogF(", "); dumpStructure("prototypeStruct", exec, baseStructure, ident); } if (chain) { - dataLog(", "); + dataLogF(", "); dumpChain(exec, chain, ident); } if (structureList) { - dataLog(", list = %p: [", structureList); + dataLogF(", list = %p: [", structureList); for (int i = 0; i < listSize; ++i) { if (i) - dataLog(", "); - dataLog("("); + dataLogF(", "); + dataLogF("("); dumpStructure("base", exec, structureList->list[i].base.get(), ident); if (structureList->list[i].isChain) { if (structureList->list[i].u.chain.get()) { - dataLog(", "); + dataLogF(", "); dumpChain(exec, structureList->list[i].u.chain.get(), ident); } } else { if (structureList->list[i].u.proto.get()) { - dataLog(", "); + dataLogF(", "); dumpStructure("proto", exec, structureList->list[i].u.proto.get(), ident); } } - dataLog(")"); + dataLogF(")"); } - dataLog("]"); + dataLogF("]"); } } - dataLog(")"); + dataLogF(")"); } #endif } -void CodeBlock::printCallOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op, CacheDumpMode cacheDumpMode) +void CodeBlock::printCallOp(ExecState* exec, int location, const Instruction*& 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", location, op, registerName(exec, func).data(), argCount, registerOffset); + dataLogF("[%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)", + dataLogF(" llint(%p, exec %p)", callLinkInfo->lastSeenCallee.get(), callLinkInfo->lastSeenCallee->executable()); } else - dataLog(" llint(not set)"); + dataLogF(" 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()); + dataLogF(" jit(%p, exec %p)", target, target->executable()); else - dataLog(" jit(not set)"); + dataLogF(" jit(not set)"); } #endif } @@ -425,12 +426,12 @@ void CodeBlock::printCallOp(ExecState* exec, int location, Vector<Instruction>:: it += 2; } -void CodeBlock::printPutByIdOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) +void CodeBlock::printPutByIdOp(ExecState* exec, int location, const Instruction*& it, const char* op) { int r0 = (++it)->u.operand; int id0 = (++it)->u.operand; int r1 = (++it)->u.operand; - dataLog("[%4d] %s\t %s, %s, %s", location, op, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data()); + dataLogF("[%4d] %s\t %s, %s, %s", location, op, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data()); dumpBytecodeCommentAndNewLine(location); it += 5; } @@ -438,7 +439,7 @@ void CodeBlock::printPutByIdOp(ExecState* exec, int location, Vector<Instruction 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()); + dataLogF(" [%4d] %s: %s\n", instructionOffset, name, pointerToSourceString(vPC[operand].u.structure).utf8().data()); } void CodeBlock::printStructures(const Instruction* vPC) @@ -455,15 +456,15 @@ void CodeBlock::printStructures(const Instruction* vPC) return; } if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto)) { - 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()); + dataLogF(" [%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)) { - 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()); + dataLogF(" [%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)) { - 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()); + dataLogF(" [%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)) { @@ -479,99 +480,103 @@ void CodeBlock::printStructures(const Instruction* vPC) 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) +void CodeBlock::dump() { + // We only use the ExecState* for things that don't actually lead to JS execution, + // like converting a JSString to a String. Hence the globalExec is appropriate. + ExecState* exec = m_globalObject->globalExec(); + size_t instructionCount = 0; for (size_t i = 0; i < instructions().size(); i += opcodeLengths[exec->interpreter()->getOpcodeID(instructions()[i].u.opcode)]) ++instructionCount; - dataLog( + dataLogF( "%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, codeTypeToString(codeType()), m_numParameters, m_numCalleeRegisters, m_numVars); if (symbolTable()->captureCount()) - dataLog("; %d captured var(s)", symbolTable()->captureCount()); + dataLogF("; %d captured var(s)", symbolTable()->captureCount()); if (usesArguments()) { - dataLog( + dataLogF( "; uses arguments, in r%d, r%d", argumentsRegister(), unmodifiedArgumentsRegister(argumentsRegister())); } if (needsFullScopeChain() && codeType() == FunctionCode) - dataLog("; activation in r%d", activationRegister()); - dataLog("\n\n"); + dataLogF("; activation in r%d", activationRegister()); + dataLogF("\n\n"); - Vector<Instruction>::const_iterator begin = instructions().begin(); - Vector<Instruction>::const_iterator end = instructions().end(); - for (Vector<Instruction>::const_iterator it = begin; it != end; ++it) + const Instruction* begin = instructions().begin(); + const Instruction* end = instructions().end(); + for (const Instruction* it = begin; it != end; ++it) dump(exec, begin, it); if (!m_identifiers.isEmpty()) { - dataLog("\nIdentifiers:\n"); + dataLogF("\nIdentifiers:\n"); size_t i = 0; do { - dataLog(" id%u = %s\n", static_cast<unsigned>(i), m_identifiers[i].string().utf8().data()); + dataLogF(" id%u = %s\n", static_cast<unsigned>(i), m_identifiers[i].string().utf8().data()); ++i; } while (i != m_identifiers.size()); } if (!m_constantRegisters.isEmpty()) { - dataLog("\nConstants:\n"); + dataLogF("\nConstants:\n"); size_t i = 0; do { - dataLog(" k%u = %s\n", static_cast<unsigned>(i), valueToSourceString(exec, m_constantRegisters[i].get()).utf8().data()); + dataLogF(" k%u = %s\n", static_cast<unsigned>(i), valueToSourceString(exec, m_constantRegisters[i].get()).utf8().data()); ++i; } while (i < m_constantRegisters.size()); } if (size_t count = m_unlinkedCode->numberOfRegExps()) { - dataLog("\nm_regexps:\n"); + dataLogF("\nm_regexps:\n"); size_t i = 0; do { - dataLog(" re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(m_unlinkedCode->regexp(i)).utf8().data()); + dataLogF(" re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(m_unlinkedCode->regexp(i)).utf8().data()); ++i; } while (i < count); } #if ENABLE(JIT) if (!m_structureStubInfos.isEmpty()) - dataLog("\nStructures:\n"); + dataLogF("\nStructures:\n"); #endif if (m_rareData && !m_rareData->m_exceptionHandlers.isEmpty()) { - dataLog("\nException Handlers:\n"); + dataLogF("\nException Handlers:\n"); unsigned i = 0; do { - 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); + dataLogF("\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()) { - dataLog("Immediate Switch Jump Tables:\n"); + dataLogF("Immediate Switch Jump Tables:\n"); unsigned i = 0; do { - dataLog(" %1d = {\n", i); + dataLogF(" %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; - dataLog("\t\t%4d => %04d\n", entry + m_rareData->m_immediateSwitchJumpTables[i].min, *iter); + dataLogF("\t\t%4d => %04d\n", entry + m_rareData->m_immediateSwitchJumpTables[i].min, *iter); } - dataLog(" }\n"); + dataLogF(" }\n"); ++i; } while (i < m_rareData->m_immediateSwitchJumpTables.size()); } if (m_rareData && !m_rareData->m_characterSwitchJumpTables.isEmpty()) { - dataLog("\nCharacter Switch Jump Tables:\n"); + dataLogF("\nCharacter Switch Jump Tables:\n"); unsigned i = 0; do { - dataLog(" %1d = {\n", i); + dataLogF(" %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) { @@ -579,72 +584,79 @@ void CodeBlock::dump(ExecState* exec) continue; ASSERT(!((i + m_rareData->m_characterSwitchJumpTables[i].min) & ~0xFFFF)); UChar ch = static_cast<UChar>(entry + m_rareData->m_characterSwitchJumpTables[i].min); - dataLog("\t\t\"%s\" => %04d\n", String(&ch, 1).utf8().data(), *iter); + dataLogF("\t\t\"%s\" => %04d\n", String(&ch, 1).utf8().data(), *iter); } - dataLog(" }\n"); + dataLogF(" }\n"); ++i; } while (i < m_rareData->m_characterSwitchJumpTables.size()); } if (m_rareData && !m_rareData->m_stringSwitchJumpTables.isEmpty()) { - dataLog("\nString Switch Jump Tables:\n"); + dataLogF("\nString Switch Jump Tables:\n"); unsigned i = 0; do { - dataLog(" %1d = {\n", i); + dataLogF(" %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) - dataLog("\t\t\"%s\" => %04d\n", String(iter->key).utf8().data(), iter->value.branchOffset); - dataLog(" }\n"); + dataLogF("\t\t\"%s\" => %04d\n", String(iter->key).utf8().data(), iter->value.branchOffset); + dataLogF(" }\n"); ++i; } while (i < m_rareData->m_stringSwitchJumpTables.size()); } - dataLog("\n"); + dataLogF("\n"); } -void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it) +void CodeBlock::dump(ExecState* exec, const Instruction* begin, const Instruction*& it) { int location = it - begin; switch (exec->interpreter()->getOpcodeID(it->u.opcode)) { case op_enter: { - dataLog("[%4d] enter", location); + dataLogF("[%4d] enter", location); dumpBytecodeCommentAndNewLine(location); break; } case op_create_activation: { int r0 = (++it)->u.operand; - dataLog("[%4d] create_activation %s", location, registerName(exec, r0).data()); + dataLogF("[%4d] create_activation %s", location, registerName(exec, r0).data()); dumpBytecodeCommentAndNewLine(location); break; } case op_create_arguments: { int r0 = (++it)->u.operand; - dataLog("[%4d] create_arguments\t %s", location, registerName(exec, r0).data()); + dataLogF("[%4d] create_arguments\t %s", location, registerName(exec, r0).data()); dumpBytecodeCommentAndNewLine(location); break; } case op_init_lazy_reg: { int r0 = (++it)->u.operand; - dataLog("[%4d] init_lazy_reg\t %s", location, registerName(exec, r0).data()); + dataLogF("[%4d] init_lazy_reg\t %s", location, registerName(exec, r0).data()); dumpBytecodeCommentAndNewLine(location); break; } + case op_get_callee: { + int r0 = (++it)->u.operand; + dataLogF("[%4d] op_get_callee %s\n", location, registerName(exec, r0).data()); + ++it; + break; + } case op_create_this: { int r0 = (++it)->u.operand; - dataLog("[%4d] create_this %s", location, registerName(exec, r0).data()); + int r1 = (++it)->u.operand; + dataLogF("[%4d] create_this %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data()); dumpBytecodeCommentAndNewLine(location); break; } case op_convert_this: { int r0 = (++it)->u.operand; - dataLog("[%4d] convert_this\t %s", location, registerName(exec, r0).data()); + dataLogF("[%4d] convert_this\t %s", location, registerName(exec, r0).data()); dumpBytecodeCommentAndNewLine(location); ++it; // Skip value profile. break; } case op_new_object: { int r0 = (++it)->u.operand; - dataLog("[%4d] new_object\t %s", location, registerName(exec, r0).data()); + dataLogF("[%4d] new_object\t %s", location, registerName(exec, r0).data()); dumpBytecodeCommentAndNewLine(location); break; } @@ -652,40 +664,43 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int dst = (++it)->u.operand; int argv = (++it)->u.operand; int argc = (++it)->u.operand; - dataLog("[%4d] new_array\t %s, %s, %d", location, registerName(exec, dst).data(), registerName(exec, argv).data(), argc); + dataLogF("[%4d] new_array\t %s, %s, %d", location, registerName(exec, dst).data(), registerName(exec, argv).data(), argc); dumpBytecodeCommentAndNewLine(location); + ++it; // Skip array allocation profile. break; } case op_new_array_with_size: { int dst = (++it)->u.operand; int length = (++it)->u.operand; - dataLog("[%4d] new_array_with_size\t %s, %s", location, registerName(exec, dst).data(), registerName(exec, length).data()); + dataLogF("[%4d] new_array_with_size\t %s, %s", location, registerName(exec, dst).data(), registerName(exec, length).data()); dumpBytecodeCommentAndNewLine(location); + ++it; // Skip array allocation profile. break; } case op_new_array_buffer: { int dst = (++it)->u.operand; int argv = (++it)->u.operand; int argc = (++it)->u.operand; - dataLog("[%4d] new_array_buffer\t %s, %d, %d", location, registerName(exec, dst).data(), argv, argc); + dataLogF("[%4d] new_array_buffer\t %s, %d, %d", location, registerName(exec, dst).data(), argv, argc); dumpBytecodeCommentAndNewLine(location); + ++it; // Skip array allocation profile. break; } case op_new_regexp: { int r0 = (++it)->u.operand; int re0 = (++it)->u.operand; - dataLog("[%4d] new_regexp\t %s, ", location, registerName(exec, r0).data()); + dataLogF("[%4d] new_regexp\t %s, ", location, registerName(exec, r0).data()); if (r0 >=0 && r0 < (int)m_unlinkedCode->numberOfRegExps()) - dataLog("%s", regexpName(re0, regexp(re0)).data()); + dataLogF("%s", regexpName(re0, regexp(re0)).data()); else - dataLog("bad_regexp(%d)", re0); + dataLogF("bad_regexp(%d)", re0); dumpBytecodeCommentAndNewLine(location); break; } case op_mov: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; - dataLog("[%4d] mov\t\t %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data()); + dataLogF("[%4d] mov\t\t %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data()); dumpBytecodeCommentAndNewLine(location); break; } @@ -735,13 +750,13 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& } case op_pre_inc: { int r0 = (++it)->u.operand; - dataLog("[%4d] pre_inc\t\t %s", location, registerName(exec, r0).data()); + dataLogF("[%4d] pre_inc\t\t %s", location, registerName(exec, r0).data()); dumpBytecodeCommentAndNewLine(location); break; } case op_pre_dec: { int r0 = (++it)->u.operand; - dataLog("[%4d] pre_dec\t\t %s", location, registerName(exec, r0).data()); + dataLogF("[%4d] pre_dec\t\t %s", location, registerName(exec, r0).data()); dumpBytecodeCommentAndNewLine(location); break; } @@ -817,7 +832,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r1 = (++it)->u.operand; int r2 = (++it)->u.operand; int offset = (++it)->u.operand; - dataLog("[%4d] check_has_instance\t\t %s, %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data(), offset, location + offset); + dataLogF("[%4d] check_has_instance\t\t %s, %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data(), offset, location + offset); dumpBytecodeCommentAndNewLine(location); break; } @@ -825,7 +840,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; - dataLog("[%4d] instanceof\t\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); + dataLogF("[%4d] instanceof\t\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); dumpBytecodeCommentAndNewLine(location); break; } @@ -867,7 +882,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int id0 = (++it)->u.operand; int value = (++it)->u.operand; int resolveInfo = (++it)->u.operand; - dataLog("[%4d] put_to_base\t %s, %s, %s, %d", location, registerName(exec, base).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, value).data(), resolveInfo); + dataLogF("[%4d] put_to_base\t %s, %s, %s, %d", location, registerName(exec, base).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, value).data(), resolveInfo); dumpBytecodeCommentAndNewLine(location); break; } @@ -880,13 +895,13 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r0 = (++it)->u.operand; int id0 = (++it)->u.operand; int resolveInfo = (++it)->u.operand; - dataLog("[%4d] resolve\t\t %s, %s, %d", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo); + dataLogF("[%4d] resolve\t\t %s, %s, %d", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo); dumpBytecodeCommentAndNewLine(location); it++; break; } case op_init_global_const_nop: { - dataLog("[%4d] init_global_const_nop\t", location); + dataLogF("[%4d] init_global_const_nop\t", location); dumpBytecodeCommentAndNewLine(location); it++; it++; @@ -897,7 +912,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& case op_init_global_const: { WriteBarrier<Unknown>* registerPointer = (++it)->u.registerPointer; int r0 = (++it)->u.operand; - dataLog("[%4d] init_global_const\t g%d(%p), %s", location, m_globalObject->findRegisterIndex(registerPointer), registerPointer, registerName(exec, r0).data()); + dataLogF("[%4d] init_global_const\t g%d(%p), %s", location, m_globalObject->findRegisterIndex(registerPointer), registerPointer, registerName(exec, r0).data()); dumpBytecodeCommentAndNewLine(location); it++; it++; @@ -906,7 +921,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& case op_init_global_const_check: { WriteBarrier<Unknown>* registerPointer = (++it)->u.registerPointer; int r0 = (++it)->u.operand; - dataLog("[%4d] init_global_const_check\t g%d(%p), %s", location, m_globalObject->findRegisterIndex(registerPointer), registerPointer, registerName(exec, r0).data()); + dataLogF("[%4d] init_global_const_check\t g%d(%p), %s", location, m_globalObject->findRegisterIndex(registerPointer), registerPointer, registerName(exec, r0).data()); dumpBytecodeCommentAndNewLine(location); it++; it++; @@ -922,7 +937,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int isStrict = (++it)->u.operand; int resolveInfo = (++it)->u.operand; int putToBaseInfo = (++it)->u.operand; - dataLog("[%4d] resolve_base%s\t %s, %s, %d, %d", location, isStrict ? "_strict" : "", registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo, putToBaseInfo); + dataLogF("[%4d] resolve_base%s\t %s, %s, %d, %d", location, isStrict ? "_strict" : "", registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo, putToBaseInfo); dumpBytecodeCommentAndNewLine(location); it++; break; @@ -930,7 +945,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& case op_ensure_property_exists: { int r0 = (++it)->u.operand; int id0 = (++it)->u.operand; - dataLog("[%4d] ensure_property_exists\t %s, %s", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data()); + dataLogF("[%4d] ensure_property_exists\t %s, %s", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data()); dumpBytecodeCommentAndNewLine(location); break; } @@ -940,7 +955,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int id0 = (++it)->u.operand; int resolveInfo = (++it)->u.operand; int putToBaseInfo = (++it)->u.operand; - dataLog("[%4d] resolve_with_base %s, %s, %s, %d, %d", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo, putToBaseInfo); + dataLogF("[%4d] resolve_with_base %s, %s, %s, %d, %d", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo, putToBaseInfo); dumpBytecodeCommentAndNewLine(location); it++; break; @@ -950,7 +965,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r1 = (++it)->u.operand; int id0 = (++it)->u.operand; int resolveInfo = (++it)->u.operand; - dataLog("[%4d] resolve_with_this %s, %s, %s, %d", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo); + dataLogF("[%4d] resolve_with_this %s, %s, %s, %d", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo); dumpBytecodeCommentAndNewLine(location); it++; break; @@ -1020,7 +1035,7 @@ 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; - dataLog("[%4d] put_getter_setter\t %s, %s, %s, %s", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); + dataLogF("[%4d] put_getter_setter\t %s, %s, %s, %s", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); dumpBytecodeCommentAndNewLine(location); break; } @@ -1028,7 +1043,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; - dataLog("[%4d] del_by_id\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data()); + dataLogF("[%4d] del_by_id\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data()); dumpBytecodeCommentAndNewLine(location); break; } @@ -1036,7 +1051,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; - dataLog("[%4d] get_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); + dataLogF("[%4d] get_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); dumpBytecodeCommentAndNewLine(location); it++; it++; @@ -1046,7 +1061,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; - dataLog("[%4d] get_argument_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); + dataLogF("[%4d] get_argument_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); dumpBytecodeCommentAndNewLine(location); ++it; ++it; @@ -1059,7 +1074,7 @@ 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; - dataLog("[%4d] get_by_pname\t %s, %s, %s, %s, %s, %s", 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()); + dataLogF("[%4d] get_by_pname\t %s, %s, %s, %s, %s, %s", 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()); dumpBytecodeCommentAndNewLine(location); break; } @@ -1067,7 +1082,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; - dataLog("[%4d] put_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); + dataLogF("[%4d] put_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); dumpBytecodeCommentAndNewLine(location); ++it; break; @@ -1076,7 +1091,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; - dataLog("[%4d] del_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); + dataLogF("[%4d] del_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); dumpBytecodeCommentAndNewLine(location); break; } @@ -1084,19 +1099,19 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r0 = (++it)->u.operand; unsigned n0 = (++it)->u.operand; int r1 = (++it)->u.operand; - dataLog("[%4d] put_by_index\t %s, %u, %s", location, registerName(exec, r0).data(), n0, registerName(exec, r1).data()); + dataLogF("[%4d] put_by_index\t %s, %u, %s", location, registerName(exec, r0).data(), n0, registerName(exec, r1).data()); dumpBytecodeCommentAndNewLine(location); break; } case op_jmp: { int offset = (++it)->u.operand; - dataLog("[%4d] jmp\t\t %d(->%d)", location, offset, location + offset); + dataLogF("[%4d] jmp\t\t %d(->%d)", location, offset, location + offset); dumpBytecodeCommentAndNewLine(location); break; } case op_loop: { int offset = (++it)->u.operand; - dataLog("[%4d] loop\t\t %d(->%d)", location, offset, location + offset); + dataLogF("[%4d] loop\t\t %d(->%d)", location, offset, location + offset); dumpBytecodeCommentAndNewLine(location); break; } @@ -1128,7 +1143,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r0 = (++it)->u.operand; Special::Pointer pointer = (++it)->u.specialPointer; int offset = (++it)->u.operand; - dataLog("[%4d] jneq_ptr\t\t %s, %d (%p), %d(->%d)", location, registerName(exec, r0).data(), pointer, m_globalObject->actualPointerFor(pointer), offset, location + offset); + dataLogF("[%4d] jneq_ptr\t\t %s, %d (%p), %d(->%d)", location, registerName(exec, r0).data(), pointer, m_globalObject->actualPointerFor(pointer), offset, location + offset); dumpBytecodeCommentAndNewLine(location); break; } @@ -1136,7 +1151,7 @@ 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; - dataLog("[%4d] jless\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLogF("[%4d] jless\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); dumpBytecodeCommentAndNewLine(location); break; } @@ -1144,7 +1159,7 @@ 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; - dataLog("[%4d] jlesseq\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLogF("[%4d] jlesseq\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); dumpBytecodeCommentAndNewLine(location); break; } @@ -1152,7 +1167,7 @@ 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; - dataLog("[%4d] jgreater\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLogF("[%4d] jgreater\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); dumpBytecodeCommentAndNewLine(location); break; } @@ -1160,7 +1175,7 @@ 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; - dataLog("[%4d] jgreatereq\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLogF("[%4d] jgreatereq\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); dumpBytecodeCommentAndNewLine(location); break; } @@ -1168,7 +1183,7 @@ 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; - dataLog("[%4d] jnless\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLogF("[%4d] jnless\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); dumpBytecodeCommentAndNewLine(location); break; } @@ -1176,7 +1191,7 @@ 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; - dataLog("[%4d] jnlesseq\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLogF("[%4d] jnlesseq\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); dumpBytecodeCommentAndNewLine(location); break; } @@ -1184,7 +1199,7 @@ 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; - dataLog("[%4d] jngreater\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLogF("[%4d] jngreater\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); dumpBytecodeCommentAndNewLine(location); break; } @@ -1192,7 +1207,7 @@ 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; - dataLog("[%4d] jngreatereq\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLogF("[%4d] jngreatereq\t\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); dumpBytecodeCommentAndNewLine(location); break; } @@ -1200,7 +1215,7 @@ 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; - dataLog("[%4d] loop_if_less\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLogF("[%4d] loop_if_less\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); dumpBytecodeCommentAndNewLine(location); break; } @@ -1208,7 +1223,7 @@ 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; - dataLog("[%4d] loop_if_lesseq\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLogF("[%4d] loop_if_lesseq\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); dumpBytecodeCommentAndNewLine(location); break; } @@ -1216,7 +1231,7 @@ 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; - dataLog("[%4d] loop_if_greater\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLogF("[%4d] loop_if_greater\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); dumpBytecodeCommentAndNewLine(location); break; } @@ -1224,12 +1239,12 @@ 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; - dataLog("[%4d] loop_if_greatereq\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLogF("[%4d] loop_if_greatereq\t %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); dumpBytecodeCommentAndNewLine(location); break; } case op_loop_hint: { - dataLog("[%4d] loop_hint", location); + dataLogF("[%4d] loop_hint", location); dumpBytecodeCommentAndNewLine(location); break; } @@ -1237,7 +1252,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int tableIndex = (++it)->u.operand; int defaultTarget = (++it)->u.operand; int scrutineeRegister = (++it)->u.operand; - dataLog("[%4d] switch_imm\t %d, %d(->%d), %s", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data()); + dataLogF("[%4d] switch_imm\t %d, %d(->%d), %s", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data()); dumpBytecodeCommentAndNewLine(location); break; } @@ -1245,7 +1260,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int tableIndex = (++it)->u.operand; int defaultTarget = (++it)->u.operand; int scrutineeRegister = (++it)->u.operand; - dataLog("[%4d] switch_char\t %d, %d(->%d), %s", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data()); + dataLogF("[%4d] switch_char\t %d, %d(->%d), %s", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data()); dumpBytecodeCommentAndNewLine(location); break; } @@ -1253,7 +1268,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int tableIndex = (++it)->u.operand; int defaultTarget = (++it)->u.operand; int scrutineeRegister = (++it)->u.operand; - dataLog("[%4d] switch_string\t %d, %d(->%d), %s", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data()); + dataLogF("[%4d] switch_string\t %d, %d(->%d), %s", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data()); dumpBytecodeCommentAndNewLine(location); break; } @@ -1261,14 +1276,14 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r0 = (++it)->u.operand; int f0 = (++it)->u.operand; int shouldCheck = (++it)->u.operand; - dataLog("[%4d] new_func\t\t %s, f%d, %s", location, registerName(exec, r0).data(), f0, shouldCheck ? "<Checked>" : "<Unchecked>"); + dataLogF("[%4d] new_func\t\t %s, f%d, %s", location, registerName(exec, r0).data(), f0, shouldCheck ? "<Checked>" : "<Unchecked>"); dumpBytecodeCommentAndNewLine(location); break; } case op_new_func_exp: { int r0 = (++it)->u.operand; int f0 = (++it)->u.operand; - dataLog("[%4d] new_func_exp\t %s, f%d", location, registerName(exec, r0).data(), f0); + dataLogF("[%4d] new_func_exp\t %s, f%d", location, registerName(exec, r0).data(), f0); dumpBytecodeCommentAndNewLine(location); break; } @@ -1285,32 +1300,32 @@ 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; - dataLog("[%4d] call_varargs\t %s, %s, %s, %d", location, registerName(exec, callee).data(), registerName(exec, thisValue).data(), registerName(exec, arguments).data(), firstFreeRegister); + dataLogF("[%4d] call_varargs\t %s, %s, %s, %d", location, registerName(exec, callee).data(), registerName(exec, thisValue).data(), registerName(exec, arguments).data(), firstFreeRegister); dumpBytecodeCommentAndNewLine(location); break; } case op_tear_off_activation: { int r0 = (++it)->u.operand; - dataLog("[%4d] tear_off_activation\t %s", location, registerName(exec, r0).data()); + dataLogF("[%4d] tear_off_activation\t %s", location, registerName(exec, r0).data()); dumpBytecodeCommentAndNewLine(location); break; } case op_tear_off_arguments: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; - dataLog("[%4d] tear_off_arguments %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data()); + dataLogF("[%4d] tear_off_arguments %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data()); dumpBytecodeCommentAndNewLine(location); break; } case op_ret: { int r0 = (++it)->u.operand; - dataLog("[%4d] ret\t\t %s", location, registerName(exec, r0).data()); + dataLogF("[%4d] ret\t\t %s", location, registerName(exec, r0).data()); dumpBytecodeCommentAndNewLine(location); break; } case op_call_put_result: { int r0 = (++it)->u.operand; - dataLog("[%4d] call_put_result\t\t %s", location, registerName(exec, r0).data()); + dataLogF("[%4d] call_put_result\t\t %s", location, registerName(exec, r0).data()); dumpBytecodeCommentAndNewLine(location); it++; break; @@ -1318,7 +1333,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& case op_ret_object_or_this: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; - dataLog("[%4d] constructor_ret\t\t %s %s", location, registerName(exec, r0).data(), registerName(exec, r1).data()); + dataLogF("[%4d] constructor_ret\t\t %s %s", location, registerName(exec, r0).data(), registerName(exec, r1).data()); dumpBytecodeCommentAndNewLine(location); break; } @@ -1330,14 +1345,14 @@ 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; - dataLog("[%4d] strcat\t\t %s, %s, %d", location, registerName(exec, r0).data(), registerName(exec, r1).data(), count); + dataLogF("[%4d] strcat\t\t %s, %s, %d", location, registerName(exec, r0).data(), registerName(exec, r1).data(), count); dumpBytecodeCommentAndNewLine(location); break; } case op_to_primitive: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; - dataLog("[%4d] to_primitive\t %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data()); + dataLogF("[%4d] to_primitive\t %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data()); dumpBytecodeCommentAndNewLine(location); break; } @@ -1347,7 +1362,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; - dataLog("[%4d] get_pnames\t %s, %s, %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data(), registerName(exec, r3).data(), offset, location + offset); + dataLogF("[%4d] get_pnames\t %s, %s, %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data(), registerName(exec, r3).data(), offset, location + offset); dumpBytecodeCommentAndNewLine(location); it += OPCODE_LENGTH(op_get_pnames) - 1; break; @@ -1359,19 +1374,19 @@ 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; - dataLog("[%4d] next_pname\t %s, %s, %s, %s, %s, %d(->%d)", location, registerName(exec, dest).data(), registerName(exec, base).data(), registerName(exec, i).data(), registerName(exec, size).data(), registerName(exec, iter).data(), offset, location + offset); + dataLogF("[%4d] next_pname\t %s, %s, %s, %s, %s, %d(->%d)", location, registerName(exec, dest).data(), registerName(exec, base).data(), registerName(exec, i).data(), registerName(exec, size).data(), registerName(exec, iter).data(), offset, location + offset); dumpBytecodeCommentAndNewLine(location); it += OPCODE_LENGTH(op_next_pname) - 1; break; } case op_push_with_scope: { int r0 = (++it)->u.operand; - dataLog("[%4d] push_with_scope\t %s", location, registerName(exec, r0).data()); + dataLogF("[%4d] push_with_scope\t %s", location, registerName(exec, r0).data()); dumpBytecodeCommentAndNewLine(location); break; } case op_pop_scope: { - dataLog("[%4d] pop_scope", location); + dataLogF("[%4d] pop_scope", location); dumpBytecodeCommentAndNewLine(location); break; } @@ -1379,33 +1394,33 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int id0 = (++it)->u.operand; int r1 = (++it)->u.operand; unsigned attributes = (++it)->u.operand; - dataLog("[%4d] push_name_scope \t%s, %s, %u", location, idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data(), attributes); + dataLogF("[%4d] push_name_scope \t%s, %s, %u", location, idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data(), attributes); dumpBytecodeCommentAndNewLine(location); break; } case op_jmp_scopes: { int scopeDelta = (++it)->u.operand; int offset = (++it)->u.operand; - dataLog("[%4d] jmp_scopes\t^%d, %d(->%d)", location, scopeDelta, offset, location + offset); + dataLogF("[%4d] jmp_scopes\t^%d, %d(->%d)", location, scopeDelta, offset, location + offset); dumpBytecodeCommentAndNewLine(location); break; } case op_catch: { int r0 = (++it)->u.operand; - dataLog("[%4d] catch\t\t %s", location, registerName(exec, r0).data()); + dataLogF("[%4d] catch\t\t %s", location, registerName(exec, r0).data()); dumpBytecodeCommentAndNewLine(location); break; } case op_throw: { int r0 = (++it)->u.operand; - dataLog("[%4d] throw\t\t %s", location, registerName(exec, r0).data()); + dataLogF("[%4d] throw\t\t %s", location, registerName(exec, r0).data()); dumpBytecodeCommentAndNewLine(location); break; } case op_throw_static_error: { int k0 = (++it)->u.operand; int k1 = (++it)->u.operand; - dataLog("[%4d] throw_static_error\t %s, %s", location, constantName(exec, k0, getConstant(k0)).data(), k1 ? "true" : "false"); + dataLogF("[%4d] throw_static_error\t %s, %s", location, constantName(exec, k0, getConstant(k0)).data(), k1 ? "true" : "false"); dumpBytecodeCommentAndNewLine(location); break; } @@ -1414,25 +1429,25 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int firstLine = (++it)->u.operand; int lastLine = (++it)->u.operand; int column = (++it)->u.operand; - dataLog("[%4d] debug\t\t %s, %d, %d, %d", location, debugHookName(debugHookID), firstLine, lastLine, column); + dataLogF("[%4d] debug\t\t %s, %d, %d, %d", location, debugHookName(debugHookID), firstLine, lastLine, column); dumpBytecodeCommentAndNewLine(location); break; } case op_profile_will_call: { int function = (++it)->u.operand; - dataLog("[%4d] profile_will_call %s", location, registerName(exec, function).data()); + dataLogF("[%4d] profile_will_call %s", location, registerName(exec, function).data()); dumpBytecodeCommentAndNewLine(location); break; } case op_profile_did_call: { int function = (++it)->u.operand; - dataLog("[%4d] profile_did_call\t %s", location, registerName(exec, function).data()); + dataLogF("[%4d] profile_did_call\t %s", location, registerName(exec, function).data()); dumpBytecodeCommentAndNewLine(location); break; } case op_end: { int r0 = (++it)->u.operand; - dataLog("[%4d] end\t\t %s", location, registerName(exec, r0).data()); + dataLogF("[%4d] end\t\t %s", location, registerName(exec, r0).data()); dumpBytecodeCommentAndNewLine(location); break; } @@ -1443,6 +1458,13 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& } } +void CodeBlock::dump(unsigned bytecodeOffset) +{ + ExecState* exec = m_globalObject->globalExec(); + const Instruction* it = instructions().begin() + bytecodeOffset; + dump(exec, instructions().begin(), it); +} + #if DUMP_CODE_BLOCK_STATISTICS static HashSet<CodeBlock*> liveCodeBlockSet; #endif @@ -1541,29 +1563,29 @@ void CodeBlock::dumpStatistics() totalSize += symbolTableTotalSize; totalSize += (liveCodeBlockSet.size() * sizeof(CodeBlock)); - 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()); + dataLogF("Number of live CodeBlocks: %d\n", liveCodeBlockSet.size()); + dataLogF("Size of a single CodeBlock [sizeof(CodeBlock)]: %zu\n", sizeof(CodeBlock)); + dataLogF("Size of all CodeBlocks: %zu\n", totalSize); + dataLogF("Average size of a CodeBlock: %zu\n", totalSize / 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()); + dataLogF("Number of FunctionCode CodeBlocks: %zu (%.3f%%)\n", isFunctionCode, static_cast<double>(isFunctionCode) * 100.0 / liveCodeBlockSet.size()); + dataLogF("Number of GlobalCode CodeBlocks: %zu (%.3f%%)\n", isGlobalCode, static_cast<double>(isGlobalCode) * 100.0 / liveCodeBlockSet.size()); + dataLogF("Number of EvalCode CodeBlocks: %zu (%.3f%%)\n", isEvalCode, static_cast<double>(isEvalCode) * 100.0 / liveCodeBlockSet.size()); - dataLog("Number of CodeBlocks with rare data: %zu (%.3f%%)\n", hasRareData, static_cast<double>(hasRareData) * 100.0 / liveCodeBlockSet.size()); + dataLogF("Number of CodeBlocks with rare data: %zu (%.3f%%)\n", hasRareData, static_cast<double>(hasRareData) * 100.0 / liveCodeBlockSet.size()); - #define PRINT_STATS(name) dataLog("Number of CodeBlocks with " #name ": %zu\n", name##IsNotEmpty); dataLog("Size of all " #name ": %zu\n", name##TotalSize); + #define PRINT_STATS(name) dataLogF("Number of CodeBlocks with " #name ": %zu\n", name##IsNotEmpty); dataLogF("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 - dataLog("Number of CodeBlocks with evalCodeCache: %zu\n", evalCodeCacheIsNotEmpty); - dataLog("Number of CodeBlocks with symbolTable: %zu\n", symbolTableIsNotEmpty); + dataLogF("Number of CodeBlocks with evalCodeCache: %zu\n", evalCodeCacheIsNotEmpty); + dataLogF("Number of CodeBlocks with symbolTable: %zu\n", symbolTableIsNotEmpty); - dataLog("Size of all symbolTables: %zu\n", symbolTableTotalSize); + dataLogF("Size of all symbolTables: %zu\n", symbolTableTotalSize); #else - dataLog("Dumping CodeBlock statistics is not enabled.\n"); + dataLogF("Dumping CodeBlock statistics is not enabled.\n"); #endif } @@ -1746,6 +1768,8 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin #if ENABLE(DFG_JIT) if (size_t size = unlinkedCodeBlock->numberOfArrayProfiles()) m_arrayProfiles.grow(size); + if (size_t size = unlinkedCodeBlock->numberOfArrayAllocationProfiles()) + m_arrayAllocationProfiles.grow(size); if (size_t size = unlinkedCodeBlock->numberOfValueProfiles()) m_valueProfiles.grow(size); #endif @@ -1786,7 +1810,8 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin case op_resolve_with_base: case op_resolve_with_this: case op_get_by_id: - case op_call_put_result: { + case op_call_put_result: + case op_get_callee: { ValueProfile* profile = &m_valueProfiles[pc[i + opLength - 1].u.operand]; ASSERT(profile->m_bytecodeOffset == -1); profile->m_bytecodeOffset = i; @@ -1800,22 +1825,32 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin break; } + case op_new_array: + case op_new_array_buffer: + case op_new_array_with_size: { + int arrayAllocationProfileIndex = pc[i + opLength - 1].u.operand; + instructions[i + opLength - 1] = &m_arrayAllocationProfiles[arrayAllocationProfileIndex]; + break; + } +#endif + case op_call: case op_call_eval: { +#if ENABLE(DFG_JIT) int arrayProfileIndex = pc[i + opLength - 1].u.operand; m_arrayProfiles[arrayProfileIndex] = ArrayProfile(i); instructions[i + opLength - 1] = &m_arrayProfiles[arrayProfileIndex]; - // fallthrough -#if !ENABLE(LLINT) - break; -#endif - } #endif #if ENABLE(LLINT) - case op_construct: instructions[i + 4] = &m_llintCallLinkInfos[pc[i + 4].u.operand]; +#endif break; + } + case op_construct: +#if ENABLE(LLINT) + instructions[i + 4] = &m_llintCallLinkInfos[pc[i + 4].u.operand]; #endif + break; case op_get_by_id_out_of_line: case op_get_by_id_self: case op_get_by_id_proto: @@ -1857,7 +1892,7 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin m_instructions = WTF::RefCountedArray<Instruction>(instructions); if (BytecodeGenerator::dumpsGeneratedCode()) - dump(m_globalObject->globalExec()); + dump(); m_globalData->finishedCompiling(this); } @@ -2118,7 +2153,7 @@ void CodeBlock::finalizeUnconditionally() 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()); + dataLogF("Clearing LLInt property access with structure %p.\n", curInstruction[4].u.structure.get()); curInstruction[4].u.structure.clear(); curInstruction[5].u.operand = 0; break; @@ -2131,7 +2166,7 @@ void CodeBlock::finalizeUnconditionally() && Heap::isMarked(curInstruction[7].u.structureChain.get())) break; if (verboseUnlinking) { - dataLog("Clearing LLInt put transition with structures %p -> %p, chain %p.\n", + dataLogF("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()); @@ -2151,7 +2186,7 @@ void CodeBlock::finalizeUnconditionally() 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); + dataLogF("Clearing LLInt call from %p.\n", this); m_llintCallLinkInfos[i].unlink(); } if (!!m_llintCallLinkInfos[i].lastSeenCallee && !Heap::isMarked(m_llintCallLinkInfos[i].lastSeenCallee.get())) @@ -2164,12 +2199,33 @@ void CodeBlock::finalizeUnconditionally() // Check if we're not live. If we are, then jettison. if (!(shouldImmediatelyAssumeLivenessDuringScan() || m_dfgData->livenessHasBeenProved)) { if (verboseUnlinking) - dataLog("Code block %p has dead weak references, jettisoning during GC.\n", this); + dataLogF("Code block %p (executable %p) has dead weak references, jettisoning during GC.\n", this, ownerExecutable()); // Make sure that the baseline JIT knows that it should re-warm-up before // optimizing. alternative()->optimizeAfterWarmUp(); + if (DFG::shouldShowDisassembly()) { + dataLogF("DFG CodeBlock %p will be jettisoned because of the following dead references:\n", this); + for (unsigned i = 0; i < m_dfgData->transitions.size(); ++i) { + WeakReferenceTransition& transition = m_dfgData->transitions[i]; + JSCell* origin = transition.m_codeOrigin.get(); + JSCell* from = transition.m_from.get(); + JSCell* to = transition.m_to.get(); + if ((!origin || Heap::isMarked(origin)) && Heap::isMarked(from)) + continue; + dataLogF(" Transition under %s, ", JSValue(origin).description()); + dataLogF("%s -> ", JSValue(from).description()); + dataLogF("%s.\n", JSValue(to).description()); + } + for (unsigned i = 0; i < m_dfgData->weakReferences.size(); ++i) { + JSCell* weak = m_dfgData->weakReferences[i].get(); + if (Heap::isMarked(weak)) + continue; + dataLogF(" Weak reference %s.\n", JSValue(weak).description()); + } + } + jettison(); return; } @@ -2178,7 +2234,7 @@ void CodeBlock::finalizeUnconditionally() for (size_t size = m_putToBaseOperations.size(), i = 0; i < size; ++i) { if (m_putToBaseOperations[i].m_structure && !Heap::isMarked(m_putToBaseOperations[i].m_structure.get())) { if (verboseUnlinking) - dataLog("Clearing putToBase info in %p.\n", this); + dataLogF("Clearing putToBase info in %p.\n", this); m_putToBaseOperations[i].m_structure.clear(); } } @@ -2192,7 +2248,7 @@ void CodeBlock::finalizeUnconditionally() m_resolveOperations[i].last().m_structure.clear(); if (m_resolveOperations[i].last().m_structure && !Heap::isMarked(m_resolveOperations[i].last().m_structure.get())) { if (verboseUnlinking) - dataLog("Clearing resolve info in %p.\n", this); + dataLogF("Clearing resolve info in %p.\n", this); m_resolveOperations[i].last().m_structure.clear(); } } @@ -2202,10 +2258,19 @@ void CodeBlock::finalizeUnconditionally() if (!!getJITCode()) { RepatchBuffer repatchBuffer(this); for (unsigned i = 0; i < numberOfCallLinkInfos(); ++i) { - if (callLinkInfo(i).isLinked() && !Heap::isMarked(callLinkInfo(i).callee.get())) { - if (verboseUnlinking) - dataLog("Clearing call from %p to %p.\n", this, callLinkInfo(i).callee.get()); - callLinkInfo(i).unlink(*m_globalData, repatchBuffer); + if (callLinkInfo(i).isLinked()) { + if (ClosureCallStubRoutine* stub = callLinkInfo(i).stub.get()) { + if (!Heap::isMarked(stub->structure()) + || !Heap::isMarked(stub->executable())) { + if (verboseUnlinking) + dataLogF("Clearing closure call from %p to %p, stub routine %p.\n", this, stub->executable(), stub); + callLinkInfo(i).unlink(*m_globalData, repatchBuffer); + } + } else if (!Heap::isMarked(callLinkInfo(i).callee.get())) { + if (verboseUnlinking) + dataLogF("Clearing call from %p to %p.\n", this, callLinkInfo(i).callee.get()); + callLinkInfo(i).unlink(*m_globalData, repatchBuffer); + } } if (!!callLinkInfo(i).lastSeenCallee && !Heap::isMarked(callLinkInfo(i).lastSeenCallee.get())) @@ -2238,7 +2303,7 @@ void CodeBlock::resetStubInternal(RepatchBuffer& repatchBuffer, StructureStubInf AccessType accessType = static_cast<AccessType>(stubInfo.accessType); if (verboseUnlinking) - dataLog("Clearing structure cache (kind %d) in %p.\n", stubInfo.accessType, this); + dataLogF("Clearing structure cache (kind %d) in %p.\n", stubInfo.accessType, this); if (isGetByIdAccess(accessType)) { if (getJITCode().jitType() == JITCode::DFGJIT) @@ -2560,6 +2625,35 @@ Instruction* CodeBlock::adjustPCIfAtCallSite(Instruction* potentialReturnPC) } #endif // ENABLE(LLINT) +#if ENABLE(JIT) +ClosureCallStubRoutine* CodeBlock::findClosureCallForReturnPC(ReturnAddressPtr returnAddress) +{ + for (unsigned i = m_callLinkInfos.size(); i--;) { + CallLinkInfo& info = m_callLinkInfos[i]; + if (!info.stub) + continue; + if (!info.stub->code().executableMemory()->contains(returnAddress.value())) + continue; + + return info.stub.get(); + } + + // The stub routine may have been jettisoned. This is rare, but we have to handle it. + const JITStubRoutineSet& set = m_globalData->heap.jitStubRoutines(); + for (unsigned i = set.size(); i--;) { + GCAwareJITStubRoutine* genericStub = set.at(i); + if (!genericStub->isClosureCall()) + continue; + ClosureCallStubRoutine* stub = static_cast<ClosureCallStubRoutine*>(genericStub); + if (!stub->code().executableMemory()->contains(returnAddress.value())) + continue; + return stub; + } + + return 0; +} +#endif + unsigned CodeBlock::bytecodeOffset(ExecState* exec, ReturnAddressPtr returnAddress) { UNUSED_PARAM(exec); @@ -2597,7 +2691,16 @@ unsigned CodeBlock::bytecodeOffset(ExecState* exec, ReturnAddressPtr returnAddre 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; + + if (getJITCode().getExecutableMemory()->contains(returnAddress.value())) { + unsigned callReturnOffset = getJITCode().offsetOf(returnAddress.value()); + CallReturnOffsetToBytecodeOffset* result = + binarySearch<CallReturnOffsetToBytecodeOffset, unsigned, getCallReturnOffset>(callIndices.begin(), callIndices.size(), callReturnOffset); + ASSERT(result->callReturnOffset == callReturnOffset); + return result->bytecodeOffset; + } + + return findClosureCallForReturnPC(returnAddress)->codeOrigin().bytecodeIndex; #endif // ENABLE(JIT) #if !ENABLE(LLINT) && !ENABLE(JIT) @@ -2605,6 +2708,26 @@ unsigned CodeBlock::bytecodeOffset(ExecState* exec, ReturnAddressPtr returnAddre #endif } +#if ENABLE(DFG_JIT) +bool CodeBlock::codeOriginForReturn(ReturnAddressPtr returnAddress, CodeOrigin& codeOrigin) +{ + if (!hasCodeOrigins()) + return false; + + if (!getJITCode().getExecutableMemory()->contains(returnAddress.value())) { + codeOrigin = findClosureCallForReturnPC(returnAddress)->codeOrigin(); + return true; + } + + unsigned offset = getJITCode().offsetOf(returnAddress.value()); + CodeOriginAtCallReturnOffset* entry = binarySearch<CodeOriginAtCallReturnOffset, unsigned, getCallReturnOffsetForCodeOrigin>(codeOrigins().begin(), codeOrigins().size(), offset, WTF::KeyMustNotBePresentInArray); + if (entry->callReturnOffset != offset) + return false; + codeOrigin = entry->codeOrigin; + return true; +} +#endif // ENABLE(DFG_JIT) + void CodeBlock::clearEvalCache() { if (!!m_alternative) @@ -2645,6 +2768,8 @@ void CodeBlock::reoptimize() ASSERT(replacement() != this); ASSERT(replacement()->alternative() == this); replacement()->tallyFrequentExitSites(); + if (DFG::shouldShowDisassembly()) + dataLogF("DFG CodeBlock %p will be jettisoned due to reoptimization of %p.\n", replacement(), this); replacement()->jettison(); countReoptimization(); optimizeAfterWarmUp(); @@ -2710,6 +2835,8 @@ void ProgramCodeBlock::jettison() { ASSERT(JITCode::isOptimizingJIT(getJITType())); ASSERT(this == replacement()); + if (DFG::shouldShowDisassembly()) + dataLogF("Jettisoning DFG CodeBlock %p.\n", this); static_cast<ProgramExecutable*>(ownerExecutable())->jettisonOptimizedCode(*globalData()); } @@ -2717,6 +2844,8 @@ void EvalCodeBlock::jettison() { ASSERT(JITCode::isOptimizingJIT(getJITType())); ASSERT(this == replacement()); + if (DFG::shouldShowDisassembly()) + dataLogF("Jettisoning DFG CodeBlock %p.\n", this); static_cast<EvalExecutable*>(ownerExecutable())->jettisonOptimizedCode(*globalData()); } @@ -2724,6 +2853,8 @@ void FunctionCodeBlock::jettison() { ASSERT(JITCode::isOptimizingJIT(getJITType())); ASSERT(this == replacement()); + if (DFG::shouldShowDisassembly()) + dataLogF("Jettisoning DFG CodeBlock %p.\n", this); static_cast<FunctionExecutable*>(ownerExecutable())->jettisonOptimizedCodeFor(*globalData(), m_isConstructor ? CodeForConstruct : CodeForCall); } @@ -2790,24 +2921,34 @@ void CodeBlock::updateAllPredictionsAndCountLiveness( #if ENABLE(DFG_JIT) m_lazyOperandValueProfiles.computeUpdatedPredictions(operation); #endif - - // Don't count the array profiles towards statistics, since each array profile - // site also has a value profile site - so we already know whether or not it's - // live. +} + +void CodeBlock::updateAllValueProfilePredictions(OperationInProgress operation) +{ + unsigned ignoredValue1, ignoredValue2; + updateAllPredictionsAndCountLiveness(operation, ignoredValue1, ignoredValue2); +} + +void CodeBlock::updateAllArrayPredictions(OperationInProgress operation) +{ for (unsigned i = m_arrayProfiles.size(); i--;) m_arrayProfiles[i].computeUpdatedPrediction(this, operation); + + // Don't count these either, for similar reasons. + for (unsigned i = m_arrayAllocationProfiles.size(); i--;) + m_arrayAllocationProfiles[i].updateIndexingType(); } void CodeBlock::updateAllPredictions(OperationInProgress operation) { - unsigned ignoredValue1, ignoredValue2; - updateAllPredictionsAndCountLiveness(operation, ignoredValue1, ignoredValue2); + updateAllValueProfilePredictions(operation); + updateAllArrayPredictions(operation); } bool CodeBlock::shouldOptimizeNow() { #if ENABLE(JIT_VERBOSE_OSR) - dataLog("Considering optimizing %p...\n", this); + dataLogF("Considering optimizing %p...\n", this); #endif #if ENABLE(VERBOSE_VALUE_PROFILE) @@ -2817,12 +2958,14 @@ bool CodeBlock::shouldOptimizeNow() if (m_optimizationDelayCounter >= Options::maximumOptimizationDelay()) return true; + updateAllArrayPredictions(); + unsigned numberOfLiveNonArgumentValueProfiles; unsigned numberOfSamplesInProfiles; updateAllPredictionsAndCountLiveness(NoOperation, numberOfLiveNonArgumentValueProfiles, numberOfSamplesInProfiles); #if ENABLE(JIT_VERBOSE_OSR) - dataLog("Profile hotness: %lf, %lf\n", (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles(), (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / numberOfValueProfiles()); + dataLogF("Profile hotness: %lf (%u / %u), %lf (%u / %u)\n", (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles(), numberOfLiveNonArgumentValueProfiles, numberOfValueProfiles(), (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / numberOfValueProfiles(), numberOfSamplesInProfiles, ValueProfile::numberOfBuckets * numberOfValueProfiles()); #endif if ((!numberOfValueProfiles() || (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles() >= Options::desiredProfileLivenessRate()) @@ -2853,7 +2996,7 @@ void CodeBlock::tallyFrequentExitSites() continue; #if DFG_ENABLE(DEBUG_VERBOSE) - 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); + dataLogF("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 } } @@ -2862,30 +3005,30 @@ void CodeBlock::tallyFrequentExitSites() #if ENABLE(VERBOSE_VALUE_PROFILE) void CodeBlock::dumpValueProfiles() { - dataLog("ValueProfile for %p:\n", this); + dataLogF("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); - dataLog(" arg = %u: ", i); + dataLogF(" arg = %u: ", i); } else - dataLog(" bc = %d: ", profile->m_bytecodeOffset); + dataLogF(" bc = %d: ", profile->m_bytecodeOffset); if (!profile->numberOfSamples() && profile->m_prediction == SpecNone) { - dataLog("<empty>\n"); + dataLogF("<empty>\n"); continue; } profile->dump(WTF::dataFile()); - dataLog("\n"); + dataLogF("\n"); } - dataLog("RareCaseProfile for %p:\n", this); + dataLogF("RareCaseProfile for %p:\n", this); for (unsigned i = 0; i < numberOfRareCaseProfiles(); ++i) { RareCaseProfile* profile = rareCaseProfile(i); - dataLog(" bc = %d: %u\n", profile->m_bytecodeOffset, profile->m_counter); + dataLogF(" bc = %d: %u\n", profile->m_bytecodeOffset, profile->m_counter); } - dataLog("SpecialFastCaseProfile for %p:\n", this); + dataLogF("SpecialFastCaseProfile for %p:\n", this); for (unsigned i = 0; i < numberOfSpecialFastCaseProfiles(); ++i) { RareCaseProfile* profile = specialFastCaseProfile(i); - dataLog(" bc = %d: %u\n", profile->m_bytecodeOffset, profile->m_counter); + dataLogF(" bc = %d: %u\n", profile->m_bytecodeOffset, profile->m_counter); } } #endif // ENABLE(VERBOSE_VALUE_PROFILE) diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h index a28064940..63a03630e 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.h +++ b/Source/JavaScriptCore/bytecode/CodeBlock.h @@ -163,7 +163,8 @@ namespace JSC { static void dumpStatistics(); - void dump(ExecState*); + void dump(); + void dump(unsigned bytecodeOffset); void printStructures(const Instruction*); void printStructure(const char* name, const Instruction*, int operand); @@ -245,6 +246,7 @@ namespace JSC { CallLinkInfo& getCallLinkInfo(unsigned bytecodeIndex) { + ASSERT(JITCode::isBaselineCode(getJITType())); return *(binarySearch<CallLinkInfo, unsigned, getCallLinkInfoBytecodeIndex>(m_callLinkInfos.begin(), m_callLinkInfos.size(), bytecodeIndex)); } #endif // ENABLE(JIT) @@ -274,6 +276,11 @@ namespace JSC { { m_incomingCalls.push(incoming); } + + bool isIncomingCallAlreadyLinked(CallLinkInfo* incoming) + { + return m_incomingCalls.isOnList(incoming); + } #endif // ENABLE(JIT) #if ENABLE(LLINT) @@ -755,6 +762,13 @@ namespace JSC { } ArrayProfile* getArrayProfile(unsigned bytecodeOffset); ArrayProfile* getOrAddArrayProfile(unsigned bytecodeOffset); + + unsigned numberOfArrayAllocationProfiles() const { return m_arrayAllocationProfiles.size(); } + ArrayAllocationProfile* addArrayAllocationProfile() + { + m_arrayAllocationProfiles.append(ArrayAllocationProfile()); + return &m_arrayAllocationProfiles.last(); + } #endif // Exception handling support @@ -806,17 +820,7 @@ namespace JSC { return m_rareData && !!m_rareData->m_codeOrigins.size(); } - bool codeOriginForReturn(ReturnAddressPtr returnAddress, CodeOrigin& codeOrigin) - { - if (!hasCodeOrigins()) - return false; - unsigned offset = getJITCode().offsetOf(returnAddress.value()); - CodeOriginAtCallReturnOffset* entry = binarySearch<CodeOriginAtCallReturnOffset, unsigned, getCallReturnOffsetForCodeOrigin>(codeOrigins().begin(), codeOrigins().size(), offset, WTF::KeyMustNotBePresentInArray); - if (entry->callReturnOffset != offset) - return false; - codeOrigin = entry->codeOrigin; - return true; - } + bool codeOriginForReturn(ReturnAddressPtr, CodeOrigin&); CodeOrigin codeOrigin(unsigned index) { @@ -1145,9 +1149,13 @@ namespace JSC { #if ENABLE(VALUE_PROFILER) bool shouldOptimizeNow(); + void updateAllValueProfilePredictions(OperationInProgress = NoOperation); + void updateAllArrayPredictions(OperationInProgress = NoOperation); void updateAllPredictions(OperationInProgress = NoOperation); #else bool shouldOptimizeNow() { return false; } + void updateAllValueProfilePredictions(OperationInProgress = NoOperation) { } + void updateAllArrayPredictions(OperationInProgress = NoOperation) { } void updateAllPredictions(OperationInProgress = NoOperation) { } #endif @@ -1176,6 +1184,10 @@ namespace JSC { private: friend class DFGCodeBlocks; + +#if ENABLE(JIT) + ClosureCallStubRoutine* findClosureCallForReturnPC(ReturnAddressPtr); +#endif #if ENABLE(DFG_JIT) void tallyFrequentExitSites(); @@ -1200,17 +1212,17 @@ namespace JSC { m_constantRegisters[i].set(*m_globalData, ownerExecutable(), constants[i].get()); } - void dump(ExecState*, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator&); + void dump(ExecState*, const Instruction* begin, const Instruction*&); CString registerName(ExecState*, int r) 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 printUnaryOp(ExecState*, int location, const Instruction*&, const char* op); + void printBinaryOp(ExecState*, int location, const Instruction*&, const char* op); + void printConditionalJump(ExecState*, const Instruction*, const Instruction*&, int location, const char* op); + void printGetByIdOp(ExecState*, int location, const Instruction*&); 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 printCallOp(ExecState*, int location, const Instruction*&, const char* op, CacheDumpMode); + void printPutByIdOp(ExecState*, int location, const Instruction*&, const char* op); void visitStructures(SlotVisitor&, Instruction* vPC); #if ENABLE(DFG_JIT) @@ -1228,6 +1240,9 @@ namespace JSC { // allow them to continue to execute soundly. if (m_dfgData->mayBeExecuting) return true; + + if (Options::forceDFGCodeBlockLiveness()) + return true; return false; } @@ -1330,6 +1345,7 @@ namespace JSC { SegmentedVector<ValueProfile, 8> m_valueProfiles; SegmentedVector<RareCaseProfile, 8> m_rareCaseProfiles; SegmentedVector<RareCaseProfile, 8> m_specialFastCaseProfiles; + SegmentedVector<ArrayAllocationProfile, 8> m_arrayAllocationProfiles; ArrayProfileVector m_arrayProfiles; unsigned m_executionEntryCount; #endif diff --git a/Source/JavaScriptCore/bytecode/DFGExitProfile.h b/Source/JavaScriptCore/bytecode/DFGExitProfile.h index 60d313ad4..7132adfd4 100644 --- a/Source/JavaScriptCore/bytecode/DFGExitProfile.h +++ b/Source/JavaScriptCore/bytecode/DFGExitProfile.h @@ -58,6 +58,8 @@ inline const char* exitKindToString(ExitKind kind) return "BadCache"; case BadWeakConstantCache: return "BadWeakConstantCache"; + case BadIndexingType: + return "BadIndexingType"; case Overflow: return "Overflow"; case NegativeZero: diff --git a/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp b/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp index 605a81c2f..d17c17325 100644 --- a/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp +++ b/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp @@ -151,7 +151,7 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec // Finally figure out if we can derive an access strategy. GetByIdStatus result; - result.m_wasSeenInJIT = true; + result.m_wasSeenInJIT = true; // This is interesting for bytecode dumping only. switch (stubInfo.accessType) { case access_unset: return computeFromLLInt(profiledBlock, bytecodeIndex, ident); @@ -252,5 +252,35 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec #endif // ENABLE(JIT) } +GetByIdStatus GetByIdStatus::computeFor(JSGlobalData& globalData, Structure* structure, Identifier& ident) +{ + // For now we only handle the super simple self access case. We could handle the + // prototype case in the future. + + if (PropertyName(ident).asIndex() != PropertyName::NotAnIndex) + return GetByIdStatus(TakesSlowPath); + + if (structure->typeInfo().overridesGetOwnPropertySlot()) + return GetByIdStatus(TakesSlowPath); + + if (!structure->propertyAccessesAreCacheable()) + return GetByIdStatus(TakesSlowPath); + + GetByIdStatus result; + result.m_wasSeenInJIT = false; // To my knowledge nobody that uses computeFor(JSGlobalData&, Structure*, Identifier&) reads this field, but I might as well be honest: no, it wasn't seen in the JIT, since I computed it statically. + unsigned attributes; + JSCell* specificValue; + result.m_offset = structure->get(globalData, ident, attributes, specificValue); + if (!isValidOffset(result.m_offset)) + return GetByIdStatus(TakesSlowPath); // It's probably a prototype lookup. Give up on life for now, even though we could totally be way smarter about it. + if (attributes & Accessor) + return GetByIdStatus(MakesCalls); + if (structure->isDictionary()) + specificValue = 0; + result.m_structureSet.add(structure); + result.m_specificValue = JSValue(specificValue); + return result; +} + } // namespace JSC diff --git a/Source/JavaScriptCore/bytecode/GetByIdStatus.h b/Source/JavaScriptCore/bytecode/GetByIdStatus.h index f38a19e8c..45d8c0b1f 100644 --- a/Source/JavaScriptCore/bytecode/GetByIdStatus.h +++ b/Source/JavaScriptCore/bytecode/GetByIdStatus.h @@ -51,6 +51,13 @@ public: { } + explicit GetByIdStatus(State state) + : m_state(state) + , m_offset(invalidOffset) + { + ASSERT(state == NoInformation || state == TakesSlowPath || state == MakesCalls); + } + GetByIdStatus( State state, bool wasSeenInJIT, const StructureSet& structureSet = StructureSet(), PropertyOffset offset = invalidOffset, JSValue specificValue = JSValue(), Vector<Structure*> chain = Vector<Structure*>()) @@ -65,6 +72,7 @@ public: } static GetByIdStatus computeFor(CodeBlock*, unsigned bytecodeIndex, Identifier&); + static GetByIdStatus computeFor(JSGlobalData&, Structure*, Identifier&); State state() const { return m_state; } diff --git a/Source/JavaScriptCore/bytecode/Instruction.h b/Source/JavaScriptCore/bytecode/Instruction.h index 9fcf509f6..50b80e03c 100644 --- a/Source/JavaScriptCore/bytecode/Instruction.h +++ b/Source/JavaScriptCore/bytecode/Instruction.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 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 @@ -47,6 +47,7 @@ namespace JSC { // curently actually use PolymorphicAccessStructureLists, which we should). Anyway, this seems like the best // solution for now - will need to something smarter if/when we actually want mixed-mode operation. + class ArrayAllocationProfile; class ArrayProfile; class JSCell; class Structure; @@ -193,6 +194,7 @@ namespace JSC { Instruction(ValueProfile* profile) { u.profile = profile; } Instruction(ArrayProfile* profile) { u.arrayProfile = profile; } + Instruction(ArrayAllocationProfile* profile) { u.arrayAllocationProfile = profile; } Instruction(WriteBarrier<Unknown>* registerPointer) { u.registerPointer = registerPointer; } @@ -212,6 +214,7 @@ namespace JSC { LLIntCallLinkInfo* callLinkInfo; ValueProfile* profile; ArrayProfile* arrayProfile; + ArrayAllocationProfile* arrayAllocationProfile; void* pointer; bool* predicatePointer; } u; diff --git a/Source/JavaScriptCore/bytecode/Opcode.cpp b/Source/JavaScriptCore/bytecode/Opcode.cpp index a27714026..0adc76b28 100644 --- a/Source/JavaScriptCore/bytecode/Opcode.cpp +++ b/Source/JavaScriptCore/bytecode/Opcode.cpp @@ -114,19 +114,19 @@ OpcodeStats::~OpcodeStats() *(currentPairIndex++) = make_pair(i, j); qsort(sortedPairIndices, numOpcodeIDs * numOpcodeIDs, sizeof(pair<int, int>), compareOpcodePairIndices); - dataLog("\nExecuted opcode statistics\n"); + dataLogF("\nExecuted opcode statistics\n"); - dataLog("Total instructions executed: %lld\n\n", totalInstructions); + dataLogF("Total instructions executed: %lld\n\n", totalInstructions); - dataLog("All opcodes by frequency:\n\n"); + dataLogF("All opcodes by frequency:\n\n"); for (int i = 0; i < numOpcodeIDs; ++i) { int index = sortedIndices[i]; - dataLog("%s:%s %lld - %.2f%%\n", opcodeNames[index], padOpcodeName((OpcodeID)index, 28), opcodeCounts[index], ((double) opcodeCounts[index]) / ((double) totalInstructions) * 100.0); + dataLogF("%s:%s %lld - %.2f%%\n", opcodeNames[index], padOpcodeName((OpcodeID)index, 28), opcodeCounts[index], ((double) opcodeCounts[index]) / ((double) totalInstructions) * 100.0); } - dataLog("\n"); - dataLog("2-opcode sequences by frequency: %lld\n\n", totalInstructions); + dataLogF("\n"); + dataLogF("2-opcode sequences by frequency: %lld\n\n", totalInstructions); for (int i = 0; i < numOpcodeIDs * numOpcodeIDs; ++i) { pair<int, int> indexPair = sortedPairIndices[i]; @@ -135,11 +135,11 @@ OpcodeStats::~OpcodeStats() if (!count) break; - 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); + dataLogF("%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("\n"); - dataLog("Most common opcodes and sequences:\n"); + dataLogF("\n"); + dataLogF("Most common opcodes and sequences:\n"); for (int i = 0; i < numOpcodeIDs; ++i) { int index = sortedIndices[i]; @@ -147,7 +147,7 @@ OpcodeStats::~OpcodeStats() double opcodeProportion = ((double) opcodeCount) / ((double) totalInstructions); if (opcodeProportion < 0.0001) break; - dataLog("\n%s:%s %lld - %.2f%%\n", opcodeNames[index], padOpcodeName((OpcodeID)index, 28), opcodeCount, opcodeProportion * 100.0); + dataLogF("\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]; @@ -160,11 +160,11 @@ OpcodeStats::~OpcodeStats() if (indexPair.first != index && indexPair.second != index) continue; - 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); + dataLogF(" %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("\n"); + dataLogF("\n"); } void OpcodeStats::recordInstruction(int opcode) diff --git a/Source/JavaScriptCore/bytecode/Opcode.h b/Source/JavaScriptCore/bytecode/Opcode.h index 8979d0b7b..5fe28bc09 100644 --- a/Source/JavaScriptCore/bytecode/Opcode.h +++ b/Source/JavaScriptCore/bytecode/Opcode.h @@ -44,13 +44,14 @@ namespace JSC { macro(op_create_activation, 2) \ macro(op_init_lazy_reg, 2) \ macro(op_create_arguments, 2) \ - macro(op_create_this, 2) \ + macro(op_create_this, 3) \ + macro(op_get_callee, 3) \ macro(op_convert_this, 3) \ \ macro(op_new_object, 2) \ - macro(op_new_array, 4) \ - macro(op_new_array_with_size, 3) \ - macro(op_new_array_buffer, 4) \ + macro(op_new_array, 5) \ + macro(op_new_array_with_size, 4) \ + macro(op_new_array_buffer, 5) \ macro(op_new_regexp, 3) \ macro(op_mov, 3) \ \ diff --git a/Source/JavaScriptCore/bytecode/Operands.h b/Source/JavaScriptCore/bytecode/Operands.h index b0f0e692c..0cea096cf 100644 --- a/Source/JavaScriptCore/bytecode/Operands.h +++ b/Source/JavaScriptCore/bytecode/Operands.h @@ -190,7 +190,7 @@ private: }; template<typename T, typename Traits> -void dumpOperands(Operands<T, Traits>& operands, FILE* out) +void dumpOperands(const Operands<T, Traits>& operands, FILE* out) { for (size_t argument = 0; argument < operands.numberOfArguments(); ++argument) { if (argument) @@ -205,16 +205,6 @@ void dumpOperands(Operands<T, Traits>& operands, FILE* out) } } -template<typename T, typename Traits> -void dumpOperands(const Operands<T, Traits>& operands, FILE* out) -{ - // Use const-cast because: - // 1) I don't feel like writing this code twice, and - // 2) Some dump() methods may not be const, and I don't really care if that's - // the case. - dumpOperands(*const_cast<Operands<T, Traits>*>(&operands), out); -} - } // namespace JSC #endif // Operands_h diff --git a/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp b/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp index 35800f3dd..7d6ba0987 100644 --- a/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp +++ b/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp @@ -29,6 +29,7 @@ #include "CodeBlock.h" #include "LLIntData.h" #include "LowLevelInterpreter.h" +#include "Operations.h" #include "Structure.h" #include "StructureChain.h" @@ -134,5 +135,77 @@ PutByIdStatus PutByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec #endif // ENABLE(JIT) } +PutByIdStatus PutByIdStatus::computeFor(JSGlobalData& globalData, JSGlobalObject* globalObject, Structure* structure, Identifier& ident, bool isDirect) +{ + if (PropertyName(ident).asIndex() != PropertyName::NotAnIndex) + return PutByIdStatus(TakesSlowPath); + + if (structure->typeInfo().overridesGetOwnPropertySlot()) + return PutByIdStatus(TakesSlowPath); + + if (!structure->propertyAccessesAreCacheable()) + return PutByIdStatus(TakesSlowPath); + + unsigned attributes; + JSCell* specificValueIgnored; + PropertyOffset offset = structure->get(globalData, ident, attributes, specificValueIgnored); + if (isValidOffset(offset)) { + if (attributes & (Accessor | ReadOnly)) + return PutByIdStatus(TakesSlowPath); + return PutByIdStatus(SimpleReplace, structure, 0, 0, offset); + } + + // Our hypothesis is that we're doing a transition. Before we prove that this is really + // true, we want to do some sanity checks. + + // Don't cache put transitions on dictionaries. + if (structure->isDictionary()) + return PutByIdStatus(TakesSlowPath); + + // If the structure corresponds to something that isn't an object, then give up, since + // we don't want to be adding properties to strings. + if (structure->typeInfo().type() == StringType) + return PutByIdStatus(TakesSlowPath); + + if (!isDirect) { + // If the prototype chain has setters or read-only properties, then give up. + if (structure->prototypeChainMayInterceptStoreTo(globalData, ident)) + return PutByIdStatus(TakesSlowPath); + + // If the prototype chain hasn't been normalized (i.e. there are proxies or dictionaries) + // then give up. The dictionary case would only happen if this structure has not been + // used in an optimized put_by_id transition. And really the only reason why we would + // bail here is that I don't really feel like having the optimizing JIT go and flatten + // dictionaries if we have evidence to suggest that those objects were never used as + // prototypes in a cacheable prototype access - i.e. there's a good chance that some of + // the other checks below will fail. + if (!isPrototypeChainNormalized(globalObject, structure)) + return PutByIdStatus(TakesSlowPath); + } + + // We only optimize if there is already a structure that the transition is cached to. + // Among other things, this allows us to guard against a transition with a specific + // value. + // + // - If we're storing a value that could be specific: this would only be a problem if + // the existing transition did have a specific value already, since if it didn't, + // then we would behave "as if" we were not storing a specific value. If it did + // have a specific value, then we'll know - the fact that we pass 0 for + // specificValue will tell us. + // + // - If we're not storing a value that could be specific: again, this would only be a + // problem if the existing transition did have a specific value, which we check for + // by passing 0 for the specificValue. + Structure* transition = Structure::addPropertyTransitionToExistingStructure(structure, ident, 0, 0, offset); + if (!transition) + return PutByIdStatus(TakesSlowPath); // This occurs in bizarre cases only. See above. + ASSERT(!transition->transitionDidInvolveSpecificValue()); + ASSERT(isValidOffset(offset)); + + return PutByIdStatus( + SimpleTransition, structure, transition, + structure->prototypeChain(globalData, globalObject), offset); +} + } // namespace JSC diff --git a/Source/JavaScriptCore/bytecode/PutByIdStatus.h b/Source/JavaScriptCore/bytecode/PutByIdStatus.h index 694915244..fe22009fe 100644 --- a/Source/JavaScriptCore/bytecode/PutByIdStatus.h +++ b/Source/JavaScriptCore/bytecode/PutByIdStatus.h @@ -33,6 +33,8 @@ namespace JSC { class CodeBlock; class Identifier; +class JSGlobalData; +class JSGlobalObject; class Structure; class StructureChain; @@ -60,6 +62,16 @@ public: { } + explicit PutByIdStatus(State state) + : m_state(state) + , m_oldStructure(0) + , m_newStructure(0) + , m_structureChain(0) + , m_offset(invalidOffset) + { + ASSERT(m_state == NoInformation || m_state == TakesSlowPath); + } + PutByIdStatus( State state, Structure* oldStructure, @@ -79,6 +91,7 @@ public: } static PutByIdStatus computeFor(CodeBlock*, unsigned bytecodeIndex, Identifier&); + static PutByIdStatus computeFor(JSGlobalData&, JSGlobalObject*, Structure*, Identifier&, bool isDirect); State state() const { return m_state; } diff --git a/Source/JavaScriptCore/bytecode/SamplingTool.cpp b/Source/JavaScriptCore/bytecode/SamplingTool.cpp index f9b8245e5..a76fee179 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) { - dataLog("\nSamplingFlags: sample counts with flags set: (%lld total)\n", total); + dataLogF("\nSamplingFlags: sample counts with flags set: (%lld total)\n", total); for (unsigned i = 0; i <= 32; ++i) { if (s_flagCounts[i]) - dataLog(" [ %02d ] : %lld\t\t(%03.2f%%)\n", i, s_flagCounts[i], (100.0 * s_flagCounts[i]) / total); + dataLogF(" [ %02d ] : %lld\t\t(%03.2f%%)\n", i, s_flagCounts[i], (100.0 * s_flagCounts[i]) / total); } - dataLog("\n"); + dataLogF("\n"); } else - dataLog("\nSamplingFlags: no samples.\n\n"); + dataLogF("\nSamplingFlags: no samples.\n\n"); } uint64_t SamplingFlags::s_flagCounts[33]; @@ -151,7 +151,7 @@ void SamplingRegion::dump() void SamplingRegion::dumpInternal() { if (!s_spectrum) { - dataLog("\nSamplingRegion: was never sampled.\n\n"); + dataLogF("\nSamplingRegion: was never sampled.\n\n"); return; } @@ -161,10 +161,10 @@ void SamplingRegion::dumpInternal() for (unsigned i = list.size(); i--;) total += list[i].count; - dataLog("\nSamplingRegion: sample counts for regions: (%lu samples)\n", total); + dataLogF("\nSamplingRegion: sample counts for regions: (%lu samples)\n", total); for (unsigned i = list.size(); i--;) - dataLog(" %3.2lf%% %s\n", (100.0 * list[i].count) / total, list[i].key); + dataLogF(" %3.2lf%% %s\n", (100.0 * list[i].count) / total, list[i].key); } #else // ENABLE(SAMPLING_REGIONS) void SamplingRegion::dump() { } @@ -371,10 +371,10 @@ void SamplingTool::dump(ExecState* exec) // (2) Print Opcode sampling results. - dataLog("\nBytecode samples [*]\n"); - dataLog(" sample %% of %% of | cti cti %%\n"); - dataLog("opcode count VM total | count of self\n"); - dataLog("------------------------------------------------------- | ----------------\n"); + dataLogF("\nBytecode samples [*]\n"); + dataLogF(" sample %% of %% of | cti cti %%\n"); + dataLogF("opcode count VM total | count of self\n"); + dataLogF("------------------------------------------------------- | ----------------\n"); for (int i = 0; i < numOpcodeIDs; ++i) { long long count = opcodeSampleInfo[i].count; @@ -392,15 +392,15 @@ void SamplingTool::dump(ExecState* exec) debugDebugPrintf("%s:%s%-6lld %.3f%%\t%.3f%%\t | %-6lld %.3f%%\n", opcodeName, opcodePadding, count, percentOfVM, percentOfTotal, countInCTIFunctions, percentInCTIFunctions); } - 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"); + dataLogF("\n[*] Samples inside host code are not charged to any Bytecode.\n\n"); + dataLogF("\tSamples inside VM:\t\t%lld / %lld (%.3f%%)\n", m_opcodeSampleCount, m_sampleCount, (static_cast<double>(m_opcodeSampleCount) * 100) / m_sampleCount); + dataLogF("\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); + dataLogF("\tsample count:\tsamples inside this opcode\n"); + dataLogF("\t%% of VM:\tsample count / all opcode samples\n"); + dataLogF("\t%% of total:\tsample count / all samples\n"); + dataLogF("\t--------------\n"); + dataLogF("\tcti count:\tsamples inside a CTI function called by this opcode\n"); + dataLogF("\tcti %% of self:\tcti count / sample count\n"); #if ENABLE(CODEBLOCK_SAMPLING) @@ -416,7 +416,7 @@ void SamplingTool::dump(ExecState* exec) // (4) Print data from 'codeBlockSamples' array. - dataLog("\nCodeBlock samples\n\n"); + dataLogF("\nCodeBlock samples\n\n"); for (int i = 0; i < scopeCount; ++i) { ScriptSampleRecord* record = codeBlockSamples[i]; @@ -426,21 +426,21 @@ void SamplingTool::dump(ExecState* exec) if (blockPercent >= 1) { //Instruction* code = codeBlock->instructions().begin(); - 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); + dataLogF("#%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); - dataLog(" Opcode and line number samples [*]\n\n"); + dataLogF(" Opcode and line number samples [*]\n\n"); for (unsigned op = 0; op < record->m_size; ++op) { int count = record->m_samples[op]; if (count) { - dataLog(" [% 4d] has sample count: % 4d\n", op, count); + dataLogF(" [% 4d] has sample count: % 4d\n", op, count); unsigned line = codeBlock->lineNumberForBytecodeOffset(op); lineCounts.set(line, (lineCounts.contains(line) ? lineCounts.get(line) : 0) + count); } } - dataLog("\n"); + dataLogF("\n"); int linesCount = lineCounts.size(); Vector<LineCountInfo> lineCountInfo(linesCount); @@ -453,12 +453,12 @@ void SamplingTool::dump(ExecState* exec) qsort(lineCountInfo.begin(), linesCount, sizeof(LineCountInfo), compareLineCountInfoSampling); for (lineno = 0; lineno < linesCount; ++lineno) { - dataLog(" Line #%d has sample count %d.\n", lineCountInfo[lineno].line, lineCountInfo[lineno].count); + dataLogF(" Line #%d has sample count %d.\n", lineCountInfo[lineno].line, lineCountInfo[lineno].count); } - 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); + dataLogF("\n"); + dataLogF(" [*] Samples inside host code are charged to the calling Bytecode.\n"); + dataLogF(" Samples on a call / return boundary are not charged to a specific opcode or line.\n\n"); + dataLogF(" 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/SpeculatedType.h b/Source/JavaScriptCore/bytecode/SpeculatedType.h index 09ba9fdfa..656bc79ee 100644 --- a/Source/JavaScriptCore/bytecode/SpeculatedType.h +++ b/Source/JavaScriptCore/bytecode/SpeculatedType.h @@ -61,6 +61,7 @@ static const SpeculatedType SpecInt32 = 0x00800000; // It's definite static const SpeculatedType SpecDoubleReal = 0x01000000; // It's definitely a non-NaN double. static const SpeculatedType SpecDoubleNaN = 0x02000000; // It's definitely a NaN. static const SpeculatedType SpecDouble = 0x03000000; // It's either a non-NaN or a NaN double. +static const SpeculatedType SpecRealNumber = 0x01800000; // It's either an Int32 or a DoubleReal. static const SpeculatedType SpecNumber = 0x03800000; // It's either an Int32 or a Double. static const SpeculatedType SpecBoolean = 0x04000000; // It's definitely a Boolean. static const SpeculatedType SpecOther = 0x08000000; // It's definitely none of the above. @@ -228,6 +229,16 @@ inline bool isInt32Speculation(SpeculatedType value) return value == SpecInt32; } +inline bool isInt32SpeculationForArithmetic(SpeculatedType value) +{ + return !(value & SpecDouble); +} + +inline bool isInt32SpeculationExpectingDefined(SpeculatedType value) +{ + return isInt32Speculation(value & ~SpecOther); +} + inline bool isDoubleRealSpeculation(SpeculatedType value) { return value == SpecDoubleReal; @@ -238,11 +249,26 @@ inline bool isDoubleSpeculation(SpeculatedType value) return !!value && (value & SpecDouble) == value; } +inline bool isDoubleSpeculationForArithmetic(SpeculatedType value) +{ + return !!(value & SpecDouble); +} + +inline bool isRealNumberSpeculation(SpeculatedType value) +{ + return !!(value & SpecRealNumber) && !(value & ~SpecRealNumber); +} + inline bool isNumberSpeculation(SpeculatedType value) { return !!(value & SpecNumber) && !(value & ~SpecNumber); } +inline bool isNumberSpeculationExpectingDefined(SpeculatedType value) +{ + return isNumberSpeculation(value & ~SpecOther); +} + inline bool isBooleanSpeculation(SpeculatedType value) { return value == SpecBoolean; diff --git a/Source/JavaScriptCore/bytecode/StructureStubInfo.h b/Source/JavaScriptCore/bytecode/StructureStubInfo.h index a1bbc9c37..445ffe6c6 100644 --- a/Source/JavaScriptCore/bytecode/StructureStubInfo.h +++ b/Source/JavaScriptCore/bytecode/StructureStubInfo.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 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 diff --git a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp index 8aa48404a..e98d4de0a 100644 --- a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp +++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp @@ -80,8 +80,6 @@ void UnlinkedFunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visito COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); Base::visitChildren(thisObject, visitor); - visitor.append(&thisObject->m_codeBlockForCall); - visitor.append(&thisObject->m_codeBlockForConstruct); visitor.append(&thisObject->m_nameValue); visitor.append(&thisObject->m_symbolTableForCall); visitor.append(&thisObject->m_symbolTableForConstruct); @@ -112,12 +110,16 @@ UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor(JSGlobalData { switch (specializationKind) { case CodeForCall: - if (m_codeBlockForCall) - return m_codeBlockForCall.get(); + if (UnlinkedFunctionCodeBlock* codeBlock = m_codeBlockForCall.get()) { + globalData.codeCache()->usedFunctionCode(globalData, codeBlock); + return codeBlock; + } break; case CodeForConstruct: - if (m_codeBlockForConstruct) - return m_codeBlockForConstruct.get(); + if (UnlinkedFunctionCodeBlock* codeBlock = m_codeBlockForConstruct.get()) { + globalData.codeCache()->usedFunctionCode(globalData, codeBlock); + return codeBlock; + } break; } @@ -128,11 +130,11 @@ UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor(JSGlobalData switch (specializationKind) { case CodeForCall: - m_codeBlockForCall.set(globalData, this, result); + m_codeBlockForCall = PassWeak<UnlinkedFunctionCodeBlock>(result); m_symbolTableForCall.set(globalData, this, result->symbolTable()); break; case CodeForConstruct: - m_codeBlockForConstruct.set(globalData, this, result); + m_codeBlockForConstruct = PassWeak<UnlinkedFunctionCodeBlock>(result); m_symbolTableForConstruct.set(globalData, this, result->symbolTable()); break; } @@ -171,6 +173,7 @@ UnlinkedCodeBlock::UnlinkedCodeBlock(JSGlobalData* globalData, Structure* struct , m_resolveOperationCount(0) , m_putToBaseOperationCount(1) , m_arrayProfileCount(0) + , m_arrayAllocationProfileCount(0) , m_valueProfileCount(0) , m_llintCallLinkInfoCount(0) #if ENABLE(BYTECODE_COMMENTS) diff --git a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h index bf3f5fdff..23937d773 100644 --- a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h +++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h @@ -36,6 +36,7 @@ #include "Nodes.h" #include "RegExp.h" #include "SpecialPointer.h" +#include "Weak.h" #include <wtf/RefCountedArray.h> #include <wtf/Vector.h> @@ -56,6 +57,7 @@ class UnlinkedFunctionCodeBlock; typedef unsigned UnlinkedValueProfile; typedef unsigned UnlinkedArrayProfile; +typedef unsigned UnlinkedArrayAllocationProfile; typedef unsigned UnlinkedLLIntCallLinkInfo; struct ExecutableInfo { @@ -107,7 +109,7 @@ public: FunctionExecutable* link(JSGlobalData&, const SourceCode&, size_t lineOffset, size_t sourceOffset); - void clearCode() + void clearCodeForRecompilation() { m_symbolTableForCall.clear(); m_symbolTableForConstruct.clear(); @@ -135,8 +137,8 @@ public: private: UnlinkedFunctionExecutable(JSGlobalData*, Structure*, const SourceCode&, FunctionBodyNode*); - WriteBarrier<UnlinkedFunctionCodeBlock> m_codeBlockForCall; - WriteBarrier<UnlinkedFunctionCodeBlock> m_codeBlockForConstruct; + Weak<UnlinkedFunctionCodeBlock> m_codeBlockForCall; + Weak<UnlinkedFunctionCodeBlock> m_codeBlockForConstruct; unsigned m_numCapturedVariables : 29; bool m_forceUsesArguments : 1; @@ -392,6 +394,8 @@ public: UnlinkedArrayProfile addArrayProfile() { return m_arrayProfileCount++; } unsigned numberOfArrayProfiles() { return m_arrayProfileCount; } + UnlinkedArrayAllocationProfile addArrayAllocationProfile() { return m_arrayAllocationProfileCount++; } + unsigned numberOfArrayAllocationProfiles() { return m_arrayAllocationProfileCount; } UnlinkedValueProfile addValueProfile() { return m_valueProfileCount++; } unsigned numberOfValueProfiles() { return m_valueProfileCount; } @@ -518,6 +522,7 @@ private: unsigned m_resolveOperationCount; unsigned m_putToBaseOperationCount; unsigned m_arrayProfileCount; + unsigned m_arrayAllocationProfileCount; unsigned m_valueProfileCount; unsigned m_llintCallLinkInfoCount; |