summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/bytecode
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/bytecode')
-rw-r--r--Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp40
-rw-r--r--Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h80
-rw-r--r--Source/JavaScriptCore/bytecode/ArrayProfile.cpp7
-rw-r--r--Source/JavaScriptCore/bytecode/ArrayProfile.h48
-rw-r--r--Source/JavaScriptCore/bytecode/ByValInfo.h8
-rw-r--r--Source/JavaScriptCore/bytecode/CallLinkInfo.cpp2
-rw-r--r--Source/JavaScriptCore/bytecode/CallLinkInfo.h9
-rw-r--r--Source/JavaScriptCore/bytecode/CodeBlock.cpp569
-rw-r--r--Source/JavaScriptCore/bytecode/CodeBlock.h54
-rw-r--r--Source/JavaScriptCore/bytecode/DFGExitProfile.h2
-rw-r--r--Source/JavaScriptCore/bytecode/GetByIdStatus.cpp32
-rw-r--r--Source/JavaScriptCore/bytecode/GetByIdStatus.h8
-rw-r--r--Source/JavaScriptCore/bytecode/Instruction.h5
-rw-r--r--Source/JavaScriptCore/bytecode/Opcode.cpp24
-rw-r--r--Source/JavaScriptCore/bytecode/Opcode.h9
-rw-r--r--Source/JavaScriptCore/bytecode/Operands.h12
-rw-r--r--Source/JavaScriptCore/bytecode/PutByIdStatus.cpp73
-rw-r--r--Source/JavaScriptCore/bytecode/PutByIdStatus.h13
-rw-r--r--Source/JavaScriptCore/bytecode/SamplingTool.cpp60
-rw-r--r--Source/JavaScriptCore/bytecode/SpeculatedType.h26
-rw-r--r--Source/JavaScriptCore/bytecode/StructureStubInfo.h2
-rw-r--r--Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp19
-rw-r--r--Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h11
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;