From 49233e234e5c787396cadb2cea33b31ae0cd65c1 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 20 Jun 2012 13:01:08 +0200 Subject: Imported WebKit commit 3a8c29f35d00659d2ce7a0ccdfa8304f14e82327 (http://svn.webkit.org/repository/webkit/trunk@120813) New snapshot with Windows build fixes --- Source/JavaScriptCore/bytecode/CodeBlock.cpp | 51 ++-- Source/JavaScriptCore/bytecode/CodeBlock.h | 55 ++-- Source/JavaScriptCore/bytecode/DFGExitProfile.h | 8 + Source/JavaScriptCore/bytecode/GetByIdStatus.cpp | 115 ++++++-- Source/JavaScriptCore/bytecode/GetByIdStatus.h | 18 +- Source/JavaScriptCore/bytecode/Instruction.h | 6 + .../bytecode/LazyOperandValueProfile.cpp | 4 +- .../bytecode/LazyOperandValueProfile.h | 2 +- Source/JavaScriptCore/bytecode/Opcode.h | 2 + Source/JavaScriptCore/bytecode/PredictedType.cpp | 301 --------------------- Source/JavaScriptCore/bytecode/PredictedType.h | 279 ------------------- Source/JavaScriptCore/bytecode/PutByIdStatus.cpp | 3 + Source/JavaScriptCore/bytecode/SpeculatedType.cpp | 301 +++++++++++++++++++++ Source/JavaScriptCore/bytecode/SpeculatedType.h | 279 +++++++++++++++++++ Source/JavaScriptCore/bytecode/StructureSet.h | 23 +- Source/JavaScriptCore/bytecode/StructureStubInfo.h | 10 +- Source/JavaScriptCore/bytecode/ValueProfile.h | 14 +- Source/JavaScriptCore/bytecode/Watchpoint.cpp | 127 +++++++++ Source/JavaScriptCore/bytecode/Watchpoint.h | 220 +++++++++++++++ 19 files changed, 1167 insertions(+), 651 deletions(-) delete mode 100644 Source/JavaScriptCore/bytecode/PredictedType.cpp delete mode 100644 Source/JavaScriptCore/bytecode/PredictedType.h create mode 100644 Source/JavaScriptCore/bytecode/SpeculatedType.cpp create mode 100644 Source/JavaScriptCore/bytecode/SpeculatedType.h create mode 100644 Source/JavaScriptCore/bytecode/Watchpoint.cpp create mode 100644 Source/JavaScriptCore/bytecode/Watchpoint.h (limited to 'Source/JavaScriptCore/bytecode') 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(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::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* 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* 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* 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* 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::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::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 = m_rareData->m_lineInfo; + Vector& 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("\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 * * 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 #include #include @@ -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 = m_rareData->m_lineInfo; + Vector& 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& callReturnIndexVector() @@ -1238,6 +1254,7 @@ namespace JSC { Vector osrEntry; SegmentedVector osrExit; Vector speculationRecovery; + SegmentedVector watchpoints; Vector transitions; Vector > weakReferences; bool mayBeExecuting; @@ -1285,7 +1302,9 @@ namespace JSC { uint32_t m_forcedOSRExitCounter; uint16_t m_optimizationDelayCounter; uint16_t m_reoptimizationRetryCounter; - + + Vector m_lineInfo; + struct RareData { WTF_MAKE_FAST_ALLOCATED; public: @@ -1307,7 +1326,6 @@ namespace JSC { // Expression info - present if debugging. Vector m_expressionInfo; // Line info - present if profiling or debugging. - Vector m_lineInfo; #if ENABLE(JIT) Vector 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 chain = Vector()) : 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& 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 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* registerPointer) { u.registerPointer = registerPointer; } + + Instruction(bool* predicatePointer) { u.predicatePointer = predicatePointer; } union { Opcode opcode; @@ -198,10 +202,12 @@ namespace JSC { WriteBarrierBase structure; WriteBarrierBase structureChain; WriteBarrierBase jsCell; + WriteBarrier* 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 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.cpp b/Source/JavaScriptCore/bytecode/PredictedType.cpp deleted file mode 100644 index 5258f4079..000000000 --- a/Source/JavaScriptCore/bytecode/PredictedType.cpp +++ /dev/null @@ -1,301 +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. - */ - -#include "config.h" -#include "PredictedType.h" - -#include "Arguments.h" -#include "JSArray.h" -#include "JSFunction.h" -#include "ValueProfile.h" -#include - -namespace JSC { - -const char* predictionToString(PredictedType value) -{ - if (value == PredictNone) - return "None"; - - static const int size = 256; - static char description[size]; - BoundsCheckedPointer ptr(description, size); - - bool isTop = true; - - if (value & PredictCellOther) - ptr.strcat("Othercell"); - else - isTop = false; - - if (value & PredictObjectOther) - ptr.strcat("Otherobj"); - else - isTop = false; - - if (value & PredictFinalObject) - ptr.strcat("Final"); - else - isTop = false; - - if (value & PredictArray) - ptr.strcat("Array"); - else - isTop = false; - - if (value & PredictInt8Array) - ptr.strcat("Int8array"); - else - isTop = false; - - if (value & PredictInt16Array) - ptr.strcat("Int16array"); - else - isTop = false; - - if (value & PredictInt32Array) - ptr.strcat("Int32array"); - else - isTop = false; - - if (value & PredictUint8Array) - ptr.strcat("Uint8array"); - else - isTop = false; - - if (value & PredictUint8ClampedArray) - ptr.strcat("Uint8clampedarray"); - else - isTop = false; - - if (value & PredictUint16Array) - ptr.strcat("Uint16array"); - else - isTop = false; - - if (value & PredictUint32Array) - ptr.strcat("Uint32array"); - else - isTop = false; - - if (value & PredictFloat32Array) - ptr.strcat("Float32array"); - else - isTop = false; - - if (value & PredictFloat64Array) - ptr.strcat("Float64array"); - else - isTop = false; - - if (value & PredictFunction) - ptr.strcat("Function"); - else - isTop = false; - - if (value & PredictMyArguments) - ptr.strcat("Myarguments"); - else - isTop = false; - - if (value & PredictForeignArguments) - ptr.strcat("Foreignarguments"); - else - isTop = false; - - if (value & PredictString) - ptr.strcat("String"); - else - isTop = false; - - if (value & PredictInt32) - ptr.strcat("Int"); - else - isTop = false; - - if (value & PredictDoubleReal) - ptr.strcat("Doublereal"); - else - isTop = false; - - if (value & PredictDoubleNaN) - ptr.strcat("Doublenan"); - else - isTop = false; - - if (value & PredictBoolean) - ptr.strcat("Bool"); - else - isTop = false; - - if (value & PredictOther) - ptr.strcat("Other"); - else - isTop = false; - - if (isTop) { - ptr = description; - ptr.strcat("Top"); - } - - if (value & PredictEmpty) - ptr.strcat("Empty"); - - *ptr++ = 0; - - return description; -} - -const char* predictionToAbbreviatedString(PredictedType prediction) -{ - if (isFinalObjectPrediction(prediction)) - return ""; - if (isArrayPrediction(prediction)) - return ""; - if (isStringPrediction(prediction)) - return ""; - if (isFunctionPrediction(prediction)) - return ""; - if (isInt8ArrayPrediction(prediction)) - return ""; - if (isInt16ArrayPrediction(prediction)) - return ""; - if (isInt32ArrayPrediction(prediction)) - return ""; - if (isUint8ArrayPrediction(prediction)) - return ""; - if (isUint16ArrayPrediction(prediction)) - return ""; - if (isUint32ArrayPrediction(prediction)) - return ""; - if (isFloat32ArrayPrediction(prediction)) - return ""; - if (isFloat64ArrayPrediction(prediction)) - return ""; - if (isMyArgumentsPrediction(prediction)) - return ""; - if (isArgumentsPrediction(prediction)) - return ""; - if (isObjectPrediction(prediction)) - return ""; - if (isCellPrediction(prediction)) - return ""; - if (isInt32Prediction(prediction)) - return ""; - if (isDoublePrediction(prediction)) - return ""; - if (isNumberPrediction(prediction)) - return ""; - if (isBooleanPrediction(prediction)) - return ""; - if (isOtherPrediction(prediction)) - return ""; - return ""; -} - -PredictedType predictionFromClassInfo(const ClassInfo* classInfo) -{ - if (classInfo == &JSFinalObject::s_info) - return PredictFinalObject; - - if (classInfo == &JSArray::s_info) - return PredictArray; - - if (classInfo == &JSString::s_info) - return PredictString; - - if (classInfo == &Arguments::s_info) - return PredictArguments; // Cannot distinguish between MyArguments and ForeignArguments at this stage. That happens in the flow analysis. - - if (classInfo->isSubClassOf(&JSFunction::s_info)) - return PredictFunction; - - - if (classInfo->typedArrayStorageType != TypedArrayNone) { - switch (classInfo->typedArrayStorageType) { - case TypedArrayInt8: - return PredictInt8Array; - case TypedArrayInt16: - return PredictInt16Array; - case TypedArrayInt32: - return PredictInt32Array; - case TypedArrayUint8: - return PredictUint8Array; - case TypedArrayUint8Clamped: - return PredictUint8ClampedArray; - case TypedArrayUint16: - return PredictUint16Array; - case TypedArrayUint32: - return PredictUint32Array; - case TypedArrayFloat32: - return PredictFloat32Array; - case TypedArrayFloat64: - return PredictFloat64Array; - default: - break; - } - } - - if (classInfo->isSubClassOf(&JSObject::s_info)) - return PredictObjectOther; - - return PredictCellOther; -} - -PredictedType predictionFromStructure(Structure* structure) -{ - return predictionFromClassInfo(structure->classInfo()); -} - -PredictedType predictionFromCell(JSCell* cell) -{ - return predictionFromStructure(cell->structure()); -} - -PredictedType predictionFromValue(JSValue value) -{ - if (value.isEmpty()) - return PredictEmpty; - if (value.isInt32()) - return PredictInt32; - if (value.isDouble()) { - double number = value.asNumber(); - if (number == number) - return PredictDoubleReal; - return PredictDoubleNaN; - } - if (value.isCell()) - return predictionFromCell(value.asCell()); - if (value.isBoolean()) - return PredictBoolean; - ASSERT(value.isUndefinedOrNull()); - return PredictOther; -} - -} // namespace JSC - 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 -inline bool mergePrediction(T& left, PredictedType right) -{ - PredictedType newPrediction = static_cast(mergePredictions(static_cast(left), right)); - bool result = newPrediction != static_cast(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/SpeculatedType.cpp b/Source/JavaScriptCore/bytecode/SpeculatedType.cpp new file mode 100644 index 000000000..02d0f7e77 --- /dev/null +++ b/Source/JavaScriptCore/bytecode/SpeculatedType.cpp @@ -0,0 +1,301 @@ +/* + * 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. + */ + +#include "config.h" +#include "SpeculatedType.h" + +#include "Arguments.h" +#include "JSArray.h" +#include "JSFunction.h" +#include "ValueProfile.h" +#include + +namespace JSC { + +const char* speculationToString(SpeculatedType value) +{ + if (value == SpecNone) + return "None"; + + static const int size = 256; + static char description[size]; + BoundsCheckedPointer ptr(description, size); + + bool isTop = true; + + if (value & SpecCellOther) + ptr.strcat("Othercell"); + else + isTop = false; + + if (value & SpecObjectOther) + ptr.strcat("Otherobj"); + else + isTop = false; + + if (value & SpecFinalObject) + ptr.strcat("Final"); + else + isTop = false; + + if (value & SpecArray) + ptr.strcat("Array"); + else + isTop = false; + + if (value & SpecInt8Array) + ptr.strcat("Int8array"); + else + isTop = false; + + if (value & SpecInt16Array) + ptr.strcat("Int16array"); + else + isTop = false; + + if (value & SpecInt32Array) + ptr.strcat("Int32array"); + else + isTop = false; + + if (value & SpecUint8Array) + ptr.strcat("Uint8array"); + else + isTop = false; + + if (value & SpecUint8ClampedArray) + ptr.strcat("Uint8clampedarray"); + else + isTop = false; + + if (value & SpecUint16Array) + ptr.strcat("Uint16array"); + else + isTop = false; + + if (value & SpecUint32Array) + ptr.strcat("Uint32array"); + else + isTop = false; + + if (value & SpecFloat32Array) + ptr.strcat("Float32array"); + else + isTop = false; + + if (value & SpecFloat64Array) + ptr.strcat("Float64array"); + else + isTop = false; + + if (value & SpecFunction) + ptr.strcat("Function"); + else + isTop = false; + + if (value & SpecMyArguments) + ptr.strcat("Myarguments"); + else + isTop = false; + + if (value & SpecForeignArguments) + ptr.strcat("Foreignarguments"); + else + isTop = false; + + if (value & SpecString) + ptr.strcat("String"); + else + isTop = false; + + if (value & SpecInt32) + ptr.strcat("Int"); + else + isTop = false; + + if (value & SpecDoubleReal) + ptr.strcat("Doublereal"); + else + isTop = false; + + if (value & SpecDoubleNaN) + ptr.strcat("Doublenan"); + else + isTop = false; + + if (value & SpecBoolean) + ptr.strcat("Bool"); + else + isTop = false; + + if (value & SpecOther) + ptr.strcat("Other"); + else + isTop = false; + + if (isTop) { + ptr = description; + ptr.strcat("Top"); + } + + if (value & SpecEmpty) + ptr.strcat("Empty"); + + *ptr++ = 0; + + return description; +} + +const char* speculationToAbbreviatedString(SpeculatedType prediction) +{ + if (isFinalObjectSpeculation(prediction)) + return ""; + if (isArraySpeculation(prediction)) + return ""; + if (isStringSpeculation(prediction)) + return ""; + if (isFunctionSpeculation(prediction)) + return ""; + if (isInt8ArraySpeculation(prediction)) + return ""; + if (isInt16ArraySpeculation(prediction)) + return ""; + if (isInt32ArraySpeculation(prediction)) + return ""; + if (isUint8ArraySpeculation(prediction)) + return ""; + if (isUint16ArraySpeculation(prediction)) + return ""; + if (isUint32ArraySpeculation(prediction)) + return ""; + if (isFloat32ArraySpeculation(prediction)) + return ""; + if (isFloat64ArraySpeculation(prediction)) + return ""; + if (isMyArgumentsSpeculation(prediction)) + return ""; + if (isArgumentsSpeculation(prediction)) + return ""; + if (isObjectSpeculation(prediction)) + return ""; + if (isCellSpeculation(prediction)) + return ""; + if (isInt32Speculation(prediction)) + return ""; + if (isDoubleSpeculation(prediction)) + return ""; + if (isNumberSpeculation(prediction)) + return ""; + if (isBooleanSpeculation(prediction)) + return ""; + if (isOtherSpeculation(prediction)) + return ""; + return ""; +} + +SpeculatedType speculationFromClassInfo(const ClassInfo* classInfo) +{ + if (classInfo == &JSFinalObject::s_info) + return SpecFinalObject; + + if (classInfo == &JSArray::s_info) + return SpecArray; + + if (classInfo == &JSString::s_info) + return SpecString; + + if (classInfo == &Arguments::s_info) + return SpecArguments; // Cannot distinguish between MyArguments and ForeignArguments at this stage. That happens in the flow analysis. + + if (classInfo->isSubClassOf(&JSFunction::s_info)) + return SpecFunction; + + + if (classInfo->typedArrayStorageType != TypedArrayNone) { + switch (classInfo->typedArrayStorageType) { + case TypedArrayInt8: + return SpecInt8Array; + case TypedArrayInt16: + return SpecInt16Array; + case TypedArrayInt32: + return SpecInt32Array; + case TypedArrayUint8: + return SpecUint8Array; + case TypedArrayUint8Clamped: + return SpecUint8ClampedArray; + case TypedArrayUint16: + return SpecUint16Array; + case TypedArrayUint32: + return SpecUint32Array; + case TypedArrayFloat32: + return SpecFloat32Array; + case TypedArrayFloat64: + return SpecFloat64Array; + default: + break; + } + } + + if (classInfo->isSubClassOf(&JSObject::s_info)) + return SpecObjectOther; + + return SpecCellOther; +} + +SpeculatedType speculationFromStructure(Structure* structure) +{ + return speculationFromClassInfo(structure->classInfo()); +} + +SpeculatedType speculationFromCell(JSCell* cell) +{ + return speculationFromStructure(cell->structure()); +} + +SpeculatedType speculationFromValue(JSValue value) +{ + if (value.isEmpty()) + return SpecEmpty; + if (value.isInt32()) + return SpecInt32; + if (value.isDouble()) { + double number = value.asNumber(); + if (number == number) + return SpecDoubleReal; + return SpecDoubleNaN; + } + if (value.isCell()) + return speculationFromCell(value.asCell()); + if (value.isBoolean()) + return SpecBoolean; + ASSERT(value.isUndefinedOrNull()); + 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 +inline bool mergeSpeculation(T& left, SpeculatedType right) +{ + SpeculatedType newSpeculation = static_cast(mergeSpeculations(static_cast(left), right)); + bool result = newSpeculation != static_cast(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 #include @@ -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 baseObjectStructure; WriteBarrierBase prototypeStructure; + bool isDirect; } getByIdProto; struct { WriteBarrierBase baseObjectStructure; WriteBarrierBase 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(linkBuffer.locationOf(label).dataLocation()); + label.m_label.m_offset = m_destination; + m_destination = bitwise_cast(linkBuffer.locationOf(label).dataLocation()); +} +#endif + +void Watchpoint::fire() +{ +#if ENABLE(JIT) + MacroAssembler::replaceWithJump( + CodeLocationLabel(bitwise_cast(m_source)), + CodeLocationLabel(bitwise_cast(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(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 +#include + +namespace JSC { + +class Watchpoint : public BasicRawSentinelNode { +public: + Watchpoint() + : m_source(std::numeric_limits::max()) + , m_destination(std::numeric_limits::max()) + { + } + +#if ENABLE(JIT) + Watchpoint(MacroAssembler::Label source) + : m_source(source.m_label.m_offset) + , m_destination(std::numeric_limits::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 { +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 > 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(m_data); + } + + const WatchpointSet* fat() const + { + ASSERT(isFat()); + return bitwise_cast(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 + -- cgit v1.2.1