diff options
Diffstat (limited to 'Source/JavaScriptCore')
45 files changed, 761 insertions, 117 deletions
diff --git a/Source/JavaScriptCore/API/JSCallbackConstructor.cpp b/Source/JavaScriptCore/API/JSCallbackConstructor.cpp index c8b4c0659..8fd2b61f1 100644 --- a/Source/JavaScriptCore/API/JSCallbackConstructor.cpp +++ b/Source/JavaScriptCore/API/JSCallbackConstructor.cpp @@ -61,7 +61,7 @@ JSCallbackConstructor::~JSCallbackConstructor() void JSCallbackConstructor::destroy(JSCell* cell) { - jsCast<JSCallbackConstructor*>(cell)->JSCallbackConstructor::~JSCallbackConstructor(); + static_cast<JSCallbackConstructor*>(cell)->JSCallbackConstructor::~JSCallbackConstructor(); } static EncodedJSValue JSC_HOST_CALL constructJSCallback(ExecState* exec) diff --git a/Source/JavaScriptCore/API/JSCallbackObject.cpp b/Source/JavaScriptCore/API/JSCallbackObject.cpp index 68c26824d..921d37897 100644 --- a/Source/JavaScriptCore/API/JSCallbackObject.cpp +++ b/Source/JavaScriptCore/API/JSCallbackObject.cpp @@ -54,13 +54,13 @@ Structure* JSCallbackObject<JSGlobalObject>::createStructure(JSGlobalData& globa template <class Parent> void JSCallbackObject<Parent>::destroy(JSCell* cell) { - jsCast<JSCallbackObject*>(cell)->JSCallbackObject::~JSCallbackObject(); + static_cast<JSCallbackObject*>(cell)->JSCallbackObject::~JSCallbackObject(); } void JSCallbackObjectData::finalize(Handle<Unknown> handle, void* context) { JSClassRef jsClass = static_cast<JSClassRef>(context); - JSObjectRef thisRef = toRef(asObject(handle.get())); + JSObjectRef thisRef = toRef(static_cast<JSObject*>(handle.get().asCell())); for (; jsClass; jsClass = jsClass->parentClass) if (JSObjectFinalizeCallback finalize = jsClass->finalize) diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog index 7bea6a152..c80a45805 100644 --- a/Source/JavaScriptCore/ChangeLog +++ b/Source/JavaScriptCore/ChangeLog @@ -1,3 +1,223 @@ +2012-05-26 Geoffrey Garen <ggaren@apple.com> + + WebKit should be lazy-finalization-safe (esp. the DOM) v2 + https://bugs.webkit.org/show_bug.cgi?id=87581 + + Reviewed by Oliver Hunt. + + * heap/MarkedBlock.cpp: + (JSC::MarkedBlock::callDestructor): + * heap/WeakBlock.h: + * heap/WeakSetInlines.h: + (JSC::WeakBlock::finalize): Since we don't guarantee destruction order, + it's not valid to access GC pointers like the Structure pointer during + finalization. We NULL out the structure pointer in debug builds to try + to make this programming mistake more obvious. + + * API/JSCallbackConstructor.cpp: + (JSC::JSCallbackConstructor::destroy): + * API/JSCallbackObject.cpp: + (JSC::::destroy): + (JSC::JSCallbackObjectData::finalize): + * runtime/Arguments.cpp: + (JSC::Arguments::destroy): + * runtime/DateInstance.cpp: + (JSC::DateInstance::destroy): + * runtime/Error.cpp: + (JSC::StrictModeTypeErrorFunction::destroy): + * runtime/Executable.cpp: + (JSC::ExecutableBase::destroy): + (JSC::NativeExecutable::destroy): + (JSC::ScriptExecutable::destroy): + (JSC::EvalExecutable::destroy): + (JSC::ProgramExecutable::destroy): + (JSC::FunctionExecutable::destroy): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::destroy): + * runtime/JSPropertyNameIterator.cpp: + (JSC::JSPropertyNameIterator::destroy): + * runtime/JSStaticScopeObject.cpp: + (JSC::JSStaticScopeObject::destroy): + * runtime/JSString.cpp: + (JSC::JSString::destroy): + * runtime/JSVariableObject.cpp: + (JSC::JSVariableObject::destroy): + * runtime/NameInstance.cpp: + (JSC::NameInstance::destroy): + * runtime/RegExp.cpp: + (JSC::RegExp::destroy): + * runtime/RegExpConstructor.cpp: + (JSC::RegExpConstructor::destroy): + * runtime/Structure.cpp: + (JSC::Structure::destroy): + * runtime/StructureChain.cpp: + (JSC::StructureChain::destroy): Use static_cast instead of jsCast because + jsCast does Structure-based validation, and our Structure is not guaranteed + to be alive when we get finalized. + +2012-05-22 Filip Pizlo <fpizlo@apple.com> + + DFG CSE should eliminate redundant WeakJSConstants + https://bugs.webkit.org/show_bug.cgi?id=87179 + + Reviewed by Gavin Barraclough. + + Merged r118141 from dfgopt. + + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::weakConstantCSE): + (CSEPhase): + (JSC::DFG::CSEPhase::performNodeCSE): + * dfg/DFGNode.h: + (JSC::DFG::Node::weakConstant): + +2012-05-22 Filip Pizlo <fpizlo@apple.com> + + DFG CSE should do redundant store elimination + https://bugs.webkit.org/show_bug.cgi?id=87161 + + Reviewed by Oliver Hunt. + + Merge r118138 from dfgopt. + + This patch adds redundant store elimination. For example, consider this + code: + + o.x = 42; + o.x = 84; + + If o.x is speculated to be a well-behaved field, the first assignment is + unnecessary, since the second just overwrites it. We would like to + eliminate the first assignment in these cases. The need for this + optimization arises mostly from stores that our runtime requires. For + example: + + o = {f:1, g:2, h:3}; + + This will have four assignments to the structure for the newly created + object - one assignment for the empty structure, one for {f}, one for + {f, g}, and one for {f, g, h}. We would like to only have the last of + those assigments in this case. + + Intriguingly, doing so for captured variables breaks the way arguments + simplification used to work. Consider that prior to either arguments + simplification or store elimination we will have IR that looks like: + + a: SetLocal(r0, Empty) + b: SetLocal(r1, Empty) + c: GetLocal(r0) + d: CreateArguments(@c) + e: SetLocal(r0, @d) + f: SetLocal(r1, @d) + + Then redundant store elimination will eliminate the stores that + initialize the arguments registers to Empty, but then arguments + simplification eliminates the stores that initialize the arguments to + the newly created arguments - and at this point we no longer have any + stores to the arguments register, leading to hilarious crashes. This + patch therefore changes arguments simplification to replace + CreateArguments with JSConstant(Empty) rather than eliminating the + SetLocals. But this revealed bugs where arguments simplification was + being overzealous, so I fixed those bugs. + + This is a minor speed-up on V8/early and a handful of other tests. + + * bytecode/CodeBlock.h: + (JSC::CodeBlock::uncheckedActivationRegister): + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::execute): + * dfg/DFGArgumentsSimplificationPhase.cpp: + (JSC::DFG::ArgumentsSimplificationPhase::run): + (JSC::DFG::ArgumentsSimplificationPhase::observeBadArgumentsUse): + (JSC::DFG::ArgumentsSimplificationPhase::observeBadArgumentsUses): + (JSC::DFG::ArgumentsSimplificationPhase::observeProperArgumentsUse): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::globalVarStoreElimination): + (CSEPhase): + (JSC::DFG::CSEPhase::putStructureStoreElimination): + (JSC::DFG::CSEPhase::putByOffsetStoreElimination): + (JSC::DFG::CSEPhase::setLocalStoreElimination): + (JSC::DFG::CSEPhase::setReplacement): + (JSC::DFG::CSEPhase::eliminate): + (JSC::DFG::CSEPhase::performNodeCSE): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::uncheckedActivationRegisterFor): + (Graph): + * dfg/DFGNode.h: + (JSC::DFG::Node::isPhantomArguments): + (Node): + (JSC::DFG::Node::hasConstant): + (JSC::DFG::Node::valueOfJSConstant): + (JSC::DFG::Node::hasStructureTransitionData): + * dfg/DFGNodeType.h: + (DFG): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::computeValueRecoveryFor): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + +2012-05-21 Filip Pizlo <fpizlo@apple.com> + + DFG ConvertThis should just be a CheckStructure if the structure is known + https://bugs.webkit.org/show_bug.cgi?id=87057 + + Reviewed by Gavin Barraclough. + + Merged r118021 from dfgopt. + + This gives ValueProfile the ability to track singleton values - i.e. profiling + sites that always see the same value. + + That is then used to profile the structure in op_convert_this. + + This is then used to optimize op_convert_this into a CheckStructure if the + structure is always the same. + + That then results in better CSE in inlined code that uses 'this', since + previously we couldn't CSE accesses on 'this' from different inline call frames. + + Also fixed a bug where we were unnecessarily flushing 'this'. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + (JSC::CodeBlock::stronglyVisitStrongReferences): + * bytecode/LazyOperandValueProfile.cpp: + (JSC::CompressedLazyOperandValueProfileHolder::computeUpdatedPredictions): + * bytecode/LazyOperandValueProfile.h: + (CompressedLazyOperandValueProfileHolder): + * bytecode/Opcode.h: + (JSC): + (JSC::padOpcodeName): + * bytecode/ValueProfile.h: + (JSC::ValueProfileBase::ValueProfileBase): + (JSC::ValueProfileBase::dump): + (JSC::ValueProfileBase::computeUpdatedPrediction): + (ValueProfileBase): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::setArgument): + (JSC::DFG::ByteCodeParser::parseBlock): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_convert_this): + (JSC::JIT::emitSlow_op_convert_this): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_convert_this): + (JSC::JIT::emitSlow_op_convert_this): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/JSValue.h: + (JSValue): + * runtime/Structure.h: + (JSC::JSValue::structureOrUndefined): + (JSC): + 2012-05-24 Tim Horton <timothy_horton@apple.com> Add feature defines for web-facing parts of CSS Regions and Exclusions diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp index 6677b302b..e3ee2ed41 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp @@ -670,6 +670,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& case op_convert_this: { int r0 = (++it)->u.operand; dataLog("[%4d] convert_this\t %s\n", location, registerName(exec, r0).data()); + ++it; // Skip value profile. break; } case op_new_object: { @@ -2085,14 +2086,14 @@ void CodeBlock::stronglyVisitStrongReferences(SlotVisitor& visitor) } } - m_lazyOperandValueProfiles.computeUpdatedPredictions(); + m_lazyOperandValueProfiles.computeUpdatedPredictions(Collection); #endif #if ENABLE(VALUE_PROFILER) for (unsigned profileIndex = 0; profileIndex < numberOfArgumentValueProfiles(); ++profileIndex) - valueProfileForArgument(profileIndex)->computeUpdatedPrediction(); + valueProfileForArgument(profileIndex)->computeUpdatedPrediction(Collection); for (unsigned profileIndex = 0; profileIndex < numberOfValueProfiles(); ++profileIndex) - valueProfile(profileIndex)->computeUpdatedPrediction(); + valueProfile(profileIndex)->computeUpdatedPrediction(Collection); #endif } diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h index c1772c3bf..ccaca3373 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.h +++ b/Source/JavaScriptCore/bytecode/CodeBlock.h @@ -449,6 +449,12 @@ namespace JSC { ASSERT(needsFullScopeChain()); return m_activationRegister; } + int uncheckedActivationRegister() + { + if (!needsFullScopeChain()) + return InvalidVirtualRegister; + return activationRegister(); + } bool usesArguments() const { return m_argumentsRegister != -1; } bool needsActivation() const diff --git a/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.cpp b/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.cpp index f199b6923..695e21219 100644 --- a/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.cpp +++ b/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.cpp @@ -33,13 +33,13 @@ namespace JSC { CompressedLazyOperandValueProfileHolder::CompressedLazyOperandValueProfileHolder() { } CompressedLazyOperandValueProfileHolder::~CompressedLazyOperandValueProfileHolder() { } -void CompressedLazyOperandValueProfileHolder::computeUpdatedPredictions() +void CompressedLazyOperandValueProfileHolder::computeUpdatedPredictions(OperationInProgress operation) { if (!m_data) return; for (unsigned i = 0; i < m_data->size(); ++i) - m_data->at(i).computeUpdatedPrediction(); + m_data->at(i).computeUpdatedPrediction(operation); } LazyOperandValueProfile* CompressedLazyOperandValueProfileHolder::add( diff --git a/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.h b/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.h index d0260f991..91e5314aa 100644 --- a/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.h +++ b/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.h @@ -155,7 +155,7 @@ public: CompressedLazyOperandValueProfileHolder(); ~CompressedLazyOperandValueProfileHolder(); - void computeUpdatedPredictions(); + void computeUpdatedPredictions(OperationInProgress); LazyOperandValueProfile* add(const LazyOperandValueProfileKey& key); diff --git a/Source/JavaScriptCore/bytecode/Opcode.h b/Source/JavaScriptCore/bytecode/Opcode.h index ebf15bbd4..aa83d9b97 100644 --- a/Source/JavaScriptCore/bytecode/Opcode.h +++ b/Source/JavaScriptCore/bytecode/Opcode.h @@ -43,7 +43,7 @@ namespace JSC { macro(op_init_lazy_reg, 2) \ macro(op_create_arguments, 2) \ macro(op_create_this, 2) \ - macro(op_convert_this, 2) \ + macro(op_convert_this, 3) \ \ macro(op_new_object, 2) \ macro(op_new_array, 4) \ diff --git a/Source/JavaScriptCore/bytecode/ValueProfile.h b/Source/JavaScriptCore/bytecode/ValueProfile.h index 73e363a8b..47fa8b72c 100644 --- a/Source/JavaScriptCore/bytecode/ValueProfile.h +++ b/Source/JavaScriptCore/bytecode/ValueProfile.h @@ -33,6 +33,7 @@ #if ENABLE(VALUE_PROFILER) +#include "Heap.h" #include "JSArray.h" #include "PredictedType.h" #include "Structure.h" @@ -51,6 +52,7 @@ struct ValueProfileBase { : m_bytecodeOffset(-1) , m_prediction(PredictNone) , m_numberOfSamplesInPrediction(0) + , m_singletonValueIsTop(false) { for (unsigned i = 0; i < totalNumberOfBuckets; ++i) m_buckets[i] = JSValue::encode(JSValue()); @@ -60,6 +62,7 @@ struct ValueProfileBase { : m_bytecodeOffset(bytecodeOffset) , m_prediction(PredictNone) , m_numberOfSamplesInPrediction(0) + , m_singletonValueIsTop(false) { for (unsigned i = 0; i < totalNumberOfBuckets; ++i) m_buckets[i] = JSValue::encode(JSValue()); @@ -112,6 +115,11 @@ struct ValueProfileBase { "samples = %u, prediction = %s", totalNumberOfSamples(), predictionToString(m_prediction)); + fprintf(out, ", value = "); + if (m_singletonValueIsTop) + fprintf(out, "TOP"); + else + fprintf(out, "%s", m_singletonValue.description()); bool first = true; for (unsigned i = 0; i < totalNumberOfBuckets; ++i) { JSValue value = JSValue::decode(m_buckets[i]); @@ -127,7 +135,7 @@ struct ValueProfileBase { } // Updates the prediction and returns the new one. - PredictedType computeUpdatedPrediction() + PredictedType computeUpdatedPrediction(OperationInProgress operation = NoOperation) { for (unsigned i = 0; i < totalNumberOfBuckets; ++i) { JSValue value = JSValue::decode(m_buckets[i]); @@ -137,9 +145,23 @@ struct ValueProfileBase { m_numberOfSamplesInPrediction++; mergePrediction(m_prediction, predictionFromValue(value)); + if (!m_singletonValueIsTop && !!value) { + if (!m_singletonValue) + m_singletonValue = value; + else if (m_singletonValue != value) + m_singletonValueIsTop = true; + } + m_buckets[i] = JSValue::encode(JSValue()); } + if (operation == Collection + && !m_singletonValueIsTop + && !!m_singletonValue + && m_singletonValue.isCell() + && !Heap::isMarked(m_singletonValue.asCell())) + m_singletonValueIsTop = true; + return m_prediction; } @@ -148,6 +170,9 @@ struct ValueProfileBase { PredictedType m_prediction; unsigned m_numberOfSamplesInPrediction; + bool m_singletonValueIsTop; + JSValue m_singletonValue; + EncodedJSValue m_buckets[totalNumberOfBuckets]; }; diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp index 330750b61..fb05e48ff 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp @@ -445,8 +445,9 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, ScopeChainN emitOpcode(op_create_this); instructions().append(m_thisRegister.index()); } else if (!codeBlock->isStrictMode() && (functionBody->usesThis() || codeBlock->usesEval() || m_shouldEmitDebugHooks)) { - emitOpcode(op_convert_this); + ValueProfile* profile = emitProfiledOpcode(op_convert_this); instructions().append(m_thisRegister.index()); + instructions().append(profile); } } diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp index 33c058e7d..ff737cf1d 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp +++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp @@ -262,7 +262,8 @@ bool AbstractState::execute(unsigned indexInBlock) switch (node.op()) { case JSConstant: - case WeakJSConstant: { + case WeakJSConstant: + case PhantomArguments: { forNode(nodeIndex).set(m_graph.valueOfJSConstant(nodeIndex)); node.setCanExit(false); break; @@ -1403,6 +1404,7 @@ bool AbstractState::execute(unsigned indexInBlock) } case PutStructure: + case PhantomPutStructure: node.setCanExit(false); clobberStructures(indexInBlock); forNode(node.child1()).set(node.structureTransitionData().newStructure); diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp index 5ab515bd7..48163a91b 100644 --- a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp @@ -283,6 +283,14 @@ public: break; } + case Phantom: + // We don't care about phantom uses, since phantom uses are all about + // just keeping things alive for OSR exit. If something - like the + // CreateArguments - is just being kept alive, then this transformation + // will not break this, since the Phantom will now just keep alive a + // PhantomArguments and OSR exit will still do the right things. + break; + default: observeBadArgumentsUses(node); break; @@ -392,31 +400,6 @@ public: VariableAccessData* variableAccessData = node.variableAccessData(); - // If this is a store into the arguments register for an InlineCallFrame* - // that does not create arguments, then kill it. - int argumentsRegister = - m_graph.uncheckedArgumentsRegisterFor(node.codeOrigin); - if ((variableAccessData->local() == argumentsRegister - || variableAccessData->local() - == unmodifiedArgumentsRegister(argumentsRegister)) - && !m_createsArguments.contains(source.codeOrigin.inlineCallFrame)) { - // Find the Flush. It should be the next instruction. - Node& flush = m_graph[block->at(indexInBlock + 1)]; - ASSERT(flush.op() == Flush); - ASSERT(flush.variableAccessData() == variableAccessData); - ASSERT(flush.child1() == nodeIndex); - // Be defensive in release mode. - if (flush.op() != Flush - || flush.variableAccessData() != variableAccessData - || flush.child1() != nodeIndex) - break; - flush.setOpAndDefaultFlags(Nop); - m_graph.clearAndDerefChild1(flush); - flush.setRefCount(0); - changed = true; - break; - } - if (variableAccessData->isCaptured()) break; @@ -583,6 +566,35 @@ public: insertionSet.execute(*block); } + for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) { + BasicBlock* block = m_graph.m_blocks[blockIndex].get(); + if (!block) + continue; + for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { + NodeIndex nodeIndex = block->at(indexInBlock); + Node& node = m_graph[nodeIndex]; + if (!node.shouldGenerate()) + continue; + if (node.op() != CreateArguments) + continue; + // If this is a CreateArguments for an InlineCallFrame* that does + // not create arguments, then replace it with a PhantomArguments. + // PhantomArguments is a constant that represents JSValue() (the + // empty value) in DFG and arguments creation for OSR exit. + if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame)) + continue; + Node phantom(Phantom, node.codeOrigin); + phantom.children = node.children; + phantom.ref(); + node.setOpAndDefaultFlags(PhantomArguments); + node.children.reset(); + NodeIndex phantomNodeIndex = m_graph.size(); + m_graph.append(phantom); + insertionSet.append(indexInBlock, phantomNodeIndex); + } + insertionSet.execute(*block); + } + if (changed) m_graph.collectGarbage(); @@ -659,9 +671,13 @@ private: } VariableAccessData* variableAccessData = child.variableAccessData(); - if (variableAccessData->isCaptured()) + if (variableAccessData->isCaptured()) { + if (child.local() == m_graph.uncheckedArgumentsRegisterFor(child.codeOrigin) + && node.codeOrigin.inlineCallFrame != child.codeOrigin.inlineCallFrame) + m_createsArguments.add(child.codeOrigin.inlineCallFrame); return; - + } + ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->second; data.mergeCallContext(node.codeOrigin.inlineCallFrame); } diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp index 27e198c75..43157963c 100644 --- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp +++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp @@ -350,8 +350,9 @@ private: stack->m_argumentPositions[argument]->addVariable(variableAccessData); NodeIndex nodeIndex = addToGraph(SetLocal, OpInfo(variableAccessData), value); m_currentBlock->variablesAtTail.argument(argument) = nodeIndex; - // Always flush arguments. - addToGraph(Flush, OpInfo(variableAccessData), nodeIndex); + // Always flush arguments, except for 'this'. + if (argument) + addToGraph(Flush, OpInfo(variableAccessData), nodeIndex); } VariableAccessData* flushArgument(int operand) @@ -1582,10 +1583,27 @@ bool ByteCodeParser::parseBlock(unsigned limit) case op_convert_this: { NodeIndex op1 = getThis(); - if (m_graph[op1].op() == ConvertThis) - setThis(op1); - else - setThis(addToGraph(ConvertThis, op1)); + if (m_graph[op1].op() != ConvertThis) { + ValueProfile* profile = + m_inlineStackTop->m_profiledBlock->valueProfileForBytecodeOffset(m_currentProfilingIndex); + profile->computeUpdatedPrediction(); +#if DFG_ENABLE(DEBUG_VERBOSE) + dataLog("[@%lu bc#%u]: profile %p: ", m_graph.size(), m_currentProfilingIndex, profile); + profile->dump(WTF::dataFile()); + dataLog("\n"); +#endif + if (profile->m_singletonValueIsTop + || !profile->m_singletonValue + || !profile->m_singletonValue.isCell() + || profile->m_singletonValue.asCell()->classInfo() != &Structure::s_info) + setThis(addToGraph(ConvertThis, op1)); + else { + addToGraph( + CheckStructure, + OpInfo(m_graph.addStructureSet(jsCast<Structure*>(profile->m_singletonValue.asCell()))), + op1); + } + } NEXT_OPCODE(op_convert_this); } diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp index 842bcc236..3eeb70e05 100644 --- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp @@ -141,6 +141,22 @@ private: return NoNode; } + NodeIndex weakConstantCSE(Node& node) + { + for (unsigned i = endIndexForPureCSE(); i--;) { + NodeIndex index = m_currentBlock->at(i); + Node& otherNode = m_graph[index]; + if (otherNode.op() != WeakJSConstant) + continue; + + if (otherNode.weakConstant() != node.weakConstant()) + continue; + + return index; + } + return NoNode; + } + NodeIndex impureCSE(Node& node) { NodeIndex child1 = canonicalize(node.child1()); @@ -200,6 +216,33 @@ private: return NoNode; } + NodeIndex globalVarStoreElimination(unsigned varNumber, JSGlobalObject* globalObject) + { + for (unsigned i = m_indexInBlock; i--;) { + NodeIndex index = m_currentBlock->at(i); + Node& node = m_graph[index]; + if (!node.shouldGenerate()) + continue; + switch (node.op()) { + case PutGlobalVar: + if (node.varNumber() == varNumber && codeBlock()->globalObjectFor(node.codeOrigin) == globalObject) + return index; + break; + + case GetGlobalVar: + if (node.varNumber() == varNumber && codeBlock()->globalObjectFor(node.codeOrigin) == globalObject) + return NoNode; + break; + + default: + break; + } + if (m_graph.clobbersWorld(index) || node.canExit()) + return NoNode; + } + return NoNode; + } + NodeIndex getByValLoadElimination(NodeIndex child1, NodeIndex child2) { for (unsigned i = m_indexInBlock; i--;) { @@ -304,6 +347,56 @@ private: return false; } + NodeIndex putStructureStoreElimination(NodeIndex child1) + { + for (unsigned i = m_indexInBlock; i--;) { + NodeIndex index = m_currentBlock->at(i); + if (index == child1) + break; + Node& node = m_graph[index]; + if (!node.shouldGenerate()) + break; + switch (node.op()) { + case CheckStructure: + return NoNode; + + case PhantomPutStructure: + if (node.child1() == child1) // No need to retrace our steps. + return NoNode; + break; + + case PutStructure: + if (node.child1() == child1) + return index; + break; + + // PutStructure needs to execute if we GC. Hence this needs to + // be careful with respect to nodes that GC. + case CreateArguments: + case TearOffArguments: + case NewFunctionNoCheck: + case NewFunction: + case NewFunctionExpression: + case CreateActivation: + case TearOffActivation: + case StrCat: + case ToPrimitive: + case NewRegexp: + case NewArrayBuffer: + case NewArray: + case NewObject: + case CreateThis: + return NoNode; + + default: + break; + } + if (m_graph.clobbersWorld(index) || node.canExit()) + return NoNode; + } + return NoNode; + } + NodeIndex getByOffsetLoadElimination(unsigned identifierNumber, NodeIndex child1) { for (unsigned i = m_indexInBlock; i--;) { @@ -350,6 +443,52 @@ private: return NoNode; } + NodeIndex putByOffsetStoreElimination(unsigned identifierNumber, NodeIndex child1) + { + for (unsigned i = m_indexInBlock; i--;) { + NodeIndex index = m_currentBlock->at(i); + if (index == child1) + break; + + Node& node = m_graph[index]; + if (!node.shouldGenerate()) + continue; + switch (node.op()) { + case GetByOffset: + if (m_graph.m_storageAccessData[node.storageAccessDataIndex()].identifierNumber == identifierNumber) + return NoNode; + break; + + case PutByOffset: + if (m_graph.m_storageAccessData[node.storageAccessDataIndex()].identifierNumber == identifierNumber) { + if (node.child1() == child1) // Must be same property storage. + return index; + return NoNode; + } + break; + + case PutByVal: + case PutByValAlias: + case GetByVal: + if (m_graph.byValIsPure(node)) { + // If PutByVal speculates that it's accessing an array with an + // integer index, then it's impossible for it to cause a structure + // change. + break; + } + return NoNode; + + default: + if (m_graph.clobbersWorld(index)) + return NoNode; + break; + } + if (node.canExit()) + return NoNode; + } + return NoNode; + } + NodeIndex getPropertyStorageLoadElimination(NodeIndex child1) { for (unsigned i = m_indexInBlock; i--;) { @@ -480,6 +619,58 @@ private: return NoNode; } + // This returns the Flush node that is keeping a SetLocal alive. + NodeIndex setLocalStoreElimination(VirtualRegister local) + { + for (unsigned i = m_indexInBlock; i--;) { + NodeIndex index = m_currentBlock->at(i); + Node& node = m_graph[index]; + if (!node.shouldGenerate()) + continue; + switch (node.op()) { + case GetLocal: + case SetLocal: + if (node.local() == local) + return NoNode; + break; + + case GetLocalUnlinked: + if (node.unlinkedLocal() == local) + return NoNode; + break; + + case Flush: { + if (node.local() != local) + break; + if (!i) + break; + NodeIndex prevIndex = m_currentBlock->at(i - 1); + if (prevIndex != node.child1().index()) + break; + ASSERT(m_graph[prevIndex].local() == local); + ASSERT(m_graph[prevIndex].variableAccessData() == node.variableAccessData()); + ASSERT(m_graph[prevIndex].shouldGenerate()); + if (m_graph[prevIndex].refCount() > 1) + break; + return index; + } + + case GetScopeChain: + if (m_graph.uncheckedActivationRegisterFor(node.codeOrigin) == local) + return NoNode; + break; + + default: + if (m_graph.clobbersWorld(index)) + return NoNode; + break; + } + if (node.canExit()) + return NoNode; + } + return NoNode; + } + void performSubstitution(Edge& child, bool addRef = true) { // Check if this operand is actually unused. @@ -501,14 +692,16 @@ private: m_graph[child].ref(); } - bool setReplacement(NodeIndex replacement) + enum PredictionHandlingMode { RequireSamePrediction, AllowPredictionMismatch }; + bool setReplacement(NodeIndex replacement, PredictionHandlingMode predictionHandlingMode = RequireSamePrediction) { if (replacement == NoNode) return false; // Be safe. Don't try to perform replacements if the predictions don't // agree. - if (m_graph[m_compileIndex].prediction() != m_graph[replacement].prediction()) + if (predictionHandlingMode == RequireSamePrediction + && m_graph[m_compileIndex].prediction() != m_graph[replacement].prediction()) return false; #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) @@ -537,6 +730,17 @@ private: node.setOpAndDefaultFlags(Phantom); } + void eliminate(NodeIndex nodeIndex, NodeType phantomType = Phantom) + { + if (nodeIndex == NoNode) + return; + Node& node = m_graph[nodeIndex]; + if (node.refCount() != 1) + return; + ASSERT(node.mustGenerate()); + node.setOpAndDefaultFlags(phantomType); + } + void performNodeCSE(Node& node) { bool shouldGenerate = node.shouldGenerate(); @@ -622,6 +826,12 @@ private: NodeIndex phiIndex = node.child1().index(); if (!setReplacement(possibleReplacement)) break; + // If the GetLocal we replaced used to refer to a SetLocal, then it now + // should refer to the child of the SetLocal instead. + if (m_graph[phiIndex].op() == SetLocal) { + ASSERT(node.child1().index() == phiIndex); + m_graph.changeEdge(node.children.child1(), m_graph[phiIndex].child1()); + } NodeIndex oldTailIndex = m_currentBlock->variablesAtTail.operand( variableAccessData->local()); if (oldTailIndex == m_compileIndex) { @@ -645,10 +855,39 @@ private: break; } + case SetLocal: { + if (m_fixpointState == FixpointNotConverged) + break; + VariableAccessData* variableAccessData = node.variableAccessData(); + if (!variableAccessData->isCaptured()) + break; + VirtualRegister local = variableAccessData->local(); + NodeIndex replacementIndex = setLocalStoreElimination(local); + if (replacementIndex == NoNode) + break; + Node& replacement = m_graph[replacementIndex]; + ASSERT(replacement.op() == Flush); + ASSERT(replacement.refCount() == 1); + ASSERT(replacement.shouldGenerate()); + ASSERT(replacement.mustGenerate()); + replacement.setOpAndDefaultFlags(Phantom); + NodeIndex setLocalIndex = replacement.child1().index(); + ASSERT(m_graph[setLocalIndex].op() == SetLocal); + m_graph.clearAndDerefChild1(replacement); + replacement.children.child1() = m_graph[setLocalIndex].child1(); + m_graph.ref(replacement.child1()); + break; + } + case JSConstant: // This is strange, but necessary. Some phases will convert nodes to constants, // which may result in duplicated constants. We use CSE to clean this up. - setReplacement(constantCSE(node)); + setReplacement(constantCSE(node), AllowPredictionMismatch); + break; + + case WeakJSConstant: + // FIXME: have CSE for weak constants against strong constants and vice-versa. + setReplacement(weakConstantCSE(node)); break; case GetArrayLength: @@ -681,6 +920,12 @@ private: setReplacement(globalVarLoadElimination(node.varNumber(), codeBlock()->globalObjectFor(node.codeOrigin))); break; + case PutGlobalVar: + if (m_fixpointState == FixpointNotConverged) + break; + eliminate(globalVarStoreElimination(node.varNumber(), codeBlock()->globalObjectFor(node.codeOrigin))); + break; + case GetByVal: if (m_graph.byValIsPure(node)) setReplacement(getByValLoadElimination(node.child1().index(), node.child2().index())); @@ -697,6 +942,12 @@ private: if (checkStructureLoadElimination(node.structureSet(), node.child1().index())) eliminate(); break; + + case PutStructure: + if (m_fixpointState == FixpointNotConverged) + break; + eliminate(putStructureStoreElimination(node.child1().index()), PhantomPutStructure); + break; case CheckFunction: if (checkFunctionElimination(node.function(), node.child1().index())) @@ -718,6 +969,12 @@ private: setReplacement(getByOffsetLoadElimination(m_graph.m_storageAccessData[node.storageAccessDataIndex()].identifierNumber, node.child1().index())); break; + case PutByOffset: + if (m_fixpointState == FixpointNotConverged) + break; + eliminate(putByOffsetStoreElimination(m_graph.m_storageAccessData[node.storageAccessDataIndex()].identifierNumber, node.child1().index())); + break; + default: // do nothing. break; diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h index 52654d23b..8ca3e2047 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.h +++ b/Source/JavaScriptCore/dfg/DFGGraph.h @@ -352,6 +352,12 @@ public: codeOrigin.inlineCallFrame->stackOffset; } + int uncheckedActivationRegisterFor(const CodeOrigin& codeOrigin) + { + ASSERT_UNUSED(codeOrigin, !codeOrigin.inlineCallFrame); + return m_codeBlock->uncheckedActivationRegister(); + } + ValueProfile* valueProfileFor(NodeIndex nodeIndex) { if (nodeIndex == NoNode) diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h index 1dbfccb8a..12ebba823 100644 --- a/Source/JavaScriptCore/dfg/DFGNode.h +++ b/Source/JavaScriptCore/dfg/DFGNode.h @@ -201,9 +201,21 @@ struct Node { return op() == WeakJSConstant; } + bool isPhantomArguments() + { + return op() == PhantomArguments; + } + bool hasConstant() { - return isConstant() || isWeakConstant(); + switch (op()) { + case JSConstant: + case WeakJSConstant: + case PhantomArguments: + return true; + default: + return false; + } } unsigned constantNumber() @@ -234,14 +246,23 @@ struct Node { JSCell* weakConstant() { + ASSERT(op() == WeakJSConstant); return bitwise_cast<JSCell*>(m_opInfo); } JSValue valueOfJSConstant(CodeBlock* codeBlock) { - if (op() == WeakJSConstant) + switch (op()) { + case WeakJSConstant: return JSValue(weakConstant()); - return codeBlock->constantRegister(FirstConstantRegisterIndex + constantNumber()).get(); + case JSConstant: + return codeBlock->constantRegister(FirstConstantRegisterIndex + constantNumber()).get(); + case PhantomArguments: + return JSValue(); + default: + ASSERT_NOT_REACHED(); + return JSValue(); // Have to return something in release mode. + } } bool isInt32Constant(CodeBlock* codeBlock) @@ -589,7 +610,7 @@ struct Node { bool hasStructureTransitionData() { - return op() == PutStructure; + return op() == PutStructure || op() == PhantomPutStructure; } StructureTransitionData& structureTransitionData() diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h index 091f96c6f..743f87955 100644 --- a/Source/JavaScriptCore/dfg/DFGNodeType.h +++ b/Source/JavaScriptCore/dfg/DFGNodeType.h @@ -37,11 +37,11 @@ namespace JSC { namespace DFG { // This macro defines a set of information about all known node types, used to populate NodeId, NodeType below. #define FOR_EACH_DFG_OP(macro) \ /* A constant in the CodeBlock's constant pool. */\ - macro(JSConstant, NodeResultJS) \ + macro(JSConstant, NodeResultJS | NodeDoesNotExit) \ \ /* A constant not in the CodeBlock's constant pool. Uses get patched to jumps that exit the */\ /* code block. */\ - macro(WeakJSConstant, NodeResultJS) \ + macro(WeakJSConstant, NodeResultJS | NodeDoesNotExit) \ \ /* Nodes for handling functions (both as call and as construct). */\ macro(ConvertThis, NodeResultJS) \ @@ -53,10 +53,10 @@ namespace JSC { namespace DFG { /* VariableAccessData, and thus will share predictions. */\ macro(GetLocal, NodeResultJS) \ macro(SetLocal, 0) \ - macro(Phantom, NodeMustGenerate) \ - macro(Nop, 0) \ - macro(Phi, 0) \ - macro(Flush, NodeMustGenerate) \ + macro(Phantom, NodeMustGenerate | NodeDoesNotExit) \ + macro(Nop, 0 | NodeDoesNotExit) \ + macro(Phi, 0 | NodeDoesNotExit) \ + macro(Flush, NodeMustGenerate | NodeDoesNotExit) \ \ /* Get the value of a local variable, without linking into the VariableAccessData */\ /* network. This is only valid for variable accesses whose predictions originated */\ @@ -64,12 +64,12 @@ namespace JSC { namespace DFG { macro(GetLocalUnlinked, NodeResultJS) \ \ /* Marker for an argument being set at the prologue of a function. */\ - macro(SetArgument, 0) \ + macro(SetArgument, 0 | NodeDoesNotExit) \ \ /* Hint that inlining begins here. No code is generated for this node. It's only */\ /* used for copying OSR data into inline frame data, to support reification of */\ /* call frames of inlined functions. */\ - macro(InlineStart, 0) \ + macro(InlineStart, 0 | NodeDoesNotExit) \ \ /* Nodes for bitwise operations. */\ macro(BitAnd, NodeResultInt32) \ @@ -118,11 +118,12 @@ namespace JSC { namespace DFG { macro(PutById, NodeMustGenerate | NodeClobbersWorld) \ macro(PutByIdDirect, NodeMustGenerate | NodeClobbersWorld) \ macro(CheckStructure, NodeMustGenerate) \ - macro(PutStructure, NodeMustGenerate | NodeClobbersWorld) \ + macro(PutStructure, NodeMustGenerate) \ + macro(PhantomPutStructure, NodeMustGenerate | NodeDoesNotExit) \ macro(GetPropertyStorage, NodeResultStorage) \ macro(GetIndexedPropertyStorage, NodeMustGenerate | NodeResultStorage) \ macro(GetByOffset, NodeResultJS) \ - macro(PutByOffset, NodeMustGenerate | NodeClobbersWorld) \ + macro(PutByOffset, NodeMustGenerate) \ macro(GetArrayLength, NodeResultInt32) \ macro(GetArgumentsLength, NodeResultInt32) \ macro(GetStringLength, NodeResultInt32) \ @@ -139,7 +140,7 @@ namespace JSC { namespace DFG { macro(GetScopedVar, NodeResultJS | NodeMustGenerate) \ macro(PutScopedVar, NodeMustGenerate | NodeClobbersWorld) \ macro(GetGlobalVar, NodeResultJS | NodeMustGenerate) \ - macro(PutGlobalVar, NodeMustGenerate | NodeClobbersWorld) \ + macro(PutGlobalVar, NodeMustGenerate) \ macro(CheckFunction, NodeMustGenerate) \ \ /* Optimizations for array mutation. */\ @@ -201,6 +202,7 @@ namespace JSC { namespace DFG { /* Nodes used for arguments. Similar to activation support, only it makes even less */\ /* sense. */\ macro(CreateArguments, NodeResultJS) \ + macro(PhantomArguments, NodeResultJS | NodeDoesNotExit) \ macro(TearOffArguments, NodeMustGenerate) \ macro(GetMyArgumentsLength, NodeResultJS | NodeMustGenerate) \ macro(GetMyArgumentByVal, NodeResultJS | NodeMustGenerate) \ diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp index de01adb1f..75f0b7a74 100644 --- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp @@ -618,7 +618,9 @@ private: case DoubleAsInt32: case GetLocalUnlinked: case GetMyArgumentsLength: - case GetMyArgumentByVal: { + case GetMyArgumentByVal: + case PhantomPutStructure: + case PhantomArguments: { // This node should never be visible at this stage of compilation. It is // inserted by fixup(), which follows this phase. ASSERT_NOT_REACHED(); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp index db71fc01f..caa21aabf 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp @@ -1360,13 +1360,15 @@ ValueRecovery SpeculativeJIT::computeValueRecoveryFor(const ValueSource& valueSo return ValueRecovery::argumentsThatWereNotCreated(); case HaveNode: { - if (isConstant(valueSource.nodeIndex())) + Node* nodePtr = &at(valueSource.nodeIndex()); + + if (nodePtr->isPhantomArguments()) + return ValueRecovery::argumentsThatWereNotCreated(); + + if (nodePtr->hasConstant()) return ValueRecovery::constant(valueOfJSConstant(valueSource.nodeIndex())); - Node* nodePtr = &at(valueSource.nodeIndex()); if (!nodePtr->shouldGenerate()) { - if (nodePtr->op() == CreateArguments) - return ValueRecovery::argumentsThatWereNotCreated(); // It's legitimately dead. As in, nobody will ever use this node, or operand, // ever. Set it to Undefined to make the GC happy after the OSR. return ValueRecovery::constant(jsUndefined()); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp index 637e335a3..6c0093e41 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp @@ -1848,6 +1848,7 @@ void SpeculativeJIT::compile(Node& node) switch (op) { case JSConstant: + case PhantomArguments: initConstantInfo(m_compileIndex); break; @@ -3429,6 +3430,15 @@ void SpeculativeJIT::compile(Node& node) break; } + case PhantomPutStructure: { + m_jit.addWeakReferenceTransition( + node.codeOrigin.codeOriginOwner(), + node.structureTransitionData().previousStructure, + node.structureTransitionData().newStructure); + noResult(m_compileIndex); + break; + } + case PutStructure: { SpeculateCellOperand base(this, node.child1()); GPRReg baseGPR = base.gpr(); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp index 543e2b913..e4939b23a 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp @@ -1924,6 +1924,7 @@ void SpeculativeJIT::compile(Node& node) switch (op) { case JSConstant: + case PhantomArguments: initConstantInfo(m_compileIndex); break; @@ -3463,6 +3464,15 @@ void SpeculativeJIT::compile(Node& node) break; } + case PhantomPutStructure: { + m_jit.addWeakReferenceTransition( + node.codeOrigin.codeOriginOwner(), + node.structureTransitionData().previousStructure, + node.structureTransitionData().newStructure); + noResult(m_compileIndex); + break; + } + case PutStructure: { SpeculateCellOperand base(this, node.child1()); GPRReg baseGPR = base.gpr(); diff --git a/Source/JavaScriptCore/heap/MarkedBlock.cpp b/Source/JavaScriptCore/heap/MarkedBlock.cpp index 42dc10371..0075f78d7 100644 --- a/Source/JavaScriptCore/heap/MarkedBlock.cpp +++ b/Source/JavaScriptCore/heap/MarkedBlock.cpp @@ -67,8 +67,12 @@ inline void MarkedBlock::callDestructor(JSCell* cell) #if ENABLE(SIMPLE_HEAP_PROFILING) m_heap->m_destroyedTypeCounts.countVPtr(vptr); #endif - cell->methodTable()->destroy(cell); +#if !ASSERT_DISABLED || ENABLE(GC_VALIDATION) + cell->clearStructure(); +#endif + + cell->methodTable()->destroy(cell); cell->zap(); } diff --git a/Source/JavaScriptCore/heap/WeakBlock.h b/Source/JavaScriptCore/heap/WeakBlock.h index dc3e89d55..6461f7b2f 100644 --- a/Source/JavaScriptCore/heap/WeakBlock.h +++ b/Source/JavaScriptCore/heap/WeakBlock.h @@ -115,16 +115,6 @@ inline WeakBlock::FreeCell* WeakBlock::asFreeCell(WeakImpl* weakImpl) return reinterpret_cast<FreeCell*>(weakImpl); } -inline void WeakBlock::finalize(WeakImpl* weakImpl) -{ - ASSERT(weakImpl->state() == WeakImpl::Dead); - weakImpl->setState(WeakImpl::Finalized); - WeakHandleOwner* weakHandleOwner = weakImpl->weakHandleOwner(); - if (!weakHandleOwner) - return; - weakHandleOwner->finalize(Handle<Unknown>::wrapSlot(&const_cast<JSValue&>(weakImpl->jsValue())), weakImpl->context()); -} - inline WeakImpl* WeakBlock::weakImpls() { return reinterpret_cast<WeakImpl*>(this) + ((sizeof(WeakBlock) + sizeof(WeakImpl) - 1) / sizeof(WeakImpl)); diff --git a/Source/JavaScriptCore/heap/WeakSetInlines.h b/Source/JavaScriptCore/heap/WeakSetInlines.h index 6e2420c45..c1c87b380 100644 --- a/Source/JavaScriptCore/heap/WeakSetInlines.h +++ b/Source/JavaScriptCore/heap/WeakSetInlines.h @@ -42,6 +42,19 @@ inline WeakImpl* WeakSet::allocate(JSValue jsValue, WeakHandleOwner* weakHandleO return new (NotNull, weakImpl) WeakImpl(jsValue, weakHandleOwner, context); } +inline void WeakBlock::finalize(WeakImpl* weakImpl) +{ + ASSERT(weakImpl->state() == WeakImpl::Dead); + weakImpl->setState(WeakImpl::Finalized); + WeakHandleOwner* weakHandleOwner = weakImpl->weakHandleOwner(); + if (!weakHandleOwner) + return; +#if !ASSERT_DISABLED || ENABLE(GC_VALIDATION) + weakImpl->jsValue().asCell()->clearStructure(); +#endif + weakHandleOwner->finalize(Handle<Unknown>::wrapSlot(&const_cast<JSValue&>(weakImpl->jsValue())), weakImpl->context()); +} + } // namespace JSC #endif // WeakSetInlines_h diff --git a/Source/JavaScriptCore/jit/JITOpcodes.cpp b/Source/JavaScriptCore/jit/JITOpcodes.cpp index d458f7fb5..aa2938cc2 100644 --- a/Source/JavaScriptCore/jit/JITOpcodes.cpp +++ b/Source/JavaScriptCore/jit/JITOpcodes.cpp @@ -1257,10 +1257,14 @@ void JIT::emit_op_init_lazy_reg(Instruction* currentInstruction) void JIT::emit_op_convert_this(Instruction* currentInstruction) { - emitGetVirtualRegister(currentInstruction[1].u.operand, regT0); + emitGetVirtualRegister(currentInstruction[1].u.operand, regT1); - emitJumpSlowCaseIfNotJSCell(regT0); - addSlowCase(branchPtr(Equal, Address(regT0, JSCell::classInfoOffset()), TrustedImmPtr(&JSString::s_info))); + emitJumpSlowCaseIfNotJSCell(regT1); + if (shouldEmitProfiling()) { + loadPtr(Address(regT1, JSCell::structureOffset()), regT0); + emitValueProfilingSite(); + } + addSlowCase(branchPtr(Equal, Address(regT1, JSCell::classInfoOffset()), TrustedImmPtr(&JSString::s_info))); } void JIT::emit_op_create_this(Instruction* currentInstruction) @@ -1315,15 +1319,21 @@ void JIT::emitSlow_op_convert_this(Instruction* currentInstruction, Vector<SlowC void* globalThis = m_codeBlock->globalObject()->globalScopeChain()->globalThis.get(); linkSlowCase(iter); - Jump isNotUndefined = branchPtr(NotEqual, regT0, TrustedImmPtr(JSValue::encode(jsUndefined()))); + if (shouldEmitProfiling()) + move(TrustedImmPtr(bitwise_cast<void*>(JSValue::encode(jsUndefined()))), regT0); + Jump isNotUndefined = branchPtr(NotEqual, regT1, TrustedImmPtr(JSValue::encode(jsUndefined()))); + emitValueProfilingSite(); move(TrustedImmPtr(globalThis), regT0); emitPutVirtualRegister(currentInstruction[1].u.operand, regT0); emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_convert_this)); - isNotUndefined.link(this); linkSlowCase(iter); + if (shouldEmitProfiling()) + move(TrustedImmPtr(bitwise_cast<void*>(JSValue::encode(m_globalData->stringStructure.get()))), regT0); + isNotUndefined.link(this); + emitValueProfilingSite(); JITStubCall stubCall(this, cti_op_convert_this); - stubCall.addArgument(regT0); + stubCall.addArgument(regT1); stubCall.call(currentInstruction[1].u.operand); } diff --git a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp index 5643fe9f3..12e47b2ee 100644 --- a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp +++ b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp @@ -1548,12 +1548,15 @@ void JIT::emit_op_convert_this(Instruction* currentInstruction) { unsigned thisRegister = currentInstruction[1].u.operand; - emitLoad(thisRegister, regT1, regT0); + emitLoad(thisRegister, regT3, regT2); - addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag))); - addSlowCase(branchPtr(Equal, Address(regT0, JSCell::classInfoOffset()), TrustedImmPtr(&JSString::s_info))); - - map(m_bytecodeOffset + OPCODE_LENGTH(op_convert_this), thisRegister, regT1, regT0); + addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::CellTag))); + if (shouldEmitProfiling()) { + loadPtr(Address(regT2, JSCell::structureOffset()), regT0); + move(regT3, regT1); + emitValueProfilingSite(); + } + addSlowCase(branchPtr(Equal, Address(regT2, JSCell::classInfoOffset()), TrustedImmPtr(&JSString::s_info))); } void JIT::emitSlow_op_convert_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) @@ -1562,16 +1565,26 @@ void JIT::emitSlow_op_convert_this(Instruction* currentInstruction, Vector<SlowC unsigned thisRegister = currentInstruction[1].u.operand; linkSlowCase(iter); - Jump isNotUndefined = branch32(NotEqual, regT1, TrustedImm32(JSValue::UndefinedTag)); + if (shouldEmitProfiling()) { + move(TrustedImm32(JSValue::UndefinedTag), regT1); + move(TrustedImm32(0), regT0); + } + Jump isNotUndefined = branch32(NotEqual, regT3, TrustedImm32(JSValue::UndefinedTag)); + emitValueProfilingSite(); move(TrustedImmPtr(globalThis), regT0); move(TrustedImm32(JSValue::CellTag), regT1); emitStore(thisRegister, regT1, regT0); emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_convert_this)); - isNotUndefined.link(this); linkSlowCase(iter); + if (shouldEmitProfiling()) { + move(TrustedImm32(JSValue::CellTag), regT1); + move(TrustedImmPtr(m_globalData->stringStructure.get()), regT0); + } + isNotUndefined.link(this); + emitValueProfilingSite(); JITStubCall stubCall(this, cti_op_convert_this); - stubCall.addArgument(regT1, regT0); + stubCall.addArgument(regT3, regT2); stubCall.call(thisRegister); } diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp index 066530c87..5cba5ea70 100644 --- a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp +++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp @@ -467,6 +467,8 @@ LLINT_SLOW_PATH_DECL(slow_path_convert_this) LLINT_BEGIN(); JSValue v1 = LLINT_OP(1).jsValue(); ASSERT(v1.isPrimitive()); + pc[OPCODE_LENGTH(op_convert_this) - 1].u.profile->m_buckets[0] = + JSValue::encode(v1.structureOrUndefined()); LLINT_RETURN(v1.toThisObject(exec)); } diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm index e1b08eaa5..dd5ab674a 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm @@ -364,11 +364,13 @@ _llint_op_convert_this: loadi PayloadOffset[cfr, t0, 8], t0 loadp JSCell::m_structure[t0], t0 bbb Structure::m_typeInfo + TypeInfo::m_type[t0], ObjectType, .opConvertThisSlow - dispatch(2) + loadi 8[PC], t1 + valueProfile(CellTag, t0, t1) + dispatch(3) .opConvertThisSlow: callSlowPath(_llint_slow_path_convert_this) - dispatch(2) + dispatch(3) _llint_op_new_object: diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm index a73085f76..5225bdda9 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm @@ -241,11 +241,13 @@ _llint_op_convert_this: btpnz t0, tagMask, .opConvertThisSlow loadp JSCell::m_structure[t0], t0 bbb Structure::m_typeInfo + TypeInfo::m_type[t0], ObjectType, .opConvertThisSlow - dispatch(2) + loadp 16[PB, PC, 8], t1 + valueProfile(t0, t1) + dispatch(3) .opConvertThisSlow: callSlowPath(_llint_slow_path_convert_this) - dispatch(2) + dispatch(3) _llint_op_new_object: diff --git a/Source/JavaScriptCore/runtime/Arguments.cpp b/Source/JavaScriptCore/runtime/Arguments.cpp index 4628cec8d..96791c326 100644 --- a/Source/JavaScriptCore/runtime/Arguments.cpp +++ b/Source/JavaScriptCore/runtime/Arguments.cpp @@ -54,7 +54,7 @@ void Arguments::visitChildren(JSCell* cell, SlotVisitor& visitor) void Arguments::destroy(JSCell* cell) { - jsCast<Arguments*>(cell)->Arguments::~Arguments(); + static_cast<Arguments*>(cell)->Arguments::~Arguments(); } void Arguments::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t length) diff --git a/Source/JavaScriptCore/runtime/DateInstance.cpp b/Source/JavaScriptCore/runtime/DateInstance.cpp index a502770c8..47a19df47 100644 --- a/Source/JavaScriptCore/runtime/DateInstance.cpp +++ b/Source/JavaScriptCore/runtime/DateInstance.cpp @@ -55,7 +55,7 @@ void DateInstance::finishCreation(JSGlobalData& globalData, double time) void DateInstance::destroy(JSCell* cell) { - jsCast<DateInstance*>(cell)->DateInstance::~DateInstance(); + static_cast<DateInstance*>(cell)->DateInstance::~DateInstance(); } const GregorianDateTime* DateInstance::calculateGregorianDateTime(ExecState* exec) const diff --git a/Source/JavaScriptCore/runtime/Error.cpp b/Source/JavaScriptCore/runtime/Error.cpp index bae07448b..a3a990d59 100644 --- a/Source/JavaScriptCore/runtime/Error.cpp +++ b/Source/JavaScriptCore/runtime/Error.cpp @@ -183,7 +183,7 @@ const ClassInfo StrictModeTypeErrorFunction::s_info = { "Function", &Base::s_inf void StrictModeTypeErrorFunction::destroy(JSCell* cell) { - jsCast<StrictModeTypeErrorFunction*>(cell)->StrictModeTypeErrorFunction::~StrictModeTypeErrorFunction(); + static_cast<StrictModeTypeErrorFunction*>(cell)->StrictModeTypeErrorFunction::~StrictModeTypeErrorFunction(); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp index 0a6425a59..0ada2cb0f 100644 --- a/Source/JavaScriptCore/runtime/Executable.cpp +++ b/Source/JavaScriptCore/runtime/Executable.cpp @@ -43,7 +43,7 @@ const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, 0, CREATE_METHOD_ #if ENABLE(JIT) void ExecutableBase::destroy(JSCell* cell) { - jsCast<ExecutableBase*>(cell)->ExecutableBase::~ExecutableBase(); + static_cast<ExecutableBase*>(cell)->ExecutableBase::~ExecutableBase(); } #endif @@ -73,7 +73,7 @@ const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase #if ENABLE(JIT) void NativeExecutable::destroy(JSCell* cell) { - jsCast<NativeExecutable*>(cell)->NativeExecutable::~NativeExecutable(); + static_cast<NativeExecutable*>(cell)->NativeExecutable::~NativeExecutable(); } #endif @@ -108,7 +108,7 @@ const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase #if ENABLE(JIT) void ScriptExecutable::destroy(JSCell* cell) { - jsCast<ScriptExecutable*>(cell)->ScriptExecutable::~ScriptExecutable(); + static_cast<ScriptExecutable*>(cell)->ScriptExecutable::~ScriptExecutable(); } #endif @@ -121,7 +121,7 @@ EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool i void EvalExecutable::destroy(JSCell* cell) { - jsCast<EvalExecutable*>(cell)->EvalExecutable::~EvalExecutable(); + static_cast<EvalExecutable*>(cell)->EvalExecutable::~EvalExecutable(); } const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(ProgramExecutable) }; @@ -133,7 +133,7 @@ ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source) void ProgramExecutable::destroy(JSCell* cell) { - jsCast<ProgramExecutable*>(cell)->ProgramExecutable::~ProgramExecutable(); + static_cast<ProgramExecutable*>(cell)->ProgramExecutable::~ProgramExecutable(); } const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionExecutable) }; @@ -166,7 +166,7 @@ FunctionExecutable::FunctionExecutable(ExecState* exec, const Identifier& name, void FunctionExecutable::destroy(JSCell* cell) { - jsCast<FunctionExecutable*>(cell)->FunctionExecutable::~FunctionExecutable(); + static_cast<FunctionExecutable*>(cell)->FunctionExecutable::~FunctionExecutable(); } JSObject* EvalExecutable::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode) diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp index 2a4231537..8c8aa9079 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -127,7 +127,7 @@ JSGlobalObject::~JSGlobalObject() void JSGlobalObject::destroy(JSCell* cell) { - jsCast<JSGlobalObject*>(cell)->JSGlobalObject::~JSGlobalObject(); + static_cast<JSGlobalObject*>(cell)->JSGlobalObject::~JSGlobalObject(); } void JSGlobalObject::init(JSObject* thisValue) diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp index 6fd8b770b..6ceb3c411 100644 --- a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp +++ b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp @@ -83,7 +83,7 @@ JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, JSObject void JSPropertyNameIterator::destroy(JSCell* cell) { - jsCast<JSPropertyNameIterator*>(cell)->JSPropertyNameIterator::~JSPropertyNameIterator(); + static_cast<JSPropertyNameIterator*>(cell)->JSPropertyNameIterator::~JSPropertyNameIterator(); } JSValue JSPropertyNameIterator::get(ExecState* exec, JSObject* base, size_t i) diff --git a/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp b/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp index fc4c27bab..e5e65673c 100644 --- a/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp +++ b/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp @@ -36,7 +36,7 @@ const ClassInfo JSStaticScopeObject::s_info = { "Object", &Base::s_info, 0, 0, C void JSStaticScopeObject::destroy(JSCell* cell) { - jsCast<JSStaticScopeObject*>(cell)->JSStaticScopeObject::~JSStaticScopeObject(); + static_cast<JSStaticScopeObject*>(cell)->JSStaticScopeObject::~JSStaticScopeObject(); } void JSStaticScopeObject::visitChildren(JSCell* cell, SlotVisitor& visitor) diff --git a/Source/JavaScriptCore/runtime/JSString.cpp b/Source/JavaScriptCore/runtime/JSString.cpp index ad6bd3812..180c64b8b 100644 --- a/Source/JavaScriptCore/runtime/JSString.cpp +++ b/Source/JavaScriptCore/runtime/JSString.cpp @@ -47,7 +47,7 @@ void JSRopeString::RopeBuilder::expand() void JSString::destroy(JSCell* cell) { - JSString* thisObject = jsCast<JSString*>(cell); + JSString* thisObject = static_cast<JSString*>(cell); thisObject->JSString::~JSString(); } diff --git a/Source/JavaScriptCore/runtime/JSValue.h b/Source/JavaScriptCore/runtime/JSValue.h index 27046097c..f74bfad90 100644 --- a/Source/JavaScriptCore/runtime/JSValue.h +++ b/Source/JavaScriptCore/runtime/JSValue.h @@ -239,6 +239,8 @@ namespace JSC { bool isCell() const; JSCell* asCell() const; JS_EXPORT_PRIVATE bool isValidCallee(); + + JSValue structureOrUndefined() const; char* description() const; diff --git a/Source/JavaScriptCore/runtime/JSVariableObject.cpp b/Source/JavaScriptCore/runtime/JSVariableObject.cpp index eb9dfd4be..9dcbead34 100644 --- a/Source/JavaScriptCore/runtime/JSVariableObject.cpp +++ b/Source/JavaScriptCore/runtime/JSVariableObject.cpp @@ -39,7 +39,7 @@ namespace JSC { void JSVariableObject::destroy(JSCell* cell) { - jsCast<JSVariableObject*>(cell)->JSVariableObject::~JSVariableObject(); + static_cast<JSVariableObject*>(cell)->JSVariableObject::~JSVariableObject(); } bool JSVariableObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) diff --git a/Source/JavaScriptCore/runtime/NameInstance.cpp b/Source/JavaScriptCore/runtime/NameInstance.cpp index aae290cb2..410fe62e7 100644 --- a/Source/JavaScriptCore/runtime/NameInstance.cpp +++ b/Source/JavaScriptCore/runtime/NameInstance.cpp @@ -38,7 +38,7 @@ NameInstance::NameInstance(JSGlobalData& globalData, Structure* structure, JSStr void NameInstance::destroy(JSCell* cell) { - jsCast<NameInstance*>(cell)->NameInstance::~NameInstance(); + static_cast<NameInstance*>(cell)->NameInstance::~NameInstance(); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/RegExp.cpp b/Source/JavaScriptCore/runtime/RegExp.cpp index b0f67607e..64e553be1 100644 --- a/Source/JavaScriptCore/runtime/RegExp.cpp +++ b/Source/JavaScriptCore/runtime/RegExp.cpp @@ -243,7 +243,7 @@ void RegExp::finishCreation(JSGlobalData& globalData) void RegExp::destroy(JSCell* cell) { - RegExp* thisObject = jsCast<RegExp*>(cell); + RegExp* thisObject = static_cast<RegExp*>(cell); #if REGEXP_FUNC_TEST_DATA_GEN RegExpFunctionalTestCollector::get()->clearRegExp(this); #endif diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp index 2c0f0c000..0f2091c27 100644 --- a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp +++ b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp @@ -104,7 +104,7 @@ void RegExpConstructor::finishCreation(ExecState* exec, RegExpPrototype* regExpP void RegExpConstructor::destroy(JSCell* cell) { - jsCast<RegExpConstructor*>(cell)->RegExpConstructor::~RegExpConstructor(); + static_cast<RegExpConstructor*>(cell)->RegExpConstructor::~RegExpConstructor(); } void RegExpConstructor::visitChildren(JSCell* cell, SlotVisitor& visitor) diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp index b22deb0fa..dc4239799 100644 --- a/Source/JavaScriptCore/runtime/Structure.cpp +++ b/Source/JavaScriptCore/runtime/Structure.cpp @@ -216,7 +216,7 @@ Structure::Structure(JSGlobalData& globalData, const Structure* previous) void Structure::destroy(JSCell* cell) { - jsCast<Structure*>(cell)->Structure::~Structure(); + static_cast<Structure*>(cell)->Structure::~Structure(); } void Structure::materializePropertyMap(JSGlobalData& globalData) diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h index 74336a288..f67c4e7f7 100644 --- a/Source/JavaScriptCore/runtime/Structure.h +++ b/Source/JavaScriptCore/runtime/Structure.h @@ -332,6 +332,13 @@ namespace JSC { return entry ? entry->offset : notFound; } + inline JSValue JSValue::structureOrUndefined() const + { + if (isCell()) + return JSValue(asCell()->structure()); + return jsUndefined(); + } + inline bool JSCell::isObject() const { return m_structure->isObject(); diff --git a/Source/JavaScriptCore/runtime/StructureChain.cpp b/Source/JavaScriptCore/runtime/StructureChain.cpp index afb2d9501..a1c97340e 100644 --- a/Source/JavaScriptCore/runtime/StructureChain.cpp +++ b/Source/JavaScriptCore/runtime/StructureChain.cpp @@ -41,7 +41,7 @@ StructureChain::StructureChain(JSGlobalData& globalData, Structure* structure) void StructureChain::destroy(JSCell* cell) { - jsCast<StructureChain*>(cell)->StructureChain::~StructureChain(); + static_cast<StructureChain*>(cell)->StructureChain::~StructureChain(); } void StructureChain::visitChildren(JSCell* cell, SlotVisitor& visitor) |