summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/bytecode
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/bytecode')
-rw-r--r--Source/JavaScriptCore/bytecode/CodeBlock.cpp51
-rw-r--r--Source/JavaScriptCore/bytecode/CodeBlock.h55
-rw-r--r--Source/JavaScriptCore/bytecode/DFGExitProfile.h8
-rw-r--r--Source/JavaScriptCore/bytecode/GetByIdStatus.cpp115
-rw-r--r--Source/JavaScriptCore/bytecode/GetByIdStatus.h18
-rw-r--r--Source/JavaScriptCore/bytecode/Instruction.h6
-rw-r--r--Source/JavaScriptCore/bytecode/LazyOperandValueProfile.cpp4
-rw-r--r--Source/JavaScriptCore/bytecode/LazyOperandValueProfile.h2
-rw-r--r--Source/JavaScriptCore/bytecode/Opcode.h2
-rw-r--r--Source/JavaScriptCore/bytecode/PredictedType.h279
-rw-r--r--Source/JavaScriptCore/bytecode/PutByIdStatus.cpp3
-rw-r--r--Source/JavaScriptCore/bytecode/SpeculatedType.cpp (renamed from Source/JavaScriptCore/bytecode/PredictedType.cpp)154
-rw-r--r--Source/JavaScriptCore/bytecode/SpeculatedType.h279
-rw-r--r--Source/JavaScriptCore/bytecode/StructureSet.h23
-rw-r--r--Source/JavaScriptCore/bytecode/StructureStubInfo.h10
-rw-r--r--Source/JavaScriptCore/bytecode/ValueProfile.h14
-rw-r--r--Source/JavaScriptCore/bytecode/Watchpoint.cpp127
-rw-r--r--Source/JavaScriptCore/bytecode/Watchpoint.h220
18 files changed, 943 insertions, 427 deletions
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index 8ef716028..60596d1c2 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -228,6 +228,7 @@ void CodeBlock::printGetByIdOp(ExecState* exec, int location, Vector<Instruction
it += 5;
}
+#if ENABLE(JIT) || ENABLE(LLINT) // unused in some configurations
static void dumpStructure(const char* name, ExecState* exec, Structure* structure, Identifier& ident)
{
if (!structure)
@@ -239,7 +240,9 @@ static void dumpStructure(const char* name, ExecState* exec, Structure* structur
if (offset != notFound)
dataLog(" (offset = %lu)", static_cast<unsigned long>(offset));
}
+#endif
+#if ENABLE(JIT) // unused when not ENABLE(JIT), leading to silly warnings
static void dumpChain(ExecState* exec, StructureChain* chain, Identifier& ident)
{
dataLog("chain = %p: [", chain);
@@ -255,6 +258,7 @@ static void dumpChain(ExecState* exec, StructureChain* chain, Identifier& ident)
}
dataLog("]");
}
+#endif
void CodeBlock::printGetByIdCacheStatus(ExecState* exec, int location)
{
@@ -265,6 +269,8 @@ void CodeBlock::printGetByIdCacheStatus(ExecState* exec, int location)
Identifier& ident = identifier(instruction[3].u.operand);
+ UNUSED_PARAM(ident); // tell the compiler to shut up in certain platform configurations.
+
#if ENABLE(LLINT)
Structure* structure = instruction[4].u.structure.get();
dataLog(" llint(");
@@ -923,15 +929,31 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
}
case op_get_global_var: {
int r0 = (++it)->u.operand;
- int index = (++it)->u.operand;
- dataLog("[%4d] get_global_var\t %s, %d\n", location, registerName(exec, r0).data(), index);
+ WriteBarrier<Unknown>* registerPointer = (++it)->u.registerPointer;
+ dataLog("[%4d] get_global_var\t %s, g%d(%p)\n", location, registerName(exec, r0).data(), m_globalObject->findRegisterIndex(registerPointer), registerPointer);
+ it++;
+ break;
+ }
+ case op_get_global_var_watchable: {
+ int r0 = (++it)->u.operand;
+ WriteBarrier<Unknown>* registerPointer = (++it)->u.registerPointer;
+ dataLog("[%4d] get_global_var_watchable\t %s, g%d(%p)\n", location, registerName(exec, r0).data(), m_globalObject->findRegisterIndex(registerPointer), registerPointer);
+ it++;
it++;
break;
}
case op_put_global_var: {
- int index = (++it)->u.operand;
+ WriteBarrier<Unknown>* registerPointer = (++it)->u.registerPointer;
int r0 = (++it)->u.operand;
- dataLog("[%4d] put_global_var\t %d, %s\n", location, index, registerName(exec, r0).data());
+ dataLog("[%4d] put_global_var\t g%d(%p), %s\n", location, m_globalObject->findRegisterIndex(registerPointer), registerPointer, registerName(exec, r0).data());
+ break;
+ }
+ case op_put_global_var_check: {
+ WriteBarrier<Unknown>* registerPointer = (++it)->u.registerPointer;
+ int r0 = (++it)->u.operand;
+ dataLog("[%4d] put_global_var_check\t g%d(%p), %s\n", location, m_globalObject->findRegisterIndex(registerPointer), registerPointer, registerName(exec, r0).data());
+ it++;
+ it++;
break;
}
case op_resolve_base: {
@@ -1145,9 +1167,9 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
}
case op_jneq_ptr: {
int r0 = (++it)->u.operand;
- int r1 = (++it)->u.operand;
+ void* pointer = (++it)->u.pointer;
int offset = (++it)->u.operand;
- dataLog("[%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, %p, %d(->%d)\n", location, registerName(exec, r0).data(), pointer, offset, location + offset);
break;
}
case op_jless: {
@@ -1306,7 +1328,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
}
case op_call_put_result: {
int r0 = (++it)->u.operand;
- dataLog("[%4d] op_call_put_result\t\t %s\n", location, registerName(exec, r0).data());
+ dataLog("[%4d] call_put_result\t\t %s\n", location, registerName(exec, r0).data());
it++;
break;
}
@@ -1578,6 +1600,7 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other, SymbolTable* symTab)
, m_forcedOSRExitCounter(0)
, m_optimizationDelayCounter(0)
, m_reoptimizationRetryCounter(0)
+ , m_lineInfo(other.m_lineInfo)
#if ENABLE(JIT)
, m_canCompileWithDFGState(DFG::CapabilityLevelNotSet)
#endif
@@ -1585,7 +1608,7 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other, SymbolTable* symTab)
setNumParameters(other.numParameters());
optimizeAfterWarmUp();
jitAfterWarmUp();
-
+
if (other.m_rareData) {
createRareDataIfNecessary();
@@ -1596,7 +1619,6 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other, SymbolTable* symTab)
m_rareData->m_characterSwitchJumpTables = other.m_rareData->m_characterSwitchJumpTables;
m_rareData->m_stringSwitchJumpTables = other.m_rareData->m_stringSwitchJumpTables;
m_rareData->m_expressionInfo = other.m_rareData->m_expressionInfo;
- m_rareData->m_lineInfo = other.m_rareData->m_lineInfo;
}
}
@@ -2141,10 +2163,7 @@ int CodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset)
{
ASSERT(bytecodeOffset < instructions().size());
- if (!m_rareData)
- return m_ownerExecutable->source().firstLine();
-
- Vector<LineInfo>& lineInfo = m_rareData->m_lineInfo;
+ Vector<LineInfo>& lineInfo = m_lineInfo;
int low = 0;
int high = lineInfo.size();
@@ -2269,6 +2288,7 @@ void CodeBlock::shrinkToFit(ShrinkMode shrinkMode)
m_constantRegisters.shrinkToFit();
} // else don't shrink these, because we would have already pointed pointers into these tables.
+ m_lineInfo.shrinkToFit();
if (m_rareData) {
m_rareData->m_exceptionHandlers.shrinkToFit();
m_rareData->m_regexps.shrinkToFit();
@@ -2276,7 +2296,6 @@ void CodeBlock::shrinkToFit(ShrinkMode shrinkMode)
m_rareData->m_characterSwitchJumpTables.shrinkToFit();
m_rareData->m_stringSwitchJumpTables.shrinkToFit();
m_rareData->m_expressionInfo.shrinkToFit();
- m_rareData->m_lineInfo.shrinkToFit();
#if ENABLE(JIT)
m_rareData->m_callReturnIndexVector.shrinkToFit();
#endif
@@ -2560,7 +2579,7 @@ bool CodeBlock::shouldOptimizeNow()
profile->computeUpdatedPrediction();
continue;
}
- if (profile->numberOfSamples() || profile->m_prediction != PredictNone)
+ if (profile->numberOfSamples() || profile->m_prediction != SpecNone)
numberOfLiveNonArgumentValueProfiles++;
profile->computeUpdatedPrediction();
}
@@ -2614,7 +2633,7 @@ void CodeBlock::dumpValueProfiles()
dataLog(" arg = %u: ", i);
} else
dataLog(" bc = %d: ", profile->m_bytecodeOffset);
- if (!profile->numberOfSamples() && profile->m_prediction == PredictNone) {
+ if (!profile->numberOfSamples() && profile->m_prediction == SpecNone) {
dataLog("<empty>\n");
continue;
}
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h
index cdc6a19e8..573d422d3 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.h
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
* Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
*
* Redistribution and use in source and binary forms, with or without
@@ -62,6 +62,7 @@
#include "UString.h"
#include "UnconditionalFinalizer.h"
#include "ValueProfile.h"
+#include "Watchpoint.h"
#include <wtf/RefCountedArray.h>
#include <wtf/FastAllocBase.h>
#include <wtf/PassOwnPtr.h>
@@ -273,10 +274,12 @@ namespace JSC {
return result;
}
- void appendOSRExit(const DFG::OSRExit& osrExit)
+ unsigned appendOSRExit(const DFG::OSRExit& osrExit)
{
createDFGDataIfNecessary();
+ unsigned result = m_dfgData->osrExit.size();
m_dfgData->osrExit.append(osrExit);
+ return result;
}
DFG::OSRExit& lastOSRExit()
@@ -284,10 +287,20 @@ namespace JSC {
return m_dfgData->osrExit.last();
}
- void appendSpeculationRecovery(const DFG::SpeculationRecovery& recovery)
+ unsigned appendSpeculationRecovery(const DFG::SpeculationRecovery& recovery)
{
createDFGDataIfNecessary();
+ unsigned result = m_dfgData->speculationRecovery.size();
m_dfgData->speculationRecovery.append(recovery);
+ return result;
+ }
+
+ unsigned appendWatchpoint(const Watchpoint& watchpoint)
+ {
+ createDFGDataIfNecessary();
+ unsigned result = m_dfgData->watchpoints.size();
+ m_dfgData->watchpoints.append(watchpoint);
+ return result;
}
unsigned numberOfOSRExits()
@@ -304,6 +317,13 @@ namespace JSC {
return m_dfgData->speculationRecovery.size();
}
+ unsigned numberOfWatchpoints()
+ {
+ if (!m_dfgData)
+ return 0;
+ return m_dfgData->watchpoints.size();
+ }
+
DFG::OSRExit& osrExit(unsigned index)
{
return m_dfgData->osrExit[index];
@@ -314,6 +334,11 @@ namespace JSC {
return m_dfgData->speculationRecovery[index];
}
+ Watchpoint& watchpoint(unsigned index)
+ {
+ return m_dfgData->watchpoints[index];
+ }
+
void appendWeakReference(JSCell* target)
{
createDFGDataIfNecessary();
@@ -576,7 +601,7 @@ namespace JSC {
bytecodeOffset].u.opcode)) - 1].u.profile == result);
return result;
}
- PredictedType valueProfilePredictionForBytecodeOffset(int bytecodeOffset)
+ SpeculatedType valueProfilePredictionForBytecodeOffset(int bytecodeOffset)
{
return valueProfileForBytecodeOffset(bytecodeOffset)->computeUpdatedPrediction();
}
@@ -686,8 +711,7 @@ namespace JSC {
void addLineInfo(unsigned bytecodeOffset, int lineNo)
{
- createRareDataIfNecessary();
- Vector<LineInfo>& lineInfo = m_rareData->m_lineInfo;
+ Vector<LineInfo>& lineInfo = m_lineInfo;
if (!lineInfo.size() || lineInfo.last().lineNumber != lineNo) {
LineInfo info = { bytecodeOffset, lineNo };
lineInfo.append(info);
@@ -695,14 +719,6 @@ namespace JSC {
}
bool hasExpressionInfo() { return m_rareData && m_rareData->m_expressionInfo.size(); }
- bool hasLineInfo() { return m_rareData && m_rareData->m_lineInfo.size(); }
- // We only generate exception handling info if the user is debugging
- // (and may want line number info), or if the function contains exception handler.
- bool needsCallReturnIndices()
- {
- return m_rareData &&
- (m_rareData->m_expressionInfo.size() || m_rareData->m_lineInfo.size() || m_rareData->m_exceptionHandlers.size());
- }
#if ENABLE(JIT)
Vector<CallReturnOffsetToBytecodeOffset>& callReturnIndexVector()
@@ -1238,6 +1254,7 @@ namespace JSC {
Vector<DFG::OSREntryData> osrEntry;
SegmentedVector<DFG::OSRExit, 8> osrExit;
Vector<DFG::SpeculationRecovery> speculationRecovery;
+ SegmentedVector<Watchpoint, 1, 0> watchpoints;
Vector<WeakReferenceTransition> transitions;
Vector<WriteBarrier<JSCell> > weakReferences;
bool mayBeExecuting;
@@ -1285,7 +1302,9 @@ namespace JSC {
uint32_t m_forcedOSRExitCounter;
uint16_t m_optimizationDelayCounter;
uint16_t m_reoptimizationRetryCounter;
-
+
+ Vector<LineInfo> m_lineInfo;
+
struct RareData {
WTF_MAKE_FAST_ALLOCATED;
public:
@@ -1307,7 +1326,6 @@ namespace JSC {
// Expression info - present if debugging.
Vector<ExpressionRangeInfo> m_expressionInfo;
// Line info - present if profiling or debugging.
- Vector<LineInfo> m_lineInfo;
#if ENABLE(JIT)
Vector<CallReturnOffsetToBytecodeOffset> m_callReturnIndexVector;
#endif
@@ -1499,6 +1517,11 @@ namespace JSC {
}
#endif
+ inline JSValue Structure::prototypeForLookup(CodeBlock* codeBlock) const
+ {
+ return prototypeForLookup(codeBlock->globalObject());
+ }
+
} // namespace JSC
#endif // CodeBlock_h
diff --git a/Source/JavaScriptCore/bytecode/DFGExitProfile.h b/Source/JavaScriptCore/bytecode/DFGExitProfile.h
index 09f9ee075..d751ce654 100644
--- a/Source/JavaScriptCore/bytecode/DFGExitProfile.h
+++ b/Source/JavaScriptCore/bytecode/DFGExitProfile.h
@@ -41,6 +41,7 @@ enum ExitKind {
InadequateCoverage, // We exited because we ended up in code that didn't have profiling coverage.
ArgumentsEscaped, // We exited because arguments escaped but we didn't expect them to.
Uncountable, // We exited for none of the above reasons, and we should not count it. Most uses of this should be viewed as a FIXME.
+ UncountableWatchpoint // We exited because of a watchpoint, which isn't counted because watchpoints do tracking themselves.
};
inline const char* exitKindToString(ExitKind kind)
@@ -58,6 +59,12 @@ inline const char* exitKindToString(ExitKind kind)
return "NegativeZero";
case InadequateCoverage:
return "InadequateCoverage";
+ case ArgumentsEscaped:
+ return "ArgumentsEscaped";
+ case Uncountable:
+ return "Uncountable";
+ case UncountableWatchpoint:
+ return "UncountableWatchpoint";
default:
return "Unknown";
}
@@ -70,6 +77,7 @@ inline bool exitKindIsCountable(ExitKind kind)
ASSERT_NOT_REACHED();
case BadType:
case Uncountable:
+ case UncountableWatchpoint:
return false;
default:
return true;
diff --git a/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp b/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp
index 11aead3df..a62a43f7f 100644
--- a/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp
+++ b/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp
@@ -44,15 +44,61 @@ GetByIdStatus GetByIdStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned
Structure* structure = instruction[4].u.structure.get();
if (!structure)
- return GetByIdStatus(NoInformation, StructureSet(), notFound, false);
+ return GetByIdStatus(NoInformation, false);
- size_t offset = structure->get(*profiledBlock->globalData(), ident);
+ unsigned attributesIgnored;
+ JSCell* specificValue;
+ size_t offset = structure->get(
+ *profiledBlock->globalData(), ident, attributesIgnored, specificValue);
if (offset == notFound)
- return GetByIdStatus(NoInformation, StructureSet(), notFound, false);
+ return GetByIdStatus(NoInformation, false);
- return GetByIdStatus(SimpleDirect, StructureSet(structure), offset, false);
+ return GetByIdStatus(Simple, false, StructureSet(structure), offset, specificValue);
#else
- return GetByIdStatus(NoInformation, StructureSet(), notFound, false);
+ return GetByIdStatus(NoInformation, false);
+#endif
+}
+
+void GetByIdStatus::computeForChain(GetByIdStatus& result, CodeBlock* profiledBlock, Identifier& ident, Structure* structure)
+{
+#if ENABLE(JIT) && ENABLE(VALUE_PROFILER)
+ // Validate the chain. If the chain is invalid, then currently the best thing
+ // we can do is to assume that TakesSlow is true. In the future, it might be
+ // worth exploring reifying the structure chain from the structure we've got
+ // instead of using the one from the cache, since that will do the right things
+ // if the structure chain has changed. But that may be harder, because we may
+ // then end up having a different type of access altogether. And it currently
+ // does not appear to be worth it to do so -- effectively, the heuristic we
+ // have now is that if the structure chain has changed between when it was
+ // cached on in the baseline JIT and when the DFG tried to inline the access,
+ // then we fall back on a polymorphic access.
+ Structure* currentStructure = structure;
+ JSObject* currentObject = 0;
+ for (unsigned i = 0; i < result.m_chain.size(); ++i) {
+ currentObject = asObject(currentStructure->prototypeForLookup(profiledBlock));
+ currentStructure = result.m_chain[i];
+ if (currentObject->structure() != currentStructure)
+ return;
+ }
+
+ ASSERT(currentObject);
+
+ unsigned attributesIgnored;
+ JSCell* specificValue;
+
+ result.m_offset = currentStructure->get(
+ *profiledBlock->globalData(), ident, attributesIgnored, specificValue);
+ if (result.m_offset == notFound)
+ return;
+
+ result.m_structureSet.add(structure);
+ result.m_specificValue = JSValue(specificValue);
+#else
+ UNUSED_PARAM(result);
+ UNUSED_PARAM(profiledBlock);
+ UNUSED_PARAM(ident);
+ UNUSED_PARAM(structure);
+ UNREACHABLE_FOR_PLATFORM();
#endif
}
@@ -89,12 +135,12 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec
}
for (int i = 0; i < listSize; ++i) {
if (!list->list[i].isDirect)
- return GetByIdStatus(MakesCalls, StructureSet(), notFound, true);
+ return GetByIdStatus(MakesCalls, 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, true);
+ return GetByIdStatus(TakesSlowPath, true);
// Finally figure out if we can derive an access strategy.
GetByIdStatus result;
@@ -105,10 +151,15 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec
case access_get_by_id_self: {
Structure* structure = stubInfo.u.getByIdSelf.baseObjectStructure.get();
- result.m_offset = structure->get(*profiledBlock->globalData(), ident);
+ unsigned attributesIgnored;
+ JSCell* specificValue;
+ result.m_offset = structure->get(
+ *profiledBlock->globalData(), ident, attributesIgnored, specificValue);
- if (result.m_offset != notFound)
+ if (result.m_offset != notFound) {
result.m_structureSet.add(structure);
+ result.m_specificValue = JSValue(specificValue);
+ }
if (result.m_offset != notFound)
ASSERT(result.m_structureSet.size());
@@ -116,29 +167,32 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec
}
case access_get_by_id_self_list: {
- PolymorphicAccessStructureList* list = stubInfo.u.getByIdProtoList.structureList;
- unsigned size = stubInfo.u.getByIdProtoList.listSize;
- for (unsigned i = 0; i < size; ++i) {
+ for (int i = 0; i < listSize; ++i) {
ASSERT(list->list[i].isDirect);
Structure* structure = list->list[i].base.get();
if (result.m_structureSet.contains(structure))
continue;
- size_t myOffset = structure->get(*profiledBlock->globalData(), ident);
+ unsigned attributesIgnored;
+ JSCell* specificValue;
+ size_t myOffset = structure->get(
+ *profiledBlock->globalData(), ident, attributesIgnored, specificValue);
if (myOffset == notFound) {
result.m_offset = notFound;
break;
}
- if (!i)
+ if (!i) {
result.m_offset = myOffset;
- else if (result.m_offset != myOffset) {
+ result.m_specificValue = JSValue(specificValue);
+ } else if (result.m_offset != myOffset) {
result.m_offset = notFound;
break;
- }
-
+ } else if (result.m_specificValue != JSValue(specificValue))
+ result.m_specificValue = JSValue();
+
result.m_structureSet.add(structure);
}
@@ -147,6 +201,27 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec
break;
}
+ case access_get_by_id_proto: {
+ if (!stubInfo.u.getByIdProto.isDirect)
+ return GetByIdStatus(MakesCalls, true);
+ result.m_chain.append(stubInfo.u.getByIdProto.prototypeStructure.get());
+ computeForChain(
+ result, profiledBlock, ident,
+ stubInfo.u.getByIdProto.baseObjectStructure.get());
+ break;
+ }
+
+ case access_get_by_id_chain: {
+ if (!stubInfo.u.getByIdChain.isDirect)
+ return GetByIdStatus(MakesCalls, true);
+ for (unsigned i = 0; i < stubInfo.u.getByIdChain.count; ++i)
+ result.m_chain.append(stubInfo.u.getByIdChain.chain->head()[i].get());
+ computeForChain(
+ result, profiledBlock, ident,
+ stubInfo.u.getByIdChain.baseObjectStructure.get());
+ break;
+ }
+
default:
ASSERT(result.m_offset == notFound);
break;
@@ -155,12 +230,14 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec
if (result.m_offset == notFound) {
result.m_state = TakesSlowPath;
result.m_structureSet.clear();
+ result.m_chain.clear();
+ result.m_specificValue = JSValue();
} else
- result.m_state = SimpleDirect;
+ result.m_state = Simple;
return result;
#else // ENABLE(JIT)
- return GetByIdStatus(NoInformation, StructureSet(), notFound, false);
+ return GetByIdStatus(NoInformation, false);
#endif // ENABLE(JIT)
}
diff --git a/Source/JavaScriptCore/bytecode/GetByIdStatus.h b/Source/JavaScriptCore/bytecode/GetByIdStatus.h
index 39476c009..42eadfd68 100644
--- a/Source/JavaScriptCore/bytecode/GetByIdStatus.h
+++ b/Source/JavaScriptCore/bytecode/GetByIdStatus.h
@@ -38,7 +38,8 @@ class GetByIdStatus {
public:
enum State {
NoInformation, // It's uncached so we have no information.
- SimpleDirect, // It's cached for a direct access to a known object property.
+ Simple, // It's cached for a simple access to a known object property with
+ // a possible structure chain and a possible specific value.
TakesSlowPath, // It's known to often take slow path.
MakesCalls // It's known to take paths that make calls.
};
@@ -49,13 +50,17 @@ public:
{
}
- GetByIdStatus(State state, const StructureSet& structureSet, size_t offset, bool wasSeenInJIT)
+ GetByIdStatus(
+ State state, bool wasSeenInJIT, const StructureSet& structureSet = StructureSet(),
+ size_t offset = notFound, JSValue specificValue = JSValue(), Vector<Structure*> chain = Vector<Structure*>())
: m_state(state)
, m_structureSet(structureSet)
+ , m_chain(chain)
+ , m_specificValue(specificValue)
, m_offset(offset)
, m_wasSeenInJIT(wasSeenInJIT)
{
- ASSERT((state == SimpleDirect) == (offset != notFound));
+ ASSERT((state == Simple) == (offset != notFound));
}
static GetByIdStatus computeFor(CodeBlock*, unsigned bytecodeIndex, Identifier&);
@@ -64,20 +69,25 @@ public:
bool isSet() const { return m_state != NoInformation; }
bool operator!() const { return !isSet(); }
- bool isSimpleDirect() const { return m_state == SimpleDirect; }
+ bool isSimple() const { return m_state == Simple; }
bool takesSlowPath() const { return m_state == TakesSlowPath || m_state == MakesCalls; }
bool makesCalls() const { return m_state == MakesCalls; }
const StructureSet& structureSet() const { return m_structureSet; }
+ const Vector<Structure*>& chain() const { return m_chain; } // Returns empty vector if this is a direct access.
+ JSValue specificValue() const { return m_specificValue; } // Returns JSValue() if there is no specific value.
size_t offset() const { return m_offset; }
bool wasSeenInJIT() const { return m_wasSeenInJIT; }
private:
+ static void computeForChain(GetByIdStatus& result, CodeBlock*, Identifier&, Structure*);
static GetByIdStatus computeFromLLInt(CodeBlock*, unsigned bytecodeIndex, Identifier&);
State m_state;
StructureSet m_structureSet;
+ Vector<Structure*> m_chain;
+ JSValue m_specificValue;
size_t m_offset;
bool m_wasSeenInJIT;
};
diff --git a/Source/JavaScriptCore/bytecode/Instruction.h b/Source/JavaScriptCore/bytecode/Instruction.h
index c4989d2db..6e76512ff 100644
--- a/Source/JavaScriptCore/bytecode/Instruction.h
+++ b/Source/JavaScriptCore/bytecode/Instruction.h
@@ -191,6 +191,10 @@ namespace JSC {
Instruction(LLIntCallLinkInfo* callLinkInfo) { u.callLinkInfo = callLinkInfo; }
Instruction(ValueProfile* profile) { u.profile = profile; }
+
+ Instruction(WriteBarrier<Unknown>* registerPointer) { u.registerPointer = registerPointer; }
+
+ Instruction(bool* predicatePointer) { u.predicatePointer = predicatePointer; }
union {
Opcode opcode;
@@ -198,10 +202,12 @@ namespace JSC {
WriteBarrierBase<Structure> structure;
WriteBarrierBase<StructureChain> structureChain;
WriteBarrierBase<JSCell> jsCell;
+ WriteBarrier<Unknown>* registerPointer;
PropertySlot::GetValueFunc getterFunc;
LLIntCallLinkInfo* callLinkInfo;
ValueProfile* profile;
void* pointer;
+ bool* predicatePointer;
} u;
private:
diff --git a/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.cpp b/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.cpp
index 695e21219..59f0d0234 100644
--- a/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.cpp
+++ b/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.cpp
@@ -84,12 +84,12 @@ LazyOperandValueProfile* LazyOperandValueProfileParser::getIfPresent(
return iter->second;
}
-PredictedType LazyOperandValueProfileParser::prediction(
+SpeculatedType LazyOperandValueProfileParser::prediction(
const LazyOperandValueProfileKey& key) const
{
LazyOperandValueProfile* profile = getIfPresent(key);
if (!profile)
- return PredictNone;
+ return SpecNone;
return profile->computeUpdatedPrediction();
}
diff --git a/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.h b/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.h
index 91e5314aa..a117db64f 100644
--- a/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.h
+++ b/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.h
@@ -174,7 +174,7 @@ public:
LazyOperandValueProfile* getIfPresent(
const LazyOperandValueProfileKey& key) const;
- PredictedType prediction(const LazyOperandValueProfileKey& key) const;
+ SpeculatedType prediction(const LazyOperandValueProfileKey& key) const;
private:
CompressedLazyOperandValueProfileHolder& m_holder;
HashMap<LazyOperandValueProfileKey, LazyOperandValueProfile*> m_map;
diff --git a/Source/JavaScriptCore/bytecode/Opcode.h b/Source/JavaScriptCore/bytecode/Opcode.h
index aa83d9b97..e0cff165a 100644
--- a/Source/JavaScriptCore/bytecode/Opcode.h
+++ b/Source/JavaScriptCore/bytecode/Opcode.h
@@ -100,7 +100,9 @@ namespace JSC {
macro(op_get_scoped_var, 5) /* has value profiling */ \
macro(op_put_scoped_var, 4) \
macro(op_get_global_var, 4) /* has value profiling */ \
+ macro(op_get_global_var_watchable, 5) /* has value profiling */ \
macro(op_put_global_var, 3) \
+ macro(op_put_global_var_check, 5) \
macro(op_resolve_base, 5) /* has value profiling */ \
macro(op_ensure_property_exists, 3) \
macro(op_resolve_with_base, 5) /* has value profiling */ \
diff --git a/Source/JavaScriptCore/bytecode/PredictedType.h b/Source/JavaScriptCore/bytecode/PredictedType.h
deleted file mode 100644
index 9f0964a14..000000000
--- a/Source/JavaScriptCore/bytecode/PredictedType.h
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * 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
- * 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.
- */
-
-#ifndef PredictedType_h
-#define PredictedType_h
-
-#include "JSValue.h"
-
-namespace JSC {
-
-class Structure;
-
-typedef uint32_t PredictedType;
-static const PredictedType PredictNone = 0x00000000; // We don't know anything yet.
-static const PredictedType PredictFinalObject = 0x00000001; // It's definitely a JSFinalObject.
-static const PredictedType PredictArray = 0x00000002; // It's definitely a JSArray.
-static const PredictedType PredictFunction = 0x00000008; // It's definitely a JSFunction or one of its subclasses.
-static const PredictedType PredictInt8Array = 0x00000010; // It's definitely an Int8Array or one of its subclasses.
-static const PredictedType PredictInt16Array = 0x00000020; // It's definitely an Int16Array or one of its subclasses.
-static const PredictedType PredictInt32Array = 0x00000040; // It's definitely an Int32Array or one of its subclasses.
-static const PredictedType PredictUint8Array = 0x00000080; // It's definitely an Uint8Array or one of its subclasses.
-static const PredictedType PredictUint8ClampedArray = 0x00000100; // It's definitely an Uint8ClampedArray or one of its subclasses.
-static const PredictedType PredictUint16Array = 0x00000200; // It's definitely an Uint16Array or one of its subclasses.
-static const PredictedType PredictUint32Array = 0x00000400; // It's definitely an Uint32Array or one of its subclasses.
-static const PredictedType PredictFloat32Array = 0x00000800; // It's definitely an Uint16Array or one of its subclasses.
-static const PredictedType PredictFloat64Array = 0x00001000; // It's definitely an Uint16Array or one of its subclasses.
-static const PredictedType PredictMyArguments = 0x00002000; // It's definitely an Arguments object, and it's definitely the one for my current frame.
-static const PredictedType PredictForeignArguments = 0x00004000; // It's definitely an Arguments object, and it's definitely not mine.
-static const PredictedType PredictArguments = 0x00006000; // It's definitely an Arguments object.
-static const PredictedType PredictObjectOther = 0x00008000; // It's definitely an object but not JSFinalObject, JSArray, or JSFunction.
-static const PredictedType PredictObjectMask = 0x0000ffff; // Bitmask used for testing for any kind of object prediction.
-static const PredictedType PredictString = 0x00010000; // It's definitely a JSString.
-static const PredictedType PredictCellOther = 0x00020000; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString.
-static const PredictedType PredictCell = 0x0003ffff; // It's definitely a JSCell.
-static const PredictedType PredictInt32 = 0x00800000; // It's definitely an Int32.
-static const PredictedType PredictDoubleReal = 0x01000000; // It's definitely a non-NaN double.
-static const PredictedType PredictDoubleNaN = 0x02000000; // It's definitely a NaN.
-static const PredictedType PredictDouble = 0x03000000; // It's either a non-NaN or a NaN double.
-static const PredictedType PredictNumber = 0x03800000; // It's either an Int32 or a Double.
-static const PredictedType PredictBoolean = 0x04000000; // It's definitely a Boolean.
-static const PredictedType PredictOther = 0x08000000; // It's definitely none of the above.
-static const PredictedType PredictTop = 0x0fffffff; // It can be any of the above.
-static const PredictedType PredictEmpty = 0x10000000; // It's definitely an empty value marker.
-static const PredictedType PredictEmptyOrTop = 0x1fffffff; // It can be any of the above.
-static const PredictedType FixedIndexedStorageMask = PredictInt8Array | PredictInt16Array | PredictInt32Array | PredictUint8Array | PredictUint8ClampedArray | PredictUint16Array | PredictUint32Array | PredictFloat32Array | PredictFloat64Array;
-
-typedef bool (*PredictionChecker)(PredictedType);
-
-// Dummy prediction checker, only useful if someone insists on requiring a prediction checker.
-inline bool isAnyPrediction(PredictedType)
-{
- return true;
-}
-
-inline bool isCellPrediction(PredictedType value)
-{
- return !!(value & PredictCell) && !(value & ~PredictCell);
-}
-
-inline bool isObjectPrediction(PredictedType value)
-{
- return !!(value & PredictObjectMask) && !(value & ~PredictObjectMask);
-}
-
-inline bool isFinalObjectPrediction(PredictedType value)
-{
- return value == PredictFinalObject;
-}
-
-inline bool isFinalObjectOrOtherPrediction(PredictedType value)
-{
- return !!(value & (PredictFinalObject | PredictOther)) && !(value & ~(PredictFinalObject | PredictOther));
-}
-
-inline bool isFixedIndexedStorageObjectPrediction(PredictedType value)
-{
- return !!value && (value & FixedIndexedStorageMask) == value;
-}
-
-inline bool isStringPrediction(PredictedType value)
-{
- return value == PredictString;
-}
-
-inline bool isArrayPrediction(PredictedType value)
-{
- return value == PredictArray;
-}
-
-inline bool isFunctionPrediction(PredictedType value)
-{
- return value == PredictFunction;
-}
-
-inline bool isInt8ArrayPrediction(PredictedType value)
-{
- return value == PredictInt8Array;
-}
-
-inline bool isInt16ArrayPrediction(PredictedType value)
-{
- return value == PredictInt16Array;
-}
-
-inline bool isInt32ArrayPrediction(PredictedType value)
-{
- return value == PredictInt32Array;
-}
-
-inline bool isUint8ArrayPrediction(PredictedType value)
-{
- return value == PredictUint8Array;
-}
-
-inline bool isUint8ClampedArrayPrediction(PredictedType value)
-{
- return value == PredictUint8ClampedArray;
-}
-
-inline bool isUint16ArrayPrediction(PredictedType value)
-{
- return value == PredictUint16Array;
-}
-
-inline bool isUint32ArrayPrediction(PredictedType value)
-{
- return value == PredictUint32Array;
-}
-
-inline bool isFloat32ArrayPrediction(PredictedType value)
-{
- return value == PredictFloat32Array;
-}
-
-inline bool isFloat64ArrayPrediction(PredictedType value)
-{
- return value == PredictFloat64Array;
-}
-
-inline bool isArgumentsPrediction(PredictedType value)
-{
- return !!value && (value & PredictArguments) == value;
-}
-
-inline bool isActionableIntMutableArrayPrediction(PredictedType value)
-{
- return isInt8ArrayPrediction(value)
- || isInt16ArrayPrediction(value)
- || isInt32ArrayPrediction(value)
- || isUint8ArrayPrediction(value)
- || isUint8ClampedArrayPrediction(value)
- || isUint16ArrayPrediction(value)
- || isUint32ArrayPrediction(value);
-}
-
-inline bool isActionableFloatMutableArrayPrediction(PredictedType value)
-{
- return isFloat32ArrayPrediction(value)
- || isFloat64ArrayPrediction(value);
-}
-
-inline bool isActionableTypedMutableArrayPrediction(PredictedType value)
-{
- return isActionableIntMutableArrayPrediction(value)
- || isActionableFloatMutableArrayPrediction(value);
-}
-
-inline bool isActionableMutableArrayPrediction(PredictedType value)
-{
- return isArrayPrediction(value)
- || isArgumentsPrediction(value)
- || isActionableTypedMutableArrayPrediction(value);
-}
-
-inline bool isActionableArrayPrediction(PredictedType value)
-{
- return isStringPrediction(value)
- || isActionableMutableArrayPrediction(value);
-}
-
-inline bool isArrayOrOtherPrediction(PredictedType value)
-{
- return !!(value & (PredictArray | PredictOther)) && !(value & ~(PredictArray | PredictOther));
-}
-
-inline bool isMyArgumentsPrediction(PredictedType value)
-{
- return value == PredictMyArguments;
-}
-
-inline bool isInt32Prediction(PredictedType value)
-{
- return value == PredictInt32;
-}
-
-inline bool isDoubleRealPrediction(PredictedType value)
-{
- return value == PredictDoubleReal;
-}
-
-inline bool isDoublePrediction(PredictedType value)
-{
- return !!value && (value & PredictDouble) == value;
-}
-
-inline bool isNumberPrediction(PredictedType value)
-{
- return !!(value & PredictNumber) && !(value & ~PredictNumber);
-}
-
-inline bool isBooleanPrediction(PredictedType value)
-{
- return value == PredictBoolean;
-}
-
-inline bool isOtherPrediction(PredictedType value)
-{
- return value == PredictOther;
-}
-
-inline bool isEmptyPrediction(PredictedType value)
-{
- return value == PredictEmpty;
-}
-
-const char* predictionToString(PredictedType value);
-const char* predictionToAbbreviatedString(PredictedType value);
-
-// Merge two predictions. Note that currently this just does left | right. It may
-// seem tempting to do so directly, but you would be doing so at your own peril,
-// since the merging protocol PredictedType may change at any time (and has already
-// changed several times in its history).
-inline PredictedType mergePredictions(PredictedType left, PredictedType right)
-{
- return left | right;
-}
-
-template<typename T>
-inline bool mergePrediction(T& left, PredictedType right)
-{
- PredictedType newPrediction = static_cast<T>(mergePredictions(static_cast<PredictedType>(left), right));
- bool result = newPrediction != static_cast<PredictedType>(left);
- left = newPrediction;
- return result;
-}
-
-PredictedType predictionFromClassInfo(const ClassInfo*);
-PredictedType predictionFromStructure(Structure*);
-PredictedType predictionFromCell(JSCell*);
-PredictedType predictionFromValue(JSValue);
-
-} // namespace JSC
-
-#endif // PredictedType_h
diff --git a/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp b/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp
index 209d4cd5e..3715606fe 100644
--- a/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp
+++ b/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp
@@ -53,6 +53,8 @@ PutByIdStatus PutByIdStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned
return PutByIdStatus(SimpleReplace, structure, 0, 0, offset);
}
+ ASSERT(structure->transitionWatchpointSetHasBeenInvalidated());
+
ASSERT(instruction[0].u.opcode == llint_op_put_by_id_transition_direct
|| instruction[0].u.opcode == llint_op_put_by_id_transition_normal);
@@ -106,6 +108,7 @@ PutByIdStatus PutByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec
case access_put_by_id_transition_normal:
case access_put_by_id_transition_direct: {
+ ASSERT(stubInfo.u.putByIdTransition.previousStructure->transitionWatchpointSetHasBeenInvalidated());
size_t offset = stubInfo.u.putByIdTransition.structure->get(
*profiledBlock->globalData(), ident);
if (offset != notFound) {
diff --git a/Source/JavaScriptCore/bytecode/PredictedType.cpp b/Source/JavaScriptCore/bytecode/SpeculatedType.cpp
index 5258f4079..02d0f7e77 100644
--- a/Source/JavaScriptCore/bytecode/PredictedType.cpp
+++ b/Source/JavaScriptCore/bytecode/SpeculatedType.cpp
@@ -27,7 +27,7 @@
*/
#include "config.h"
-#include "PredictedType.h"
+#include "SpeculatedType.h"
#include "Arguments.h"
#include "JSArray.h"
@@ -37,9 +37,9 @@
namespace JSC {
-const char* predictionToString(PredictedType value)
+const char* speculationToString(SpeculatedType value)
{
- if (value == PredictNone)
+ if (value == SpecNone)
return "None";
static const int size = 256;
@@ -48,112 +48,112 @@ const char* predictionToString(PredictedType value)
bool isTop = true;
- if (value & PredictCellOther)
+ if (value & SpecCellOther)
ptr.strcat("Othercell");
else
isTop = false;
- if (value & PredictObjectOther)
+ if (value & SpecObjectOther)
ptr.strcat("Otherobj");
else
isTop = false;
- if (value & PredictFinalObject)
+ if (value & SpecFinalObject)
ptr.strcat("Final");
else
isTop = false;
- if (value & PredictArray)
+ if (value & SpecArray)
ptr.strcat("Array");
else
isTop = false;
- if (value & PredictInt8Array)
+ if (value & SpecInt8Array)
ptr.strcat("Int8array");
else
isTop = false;
- if (value & PredictInt16Array)
+ if (value & SpecInt16Array)
ptr.strcat("Int16array");
else
isTop = false;
- if (value & PredictInt32Array)
+ if (value & SpecInt32Array)
ptr.strcat("Int32array");
else
isTop = false;
- if (value & PredictUint8Array)
+ if (value & SpecUint8Array)
ptr.strcat("Uint8array");
else
isTop = false;
- if (value & PredictUint8ClampedArray)
+ if (value & SpecUint8ClampedArray)
ptr.strcat("Uint8clampedarray");
else
isTop = false;
- if (value & PredictUint16Array)
+ if (value & SpecUint16Array)
ptr.strcat("Uint16array");
else
isTop = false;
- if (value & PredictUint32Array)
+ if (value & SpecUint32Array)
ptr.strcat("Uint32array");
else
isTop = false;
- if (value & PredictFloat32Array)
+ if (value & SpecFloat32Array)
ptr.strcat("Float32array");
else
isTop = false;
- if (value & PredictFloat64Array)
+ if (value & SpecFloat64Array)
ptr.strcat("Float64array");
else
isTop = false;
- if (value & PredictFunction)
+ if (value & SpecFunction)
ptr.strcat("Function");
else
isTop = false;
- if (value & PredictMyArguments)
+ if (value & SpecMyArguments)
ptr.strcat("Myarguments");
else
isTop = false;
- if (value & PredictForeignArguments)
+ if (value & SpecForeignArguments)
ptr.strcat("Foreignarguments");
else
isTop = false;
- if (value & PredictString)
+ if (value & SpecString)
ptr.strcat("String");
else
isTop = false;
- if (value & PredictInt32)
+ if (value & SpecInt32)
ptr.strcat("Int");
else
isTop = false;
- if (value & PredictDoubleReal)
+ if (value & SpecDoubleReal)
ptr.strcat("Doublereal");
else
isTop = false;
- if (value & PredictDoubleNaN)
+ if (value & SpecDoubleNaN)
ptr.strcat("Doublenan");
else
isTop = false;
- if (value & PredictBoolean)
+ if (value & SpecBoolean)
ptr.strcat("Bool");
else
isTop = false;
- if (value & PredictOther)
+ if (value & SpecOther)
ptr.strcat("Other");
else
isTop = false;
@@ -163,7 +163,7 @@ const char* predictionToString(PredictedType value)
ptr.strcat("Top");
}
- if (value & PredictEmpty)
+ if (value & SpecEmpty)
ptr.strcat("Empty");
*ptr++ = 0;
@@ -171,130 +171,130 @@ const char* predictionToString(PredictedType value)
return description;
}
-const char* predictionToAbbreviatedString(PredictedType prediction)
+const char* speculationToAbbreviatedString(SpeculatedType prediction)
{
- if (isFinalObjectPrediction(prediction))
+ if (isFinalObjectSpeculation(prediction))
return "<Final>";
- if (isArrayPrediction(prediction))
+ if (isArraySpeculation(prediction))
return "<Array>";
- if (isStringPrediction(prediction))
+ if (isStringSpeculation(prediction))
return "<String>";
- if (isFunctionPrediction(prediction))
+ if (isFunctionSpeculation(prediction))
return "<Function>";
- if (isInt8ArrayPrediction(prediction))
+ if (isInt8ArraySpeculation(prediction))
return "<Int8array>";
- if (isInt16ArrayPrediction(prediction))
+ if (isInt16ArraySpeculation(prediction))
return "<Int16array>";
- if (isInt32ArrayPrediction(prediction))
+ if (isInt32ArraySpeculation(prediction))
return "<Int32array>";
- if (isUint8ArrayPrediction(prediction))
+ if (isUint8ArraySpeculation(prediction))
return "<Uint8array>";
- if (isUint16ArrayPrediction(prediction))
+ if (isUint16ArraySpeculation(prediction))
return "<Uint16array>";
- if (isUint32ArrayPrediction(prediction))
+ if (isUint32ArraySpeculation(prediction))
return "<Uint32array>";
- if (isFloat32ArrayPrediction(prediction))
+ if (isFloat32ArraySpeculation(prediction))
return "<Float32array>";
- if (isFloat64ArrayPrediction(prediction))
+ if (isFloat64ArraySpeculation(prediction))
return "<Float64array>";
- if (isMyArgumentsPrediction(prediction))
+ if (isMyArgumentsSpeculation(prediction))
return "<Myarguments>";
- if (isArgumentsPrediction(prediction))
+ if (isArgumentsSpeculation(prediction))
return "<Arguments>";
- if (isObjectPrediction(prediction))
+ if (isObjectSpeculation(prediction))
return "<Object>";
- if (isCellPrediction(prediction))
+ if (isCellSpeculation(prediction))
return "<Cell>";
- if (isInt32Prediction(prediction))
+ if (isInt32Speculation(prediction))
return "<Int32>";
- if (isDoublePrediction(prediction))
+ if (isDoubleSpeculation(prediction))
return "<Double>";
- if (isNumberPrediction(prediction))
+ if (isNumberSpeculation(prediction))
return "<Number>";
- if (isBooleanPrediction(prediction))
+ if (isBooleanSpeculation(prediction))
return "<Boolean>";
- if (isOtherPrediction(prediction))
+ if (isOtherSpeculation(prediction))
return "<Other>";
return "";
}
-PredictedType predictionFromClassInfo(const ClassInfo* classInfo)
+SpeculatedType speculationFromClassInfo(const ClassInfo* classInfo)
{
if (classInfo == &JSFinalObject::s_info)
- return PredictFinalObject;
+ return SpecFinalObject;
if (classInfo == &JSArray::s_info)
- return PredictArray;
+ return SpecArray;
if (classInfo == &JSString::s_info)
- return PredictString;
+ return SpecString;
if (classInfo == &Arguments::s_info)
- return PredictArguments; // Cannot distinguish between MyArguments and ForeignArguments at this stage. That happens in the flow analysis.
+ return SpecArguments; // Cannot distinguish between MyArguments and ForeignArguments at this stage. That happens in the flow analysis.
if (classInfo->isSubClassOf(&JSFunction::s_info))
- return PredictFunction;
+ return SpecFunction;
if (classInfo->typedArrayStorageType != TypedArrayNone) {
switch (classInfo->typedArrayStorageType) {
case TypedArrayInt8:
- return PredictInt8Array;
+ return SpecInt8Array;
case TypedArrayInt16:
- return PredictInt16Array;
+ return SpecInt16Array;
case TypedArrayInt32:
- return PredictInt32Array;
+ return SpecInt32Array;
case TypedArrayUint8:
- return PredictUint8Array;
+ return SpecUint8Array;
case TypedArrayUint8Clamped:
- return PredictUint8ClampedArray;
+ return SpecUint8ClampedArray;
case TypedArrayUint16:
- return PredictUint16Array;
+ return SpecUint16Array;
case TypedArrayUint32:
- return PredictUint32Array;
+ return SpecUint32Array;
case TypedArrayFloat32:
- return PredictFloat32Array;
+ return SpecFloat32Array;
case TypedArrayFloat64:
- return PredictFloat64Array;
+ return SpecFloat64Array;
default:
break;
}
}
if (classInfo->isSubClassOf(&JSObject::s_info))
- return PredictObjectOther;
+ return SpecObjectOther;
- return PredictCellOther;
+ return SpecCellOther;
}
-PredictedType predictionFromStructure(Structure* structure)
+SpeculatedType speculationFromStructure(Structure* structure)
{
- return predictionFromClassInfo(structure->classInfo());
+ return speculationFromClassInfo(structure->classInfo());
}
-PredictedType predictionFromCell(JSCell* cell)
+SpeculatedType speculationFromCell(JSCell* cell)
{
- return predictionFromStructure(cell->structure());
+ return speculationFromStructure(cell->structure());
}
-PredictedType predictionFromValue(JSValue value)
+SpeculatedType speculationFromValue(JSValue value)
{
if (value.isEmpty())
- return PredictEmpty;
+ return SpecEmpty;
if (value.isInt32())
- return PredictInt32;
+ return SpecInt32;
if (value.isDouble()) {
double number = value.asNumber();
if (number == number)
- return PredictDoubleReal;
- return PredictDoubleNaN;
+ return SpecDoubleReal;
+ return SpecDoubleNaN;
}
if (value.isCell())
- return predictionFromCell(value.asCell());
+ return speculationFromCell(value.asCell());
if (value.isBoolean())
- return PredictBoolean;
+ return SpecBoolean;
ASSERT(value.isUndefinedOrNull());
- return PredictOther;
+ return SpecOther;
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/bytecode/SpeculatedType.h b/Source/JavaScriptCore/bytecode/SpeculatedType.h
new file mode 100644
index 000000000..91fb4fe4d
--- /dev/null
+++ b/Source/JavaScriptCore/bytecode/SpeculatedType.h
@@ -0,0 +1,279 @@
+/*
+ * 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
+ * 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.
+ */
+
+#ifndef SpeculatedType_h
+#define SpeculatedType_h
+
+#include "JSValue.h"
+
+namespace JSC {
+
+class Structure;
+
+typedef uint32_t SpeculatedType;
+static const SpeculatedType SpecNone = 0x00000000; // We don't know anything yet.
+static const SpeculatedType SpecFinalObject = 0x00000001; // It's definitely a JSFinalObject.
+static const SpeculatedType SpecArray = 0x00000002; // It's definitely a JSArray.
+static const SpeculatedType SpecFunction = 0x00000008; // It's definitely a JSFunction or one of its subclasses.
+static const SpeculatedType SpecInt8Array = 0x00000010; // It's definitely an Int8Array or one of its subclasses.
+static const SpeculatedType SpecInt16Array = 0x00000020; // It's definitely an Int16Array or one of its subclasses.
+static const SpeculatedType SpecInt32Array = 0x00000040; // It's definitely an Int32Array or one of its subclasses.
+static const SpeculatedType SpecUint8Array = 0x00000080; // It's definitely an Uint8Array or one of its subclasses.
+static const SpeculatedType SpecUint8ClampedArray = 0x00000100; // It's definitely an Uint8ClampedArray or one of its subclasses.
+static const SpeculatedType SpecUint16Array = 0x00000200; // It's definitely an Uint16Array or one of its subclasses.
+static const SpeculatedType SpecUint32Array = 0x00000400; // It's definitely an Uint32Array or one of its subclasses.
+static const SpeculatedType SpecFloat32Array = 0x00000800; // It's definitely an Uint16Array or one of its subclasses.
+static const SpeculatedType SpecFloat64Array = 0x00001000; // It's definitely an Uint16Array or one of its subclasses.
+static const SpeculatedType SpecMyArguments = 0x00002000; // It's definitely an Arguments object, and it's definitely the one for my current frame.
+static const SpeculatedType SpecForeignArguments = 0x00004000; // It's definitely an Arguments object, and it's definitely not mine.
+static const SpeculatedType SpecArguments = 0x00006000; // It's definitely an Arguments object.
+static const SpeculatedType SpecObjectOther = 0x00008000; // It's definitely an object but not JSFinalObject, JSArray, or JSFunction.
+static const SpeculatedType SpecObjectMask = 0x0000ffff; // Bitmask used for testing for any kind of object prediction.
+static const SpeculatedType SpecString = 0x00010000; // It's definitely a JSString.
+static const SpeculatedType SpecCellOther = 0x00020000; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString.
+static const SpeculatedType SpecCell = 0x0003ffff; // It's definitely a JSCell.
+static const SpeculatedType SpecInt32 = 0x00800000; // It's definitely an Int32.
+static const SpeculatedType SpecDoubleReal = 0x01000000; // It's definitely a non-NaN double.
+static const SpeculatedType SpecDoubleNaN = 0x02000000; // It's definitely a NaN.
+static const SpeculatedType SpecDouble = 0x03000000; // It's either a non-NaN or a NaN double.
+static const SpeculatedType SpecNumber = 0x03800000; // It's either an Int32 or a Double.
+static const SpeculatedType SpecBoolean = 0x04000000; // It's definitely a Boolean.
+static const SpeculatedType SpecOther = 0x08000000; // It's definitely none of the above.
+static const SpeculatedType SpecTop = 0x0fffffff; // It can be any of the above.
+static const SpeculatedType SpecEmpty = 0x10000000; // It's definitely an empty value marker.
+static const SpeculatedType SpecEmptyOrTop = 0x1fffffff; // It can be any of the above.
+static const SpeculatedType FixedIndexedStorageMask = SpecInt8Array | SpecInt16Array | SpecInt32Array | SpecUint8Array | SpecUint8ClampedArray | SpecUint16Array | SpecUint32Array | SpecFloat32Array | SpecFloat64Array;
+
+typedef bool (*SpeculatedTypeChecker)(SpeculatedType);
+
+// Dummy prediction checker, only useful if someone insists on requiring a prediction checker.
+inline bool isAnySpeculation(SpeculatedType)
+{
+ return true;
+}
+
+inline bool isCellSpeculation(SpeculatedType value)
+{
+ return !!(value & SpecCell) && !(value & ~SpecCell);
+}
+
+inline bool isObjectSpeculation(SpeculatedType value)
+{
+ return !!(value & SpecObjectMask) && !(value & ~SpecObjectMask);
+}
+
+inline bool isFinalObjectSpeculation(SpeculatedType value)
+{
+ return value == SpecFinalObject;
+}
+
+inline bool isFinalObjectOrOtherSpeculation(SpeculatedType value)
+{
+ return !!(value & (SpecFinalObject | SpecOther)) && !(value & ~(SpecFinalObject | SpecOther));
+}
+
+inline bool isFixedIndexedStorageObjectSpeculation(SpeculatedType value)
+{
+ return !!value && (value & FixedIndexedStorageMask) == value;
+}
+
+inline bool isStringSpeculation(SpeculatedType value)
+{
+ return value == SpecString;
+}
+
+inline bool isArraySpeculation(SpeculatedType value)
+{
+ return value == SpecArray;
+}
+
+inline bool isFunctionSpeculation(SpeculatedType value)
+{
+ return value == SpecFunction;
+}
+
+inline bool isInt8ArraySpeculation(SpeculatedType value)
+{
+ return value == SpecInt8Array;
+}
+
+inline bool isInt16ArraySpeculation(SpeculatedType value)
+{
+ return value == SpecInt16Array;
+}
+
+inline bool isInt32ArraySpeculation(SpeculatedType value)
+{
+ return value == SpecInt32Array;
+}
+
+inline bool isUint8ArraySpeculation(SpeculatedType value)
+{
+ return value == SpecUint8Array;
+}
+
+inline bool isUint8ClampedArraySpeculation(SpeculatedType value)
+{
+ return value == SpecUint8ClampedArray;
+}
+
+inline bool isUint16ArraySpeculation(SpeculatedType value)
+{
+ return value == SpecUint16Array;
+}
+
+inline bool isUint32ArraySpeculation(SpeculatedType value)
+{
+ return value == SpecUint32Array;
+}
+
+inline bool isFloat32ArraySpeculation(SpeculatedType value)
+{
+ return value == SpecFloat32Array;
+}
+
+inline bool isFloat64ArraySpeculation(SpeculatedType value)
+{
+ return value == SpecFloat64Array;
+}
+
+inline bool isArgumentsSpeculation(SpeculatedType value)
+{
+ return !!value && (value & SpecArguments) == value;
+}
+
+inline bool isActionableIntMutableArraySpeculation(SpeculatedType value)
+{
+ return isInt8ArraySpeculation(value)
+ || isInt16ArraySpeculation(value)
+ || isInt32ArraySpeculation(value)
+ || isUint8ArraySpeculation(value)
+ || isUint8ClampedArraySpeculation(value)
+ || isUint16ArraySpeculation(value)
+ || isUint32ArraySpeculation(value);
+}
+
+inline bool isActionableFloatMutableArraySpeculation(SpeculatedType value)
+{
+ return isFloat32ArraySpeculation(value)
+ || isFloat64ArraySpeculation(value);
+}
+
+inline bool isActionableTypedMutableArraySpeculation(SpeculatedType value)
+{
+ return isActionableIntMutableArraySpeculation(value)
+ || isActionableFloatMutableArraySpeculation(value);
+}
+
+inline bool isActionableMutableArraySpeculation(SpeculatedType value)
+{
+ return isArraySpeculation(value)
+ || isArgumentsSpeculation(value)
+ || isActionableTypedMutableArraySpeculation(value);
+}
+
+inline bool isActionableArraySpeculation(SpeculatedType value)
+{
+ return isStringSpeculation(value)
+ || isActionableMutableArraySpeculation(value);
+}
+
+inline bool isArrayOrOtherSpeculation(SpeculatedType value)
+{
+ return !!(value & (SpecArray | SpecOther)) && !(value & ~(SpecArray | SpecOther));
+}
+
+inline bool isMyArgumentsSpeculation(SpeculatedType value)
+{
+ return value == SpecMyArguments;
+}
+
+inline bool isInt32Speculation(SpeculatedType value)
+{
+ return value == SpecInt32;
+}
+
+inline bool isDoubleRealSpeculation(SpeculatedType value)
+{
+ return value == SpecDoubleReal;
+}
+
+inline bool isDoubleSpeculation(SpeculatedType value)
+{
+ return !!value && (value & SpecDouble) == value;
+}
+
+inline bool isNumberSpeculation(SpeculatedType value)
+{
+ return !!(value & SpecNumber) && !(value & ~SpecNumber);
+}
+
+inline bool isBooleanSpeculation(SpeculatedType value)
+{
+ return value == SpecBoolean;
+}
+
+inline bool isOtherSpeculation(SpeculatedType value)
+{
+ return value == SpecOther;
+}
+
+inline bool isEmptySpeculation(SpeculatedType value)
+{
+ return value == SpecEmpty;
+}
+
+const char* speculationToString(SpeculatedType value);
+const char* speculationToAbbreviatedString(SpeculatedType value);
+
+// Merge two predictions. Note that currently this just does left | right. It may
+// seem tempting to do so directly, but you would be doing so at your own peril,
+// since the merging protocol SpeculatedType may change at any time (and has already
+// changed several times in its history).
+inline SpeculatedType mergeSpeculations(SpeculatedType left, SpeculatedType right)
+{
+ return left | right;
+}
+
+template<typename T>
+inline bool mergeSpeculation(T& left, SpeculatedType right)
+{
+ SpeculatedType newSpeculation = static_cast<T>(mergeSpeculations(static_cast<SpeculatedType>(left), right));
+ bool result = newSpeculation != static_cast<SpeculatedType>(left);
+ left = newSpeculation;
+ return result;
+}
+
+SpeculatedType speculationFromClassInfo(const ClassInfo*);
+SpeculatedType speculationFromStructure(Structure*);
+SpeculatedType speculationFromCell(JSCell*);
+SpeculatedType speculationFromValue(JSValue);
+
+} // namespace JSC
+
+#endif // SpeculatedType_h
diff --git a/Source/JavaScriptCore/bytecode/StructureSet.h b/Source/JavaScriptCore/bytecode/StructureSet.h
index bfc30fc3c..2bbc50cad 100644
--- a/Source/JavaScriptCore/bytecode/StructureSet.h
+++ b/Source/JavaScriptCore/bytecode/StructureSet.h
@@ -26,7 +26,7 @@
#ifndef StructureSet_h
#define StructureSet_h
-#include "PredictedType.h"
+#include "SpeculatedType.h"
#include "Structure.h"
#include <stdio.h>
#include <wtf/Vector.h>
@@ -90,6 +90,13 @@ public:
return false;
}
+ bool containsOnly(Structure* structure) const
+ {
+ if (size() != 1)
+ return false;
+ return singletonStructure() == structure;
+ }
+
bool isSubsetOf(const StructureSet& other) const
{
for (size_t i = 0; i < m_structures.size(); ++i) {
@@ -115,18 +122,26 @@ public:
return true;
}
+ // Call this if you know that the structure set must consist of exactly
+ // one structure.
+ Structure* singletonStructure() const
+ {
+ ASSERT(m_structures.size() == 1);
+ return m_structures[0];
+ }
+
Structure* at(size_t i) const { return m_structures.at(i); }
Structure* operator[](size_t i) const { return at(i); }
Structure* last() const { return m_structures.last(); }
- PredictedType predictionFromStructures() const
+ SpeculatedType speculationFromStructures() const
{
- PredictedType result = PredictNone;
+ SpeculatedType result = SpecNone;
for (size_t i = 0; i < m_structures.size(); ++i)
- mergePrediction(result, predictionFromStructure(m_structures[i]));
+ mergeSpeculation(result, speculationFromStructure(m_structures[i]));
return result;
}
diff --git a/Source/JavaScriptCore/bytecode/StructureStubInfo.h b/Source/JavaScriptCore/bytecode/StructureStubInfo.h
index 9aa40532a..573f6e975 100644
--- a/Source/JavaScriptCore/bytecode/StructureStubInfo.h
+++ b/Source/JavaScriptCore/bytecode/StructureStubInfo.h
@@ -102,20 +102,23 @@ namespace JSC {
u.getByIdSelf.baseObjectStructure.set(globalData, owner, baseObjectStructure);
}
- void initGetByIdProto(JSGlobalData& globalData, JSCell* owner, Structure* baseObjectStructure, Structure* prototypeStructure)
+ void initGetByIdProto(JSGlobalData& globalData, JSCell* owner, Structure* baseObjectStructure, Structure* prototypeStructure, bool isDirect)
{
accessType = access_get_by_id_proto;
u.getByIdProto.baseObjectStructure.set(globalData, owner, baseObjectStructure);
u.getByIdProto.prototypeStructure.set(globalData, owner, prototypeStructure);
+ u.getByIdProto.isDirect = isDirect;
}
- void initGetByIdChain(JSGlobalData& globalData, JSCell* owner, Structure* baseObjectStructure, StructureChain* chain)
+ void initGetByIdChain(JSGlobalData& globalData, JSCell* owner, Structure* baseObjectStructure, StructureChain* chain, unsigned count, bool isDirect)
{
accessType = access_get_by_id_chain;
u.getByIdChain.baseObjectStructure.set(globalData, owner, baseObjectStructure);
u.getByIdChain.chain.set(globalData, owner, chain);
+ u.getByIdChain.count = count;
+ u.getByIdChain.isDirect = isDirect;
}
void initGetByIdSelfList(PolymorphicAccessStructureList* structureList, int listSize)
@@ -251,10 +254,13 @@ namespace JSC {
struct {
WriteBarrierBase<Structure> baseObjectStructure;
WriteBarrierBase<Structure> prototypeStructure;
+ bool isDirect;
} getByIdProto;
struct {
WriteBarrierBase<Structure> baseObjectStructure;
WriteBarrierBase<StructureChain> chain;
+ unsigned count : 31;
+ bool isDirect : 1;
} getByIdChain;
struct {
PolymorphicAccessStructureList* structureList;
diff --git a/Source/JavaScriptCore/bytecode/ValueProfile.h b/Source/JavaScriptCore/bytecode/ValueProfile.h
index 47fa8b72c..31e76842f 100644
--- a/Source/JavaScriptCore/bytecode/ValueProfile.h
+++ b/Source/JavaScriptCore/bytecode/ValueProfile.h
@@ -35,7 +35,7 @@
#include "Heap.h"
#include "JSArray.h"
-#include "PredictedType.h"
+#include "SpeculatedType.h"
#include "Structure.h"
#include "WriteBarrier.h"
@@ -50,7 +50,7 @@ struct ValueProfileBase {
ValueProfileBase()
: m_bytecodeOffset(-1)
- , m_prediction(PredictNone)
+ , m_prediction(SpecNone)
, m_numberOfSamplesInPrediction(0)
, m_singletonValueIsTop(false)
{
@@ -60,7 +60,7 @@ struct ValueProfileBase {
ValueProfileBase(int bytecodeOffset)
: m_bytecodeOffset(bytecodeOffset)
- , m_prediction(PredictNone)
+ , m_prediction(SpecNone)
, m_numberOfSamplesInPrediction(0)
, m_singletonValueIsTop(false)
{
@@ -114,7 +114,7 @@ struct ValueProfileBase {
fprintf(out,
"samples = %u, prediction = %s",
totalNumberOfSamples(),
- predictionToString(m_prediction));
+ speculationToString(m_prediction));
fprintf(out, ", value = ");
if (m_singletonValueIsTop)
fprintf(out, "TOP");
@@ -135,7 +135,7 @@ struct ValueProfileBase {
}
// Updates the prediction and returns the new one.
- PredictedType computeUpdatedPrediction(OperationInProgress operation = NoOperation)
+ SpeculatedType computeUpdatedPrediction(OperationInProgress operation = NoOperation)
{
for (unsigned i = 0; i < totalNumberOfBuckets; ++i) {
JSValue value = JSValue::decode(m_buckets[i]);
@@ -143,7 +143,7 @@ struct ValueProfileBase {
continue;
m_numberOfSamplesInPrediction++;
- mergePrediction(m_prediction, predictionFromValue(value));
+ mergeSpeculation(m_prediction, speculationFromValue(value));
if (!m_singletonValueIsTop && !!value) {
if (!m_singletonValue)
@@ -167,7 +167,7 @@ struct ValueProfileBase {
int m_bytecodeOffset; // -1 for prologue
- PredictedType m_prediction;
+ SpeculatedType m_prediction;
unsigned m_numberOfSamplesInPrediction;
bool m_singletonValueIsTop;
diff --git a/Source/JavaScriptCore/bytecode/Watchpoint.cpp b/Source/JavaScriptCore/bytecode/Watchpoint.cpp
new file mode 100644
index 000000000..1dd633f52
--- /dev/null
+++ b/Source/JavaScriptCore/bytecode/Watchpoint.cpp
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ * 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 "Watchpoint.h"
+
+#include "LinkBuffer.h"
+
+namespace JSC {
+
+Watchpoint::~Watchpoint()
+{
+ if (isOnList())
+ remove();
+}
+
+#if ENABLE(JIT)
+void Watchpoint::correctLabels(LinkBuffer& linkBuffer)
+{
+ MacroAssembler::Label label;
+ label.m_label.m_offset = m_source;
+ m_source = bitwise_cast<uintptr_t>(linkBuffer.locationOf(label).dataLocation());
+ label.m_label.m_offset = m_destination;
+ m_destination = bitwise_cast<uintptr_t>(linkBuffer.locationOf(label).dataLocation());
+}
+#endif
+
+void Watchpoint::fire()
+{
+#if ENABLE(JIT)
+ MacroAssembler::replaceWithJump(
+ CodeLocationLabel(bitwise_cast<void*>(m_source)),
+ CodeLocationLabel(bitwise_cast<void*>(m_destination)));
+ if (isOnList())
+ remove();
+#else
+ UNREACHABLE_FOR_PLATFORM();
+#endif
+}
+
+WatchpointSet::WatchpointSet(InitialWatchpointSetMode mode)
+ : m_isWatched(mode == InitializedWatching)
+ , m_isInvalidated(false)
+{
+}
+
+WatchpointSet::~WatchpointSet()
+{
+ // Fire all watchpoints. This is necessary because it is possible, say with
+ // structure watchpoints, for the watchpoint set owner to die while the
+ // watchpoint owners are still live.
+ fireAllWatchpoints();
+}
+
+void WatchpointSet::add(Watchpoint* watchpoint)
+{
+ if (!watchpoint)
+ return;
+ m_set.push(watchpoint);
+ m_isWatched = true;
+}
+
+void WatchpointSet::notifyWriteSlow()
+{
+ ASSERT(m_isWatched);
+
+ fireAllWatchpoints();
+ m_isWatched = false;
+ m_isInvalidated = true;
+}
+
+void WatchpointSet::fireAllWatchpoints()
+{
+ while (!m_set.isEmpty())
+ m_set.begin()->fire();
+}
+
+void InlineWatchpointSet::add(Watchpoint* watchpoint)
+{
+ inflate()->add(watchpoint);
+}
+
+WatchpointSet* InlineWatchpointSet::inflateSlow()
+{
+ ASSERT(isThin());
+ WatchpointSet* fat = adoptRef(new WatchpointSet(InitializedBlind)).leakRef();
+ if (m_data & IsInvalidatedFlag)
+ fat->m_isInvalidated = true;
+ if (m_data & IsWatchedFlag)
+ fat->m_isWatched = true;
+ m_data = bitwise_cast<uintptr_t>(fat);
+ return fat;
+}
+
+void InlineWatchpointSet::freeFat()
+{
+ ASSERT(isFat());
+ fat()->deref();
+}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/bytecode/Watchpoint.h b/Source/JavaScriptCore/bytecode/Watchpoint.h
new file mode 100644
index 000000000..0055bf607
--- /dev/null
+++ b/Source/JavaScriptCore/bytecode/Watchpoint.h
@@ -0,0 +1,220 @@
+/*
+ * 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.
+ * 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.
+ */
+
+#ifndef Watchpoint_h
+#define Watchpoint_h
+
+#include "CodeLocation.h"
+#include "MacroAssembler.h"
+#include <wtf/RefCounted.h>
+#include <wtf/SentinelLinkedList.h>
+
+namespace JSC {
+
+class Watchpoint : public BasicRawSentinelNode<Watchpoint> {
+public:
+ Watchpoint()
+ : m_source(std::numeric_limits<uintptr_t>::max())
+ , m_destination(std::numeric_limits<uintptr_t>::max())
+ {
+ }
+
+#if ENABLE(JIT)
+ Watchpoint(MacroAssembler::Label source)
+ : m_source(source.m_label.m_offset)
+ , m_destination(std::numeric_limits<uintptr_t>::max())
+ {
+ }
+
+ void setDestination(MacroAssembler::Label destination)
+ {
+ m_destination = destination.m_label.m_offset;
+ }
+
+ void correctLabels(LinkBuffer&);
+#endif
+
+ ~Watchpoint();
+
+ void fire();
+
+private:
+ uintptr_t m_source;
+ uintptr_t m_destination;
+};
+
+enum InitialWatchpointSetMode { InitializedWatching, InitializedBlind };
+
+class InlineWatchpointSet;
+
+class WatchpointSet : public RefCounted<WatchpointSet> {
+public:
+ WatchpointSet(InitialWatchpointSetMode);
+ ~WatchpointSet();
+
+ bool isStillValid() const { return !m_isInvalidated; }
+ bool hasBeenInvalidated() const { return m_isInvalidated; }
+
+ // As a convenience, this will ignore 0. That's because code paths in the DFG
+ // that create speculation watchpoints may choose to bail out if speculation
+ // had already been terminated.
+ void add(Watchpoint*);
+
+ // Force the watchpoint set to behave as if it was being watched even if no
+ // watchpoints have been installed. This will result in invalidation if the
+ // watchpoint would have fired. That's a pretty good indication that you
+ // probably don't want to set watchpoints, since we typically don't want to
+ // set watchpoints that we believe will actually be fired.
+ void startWatching() { m_isWatched = true; }
+
+ void notifyWrite()
+ {
+ if (!m_isWatched)
+ return;
+ notifyWriteSlow();
+ }
+
+ bool* addressOfIsWatched() { return &m_isWatched; }
+
+ void notifyWriteSlow(); // Call only if you've checked isWatched.
+
+private:
+ void fireAllWatchpoints();
+
+ friend class InlineWatchpointSet;
+
+ SentinelLinkedList<Watchpoint, BasicRawSentinelNode<Watchpoint> > m_set;
+ bool m_isWatched;
+ bool m_isInvalidated;
+};
+
+// InlineWatchpointSet is a low-overhead, non-copyable watchpoint set in which
+// it is not possible to quickly query whether it is being watched in a single
+// branch. There is a fairly simple tradeoff between WatchpointSet and
+// InlineWatchpointSet:
+//
+// Do you have to emit JIT code that rapidly tests whether the watchpoint set
+// is being watched? If so, use WatchpointSet.
+//
+// Do you need multiple parties to have pointers to the same WatchpointSet?
+// If so, use WatchpointSet.
+//
+// Do you have to allocate a lot of watchpoint sets? If so, use
+// InlineWatchpointSet unless you answered "yes" to the previous questions.
+//
+// InlineWatchpointSet will use just one pointer-width word of memory unless
+// you actually add watchpoints to it, in which case it internally inflates
+// to a pointer to a WatchpointSet, and transfers its state to the
+// WatchpointSet.
+
+class InlineWatchpointSet {
+ WTF_MAKE_NONCOPYABLE(InlineWatchpointSet);
+public:
+ InlineWatchpointSet(InitialWatchpointSetMode mode)
+ : m_data((mode == InitializedWatching ? IsWatchedFlag : 0) | IsThinFlag)
+ {
+ }
+
+ ~InlineWatchpointSet()
+ {
+ if (isThin())
+ return;
+ freeFat();
+ }
+
+ bool hasBeenInvalidated() const
+ {
+ if (isFat())
+ return fat()->hasBeenInvalidated();
+ return m_data & IsInvalidatedFlag;
+ }
+
+ bool isStillValid() const
+ {
+ return !hasBeenInvalidated();
+ }
+
+ void add(Watchpoint*);
+
+ void startWatching()
+ {
+ if (isFat()) {
+ fat()->startWatching();
+ return;
+ }
+ m_data |= IsWatchedFlag;
+ }
+
+ void notifyWrite()
+ {
+ if (isFat()) {
+ fat()->notifyWrite();
+ return;
+ }
+ if (!(m_data & IsWatchedFlag))
+ return;
+ m_data |= IsInvalidatedFlag;
+ }
+
+private:
+ static const uintptr_t IsThinFlag = 1;
+ static const uintptr_t IsInvalidatedFlag = 2;
+ static const uintptr_t IsWatchedFlag = 4;
+
+ bool isThin() const { return m_data & IsThinFlag; }
+ bool isFat() const { return !isThin(); };
+
+ WatchpointSet* fat()
+ {
+ ASSERT(isFat());
+ return bitwise_cast<WatchpointSet*>(m_data);
+ }
+
+ const WatchpointSet* fat() const
+ {
+ ASSERT(isFat());
+ return bitwise_cast<WatchpointSet*>(m_data);
+ }
+
+ WatchpointSet* inflate()
+ {
+ if (LIKELY(isFat()))
+ return fat();
+ return inflateSlow();
+ }
+
+ JS_EXPORT_PRIVATE WatchpointSet* inflateSlow();
+ JS_EXPORT_PRIVATE void freeFat();
+
+ uintptr_t m_data;
+};
+
+} // namespace JSC
+
+#endif // Watchpoint_h
+