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