diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-06-20 13:01:08 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-06-20 13:01:08 +0200 |
commit | 49233e234e5c787396cadb2cea33b31ae0cd65c1 (patch) | |
tree | 5410cb9a8fd53168bb60d62c54b654d86f03c38d /Source/JavaScriptCore/bytecode | |
parent | b211c645d8ab690f713515dfdc84d80b11c27d2c (diff) | |
download | qtwebkit-49233e234e5c787396cadb2cea33b31ae0cd65c1.tar.gz |
Imported WebKit commit 3a8c29f35d00659d2ce7a0ccdfa8304f14e82327 (http://svn.webkit.org/repository/webkit/trunk@120813)
New snapshot with Windows build fixes
Diffstat (limited to 'Source/JavaScriptCore/bytecode')
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 + |