diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-08-21 10:57:44 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-08-21 10:57:44 +0200 |
commit | 5ef7c8a6a70875d4430752d146bdcb069605d71d (patch) | |
tree | f6256640b6c46d7da221435803cae65326817ba2 /Source/JavaScriptCore | |
parent | decad929f578d8db641febc8740649ca6c574638 (diff) | |
download | qtwebkit-5ef7c8a6a70875d4430752d146bdcb069605d71d.tar.gz |
Imported WebKit commit 356d83016b090995d08ad568f2d2c243aa55e831 (http://svn.webkit.org/repository/webkit/trunk@126147)
New snapshot including various build fixes for newer Qt 5
Diffstat (limited to 'Source/JavaScriptCore')
56 files changed, 2505 insertions, 913 deletions
diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt index 146a11910..317814aa9 100644 --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt @@ -39,6 +39,7 @@ SET(JavaScriptCore_SOURCES assembler/LinkBuffer.cpp + bytecode/ArrayProfile.cpp bytecode/CallLinkInfo.cpp bytecode/CallLinkStatus.cpp bytecode/CodeBlock.cpp diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog index 063b2f519..4297df1e5 100644 --- a/Source/JavaScriptCore/ChangeLog +++ b/Source/JavaScriptCore/ChangeLog @@ -1,3 +1,843 @@ +2012-08-20 Mark Lam <mark.lam@apple.com> + + Fix broken non-JIT build. + https://bugs.webkit.org/show_bug.cgi?id=94564. + + Reviewed by Filip Pizlo. + + Added some UNUSED_PARAM() macros to make the compiler happy. + + * runtime/Executable.cpp: + (JSC::EvalExecutable::compileInternal): + (JSC::ProgramExecutable::compileInternal): + (JSC::FunctionExecutable::compileForCallInternal): + (JSC::FunctionExecutable::compileForConstructInternal): + +2012-08-20 Mark Lam <mark.lam@apple.com> + + Fixed erroneous line number for LLint frame when throwing exceptions. + https://bugs.webkit.org/show_bug.cgi?id=94051. + + Reviewed by Filip Pizlo. + + For LLInt frames, before throwing an exception, adjust the PC from the + return PC back to the call PC if we are indeed at a call site. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::adjustPCIfAtCallSite): + (JSC): + (JSC::CodeBlock::bytecodeOffset): + * bytecode/CodeBlock.h: + (CodeBlock): + * llint/LLIntExceptions.cpp: + (JSC::LLInt::fixupPCforExceptionIfNeeded): + (LLInt): + (JSC::LLInt::interpreterThrowInCaller): + (JSC::LLInt::returnToThrow): + (JSC::LLInt::callToThrow): + +2012-08-20 Filip Pizlo <fpizlo@apple.com> + + fast/js/dfg-peephole-compare-final-object-to-final-object-or-other-when-both-proven-final-object.html on 32-bit + https://bugs.webkit.org/show_bug.cgi?id=94538 + + Reviewed by Mark Hahnenberg. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality): + +2012-08-20 Filip Pizlo <fpizlo@apple.com> + + fast/js/dfg-compare-final-object-to-final-object-or-other-when-both-proven-final-object.html crashes on 32-bit + https://bugs.webkit.org/show_bug.cgi?id=94026 + + Reviewed by Mark Hahnenberg. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality): + +2012-08-19 Filip Pizlo <fpizlo@apple.com> + + The relationship between abstract values and structure transition watchpoints should be rationalized + https://bugs.webkit.org/show_bug.cgi?id=94205 + + Reviewed by Geoffrey Garen. + + This patch does a number of things related to the handling of the abstract values + arrising from values with structures known to be watchpointable: + + - This rationalizes the relationship between the structure that we know an object + to have *right now* based on having executed a check against that structure, and + the structure that we know the object could have *in the future* based on a type + check executed in the past over a structure that was watchpointable. + + - We use the above to assert that structure transition watchpoints are being used + soundly. + + - We use the above to strength reduce CheckStructure into StructureTransitionWatchpoint + whenever possible. + + - This rationalizes the handling of CFA over constants that appeared in the bytecode. + If at compile-time the constant has a watchpointable structure, then we can prove + what structures it may have in the future. The analysis uses this to both assert + that structure transition watchpoints are being used correctly, and to find + opportunities for using them more aggressively. + + The net effect of all of these changes is that OSR entry should work more smoothly. + It may also be a slight win due to strength reductions, though most of those strength + reductions would have already been done by the parser and the structure check hoister. + + * GNUmakefile.list.am: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::beginBasicBlock): + (JSC::DFG::AbstractState::execute): + * dfg/DFGAbstractValue.h: + (DFG): + (JSC::DFG::AbstractValue::clear): + (JSC::DFG::AbstractValue::isClear): + (JSC::DFG::AbstractValue::makeTop): + (JSC::DFG::AbstractValue::clobberStructures): + (JSC::DFG::AbstractValue::isTop): + (JSC::DFG::AbstractValue::setFuturePossibleStructure): + (AbstractValue): + (JSC::DFG::AbstractValue::filterFuturePossibleStructure): + (JSC::DFG::AbstractValue::setMostSpecific): + (JSC::DFG::AbstractValue::set): + (JSC::DFG::AbstractValue::operator==): + (JSC::DFG::AbstractValue::merge): + (JSC::DFG::AbstractValue::filter): + (JSC::DFG::AbstractValue::filterValueByType): + (JSC::DFG::AbstractValue::validateType): + (JSC::DFG::AbstractValue::validate): + (JSC::DFG::AbstractValue::checkConsistency): + (JSC::DFG::AbstractValue::dump): + * dfg/DFGArgumentsSimplificationPhase.cpp: + (JSC::DFG::ArgumentsSimplificationPhase::run): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::checkStructureLoadElimination): + (JSC::DFG::CSEPhase::structureTransitionWatchpointElimination): + (JSC::DFG::CSEPhase::performNodeCSE): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + * dfg/DFGNode.h: + (JSC::DFG::Node::convertToStructureTransitionWatchpoint): + (Node): + (JSC::DFG::Node::hasStructure): + * dfg/DFGNodeType.h: + (DFG): + * dfg/DFGOSREntry.cpp: + (JSC::DFG::prepareOSREntry): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::convertLastOSRExitToForward): + (JSC::DFG::SpeculativeJIT::forwardSpeculationWatchpoint): + (DFG): + (JSC::DFG::SpeculativeJIT::speculationWatchpointWithConditionalDirection): + (JSC::DFG::SpeculativeJIT::forwardSpeculationCheck): + (JSC::DFG::SpeculativeJIT::speculateArray): + * dfg/DFGSpeculativeJIT.h: + (SpeculativeJIT): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGStructureAbstractValue.h: Added. + (DFG): + (StructureAbstractValue): + (JSC::DFG::StructureAbstractValue::StructureAbstractValue): + (JSC::DFG::StructureAbstractValue::clear): + (JSC::DFG::StructureAbstractValue::makeTop): + (JSC::DFG::StructureAbstractValue::top): + (JSC::DFG::StructureAbstractValue::add): + (JSC::DFG::StructureAbstractValue::addAll): + (JSC::DFG::StructureAbstractValue::contains): + (JSC::DFG::StructureAbstractValue::isSubsetOf): + (JSC::DFG::StructureAbstractValue::doesNotContainAnyOtherThan): + (JSC::DFG::StructureAbstractValue::isSupersetOf): + (JSC::DFG::StructureAbstractValue::filter): + (JSC::DFG::StructureAbstractValue::isClear): + (JSC::DFG::StructureAbstractValue::isTop): + (JSC::DFG::StructureAbstractValue::isClearOrTop): + (JSC::DFG::StructureAbstractValue::isNeitherClearNorTop): + (JSC::DFG::StructureAbstractValue::size): + (JSC::DFG::StructureAbstractValue::at): + (JSC::DFG::StructureAbstractValue::operator[]): + (JSC::DFG::StructureAbstractValue::last): + (JSC::DFG::StructureAbstractValue::speculationFromStructures): + (JSC::DFG::StructureAbstractValue::hasSingleton): + (JSC::DFG::StructureAbstractValue::singleton): + (JSC::DFG::StructureAbstractValue::operator==): + (JSC::DFG::StructureAbstractValue::dump): + (JSC::DFG::StructureAbstractValue::topValue): + * dfg/DFGStructureCheckHoistingPhase.cpp: + (JSC::DFG::StructureCheckHoistingPhase::run): + +2012-08-17 Filip Pizlo <fpizlo@apple.com> + + The current state of the call frame should be taken into account in the DFG for both predictions and proofs + https://bugs.webkit.org/show_bug.cgi?id=94412 + + Reviewed by Geoffrey Garen. + + This ensures that no matter how smart the DFG gets, it'll always know through + which entrypoint OSR will try to enter, and with which values it will attempt + to do so. For prologue OSR, this has no effect other than adding the current + arguments to the argument predictions. For loop OSR, this makes our treatment + of the loop slightly more conservative - just conservative enough to ensure + that OSR succeeds. + + * bytecode/CodeBlock.cpp: + (JSC::ProgramCodeBlock::compileOptimized): + (JSC::EvalCodeBlock::compileOptimized): + (JSC::FunctionCodeBlock::compileOptimized): + * bytecode/CodeBlock.h: + (CodeBlock): + (ProgramCodeBlock): + (EvalCodeBlock): + (FunctionCodeBlock): + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::initialize): + * dfg/DFGAbstractValue.h: + (JSC::DFG::AbstractValue::setMostSpecific): + (AbstractValue): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::fixVariableAccessPredictions): + (JSC::DFG::ByteCodeParser::parse): + * dfg/DFGDriver.cpp: + (JSC::DFG::compile): + (JSC::DFG::tryCompile): + (JSC::DFG::tryCompileFunction): + * dfg/DFGDriver.h: + (DFG): + (JSC::DFG::tryCompile): + (JSC::DFG::tryCompileFunction): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::Graph): + (Graph): + * jit/JITDriver.h: + (JSC::jitCompileIfAppropriate): + (JSC::jitCompileFunctionIfAppropriate): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * runtime/Executable.cpp: + (JSC::EvalExecutable::compileOptimized): + (JSC::EvalExecutable::compileInternal): + (JSC::ProgramExecutable::compileOptimized): + (JSC::ProgramExecutable::compileInternal): + (JSC::FunctionExecutable::compileOptimizedForCall): + (JSC::FunctionExecutable::compileOptimizedForConstruct): + (JSC::FunctionExecutable::compileForCallInternal): + (JSC::FunctionExecutable::compileForConstructInternal): + * runtime/Executable.h: + (EvalExecutable): + (ProgramExecutable): + (FunctionExecutable): + (JSC::FunctionExecutable::compileOptimizedFor): + * runtime/ExecutionHarness.h: + (JSC::prepareForExecution): + (JSC::prepareFunctionForExecution): + +2012-08-17 Filip Pizlo <fpizlo@apple.com> + + DFG CSE should be more honest about when it changed the IR + https://bugs.webkit.org/show_bug.cgi?id=94408 + + Reviewed by Geoffrey Garen. + + The CSE phase now always returns true if it changed the IR. + + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::setReplacement): + (JSC::DFG::CSEPhase::eliminate): + (JSC::DFG::CSEPhase::performNodeCSE): + +2012-08-17 Filip Pizlo <fpizlo@apple.com> + + DFG is still too pessimistic about what constitutes a side-effect on array accesses + https://bugs.webkit.org/show_bug.cgi?id=94309 + + Reviewed by Geoffrey Garen. + + This change means that even if structure transition watchpoints are not used for + hoisting of clobbered structure checks, we still retain good performance on the + benchmarks we care about. That's important, since butterflies will likely make + most array structures not watchpointable. + + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::execute): + * dfg/DFGStructureCheckHoistingPhase.cpp: + (JSC::DFG::StructureCheckHoistingPhase::run): + +2012-08-17 Milian Wolff <milian.wolff@kdab.com> + + [Qt] QNX build fails due to ctype usage in system headers + https://bugs.webkit.org/show_bug.cgi?id=93849 + + Reviewed by Simon Hausmann. + + Move the check for whether DisallowCType should be active or not + to the DisallowCType.h header. This way, we can update the list + of platforms or OSes which do not work with this header in a + central place. All users can now safely include the header + and do not need to place custom guards around it. + + * config.h: + +2012-08-16 Simon Hausmann <simon.hausmann@nokia.com> + + [Qt] Replace use of internal Weak smart pointer with JSWeakObjectMap + https://bugs.webkit.org/show_bug.cgi?id=93872 + + Reviewed by Kenneth Rohde Christiansen. + + * Target.pri: Add missing JSWeakObjectMap file to build. + +2012-08-16 Filip Pizlo <fpizlo@apple.com> + + Structure check hoisting should be less expensive + https://bugs.webkit.org/show_bug.cgi?id=94201 + + Reviewed by Mark Hahnenberg. + + This appears like a broad win on short-running programs. + + * dfg/DFGArgumentsSimplificationPhase.cpp: + (JSC::DFG::ArgumentsSimplificationPhase::run): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::performNodeCSE): + * dfg/DFGDriver.cpp: + (JSC::DFG::compile): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::compareAndSwap): + (Graph): + (JSC::DFG::Graph::substitute): + (JSC::DFG::Graph::substituteGetLocal): + * dfg/DFGStructureCheckHoistingPhase.cpp: + (JSC::DFG::StructureCheckHoistingPhase::run): + +2012-08-16 Filip Pizlo <fpizlo@apple.com> + + All op_resolve_global instructions should end up in the list of global resolve instructions + https://bugs.webkit.org/show_bug.cgi?id=94247 + <rdar://problem/12103500> + + Reviewed by Mark Hahnenberg. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitResolveWithBase): + +2012-08-15 Bruno de Oliveira Abinader <bruno.abinader@basyskom.com> + + [css3-text] Add CSS3 Text decoration compile flag + https://bugs.webkit.org/show_bug.cgi?id=93863 + + Reviewed by Julien Chaffraix. + + This patch handles the compile flag implementation, which will come disabled by + default, thus not exposing the CSS3 text decoration features to the web, unless + when explicitly enabling it with "--css3-text-decoration" build parameter. + + * Configurations/FeatureDefines.xcconfig: + +2012-08-15 Sheriff Bot <webkit.review.bot@gmail.com> + + Unreviewed, rolling out r125687. + http://trac.webkit.org/changeset/125687 + https://bugs.webkit.org/show_bug.cgi?id=94147 + + It broke the whole world (Requested by Ossy_night on #webkit). + + * API/JSValueRef.cpp: + (JSValueToBoolean): + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * bytecode/Watchpoint.h: + (WatchpointSet): + * debugger/DebuggerCallFrame.h: + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::execute): + * dfg/DFGCFGSimplificationPhase.cpp: + (JSC::DFG::CFGSimplificationPhase::run): + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull): + (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull): + (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull): + (JSC::DFG::SpeculativeJIT::compile): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_is_undefined): + (JSC::JIT::emit_op_jeq_null): + (JSC::JIT::emit_op_jneq_null): + (JSC::JIT::emit_op_eq_null): + (JSC::JIT::emit_op_neq_null): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_is_undefined): + (JSC::JIT::emit_op_jeq_null): + (JSC::JIT::emit_op_jneq_null): + (JSC::JIT::emit_op_eq_null): + (JSC::JIT::emit_op_neq_null): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/ArrayPrototype.cpp: + (JSC::arrayProtoFuncFilter): + (JSC::arrayProtoFuncEvery): + (JSC::arrayProtoFuncSome): + * runtime/BooleanConstructor.cpp: + (JSC::constructBoolean): + (JSC::callBooleanConstructor): + * runtime/JSCell.h: + (JSCell): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::JSGlobalObject): + * runtime/JSGlobalObject.h: + (JSGlobalObject): + * runtime/JSString.h: + (JSC::JSCell::toBoolean): + (JSC::JSValue::toBoolean): + * runtime/JSValue.h: + * runtime/ObjectConstructor.cpp: + (JSC::toPropertyDescriptor): + * runtime/Operations.cpp: + (JSC::jsTypeStringForValue): + (JSC::jsIsObjectType): + * runtime/Operations.h: + (JSC): + (JSC::JSValue::equalSlowCaseInline): + * runtime/RegExpConstructor.cpp: + (JSC::setRegExpConstructorMultiline): + * runtime/RegExpPrototype.cpp: + (JSC::regExpProtoFuncToString): + * runtime/Structure.h: + +2012-08-15 Gabor Ballabas <gaborb@inf.u-szeged.hu> + + Buildfix after r125541 + https://bugs.webkit.org/show_bug.cgi?id=94097 + + Reviewed by Filip Pizlo. + + r125541 has broken the traditional ARM port build of JSC. + + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::neg32): + (JSC::MacroAssemblerARM::xor32): + +2012-08-14 Mark Hahnenberg <mhahnenberg@apple.com> + + Change behavior of MasqueradesAsUndefined to better accommodate DFG changes + https://bugs.webkit.org/show_bug.cgi?id=93884 + + Reviewed by Geoffrey Garen. + + With some upcoming changes to the DFG to remove uses of ClassInfo, we will be changing the behavior of + MasqueradesAsUndefined. In order to make this change consistent across all of our execution engines, + we will make this change to MasqueradesAsUndefined as a separate patch. After this patch, MasqueradesAsUndefined + objects will only masquerade as undefined in their original context (i.e. their original JSGlobalObject). + For example, if an object that masquerades as undefined in frame A is passed to frame B, it will not + masquerade as undefined within frame B, but it will continue to masquerade in frame A. + + There are two primary changes that are taking place here. One is to thread the ExecState* through + JSValue::toBoolean and JSCell::toBoolean so that JSCell::toBoolean can check the object's + JSGlobalObject to compare it to the lexical JSGlobalObject of the currently running code. If the two + are distinct, then the object cannot MasqueradeAsUndefined. + + The other change is to perform this comparison of JSGlobalObjects everywhere where the MasqueradesAsUndefined + flag in the Structure is checked. For C++ code, this check has been factored into its own function in + Structure::masqueradesAsUndefined. We only perform this check in the DFG if the current JSGlobalObject has + had a MasqueradesAsUndefined object allocated within its context. This conditional compilation is managed + through the use of a WatchpointSet in each JSGlobalObject and alternate create() functions for JS DOM wrappers + that are MasqueradesAsUndefined. + + * API/JSValueRef.cpp: + (JSValueToBoolean): + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * bytecode/Watchpoint.h: + (WatchpointSet): + * debugger/DebuggerCallFrame.h: + (JSC::DebuggerCallFrame::callFrame): + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::execute): + * dfg/DFGCFGSimplificationPhase.cpp: + (JSC::DFG::CFGSimplificationPhase::run): + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull): + (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull): + (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull): + (JSC::DFG::SpeculativeJIT::compile): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_is_undefined): + (JSC::JIT::emit_op_jeq_null): + (JSC::JIT::emit_op_jneq_null): + (JSC::JIT::emit_op_eq_null): + (JSC::JIT::emit_op_neq_null): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_is_undefined): + (JSC::JIT::emit_op_jeq_null): + (JSC::JIT::emit_op_jneq_null): + (JSC::JIT::emit_op_eq_null): + (JSC::JIT::emit_op_neq_null): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/ArrayPrototype.cpp: + (JSC::arrayProtoFuncFilter): + (JSC::arrayProtoFuncEvery): + (JSC::arrayProtoFuncSome): + * runtime/BooleanConstructor.cpp: + (JSC::constructBoolean): + (JSC::callBooleanConstructor): + * runtime/JSCell.h: + (JSCell): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::JSGlobalObject): + * runtime/JSGlobalObject.h: + (JSGlobalObject): + (JSC::JSGlobalObject::masqueradesAsUndefinedWatchpoint): + * runtime/JSString.h: + (JSC::JSCell::toBoolean): + (JSC::JSValue::toBoolean): + * runtime/JSValue.h: + * runtime/ObjectConstructor.cpp: + (JSC::toPropertyDescriptor): + * runtime/Operations.cpp: + (JSC::jsTypeStringForValue): + (JSC::jsIsObjectType): + * runtime/Operations.h: + (JSC): + (JSC::JSValue::equalSlowCaseInline): + * runtime/RegExpConstructor.cpp: + (JSC::setRegExpConstructorMultiline): + * runtime/RegExpPrototype.cpp: + (JSC::regExpProtoFuncToString): + * runtime/Structure.h: + (Structure): + (JSC::Structure::globalObjectOffset): + (JSC::Structure::masqueradesAsUndefined): + (JSC): + +2012-08-14 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, build fix for !ENABLE(DFG_JIT) + + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_get_by_val): + (JSC::JIT::emit_op_put_by_val): + (JSC::JIT::privateCompilePatchGetArrayLength): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emit_op_get_by_val): + (JSC::JIT::emit_op_put_by_val): + (JSC::JIT::privateCompilePatchGetArrayLength): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + +2012-08-13 Filip Pizlo <fpizlo@apple.com> + + Array checks should use the structure, not the class info + https://bugs.webkit.org/show_bug.cgi?id=93150 + + Reviewed by Mark Hahnenberg. + + This changes all array checks used in array accesses (get, put, get length, + push, pop) to use the structure, not the class info. Additionally, these + checks in the LLInt and baseline JIT record the structure in an ArrayProfile, + so that the DFG can know exactly what structure to check for. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * Target.pri: + * bytecode/ArrayProfile.cpp: Added. + (JSC): + (JSC::ArrayProfile::computeUpdatedPrediction): + * bytecode/ArrayProfile.h: Added. + (JSC): + (JSC::arrayModeFromStructure): + (ArrayProfile): + (JSC::ArrayProfile::ArrayProfile): + (JSC::ArrayProfile::bytecodeOffset): + (JSC::ArrayProfile::addressOfLastSeenStructure): + (JSC::ArrayProfile::observeStructure): + (JSC::ArrayProfile::expectedStructure): + (JSC::ArrayProfile::structureIsPolymorphic): + (JSC::ArrayProfile::hasDefiniteStructure): + (JSC::ArrayProfile::observedArrayModes): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + (JSC::CodeBlock::getArrayProfile): + (JSC): + (JSC::CodeBlock::getOrAddArrayProfile): + (JSC::CodeBlock::updateAllPredictionsAndCountLiveness): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::executionEntryCount): + (JSC::CodeBlock::numberOfArrayProfiles): + (JSC::CodeBlock::arrayProfiles): + (JSC::CodeBlock::addArrayProfile): + (CodeBlock): + * bytecode/Instruction.h: + (JSC): + (JSC::Instruction::Instruction): + * bytecode/Opcode.h: + (JSC): + (JSC::padOpcodeName): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitGetArgumentByVal): + (JSC::BytecodeGenerator::emitGetByVal): + (JSC::BytecodeGenerator::emitPutByVal): + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::initialize): + (JSC::DFG::AbstractState::execute): + * dfg/DFGAbstractValue.h: + (JSC::DFG::StructureAbstractValue::hasSingleton): + (StructureAbstractValue): + (JSC::DFG::StructureAbstractValue::singleton): + * dfg/DFGArgumentsSimplificationPhase.cpp: + (JSC::DFG::ArgumentsSimplificationPhase::run): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::speculateArray): + (DFG): + (JSC::DFG::SpeculativeJIT::compile): + (JSC::DFG::SpeculativeJIT::checkArgumentTypes): + (JSC::DFG::SpeculativeJIT::compileGetIndexedPropertyStorage): + * dfg/DFGSpeculativeJIT.h: + (SpeculativeJIT): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGStructureCheckHoistingPhase.cpp: + (JSC::DFG::StructureCheckHoistingPhase::run): + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_get_by_val): + (JSC::JIT::emit_op_put_by_val): + (JSC::JIT::privateCompilePatchGetArrayLength): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emit_op_get_by_val): + (JSC::JIT::emit_op_put_by_val): + (JSC::JIT::privateCompilePatchGetArrayLength): + * llint/LLIntOffsetsExtractor.cpp: + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/Structure.h: + (Structure): + (JSC::Structure::classInfoOffset): + +2012-08-14 Gabor Ballabas <gaborb@inf.u-szeged.hu> + + Rename functions in the ARM port of DFG-JIT for better code readability. + https://bugs.webkit.org/show_bug.cgi?id=93609 + + Reviewed by Zoltan Herczeg. + + Rename functions in the ARM port of DFG-JIT for better code + readability, and for following the WebKit coding style + wherever it is possible. + + * assembler/ARMAssembler.cpp: + (JSC::ARMAssembler::genInt): + (JSC::ARMAssembler::getImm): + (JSC::ARMAssembler::moveImm): + (JSC::ARMAssembler::encodeComplexImm): + (JSC::ARMAssembler::dataTransfer32): + (JSC::ARMAssembler::baseIndexTransfer32): + (JSC::ARMAssembler::dataTransfer16): + (JSC::ARMAssembler::baseIndexTransfer16): + (JSC::ARMAssembler::dataTransferFloat): + (JSC::ARMAssembler::baseIndexTransferFloat): + * assembler/ARMAssembler.h: + (JSC::ARMAssembler::bitAnd): + (JSC::ARMAssembler::bitAnds): + (JSC::ARMAssembler::eor): + (JSC::ARMAssembler::eors): + (JSC::ARMAssembler::sub): + (JSC::ARMAssembler::subs): + (JSC::ARMAssembler::rsb): + (JSC::ARMAssembler::rsbs): + (JSC::ARMAssembler::add): + (JSC::ARMAssembler::adds): + (JSC::ARMAssembler::adc): + (JSC::ARMAssembler::adcs): + (JSC::ARMAssembler::sbc): + (JSC::ARMAssembler::sbcs): + (JSC::ARMAssembler::rsc): + (JSC::ARMAssembler::rscs): + (JSC::ARMAssembler::tst): + (JSC::ARMAssembler::teq): + (JSC::ARMAssembler::cmp): + (JSC::ARMAssembler::cmn): + (JSC::ARMAssembler::orr): + (JSC::ARMAssembler::orrs): + (JSC::ARMAssembler::mov): + (JSC::ARMAssembler::movw): + (JSC::ARMAssembler::movt): + (JSC::ARMAssembler::movs): + (JSC::ARMAssembler::bic): + (JSC::ARMAssembler::bics): + (JSC::ARMAssembler::mvn): + (JSC::ARMAssembler::mvns): + (JSC::ARMAssembler::mul): + (JSC::ARMAssembler::muls): + (JSC::ARMAssembler::mull): + (JSC::ARMAssembler::vmov_f64): + (JSC::ARMAssembler::vadd_f64): + (JSC::ARMAssembler::vdiv_f64): + (JSC::ARMAssembler::vsub_f64): + (JSC::ARMAssembler::vmul_f64): + (JSC::ARMAssembler::vcmp_f64): + (JSC::ARMAssembler::vsqrt_f64): + (JSC::ARMAssembler::vabs_f64): + (JSC::ARMAssembler::vneg_f64): + (JSC::ARMAssembler::ldrImmediate): + (JSC::ARMAssembler::ldrUniqueImmediate): + (JSC::ARMAssembler::dtrUp): + (JSC::ARMAssembler::dtrUpRegister): + (JSC::ARMAssembler::dtrDown): + (JSC::ARMAssembler::dtrDownRegister): + (JSC::ARMAssembler::halfDtrUp): + (JSC::ARMAssembler::halfDtrUpRegister): + (JSC::ARMAssembler::halfDtrDown): + (JSC::ARMAssembler::halfDtrDownRegister): + (JSC::ARMAssembler::doubleDtrUp): + (JSC::ARMAssembler::doubleDtrDown): + (JSC::ARMAssembler::push): + (JSC::ARMAssembler::pop): + (JSC::ARMAssembler::poke): + (JSC::ARMAssembler::peek): + (JSC::ARMAssembler::vmov_vfp64): + (JSC::ARMAssembler::vmov_arm64): + (JSC::ARMAssembler::vmov_vfp32): + (JSC::ARMAssembler::vmov_arm32): + (JSC::ARMAssembler::vcvt_f64_s32): + (JSC::ARMAssembler::vcvt_s32_f64): + (JSC::ARMAssembler::vcvt_u32_f64): + (JSC::ARMAssembler::vcvt_f64_f32): + (JSC::ARMAssembler::vcvt_f32_f64): + (JSC::ARMAssembler::clz): + (JSC::ARMAssembler::lslRegister): + (JSC::ARMAssembler::lsrRegister): + (JSC::ARMAssembler::asrRegister): + (JSC::ARMAssembler::align): + (JSC::ARMAssembler::loadBranchTarget): + (JSC::ARMAssembler::vmov): + * assembler/MacroAssemblerARM.cpp: + (JSC::MacroAssemblerARM::load32WithUnalignedHalfWords): + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::add32): + (JSC::MacroAssemblerARM::and32): + (JSC::MacroAssemblerARM::lshift32): + (JSC::MacroAssemblerARM::mul32): + (JSC::MacroAssemblerARM::or32): + (JSC::MacroAssemblerARM::rshift32): + (JSC::MacroAssemblerARM::urshift32): + (JSC::MacroAssemblerARM::sub32): + (JSC::MacroAssemblerARM::xor32): + (JSC::MacroAssemblerARM::countLeadingZeros32): + (JSC::MacroAssemblerARM::convertibleLoadPtr): + (JSC::MacroAssemblerARM::load32WithAddressOffsetPatch): + (JSC::MacroAssemblerARM::load32WithCompactAddressOffsetPatch): + (JSC::MacroAssemblerARM::store32WithAddressOffsetPatch): + (JSC::MacroAssemblerARM::store32): + (JSC::MacroAssemblerARM::pop): + (JSC::MacroAssemblerARM::push): + (JSC::MacroAssemblerARM::move): + (JSC::MacroAssemblerARM::swap): + (JSC::MacroAssemblerARM::branch32): + (JSC::MacroAssemblerARM::branchTest32): + (JSC::MacroAssemblerARM::mull32): + (JSC::MacroAssemblerARM::branchSub32): + (JSC::MacroAssemblerARM::compare32): + (JSC::MacroAssemblerARM::test32): + (JSC::MacroAssemblerARM::load32): + (JSC::MacroAssemblerARM::relativeTableJump): + (JSC::MacroAssemblerARM::moveWithPatch): + (JSC::MacroAssemblerARM::loadDouble): + (JSC::MacroAssemblerARM::moveDouble): + (JSC::MacroAssemblerARM::addDouble): + (JSC::MacroAssemblerARM::divDouble): + (JSC::MacroAssemblerARM::subDouble): + (JSC::MacroAssemblerARM::mulDouble): + (JSC::MacroAssemblerARM::sqrtDouble): + (JSC::MacroAssemblerARM::absDouble): + (JSC::MacroAssemblerARM::negateDouble): + (JSC::MacroAssemblerARM::convertInt32ToDouble): + (JSC::MacroAssemblerARM::convertFloatToDouble): + (JSC::MacroAssemblerARM::convertDoubleToFloat): + (JSC::MacroAssemblerARM::branchDouble): + (JSC::MacroAssemblerARM::branchTruncateDoubleToInt32): + (JSC::MacroAssemblerARM::branchTruncateDoubleToUint32): + (JSC::MacroAssemblerARM::truncateDoubleToInt32): + (JSC::MacroAssemblerARM::truncateDoubleToUint32): + (JSC::MacroAssemblerARM::branchConvertDoubleToInt32): + (JSC::MacroAssemblerARM::branchDoubleNonZero): + (JSC::MacroAssemblerARM::branchDoubleZeroOrNaN): + +2012-08-13 Simon Hausmann <simon.hausmann@nokia.com> + + Unreviewed, rolling out r125444. + http://trac.webkit.org/changeset/125444 + https://bugs.webkit.org/show_bug.cgi?id=93872 + + Broke some tests + + * Target.pri: + +2012-08-13 Simon Hausmann <simon.hausmann@nokia.com> + + [Qt] Replace use of internal Weak smart pointer with JSWeakObjectMap + https://bugs.webkit.org/show_bug.cgi?id=93872 + + Reviewed by Kenneth Rohde Christiansen. + + * Target.pri: Add missing JSWeakObjectMap file to build. + +2012-08-13 Raphael Kubo da Costa <rakuco@webkit.org> + + [CMake] Remove glib-related Find modules and write single new one instead. + https://bugs.webkit.org/show_bug.cgi?id=93786 + + Reviewed by Rob Buis. + + * shell/PlatformEfl.cmake: Use GLIB_* instead of Glib_*. + +2012-08-12 Allan Sandfeld Jensen <allan.jensen@nokia.com> + + Doesn't build with ENABLE_JIT=0 + https://bugs.webkit.org/show_bug.cgi?id=85042 + + Reviewed by Eric Seidel. + + Include headers without which CallFrame.h does not build, and + fix gcc warning about comparing unsigned int with 0. + + * dfg/DFGDriver.cpp: + * interpreter/Interpreter.cpp: + (JSC::Interpreter::isOpcode): + 2012-08-10 Yong Li <yoli@rim.com> [BlackBerry] GCActivityCallback should always schedule GC even allocated bytes is a small number diff --git a/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig b/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig index 40d95cb9c..9c1b8ffa7 100644 --- a/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig +++ b/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig @@ -48,6 +48,7 @@ ENABLE_CSS_COMPOSITING = ; ENABLE_CSS_STICKY_POSITION = ENABLE_CSS_STICKY_POSITION; ENABLE_CSS_VARIABLES = ; ENABLE_CSS3_FLEXBOX = ENABLE_CSS3_FLEXBOX; +ENABLE_CSS3_TEXT_DECORATION = ; ENABLE_CUSTOM_SCHEME_HANDLER = ; ENABLE_DASHBOARD_SUPPORT = $(ENABLE_DASHBOARD_SUPPORT_$(REAL_PLATFORM_NAME)); ENABLE_DASHBOARD_SUPPORT_macosx = ENABLE_DASHBOARD_SUPPORT; @@ -139,4 +140,4 @@ ENABLE_WIDGET_REGION_macosx = ENABLE_WIDGET_REGION; ENABLE_WORKERS = ENABLE_WORKERS; ENABLE_XSLT = ENABLE_XSLT; -FEATURE_DEFINES = $(ENABLE_3D_RENDERING) $(ENABLE_ACCELERATED_2D_CANVAS) $(ENABLE_ANIMATION_API) $(ENABLE_BLOB) $(ENABLE_CHANNEL_MESSAGING) $(ENABLE_CSP_NEXT) $(ENABLE_CSS_BOX_DECORATION_BREAK) $(ENABLE_CSS_EXCLUSIONS) $(ENABLE_CSS_FILTERS) $(ENABLE_CSS_HIERARCHIES) $(ENABLE_CSS_IMAGE_ORIENTATION) $(ENABLE_CSS_IMAGE_RESOLUTION) $(ENABLE_CSS_REGIONS) $(ENABLE_CSS_SHADERS) $(ENABLE_CSS_COMPOSITING) $(ENABLE_CSS_STICKY_POSITION) $(ENABLE_CSS_VARIABLES) $(ENABLE_CSS3_FLEXBOX) $(ENABLE_CUSTOM_SCHEME_HANDLER) $(ENABLE_DASHBOARD_SUPPORT) $(ENABLE_DATALIST_ELEMENT) $(ENABLE_DATA_TRANSFER_ITEMS) $(ENABLE_DETAILS_ELEMENT) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DIALOG_ELEMENT) $(ENABLE_DIRECTORY_UPLOAD) $(ENABLE_FILE_SYSTEM) $(ENABLE_FILTERS) $(ENABLE_FULLSCREEN_API) $(ENABLE_GAMEPAD) $(ENABLE_GEOLOCATION) $(ENABLE_HIGH_DPI_CANVAS) $(ENABLE_ICONDATABASE) $(ENABLE_IFRAME_SEAMLESS) $(ENABLE_INDEXED_DATABASE) $(ENABLE_INPUT_SPEECH) $(ENABLE_INPUT_TYPE_COLOR) $(ENABLE_INPUT_TYPE_DATE) $(ENABLE_INPUT_TYPE_DATETIME) $(ENABLE_INPUT_TYPE_DATETIMELOCAL) $(ENABLE_INPUT_TYPE_MONTH) $(ENABLE_INPUT_TYPE_TIME) $(ENABLE_INPUT_TYPE_WEEK) $(ENABLE_JAVASCRIPT_DEBUGGER) $(ENABLE_LEGACY_CSS_VENDOR_PREFIXES) $(ENABLE_LEGACY_NOTIFICATIONS) $(ENABLE_LINK_PREFETCH) $(ENABLE_LINK_PRERENDER) $(ENABLE_MATHML) $(ENABLE_MEDIA_SOURCE) $(ENABLE_MEDIA_STATISTICS) $(ENABLE_METER_ELEMENT) $(ENABLE_MHTML) $(ENABLE_MICRODATA) $(ENABLE_MUTATION_OBSERVERS) $(ENABLE_NOTIFICATIONS) $(ENABLE_PAGE_VISIBILITY_API) $(ENABLE_PROGRESS_ELEMENT) $(ENABLE_QUOTA) $(ENABLE_REGISTER_PROTOCOL_HANDLER) $(ENABLE_REQUEST_ANIMATION_FRAME) $(ENABLE_SCRIPTED_SPEECH) $(ENABLE_SHADOW_DOM) $(ENABLE_SHARED_WORKERS) $(ENABLE_SQL_DATABASE) $(ENABLE_STYLE_SCOPED) $(ENABLE_SVG) $(ENABLE_SVG_DOM_OBJC_BINDINGS) $(ENABLE_SVG_FONTS) $(ENABLE_TEXT_AUTOSIZING) $(ENABLE_TEXT_NOTIFICATIONS_ONLY) $(ENABLE_TOUCH_ICON_LOADING) $(ENABLE_UNDO_MANAGER) $(ENABLE_VIDEO) $(ENABLE_VIDEO_TRACK) $(ENABLE_WEBGL) $(ENABLE_WEB_AUDIO) $(ENABLE_WEB_SOCKETS) $(ENABLE_WEB_TIMING) $(ENABLE_WIDGET_REGION) $(ENABLE_WORKERS) $(ENABLE_XSLT); +FEATURE_DEFINES = $(ENABLE_3D_RENDERING) $(ENABLE_ACCELERATED_2D_CANVAS) $(ENABLE_ANIMATION_API) $(ENABLE_BLOB) $(ENABLE_CHANNEL_MESSAGING) $(ENABLE_CSP_NEXT) $(ENABLE_CSS_BOX_DECORATION_BREAK) $(ENABLE_CSS_EXCLUSIONS) $(ENABLE_CSS_FILTERS) $(ENABLE_CSS_HIERARCHIES) $(ENABLE_CSS_IMAGE_ORIENTATION) $(ENABLE_CSS_IMAGE_RESOLUTION) $(ENABLE_CSS_REGIONS) $(ENABLE_CSS_SHADERS) $(ENABLE_CSS_COMPOSITING) $(ENABLE_CSS_STICKY_POSITION) $(ENABLE_CSS_VARIABLES) $(ENABLE_CSS3_FLEXBOX) $(ENABLE_CSS3_TEXT_DECORATION) $(ENABLE_CUSTOM_SCHEME_HANDLER) $(ENABLE_DASHBOARD_SUPPORT) $(ENABLE_DATALIST_ELEMENT) $(ENABLE_DATA_TRANSFER_ITEMS) $(ENABLE_DETAILS_ELEMENT) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DIALOG_ELEMENT) $(ENABLE_DIRECTORY_UPLOAD) $(ENABLE_FILE_SYSTEM) $(ENABLE_FILTERS) $(ENABLE_FULLSCREEN_API) $(ENABLE_GAMEPAD) $(ENABLE_GEOLOCATION) $(ENABLE_HIGH_DPI_CANVAS) $(ENABLE_ICONDATABASE) $(ENABLE_IFRAME_SEAMLESS) $(ENABLE_INDEXED_DATABASE) $(ENABLE_INPUT_SPEECH) $(ENABLE_INPUT_TYPE_COLOR) $(ENABLE_INPUT_TYPE_DATE) $(ENABLE_INPUT_TYPE_DATETIME) $(ENABLE_INPUT_TYPE_DATETIMELOCAL) $(ENABLE_INPUT_TYPE_MONTH) $(ENABLE_INPUT_TYPE_TIME) $(ENABLE_INPUT_TYPE_WEEK) $(ENABLE_JAVASCRIPT_DEBUGGER) $(ENABLE_LEGACY_CSS_VENDOR_PREFIXES) $(ENABLE_LEGACY_NOTIFICATIONS) $(ENABLE_LINK_PREFETCH) $(ENABLE_LINK_PRERENDER) $(ENABLE_MATHML) $(ENABLE_MEDIA_SOURCE) $(ENABLE_MEDIA_STATISTICS) $(ENABLE_METER_ELEMENT) $(ENABLE_MHTML) $(ENABLE_MICRODATA) $(ENABLE_MUTATION_OBSERVERS) $(ENABLE_NOTIFICATIONS) $(ENABLE_PAGE_VISIBILITY_API) $(ENABLE_PROGRESS_ELEMENT) $(ENABLE_QUOTA) $(ENABLE_REGISTER_PROTOCOL_HANDLER) $(ENABLE_REQUEST_ANIMATION_FRAME) $(ENABLE_SCRIPTED_SPEECH) $(ENABLE_SHADOW_DOM) $(ENABLE_SHARED_WORKERS) $(ENABLE_SQL_DATABASE) $(ENABLE_STYLE_SCOPED) $(ENABLE_SVG) $(ENABLE_SVG_DOM_OBJC_BINDINGS) $(ENABLE_SVG_FONTS) $(ENABLE_TEXT_AUTOSIZING) $(ENABLE_TEXT_NOTIFICATIONS_ONLY) $(ENABLE_TOUCH_ICON_LOADING) $(ENABLE_UNDO_MANAGER) $(ENABLE_VIDEO) $(ENABLE_VIDEO_TRACK) $(ENABLE_WEBGL) $(ENABLE_WEB_AUDIO) $(ENABLE_WEB_SOCKETS) $(ENABLE_WEB_TIMING) $(ENABLE_WIDGET_REGION) $(ENABLE_WORKERS) $(ENABLE_XSLT); diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am index ab8b110c2..c504962cc 100644 --- a/Source/JavaScriptCore/GNUmakefile.list.am +++ b/Source/JavaScriptCore/GNUmakefile.list.am @@ -82,6 +82,8 @@ javascriptcore_sources += \ Source/JavaScriptCore/assembler/RepatchBuffer.h \ Source/JavaScriptCore/assembler/SH4Assembler.h \ Source/JavaScriptCore/assembler/X86Assembler.h \ + Source/JavaScriptCore/bytecode/ArrayProfile.cpp \ + Source/JavaScriptCore/bytecode/ArrayProfile.h \ Source/JavaScriptCore/bytecode/BytecodeConventions.h \ Source/JavaScriptCore/bytecode/CallLinkInfo.cpp \ Source/JavaScriptCore/bytecode/CallLinkInfo.h \ @@ -227,6 +229,7 @@ javascriptcore_sources += \ Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp \ Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp \ Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h \ + Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h \ Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp \ Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.h \ Source/JavaScriptCore/dfg/DFGThunks.cpp \ diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj index 2efa84059..e91baa473 100644 --- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj +++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj @@ -1530,6 +1530,14 @@ Name="bytecode" > <File + RelativePath="..\..\bytecode\ArrayProfile.cpp" + > + </File> + <File + RelativePath="..\..\bytecode\ArrayProfile.h" + > + </File> + <File RelativePath="..\..\bytecode\CallLinkInfo.cpp" > </File> diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/testRegExp/testRegExp.vcproj b/Source/JavaScriptCore/JavaScriptCore.vcproj/testRegExp/testRegExp.vcproj index b7053908d..57b9ce643 100755 --- a/Source/JavaScriptCore/JavaScriptCore.vcproj/testRegExp/testRegExp.vcproj +++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/testRegExp/testRegExp.vcproj @@ -50,6 +50,7 @@ /> <Tool Name="VCLinkerTool" + AdditionalOptions="/SAFESEH" /> <Tool Name="VCALinkTool" @@ -111,6 +112,7 @@ /> <Tool Name="VCLinkerTool" + AdditionalOptions="/SAFESEH" /> <Tool Name="VCALinkTool" @@ -172,6 +174,7 @@ /> <Tool Name="VCLinkerTool" + AdditionalOptions="/SAFESEH" /> <Tool Name="VCALinkTool" @@ -233,6 +236,7 @@ /> <Tool Name="VCLinkerTool" + AdditionalOptions="/SAFESEH" /> <Tool Name="VCALinkTool" @@ -295,6 +299,7 @@ /> <Tool Name="VCLinkerTool" + AdditionalOptions="/SAFESEH" /> <Tool Name="VCALinkTool" @@ -356,6 +361,7 @@ /> <Tool Name="VCLinkerTool" + AdditionalOptions="/SAFESEH" /> <Tool Name="VCALinkTool" @@ -417,6 +423,7 @@ /> <Tool Name="VCLinkerTool" + AdditionalOptions="/SAFESEH" /> <Tool Name="VCALinkTool" diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj index add311969..a41fb993b 100644 --- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj +++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj @@ -140,6 +140,9 @@ 0F620179143FCD480068B77C /* DFGAbstractState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F62016D143FCD2F0068B77C /* DFGAbstractState.cpp */; }; 0F63943F15C75F19006A597C /* DFGStructureCheckHoistingPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F63943D15C75F14006A597C /* DFGStructureCheckHoistingPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F63944015C75F1D006A597C /* DFGStructureCheckHoistingPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F63943C15C75F14006A597C /* DFGStructureCheckHoistingPhase.cpp */; }; + 0F63945415D07055006A597C /* ArrayProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F63945115D07051006A597C /* ArrayProfile.cpp */; }; + 0F63945515D07057006A597C /* ArrayProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F63945215D07051006A597C /* ArrayProfile.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F63947815DCE34B006A597C /* DFGStructureAbstractValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F63947615DCE347006A597C /* DFGStructureAbstractValue.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F66E16B14DF3F1600B7B2E4 /* DFGAdjacencyList.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F66E16814DF3F1300B7B2E4 /* DFGAdjacencyList.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F66E16C14DF3F1600B7B2E4 /* DFGEdge.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F66E16914DF3F1300B7B2E4 /* DFGEdge.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F766D2815A8CC1E008F363E /* JITStubRoutine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F766D2615A8CC1B008F363E /* JITStubRoutine.cpp */; }; @@ -889,6 +892,9 @@ 0F620172143FCD2F0068B77C /* DFGVariableAccessData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGVariableAccessData.h; path = dfg/DFGVariableAccessData.h; sourceTree = "<group>"; }; 0F63943C15C75F14006A597C /* DFGStructureCheckHoistingPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGStructureCheckHoistingPhase.cpp; path = dfg/DFGStructureCheckHoistingPhase.cpp; sourceTree = "<group>"; }; 0F63943D15C75F14006A597C /* DFGStructureCheckHoistingPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStructureCheckHoistingPhase.h; path = dfg/DFGStructureCheckHoistingPhase.h; sourceTree = "<group>"; }; + 0F63945115D07051006A597C /* ArrayProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayProfile.cpp; sourceTree = "<group>"; }; + 0F63945215D07051006A597C /* ArrayProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayProfile.h; sourceTree = "<group>"; }; + 0F63947615DCE347006A597C /* DFGStructureAbstractValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStructureAbstractValue.h; path = dfg/DFGStructureAbstractValue.h; sourceTree = "<group>"; }; 0F66E16814DF3F1300B7B2E4 /* DFGAdjacencyList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGAdjacencyList.h; path = dfg/DFGAdjacencyList.h; sourceTree = "<group>"; }; 0F66E16914DF3F1300B7B2E4 /* DFGEdge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGEdge.h; path = dfg/DFGEdge.h; sourceTree = "<group>"; }; 0F766D1C15A5028D008F363E /* JITStubRoutine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITStubRoutine.h; sourceTree = "<group>"; }; @@ -2325,6 +2331,7 @@ 86EC9DC31328DF82002B2AD7 /* DFGSpeculativeJIT.h */, 86880F1B14328BB900B08D42 /* DFGSpeculativeJIT32_64.cpp */, 86880F4C14353B2100B08D42 /* DFGSpeculativeJIT64.cpp */, + 0F63947615DCE347006A597C /* DFGStructureAbstractValue.h */, 0F63943C15C75F14006A597C /* DFGStructureCheckHoistingPhase.cpp */, 0F63943D15C75F14006A597C /* DFGStructureCheckHoistingPhase.h */, 0FC0979F146B28C700CF2442 /* DFGThunks.cpp */, @@ -2407,6 +2414,8 @@ 969A078F0ED1D3AE00F1F681 /* bytecode */ = { isa = PBXGroup; children = ( + 0F63945115D07051006A597C /* ArrayProfile.cpp */, + 0F63945215D07051006A597C /* ArrayProfile.h */, 0F56A1D415001CF2002992B1 /* ExecutionCounter.cpp */, 0F56A1D115000F31002992B1 /* ExecutionCounter.h */, 0FB5467C14F5CFD3002C2989 /* MethodOfGettingAValueProfile.cpp */, @@ -2867,6 +2876,8 @@ 0F766D4415B2A3C0008F363E /* DFGRegisterSet.h in Headers */, 0F766D4615B3701F008F363E /* DFGScratchRegisterAllocator.h in Headers */, 0F63943F15C75F19006A597C /* DFGStructureCheckHoistingPhase.h in Headers */, + 0F63945515D07057006A597C /* ArrayProfile.h in Headers */, + 0F63947815DCE34B006A597C /* DFGStructureAbstractValue.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3465,6 +3476,7 @@ 0F766D3415AE2538008F363E /* JumpReplacementWatchpoint.cpp in Sources */, 0F766D3815AE4A1C008F363E /* StructureStubClearingWatchpoint.cpp in Sources */, 0F63944015C75F1D006A597C /* DFGStructureCheckHoistingPhase.cpp in Sources */, + 0F63945415D07055006A597C /* ArrayProfile.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Source/JavaScriptCore/Target.pri b/Source/JavaScriptCore/Target.pri index 3d0e41df4..e8622363c 100644 --- a/Source/JavaScriptCore/Target.pri +++ b/Source/JavaScriptCore/Target.pri @@ -40,12 +40,14 @@ SOURCES += \ API/JSObjectRef.cpp \ API/JSStringRef.cpp \ API/JSValueRef.cpp \ + API/JSWeakObjectMapRefPrivate.cpp \ API/OpaqueJSString.cpp \ assembler/ARMAssembler.cpp \ assembler/ARMv7Assembler.cpp \ assembler/LinkBuffer.cpp \ assembler/MacroAssemblerARM.cpp \ assembler/MacroAssemblerSH4.cpp \ + bytecode/ArrayProfile.cpp \ bytecode/CallLinkInfo.cpp \ bytecode/CallLinkStatus.cpp \ bytecode/CodeBlock.cpp \ diff --git a/Source/JavaScriptCore/assembler/ARMAssembler.cpp b/Source/JavaScriptCore/assembler/ARMAssembler.cpp index 533640ea8..9655557a5 100644 --- a/Source/JavaScriptCore/assembler/ARMAssembler.cpp +++ b/Source/JavaScriptCore/assembler/ARMAssembler.cpp @@ -187,11 +187,11 @@ int ARMAssembler::genInt(int reg, ARMWord imm, bool positive) } if (positive) { - mov_r(reg, imm1); - orr_r(reg, reg, imm2); + mov(reg, imm1); + orr(reg, reg, imm2); } else { - mvn_r(reg, imm1); - bic_r(reg, reg, imm2); + mvn(reg, imm1); + bic(reg, reg, imm2); } return 1; @@ -210,7 +210,7 @@ ARMWord ARMAssembler::getImm(ARMWord imm, int tmpReg, bool invert) if (tmp != InvalidImmediate) { if (invert) return tmp | Op2InvertedImmediate; - mvn_r(tmpReg, tmp); + mvn(tmpReg, tmp); return tmpReg; } @@ -224,13 +224,13 @@ void ARMAssembler::moveImm(ARMWord imm, int dest) // Do it by 1 instruction tmp = getOp2(imm); if (tmp != InvalidImmediate) { - mov_r(dest, tmp); + mov(dest, tmp); return; } tmp = getOp2(~imm); if (tmp != InvalidImmediate) { - mvn_r(dest, tmp); + mvn(dest, tmp); return; } @@ -242,11 +242,11 @@ ARMWord ARMAssembler::encodeComplexImm(ARMWord imm, int dest) #if WTF_ARM_ARCH_AT_LEAST(7) ARMWord tmp = getImm16Op2(imm); if (tmp != InvalidImmediate) { - movw_r(dest, tmp); + movw(dest, tmp); return dest; } - movw_r(dest, getImm16Op2(imm & 0xffff)); - movt_r(dest, getImm16Op2(imm >> 16)); + movw(dest, getImm16Op2(imm & 0xffff)); + movt(dest, getImm16Op2(imm >> 16)); return dest; #else // Do it by 2 instruction @@ -255,7 +255,7 @@ ARMWord ARMAssembler::encodeComplexImm(ARMWord imm, int dest) if (genInt(dest, ~imm, false)) return dest; - ldr_imm(dest, imm); + ldrImmediate(dest, imm); return dest; #endif } @@ -266,23 +266,23 @@ void ARMAssembler::dataTransfer32(DataTransferTypeA transferType, RegisterID src { if (offset >= 0) { if (offset <= 0xfff) - dtr_u(transferType, srcDst, base, offset); + dtrUp(transferType, srcDst, base, offset); else if (offset <= 0xfffff) { - add_r(ARMRegisters::S0, base, Op2Immediate | (offset >> 12) | (10 << 8)); - dtr_u(transferType, srcDst, ARMRegisters::S0, (offset & 0xfff)); + add(ARMRegisters::S0, base, Op2Immediate | (offset >> 12) | (10 << 8)); + dtrUp(transferType, srcDst, ARMRegisters::S0, (offset & 0xfff)); } else { moveImm(offset, ARMRegisters::S0); - dtr_ur(transferType, srcDst, base, ARMRegisters::S0); + dtrUpRegister(transferType, srcDst, base, ARMRegisters::S0); } } else { if (offset >= -0xfff) - dtr_d(transferType, srcDst, base, -offset); + dtrDown(transferType, srcDst, base, -offset); else if (offset >= -0xfffff) { - sub_r(ARMRegisters::S0, base, Op2Immediate | (-offset >> 12) | (10 << 8)); - dtr_d(transferType, srcDst, ARMRegisters::S0, (-offset & 0xfff)); + sub(ARMRegisters::S0, base, Op2Immediate | (-offset >> 12) | (10 << 8)); + dtrDown(transferType, srcDst, ARMRegisters::S0, (-offset & 0xfff)); } else { moveImm(offset, ARMRegisters::S0); - dtr_ur(transferType, srcDst, base, ARMRegisters::S0); + dtrUpRegister(transferType, srcDst, base, ARMRegisters::S0); } } } @@ -293,11 +293,11 @@ void ARMAssembler::baseIndexTransfer32(DataTransferTypeA transferType, RegisterI ARMWord op2 = lsl(index, scale); if (!offset) { - dtr_ur(transferType, srcDst, base, op2); + dtrUpRegister(transferType, srcDst, base, op2); return; } - add_r(ARMRegisters::S1, base, op2); + add(ARMRegisters::S1, base, op2); dataTransfer32(transferType, srcDst, ARMRegisters::S1, offset); } @@ -305,23 +305,23 @@ void ARMAssembler::dataTransfer16(DataTransferTypeB transferType, RegisterID src { if (offset >= 0) { if (offset <= 0xff) - dtrh_u(transferType, srcDst, base, getOp2Half(offset)); + halfDtrUp(transferType, srcDst, base, getOp2Half(offset)); else if (offset <= 0xffff) { - add_r(ARMRegisters::S0, base, Op2Immediate | (offset >> 8) | (12 << 8)); - dtrh_u(transferType, srcDst, ARMRegisters::S0, getOp2Half(offset & 0xff)); + add(ARMRegisters::S0, base, Op2Immediate | (offset >> 8) | (12 << 8)); + halfDtrUp(transferType, srcDst, ARMRegisters::S0, getOp2Half(offset & 0xff)); } else { moveImm(offset, ARMRegisters::S0); - dtrh_ur(transferType, srcDst, base, ARMRegisters::S0); + halfDtrUpRegister(transferType, srcDst, base, ARMRegisters::S0); } } else { if (offset >= -0xff) - dtrh_d(transferType, srcDst, base, getOp2Half(-offset)); + halfDtrDown(transferType, srcDst, base, getOp2Half(-offset)); else if (offset >= -0xffff) { - sub_r(ARMRegisters::S0, base, Op2Immediate | (-offset >> 8) | (12 << 8)); - dtrh_d(transferType, srcDst, ARMRegisters::S0, getOp2Half(-offset & 0xff)); + sub(ARMRegisters::S0, base, Op2Immediate | (-offset >> 8) | (12 << 8)); + halfDtrDown(transferType, srcDst, ARMRegisters::S0, getOp2Half(-offset & 0xff)); } else { moveImm(offset, ARMRegisters::S0); - dtrh_ur(transferType, srcDst, base, ARMRegisters::S0); + halfDtrUpRegister(transferType, srcDst, base, ARMRegisters::S0); } } } @@ -329,11 +329,11 @@ void ARMAssembler::dataTransfer16(DataTransferTypeB transferType, RegisterID src void ARMAssembler::baseIndexTransfer16(DataTransferTypeB transferType, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset) { if (!scale && !offset) { - dtrh_ur(transferType, srcDst, base, index); + halfDtrUpRegister(transferType, srcDst, base, index); return; } - add_r(ARMRegisters::S1, base, lsl(index, scale)); + add(ARMRegisters::S1, base, lsl(index, scale)); dataTransfer16(transferType, srcDst, ARMRegisters::S1, offset); } @@ -342,36 +342,36 @@ void ARMAssembler::dataTransferFloat(DataTransferTypeFloat transferType, FPRegis // VFP cannot directly access memory that is not four-byte-aligned if (!(offset & 0x3)) { if (offset <= 0x3ff && offset >= 0) { - fdtr_u(transferType, srcDst, base, offset >> 2); + doubleDtrUp(transferType, srcDst, base, offset >> 2); return; } if (offset <= 0x3ffff && offset >= 0) { - add_r(ARMRegisters::S0, base, Op2Immediate | (offset >> 10) | (11 << 8)); - fdtr_u(transferType, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff); + add(ARMRegisters::S0, base, Op2Immediate | (offset >> 10) | (11 << 8)); + doubleDtrUp(transferType, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff); return; } offset = -offset; if (offset <= 0x3ff && offset >= 0) { - fdtr_d(transferType, srcDst, base, offset >> 2); + doubleDtrDown(transferType, srcDst, base, offset >> 2); return; } if (offset <= 0x3ffff && offset >= 0) { - sub_r(ARMRegisters::S0, base, Op2Immediate | (offset >> 10) | (11 << 8)); - fdtr_d(transferType, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff); + sub(ARMRegisters::S0, base, Op2Immediate | (offset >> 10) | (11 << 8)); + doubleDtrDown(transferType, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff); return; } offset = -offset; } moveImm(offset, ARMRegisters::S0); - add_r(ARMRegisters::S0, ARMRegisters::S0, base); - fdtr_u(transferType, srcDst, ARMRegisters::S0, 0); + add(ARMRegisters::S0, ARMRegisters::S0, base); + doubleDtrUp(transferType, srcDst, ARMRegisters::S0, 0); } void ARMAssembler::baseIndexTransferFloat(DataTransferTypeFloat transferType, FPRegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset) { - add_r(ARMRegisters::S1, base, lsl(index, scale)); + add(ARMRegisters::S1, base, lsl(index, scale)); dataTransferFloat(transferType, srcDst, ARMRegisters::S1, offset); } diff --git a/Source/JavaScriptCore/assembler/ARMAssembler.h b/Source/JavaScriptCore/assembler/ARMAssembler.h index ac918f31e..38d0c5e6d 100644 --- a/Source/JavaScriptCore/assembler/ARMAssembler.h +++ b/Source/JavaScriptCore/assembler/ARMAssembler.h @@ -268,355 +268,355 @@ namespace JSC { | (sm >> 1) | ((sm & 0x1) << 5)); } - void and_r(int rd, int rn, ARMWord op2, Condition cc = AL) + void bitAnd(int rd, int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | AND, rd, rn, op2); } - void ands_r(int rd, int rn, ARMWord op2, Condition cc = AL) + void bitAnds(int rd, int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | AND | SetConditionalCodes, rd, rn, op2); } - void eor_r(int rd, int rn, ARMWord op2, Condition cc = AL) + void eor(int rd, int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | EOR, rd, rn, op2); } - void eors_r(int rd, int rn, ARMWord op2, Condition cc = AL) + void eors(int rd, int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | EOR | SetConditionalCodes, rd, rn, op2); } - void sub_r(int rd, int rn, ARMWord op2, Condition cc = AL) + void sub(int rd, int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | SUB, rd, rn, op2); } - void subs_r(int rd, int rn, ARMWord op2, Condition cc = AL) + void subs(int rd, int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | SUB | SetConditionalCodes, rd, rn, op2); } - void rsb_r(int rd, int rn, ARMWord op2, Condition cc = AL) + void rsb(int rd, int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | RSB, rd, rn, op2); } - void rsbs_r(int rd, int rn, ARMWord op2, Condition cc = AL) + void rsbs(int rd, int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | RSB | SetConditionalCodes, rd, rn, op2); } - void add_r(int rd, int rn, ARMWord op2, Condition cc = AL) + void add(int rd, int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | ADD, rd, rn, op2); } - void adds_r(int rd, int rn, ARMWord op2, Condition cc = AL) + void adds(int rd, int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | ADD | SetConditionalCodes, rd, rn, op2); } - void adc_r(int rd, int rn, ARMWord op2, Condition cc = AL) + void adc(int rd, int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | ADC, rd, rn, op2); } - void adcs_r(int rd, int rn, ARMWord op2, Condition cc = AL) + void adcs(int rd, int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | ADC | SetConditionalCodes, rd, rn, op2); } - void sbc_r(int rd, int rn, ARMWord op2, Condition cc = AL) + void sbc(int rd, int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | SBC, rd, rn, op2); } - void sbcs_r(int rd, int rn, ARMWord op2, Condition cc = AL) + void sbcs(int rd, int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | SBC | SetConditionalCodes, rd, rn, op2); } - void rsc_r(int rd, int rn, ARMWord op2, Condition cc = AL) + void rsc(int rd, int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | RSC, rd, rn, op2); } - void rscs_r(int rd, int rn, ARMWord op2, Condition cc = AL) + void rscs(int rd, int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | RSC | SetConditionalCodes, rd, rn, op2); } - void tst_r(int rn, ARMWord op2, Condition cc = AL) + void tst(int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | TST | SetConditionalCodes, 0, rn, op2); } - void teq_r(int rn, ARMWord op2, Condition cc = AL) + void teq(int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | TEQ | SetConditionalCodes, 0, rn, op2); } - void cmp_r(int rn, ARMWord op2, Condition cc = AL) + void cmp(int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | CMP | SetConditionalCodes, 0, rn, op2); } - void cmn_r(int rn, ARMWord op2, Condition cc = AL) + void cmn(int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | CMN | SetConditionalCodes, 0, rn, op2); } - void orr_r(int rd, int rn, ARMWord op2, Condition cc = AL) + void orr(int rd, int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | ORR, rd, rn, op2); } - void orrs_r(int rd, int rn, ARMWord op2, Condition cc = AL) + void orrs(int rd, int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | ORR | SetConditionalCodes, rd, rn, op2); } - void mov_r(int rd, ARMWord op2, Condition cc = AL) + void mov(int rd, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | MOV, rd, ARMRegisters::r0, op2); } #if WTF_ARM_ARCH_AT_LEAST(7) - void movw_r(int rd, ARMWord op2, Condition cc = AL) + void movw(int rd, ARMWord op2, Condition cc = AL) { ASSERT((op2 | 0xf0fff) == 0xf0fff); m_buffer.putInt(toARMWord(cc) | MOVW | RD(rd) | op2); } - void movt_r(int rd, ARMWord op2, Condition cc = AL) + void movt(int rd, ARMWord op2, Condition cc = AL) { ASSERT((op2 | 0xf0fff) == 0xf0fff); m_buffer.putInt(toARMWord(cc) | MOVT | RD(rd) | op2); } #endif - void movs_r(int rd, ARMWord op2, Condition cc = AL) + void movs(int rd, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | MOV | SetConditionalCodes, rd, ARMRegisters::r0, op2); } - void bic_r(int rd, int rn, ARMWord op2, Condition cc = AL) + void bic(int rd, int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | BIC, rd, rn, op2); } - void bics_r(int rd, int rn, ARMWord op2, Condition cc = AL) + void bics(int rd, int rn, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | BIC | SetConditionalCodes, rd, rn, op2); } - void mvn_r(int rd, ARMWord op2, Condition cc = AL) + void mvn(int rd, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | MVN, rd, ARMRegisters::r0, op2); } - void mvns_r(int rd, ARMWord op2, Condition cc = AL) + void mvns(int rd, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | MVN | SetConditionalCodes, rd, ARMRegisters::r0, op2); } - void mul_r(int rd, int rn, int rm, Condition cc = AL) + void mul(int rd, int rn, int rm, Condition cc = AL) { m_buffer.putInt(toARMWord(cc) | MUL | RN(rd) | RS(rn) | RM(rm)); } - void muls_r(int rd, int rn, int rm, Condition cc = AL) + void muls(int rd, int rn, int rm, Condition cc = AL) { m_buffer.putInt(toARMWord(cc) | MUL | SetConditionalCodes | RN(rd) | RS(rn) | RM(rm)); } - void mull_r(int rdhi, int rdlo, int rn, int rm, Condition cc = AL) + void mull(int rdhi, int rdlo, int rn, int rm, Condition cc = AL) { m_buffer.putInt(toARMWord(cc) | MULL | RN(rdhi) | RD(rdlo) | RS(rn) | RM(rm)); } - void vmov_f64_r(int dd, int dm, Condition cc = AL) + void vmov_f64(int dd, int dm, Condition cc = AL) { emitDoublePrecisionInstruction(toARMWord(cc) | VMOV_F64, dd, 0, dm); } - void vadd_f64_r(int dd, int dn, int dm, Condition cc = AL) + void vadd_f64(int dd, int dn, int dm, Condition cc = AL) { emitDoublePrecisionInstruction(toARMWord(cc) | VADD_F64, dd, dn, dm); } - void vdiv_f64_r(int dd, int dn, int dm, Condition cc = AL) + void vdiv_f64(int dd, int dn, int dm, Condition cc = AL) { emitDoublePrecisionInstruction(toARMWord(cc) | VDIV_F64, dd, dn, dm); } - void vsub_f64_r(int dd, int dn, int dm, Condition cc = AL) + void vsub_f64(int dd, int dn, int dm, Condition cc = AL) { emitDoublePrecisionInstruction(toARMWord(cc) | VSUB_F64, dd, dn, dm); } - void vmul_f64_r(int dd, int dn, int dm, Condition cc = AL) + void vmul_f64(int dd, int dn, int dm, Condition cc = AL) { emitDoublePrecisionInstruction(toARMWord(cc) | VMUL_F64, dd, dn, dm); } - void vcmp_f64_r(int dd, int dm, Condition cc = AL) + void vcmp_f64(int dd, int dm, Condition cc = AL) { emitDoublePrecisionInstruction(toARMWord(cc) | VCMP_F64, dd, 0, dm); } - void vsqrt_f64_r(int dd, int dm, Condition cc = AL) + void vsqrt_f64(int dd, int dm, Condition cc = AL) { emitDoublePrecisionInstruction(toARMWord(cc) | VSQRT_F64, dd, 0, dm); } - void vabs_f64_r(int dd, int dm, Condition cc = AL) + void vabs_f64(int dd, int dm, Condition cc = AL) { emitDoublePrecisionInstruction(toARMWord(cc) | VABS_F64, dd, 0, dm); } - void vneg_f64_r(int dd, int dm, Condition cc = AL) + void vneg_f64(int dd, int dm, Condition cc = AL) { emitDoublePrecisionInstruction(toARMWord(cc) | VNEG_F64, dd, 0, dm); } - void ldr_imm(int rd, ARMWord imm, Condition cc = AL) + void ldrImmediate(int rd, ARMWord imm, Condition cc = AL) { m_buffer.putIntWithConstantInt(toARMWord(cc) | LoadUint32 | DataTransferUp | RN(ARMRegisters::pc) | RD(rd), imm, true); } - void ldr_un_imm(int rd, ARMWord imm, Condition cc = AL) + void ldrUniqueImmediate(int rd, ARMWord imm, Condition cc = AL) { m_buffer.putIntWithConstantInt(toARMWord(cc) | LoadUint32 | DataTransferUp | RN(ARMRegisters::pc) | RD(rd), imm); } - void dtr_u(DataTransferTypeA transferType, int rd, int rb, ARMWord op2, Condition cc = AL) + void dtrUp(DataTransferTypeA transferType, int rd, int rb, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | transferType | DataTransferUp, rd, rb, op2); } - void dtr_ur(DataTransferTypeA transferType, int rd, int rb, int rm, Condition cc = AL) + void dtrUpRegister(DataTransferTypeA transferType, int rd, int rb, int rm, Condition cc = AL) { emitInstruction(toARMWord(cc) | transferType | DataTransferUp | Op2IsRegisterArgument, rd, rb, rm); } - void dtr_d(DataTransferTypeA transferType, int rd, int rb, ARMWord op2, Condition cc = AL) + void dtrDown(DataTransferTypeA transferType, int rd, int rb, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | transferType, rd, rb, op2); } - void dtr_dr(DataTransferTypeA transferType, int rd, int rb, int rm, Condition cc = AL) + void dtrDownRegister(DataTransferTypeA transferType, int rd, int rb, int rm, Condition cc = AL) { emitInstruction(toARMWord(cc) | transferType | Op2IsRegisterArgument, rd, rb, rm); } - void dtrh_u(DataTransferTypeB transferType, int rd, int rb, ARMWord op2, Condition cc = AL) + void halfDtrUp(DataTransferTypeB transferType, int rd, int rb, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | transferType | DataTransferUp, rd, rb, op2); } - void dtrh_ur(DataTransferTypeB transferType, int rd, int rn, int rm, Condition cc = AL) + void halfDtrUpRegister(DataTransferTypeB transferType, int rd, int rn, int rm, Condition cc = AL) { emitInstruction(toARMWord(cc) | transferType | DataTransferUp, rd, rn, rm); } - void dtrh_d(DataTransferTypeB transferType, int rd, int rb, ARMWord op2, Condition cc = AL) + void halfDtrDown(DataTransferTypeB transferType, int rd, int rb, ARMWord op2, Condition cc = AL) { emitInstruction(toARMWord(cc) | transferType, rd, rb, op2); } - void dtrh_dr(DataTransferTypeB transferType, int rd, int rn, int rm, Condition cc = AL) + void halfDtrDownRegister(DataTransferTypeB transferType, int rd, int rn, int rm, Condition cc = AL) { emitInstruction(toARMWord(cc) | transferType, rd, rn, rm); } - void fdtr_u(DataTransferTypeFloat type, int rd, int rb, ARMWord op2, Condition cc = AL) + void doubleDtrUp(DataTransferTypeFloat type, int rd, int rb, ARMWord op2, Condition cc = AL) { ASSERT(op2 <= 0xff && rd <= 15); /* Only d0-d15 and s0, s2, s4 ... s30 are supported. */ m_buffer.putInt(toARMWord(cc) | DataTransferUp | type | (rd << 12) | RN(rb) | op2); } - void fdtr_d(DataTransferTypeFloat type, int rd, int rb, ARMWord op2, Condition cc = AL) + void doubleDtrDown(DataTransferTypeFloat type, int rd, int rb, ARMWord op2, Condition cc = AL) { ASSERT(op2 <= 0xff && rd <= 15); /* Only d0-d15 and s0, s2, s4 ... s30 are supported. */ m_buffer.putInt(toARMWord(cc) | type | (rd << 12) | RN(rb) | op2); } - void push_r(int reg, Condition cc = AL) + void push(int reg, Condition cc = AL) { ASSERT(ARMWord(reg) <= 0xf); m_buffer.putInt(toARMWord(cc) | StoreUint32 | DataTransferWriteBack | RN(ARMRegisters::sp) | RD(reg) | 0x4); } - void pop_r(int reg, Condition cc = AL) + void pop(int reg, Condition cc = AL) { ASSERT(ARMWord(reg) <= 0xf); m_buffer.putInt(toARMWord(cc) | (LoadUint32 ^ DataTransferPostUpdate) | DataTransferUp | RN(ARMRegisters::sp) | RD(reg) | 0x4); } - inline void poke_r(int reg, Condition cc = AL) + inline void poke(int reg, Condition cc = AL) { - dtr_d(StoreUint32, ARMRegisters::sp, 0, reg, cc); + dtrDown(StoreUint32, ARMRegisters::sp, 0, reg, cc); } - inline void peek_r(int reg, Condition cc = AL) + inline void peek(int reg, Condition cc = AL) { - dtr_u(LoadUint32, reg, ARMRegisters::sp, 0, cc); + dtrUp(LoadUint32, reg, ARMRegisters::sp, 0, cc); } - void vmov_vfp64_r(int sm, int rt, int rt2, Condition cc = AL) + void vmov_vfp64(int sm, int rt, int rt2, Condition cc = AL) { ASSERT(rt != rt2); m_buffer.putInt(toARMWord(cc) | VMOV_VFP64 | RN(rt2) | RD(rt) | (sm & 0xf) | ((sm & 0x10) << (5 - 4))); } - void vmov_arm64_r(int rt, int rt2, int sm, Condition cc = AL) + void vmov_arm64(int rt, int rt2, int sm, Condition cc = AL) { ASSERT(rt != rt2); m_buffer.putInt(toARMWord(cc) | VMOV_ARM64 | RN(rt2) | RD(rt) | (sm & 0xf) | ((sm & 0x10) << (5 - 4))); } - void vmov_vfp32_r(int sn, int rt, Condition cc = AL) + void vmov_vfp32(int sn, int rt, Condition cc = AL) { ASSERT(rt <= 15); emitSinglePrecisionInstruction(toARMWord(cc) | VMOV_VFP32, rt << 1, sn, 0); } - void vmov_arm32_r(int rt, int sn, Condition cc = AL) + void vmov_arm32(int rt, int sn, Condition cc = AL) { ASSERT(rt <= 15); emitSinglePrecisionInstruction(toARMWord(cc) | VMOV_ARM32, rt << 1, sn, 0); } - void vcvt_f64_s32_r(int dd, int sm, Condition cc = AL) + void vcvt_f64_s32(int dd, int sm, Condition cc = AL) { ASSERT(!(sm & 0x1)); // sm must be divisible by 2 emitDoublePrecisionInstruction(toARMWord(cc) | VCVT_F64_S32, dd, 0, (sm >> 1)); } - void vcvt_s32_f64_r(int sd, int dm, Condition cc = AL) + void vcvt_s32_f64(int sd, int dm, Condition cc = AL) { ASSERT(!(sd & 0x1)); // sd must be divisible by 2 emitDoublePrecisionInstruction(toARMWord(cc) | VCVT_S32_F64, (sd >> 1), 0, dm); } - void vcvt_u32_f64_r(int sd, int dm, Condition cc = AL) + void vcvt_u32_f64(int sd, int dm, Condition cc = AL) { ASSERT(!(sd & 0x1)); // sd must be divisible by 2 emitDoublePrecisionInstruction(toARMWord(cc) | VCVT_U32_F64, (sd >> 1), 0, dm); } - void vcvt_f64_f32_r(int dd, int sm, Condition cc = AL) + void vcvt_f64_f32(int dd, int sm, Condition cc = AL) { ASSERT(dd <= 15 && sm <= 15); emitDoublePrecisionInstruction(toARMWord(cc) | VCVT_F64_F32, dd, 0, sm); } - void vcvt_f32_f64_r(int dd, int sm, Condition cc = AL) + void vcvt_f32_f64(int dd, int sm, Condition cc = AL) { ASSERT(dd <= 15 && sm <= 15); emitDoublePrecisionInstruction(toARMWord(cc) | VCVT_F32_F64, dd, 0, sm); @@ -627,7 +627,7 @@ namespace JSC { m_buffer.putInt(toARMWord(cc) | VMRS_APSR); } - void clz_r(int rd, int rm, Condition cc = AL) + void clz(int rd, int rm, Condition cc = AL) { m_buffer.putInt(toARMWord(cc) | CLZ | RD(rd) | RM(rm)); } @@ -674,21 +674,21 @@ namespace JSC { return reg | (value << 7) | 0x40; } - static ARMWord lsl_r(int reg, int shiftReg) + static ARMWord lslRegister(int reg, int shiftReg) { ASSERT(reg <= ARMRegisters::pc); ASSERT(shiftReg <= ARMRegisters::pc); return reg | (shiftReg << 8) | 0x10; } - static ARMWord lsr_r(int reg, int shiftReg) + static ARMWord lsrRegister(int reg, int shiftReg) { ASSERT(reg <= ARMRegisters::pc); ASSERT(shiftReg <= ARMRegisters::pc); return reg | (shiftReg << 8) | 0x30; } - static ARMWord asr_r(int reg, int shiftReg) + static ARMWord asrRegister(int reg, int shiftReg) { ASSERT(reg <= ARMRegisters::pc); ASSERT(shiftReg <= ARMRegisters::pc); @@ -742,7 +742,7 @@ namespace JSC { AssemblerLabel align(int alignment) { while (!m_buffer.isAligned(alignment)) - mov_r(ARMRegisters::r0, ARMRegisters::r0); + mov(ARMRegisters::r0, ARMRegisters::r0); return label(); } @@ -751,7 +751,7 @@ namespace JSC { { ensureSpace(sizeof(ARMWord), sizeof(ARMWord)); m_jumps.append(m_buffer.codeSize() | (useConstantPool & 0x1)); - ldr_un_imm(rd, InvalidBranchTarget, cc); + ldrUniqueImmediate(rd, InvalidBranchTarget, cc); return m_buffer.label(); } @@ -767,12 +767,12 @@ namespace JSC { // DFG assembly helpers for moving data between fp and registers. void vmov(RegisterID rd1, RegisterID rd2, FPRegisterID rn) { - vmov_arm64_r(rd1, rd2, rn); + vmov_arm64(rd1, rd2, rn); } void vmov(FPRegisterID rd, RegisterID rn1, RegisterID rn2) { - vmov_vfp64_r(rd, rn1, rn2); + vmov_vfp64(rd, rn1, rn2); } // Patching helpers diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerARM.cpp b/Source/JavaScriptCore/assembler/MacroAssemblerARM.cpp index a251a4376..98dc3e987 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerARM.cpp +++ b/Source/JavaScriptCore/assembler/MacroAssemblerARM.cpp @@ -76,21 +76,21 @@ void MacroAssemblerARM::load32WithUnalignedHalfWords(BaseIndex address, Register op2 = m_assembler.lsl(address.index, static_cast<int>(address.scale)); if (address.offset >= 0 && address.offset + 0x2 <= 0xff) { - m_assembler.add_r(ARMRegisters::S0, address.base, op2); - m_assembler.dtrh_u(ARMAssembler::LoadUint16, dest, ARMRegisters::S0, ARMAssembler::getOp2Half(address.offset)); - m_assembler.dtrh_u(ARMAssembler::LoadUint16, ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Half(address.offset + 0x2)); + m_assembler.add(ARMRegisters::S0, address.base, op2); + m_assembler.halfDtrUp(ARMAssembler::LoadUint16, dest, ARMRegisters::S0, ARMAssembler::getOp2Half(address.offset)); + m_assembler.halfDtrUp(ARMAssembler::LoadUint16, ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Half(address.offset + 0x2)); } else if (address.offset < 0 && address.offset >= -0xff) { - m_assembler.add_r(ARMRegisters::S0, address.base, op2); - m_assembler.dtrh_d(ARMAssembler::LoadUint16, dest, ARMRegisters::S0, ARMAssembler::getOp2Half(-address.offset)); - m_assembler.dtrh_d(ARMAssembler::LoadUint16, ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Half(-address.offset - 0x2)); + m_assembler.add(ARMRegisters::S0, address.base, op2); + m_assembler.halfDtrDown(ARMAssembler::LoadUint16, dest, ARMRegisters::S0, ARMAssembler::getOp2Half(-address.offset)); + m_assembler.halfDtrDown(ARMAssembler::LoadUint16, ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Half(-address.offset - 0x2)); } else { m_assembler.moveImm(address.offset, ARMRegisters::S0); - m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, op2); - m_assembler.dtrh_ur(ARMAssembler::LoadUint16, dest, address.base, ARMRegisters::S0); - m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::Op2Immediate | 0x2); - m_assembler.dtrh_ur(ARMAssembler::LoadUint16, ARMRegisters::S0, address.base, ARMRegisters::S0); + m_assembler.add(ARMRegisters::S0, ARMRegisters::S0, op2); + m_assembler.halfDtrUpRegister(ARMAssembler::LoadUint16, dest, address.base, ARMRegisters::S0); + m_assembler.add(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::Op2Immediate | 0x2); + m_assembler.halfDtrUpRegister(ARMAssembler::LoadUint16, ARMRegisters::S0, address.base, ARMRegisters::S0); } - m_assembler.orr_r(dest, dest, m_assembler.lsl(ARMRegisters::S0, 16)); + m_assembler.orr(dest, dest, m_assembler.lsl(ARMRegisters::S0, 16)); } #endif diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerARM.h b/Source/JavaScriptCore/assembler/MacroAssemblerARM.h index 85d0ffbcc..295354119 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerARM.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerARM.h @@ -86,12 +86,12 @@ public: void add32(RegisterID src, RegisterID dest) { - m_assembler.adds_r(dest, dest, src); + m_assembler.adds(dest, dest, src); } void add32(RegisterID op1, RegisterID op2, RegisterID dest) { - m_assembler.adds_r(dest, op1, op2); + m_assembler.adds(dest, op1, op2); } void add32(TrustedImm32 imm, Address address) @@ -103,13 +103,13 @@ public: void add32(TrustedImm32 imm, RegisterID dest) { - m_assembler.adds_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); + m_assembler.adds(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } void add32(AbsoluteAddress src, RegisterID dest) { move(TrustedImmPtr(src.m_ptr), ARMRegisters::S1); - m_assembler.dtr_u(ARMAssembler::LoadUint32, ARMRegisters::S1, ARMRegisters::S1, 0); + m_assembler.dtrUp(ARMAssembler::LoadUint32, ARMRegisters::S1, ARMRegisters::S1, 0); add32(ARMRegisters::S1, dest); } @@ -121,35 +121,35 @@ public: void add32(RegisterID src, TrustedImm32 imm, RegisterID dest) { - m_assembler.adds_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); + m_assembler.adds(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } void and32(RegisterID src, RegisterID dest) { - m_assembler.ands_r(dest, dest, src); + m_assembler.bitAnds(dest, dest, src); } void and32(RegisterID op1, RegisterID op2, RegisterID dest) { - m_assembler.ands_r(dest, op1, op2); + m_assembler.bitAnds(dest, op1, op2); } void and32(TrustedImm32 imm, RegisterID dest) { ARMWord w = m_assembler.getImm(imm.m_value, ARMRegisters::S0, true); if (w & ARMAssembler::Op2InvertedImmediate) - m_assembler.bics_r(dest, dest, w & ~ARMAssembler::Op2InvertedImmediate); + m_assembler.bics(dest, dest, w & ~ARMAssembler::Op2InvertedImmediate); else - m_assembler.ands_r(dest, dest, w); + m_assembler.bitAnds(dest, dest, w); } void and32(TrustedImm32 imm, RegisterID src, RegisterID dest) { ARMWord w = m_assembler.getImm(imm.m_value, ARMRegisters::S0, true); if (w & ARMAssembler::Op2InvertedImmediate) - m_assembler.bics_r(dest, src, w & ~ARMAssembler::Op2InvertedImmediate); + m_assembler.bics(dest, src, w & ~ARMAssembler::Op2InvertedImmediate); else - m_assembler.ands_r(dest, src, w); + m_assembler.bitAnds(dest, src, w); } void lshift32(RegisterID shiftAmount, RegisterID dest) @@ -160,19 +160,19 @@ public: void lshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest) { ARMWord w = ARMAssembler::getOp2Byte(0x1f); - m_assembler.and_r(ARMRegisters::S0, shiftAmount, w); + m_assembler.bitAnd(ARMRegisters::S0, shiftAmount, w); - m_assembler.movs_r(dest, m_assembler.lsl_r(src, ARMRegisters::S0)); + m_assembler.movs(dest, m_assembler.lslRegister(src, ARMRegisters::S0)); } void lshift32(TrustedImm32 imm, RegisterID dest) { - m_assembler.movs_r(dest, m_assembler.lsl(dest, imm.m_value & 0x1f)); + m_assembler.movs(dest, m_assembler.lsl(dest, imm.m_value & 0x1f)); } void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest) { - m_assembler.movs_r(dest, m_assembler.lsl(src, imm.m_value & 0x1f)); + m_assembler.movs(dest, m_assembler.lsl(src, imm.m_value & 0x1f)); } void mul32(RegisterID op1, RegisterID op2, RegisterID dest) @@ -188,7 +188,7 @@ public: op2 = tmp; } } - m_assembler.muls_r(dest, op1, op2); + m_assembler.muls(dest, op1, op2); } void mul32(RegisterID src, RegisterID dest) @@ -199,32 +199,32 @@ public: void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest) { move(imm, ARMRegisters::S0); - m_assembler.muls_r(dest, src, ARMRegisters::S0); + m_assembler.muls(dest, src, ARMRegisters::S0); } void neg32(RegisterID srcDest) { - m_assembler.rsbs_r(srcDest, srcDest, ARMAssembler::getOp2Byte(0)); + m_assembler.rsbs(srcDest, srcDest, ARMAssembler::getOp2Byte(0)); } void or32(RegisterID src, RegisterID dest) { - m_assembler.orrs_r(dest, dest, src); + m_assembler.orrs(dest, dest, src); } void or32(TrustedImm32 imm, RegisterID dest) { - m_assembler.orrs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); + m_assembler.orrs(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } void or32(TrustedImm32 imm, RegisterID src, RegisterID dest) { - m_assembler.orrs_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); + m_assembler.orrs(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } void or32(RegisterID op1, RegisterID op2, RegisterID dest) { - m_assembler.orrs_r(dest, op1, op2); + m_assembler.orrs(dest, op1, op2); } void rshift32(RegisterID shiftAmount, RegisterID dest) @@ -235,9 +235,9 @@ public: void rshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest) { ARMWord w = ARMAssembler::getOp2Byte(0x1f); - m_assembler.and_r(ARMRegisters::S0, shiftAmount, w); + m_assembler.bitAnd(ARMRegisters::S0, shiftAmount, w); - m_assembler.movs_r(dest, m_assembler.asr_r(src, ARMRegisters::S0)); + m_assembler.movs(dest, m_assembler.asrRegister(src, ARMRegisters::S0)); } void rshift32(TrustedImm32 imm, RegisterID dest) @@ -247,7 +247,7 @@ public: void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest) { - m_assembler.movs_r(dest, m_assembler.asr(src, imm.m_value & 0x1f)); + m_assembler.movs(dest, m_assembler.asr(src, imm.m_value & 0x1f)); } void urshift32(RegisterID shiftAmount, RegisterID dest) @@ -258,29 +258,29 @@ public: void urshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest) { ARMWord w = ARMAssembler::getOp2Byte(0x1f); - m_assembler.and_r(ARMRegisters::S0, shiftAmount, w); + m_assembler.bitAnd(ARMRegisters::S0, shiftAmount, w); - m_assembler.movs_r(dest, m_assembler.lsr_r(src, ARMRegisters::S0)); + m_assembler.movs(dest, m_assembler.lsrRegister(src, ARMRegisters::S0)); } void urshift32(TrustedImm32 imm, RegisterID dest) { - m_assembler.movs_r(dest, m_assembler.lsr(dest, imm.m_value & 0x1f)); + m_assembler.movs(dest, m_assembler.lsr(dest, imm.m_value & 0x1f)); } void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest) { - m_assembler.movs_r(dest, m_assembler.lsr(src, imm.m_value & 0x1f)); + m_assembler.movs(dest, m_assembler.lsr(src, imm.m_value & 0x1f)); } void sub32(RegisterID src, RegisterID dest) { - m_assembler.subs_r(dest, dest, src); + m_assembler.subs(dest, dest, src); } void sub32(TrustedImm32 imm, RegisterID dest) { - m_assembler.subs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); + m_assembler.subs(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } void sub32(TrustedImm32 imm, Address address) @@ -298,39 +298,39 @@ public: void sub32(RegisterID src, TrustedImm32 imm, RegisterID dest) { - m_assembler.subs_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); + m_assembler.subs(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } void xor32(RegisterID src, RegisterID dest) { - m_assembler.eors_r(dest, dest, src); + m_assembler.eors(dest, dest, src); } void xor32(RegisterID op1, RegisterID op2, RegisterID dest) { - m_assembler.eors_r(dest, op1, op2); + m_assembler.eors(dest, op1, op2); } void xor32(TrustedImm32 imm, RegisterID dest) { if (imm.m_value == -1) - m_assembler.mvns_r(dest, dest); + m_assembler.mvns(dest, dest); else - m_assembler.eors_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); + m_assembler.eors(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest) { if (imm.m_value == -1) - m_assembler.mvns_r(dest, src); + m_assembler.mvns(dest, src); else - m_assembler.eors_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); + m_assembler.eors(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } void countLeadingZeros32(RegisterID src, RegisterID dest) { #if WTF_ARM_ARCH_AT_LEAST(5) - m_assembler.clz_r(dest, src); + m_assembler.clz(dest, src); #else UNUSED_PARAM(src); UNUSED_PARAM(dest); @@ -396,15 +396,15 @@ public: { ConvertibleLoadLabel result(this); ASSERT(address.offset >= 0 && address.offset <= 255); - m_assembler.dtr_u(ARMAssembler::LoadUint32, dest, address.base, address.offset); + m_assembler.dtrUp(ARMAssembler::LoadUint32, dest, address.base, address.offset); return result; } DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) { DataLabel32 dataLabel(this); - m_assembler.ldr_un_imm(ARMRegisters::S0, 0); - m_assembler.dtr_ur(ARMAssembler::LoadUint32, dest, address.base, ARMRegisters::S0); + m_assembler.ldrUniqueImmediate(ARMRegisters::S0, 0); + m_assembler.dtrUpRegister(ARMAssembler::LoadUint32, dest, address.base, ARMRegisters::S0); return dataLabel; } @@ -418,17 +418,17 @@ public: DataLabelCompact dataLabel(this); ASSERT(isCompactPtrAlignedAddressOffset(address.offset)); if (address.offset >= 0) - m_assembler.dtr_u(ARMAssembler::LoadUint32, dest, address.base, address.offset); + m_assembler.dtrUp(ARMAssembler::LoadUint32, dest, address.base, address.offset); else - m_assembler.dtr_d(ARMAssembler::LoadUint32, dest, address.base, address.offset); + m_assembler.dtrDown(ARMAssembler::LoadUint32, dest, address.base, address.offset); return dataLabel; } DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) { DataLabel32 dataLabel(this); - m_assembler.ldr_un_imm(ARMRegisters::S0, 0); - m_assembler.dtr_ur(ARMAssembler::StoreUint32, src, address.base, ARMRegisters::S0); + m_assembler.ldrUniqueImmediate(ARMRegisters::S0, 0); + m_assembler.dtrUpRegister(ARMAssembler::StoreUint32, src, address.base, ARMRegisters::S0); return dataLabel; } @@ -466,25 +466,25 @@ public: void store32(RegisterID src, void* address) { - m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address)); - m_assembler.dtr_u(ARMAssembler::StoreUint32, src, ARMRegisters::S0, 0); + m_assembler.ldrUniqueImmediate(ARMRegisters::S0, reinterpret_cast<ARMWord>(address)); + m_assembler.dtrUp(ARMAssembler::StoreUint32, src, ARMRegisters::S0, 0); } void store32(TrustedImm32 imm, void* address) { - m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address)); + m_assembler.ldrUniqueImmediate(ARMRegisters::S0, reinterpret_cast<ARMWord>(address)); m_assembler.moveImm(imm.m_value, ARMRegisters::S1); - m_assembler.dtr_u(ARMAssembler::StoreUint32, ARMRegisters::S1, ARMRegisters::S0, 0); + m_assembler.dtrUp(ARMAssembler::StoreUint32, ARMRegisters::S1, ARMRegisters::S0, 0); } void pop(RegisterID dest) { - m_assembler.pop_r(dest); + m_assembler.pop(dest); } void push(RegisterID src) { - m_assembler.push_r(src); + m_assembler.push(src); } void push(Address address) @@ -507,7 +507,7 @@ public: void move(RegisterID src, RegisterID dest) { if (src != dest) - m_assembler.mov_r(dest, src); + m_assembler.mov(dest, src); } void move(TrustedImmPtr imm, RegisterID dest) @@ -517,9 +517,9 @@ public: void swap(RegisterID reg1, RegisterID reg2) { - m_assembler.mov_r(ARMRegisters::S0, reg1); - m_assembler.mov_r(reg1, reg2); - m_assembler.mov_r(reg2, ARMRegisters::S0); + m_assembler.mov(ARMRegisters::S0, reg1); + m_assembler.mov(reg1, reg2); + m_assembler.mov(reg2, ARMRegisters::S0); } void signExtend32ToPtr(RegisterID src, RegisterID dest) @@ -549,7 +549,7 @@ public: Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right, int useConstantPool = 0) { - m_assembler.cmp_r(left, right); + m_assembler.cmp(left, right); return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool)); } @@ -557,9 +557,9 @@ public: { ARMWord tmp = (right.m_value == 0x80000000) ? ARMAssembler::InvalidImmediate : m_assembler.getOp2(-right.m_value); if (tmp != ARMAssembler::InvalidImmediate) - m_assembler.cmn_r(left, tmp); + m_assembler.cmn(left, tmp); else - m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0)); + m_assembler.cmp(left, m_assembler.getImm(right.m_value, ARMRegisters::S0)); return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool)); } @@ -609,7 +609,7 @@ public: Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask) { ASSERT((cond == Zero) || (cond == NonZero)); - m_assembler.tst_r(reg, mask); + m_assembler.tst(reg, mask); return Jump(m_assembler.jmp(ARMCondition(cond))); } @@ -618,9 +618,9 @@ public: ASSERT((cond == Zero) || (cond == NonZero)); ARMWord w = m_assembler.getImm(mask.m_value, ARMRegisters::S0, true); if (w & ARMAssembler::Op2InvertedImmediate) - m_assembler.bics_r(ARMRegisters::S0, reg, w & ~ARMAssembler::Op2InvertedImmediate); + m_assembler.bics(ARMRegisters::S0, reg, w & ~ARMAssembler::Op2InvertedImmediate); else - m_assembler.tst_r(reg, w); + m_assembler.tst(reg, w); return Jump(m_assembler.jmp(ARMCondition(cond))); } @@ -705,8 +705,8 @@ public: op2 = tmp; } } - m_assembler.mull_r(ARMRegisters::S1, dest, op1, op2); - m_assembler.cmp_r(ARMRegisters::S1, m_assembler.asr(dest, 31)); + m_assembler.mull(ARMRegisters::S1, dest, op1, op2); + m_assembler.cmp(ARMRegisters::S1, m_assembler.asr(dest, 31)); } Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest) @@ -763,7 +763,7 @@ public: Jump branchSub32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest) { ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - m_assembler.subs_r(dest, op1, op2); + m_assembler.subs(dest, op1, op2); return Jump(m_assembler.jmp(ARMCondition(cond))); } @@ -809,16 +809,16 @@ public: void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest) { - m_assembler.cmp_r(left, right); - m_assembler.mov_r(dest, ARMAssembler::getOp2Byte(0)); - m_assembler.mov_r(dest, ARMAssembler::getOp2Byte(1), ARMCondition(cond)); + m_assembler.cmp(left, right); + m_assembler.mov(dest, ARMAssembler::getOp2Byte(0)); + m_assembler.mov(dest, ARMAssembler::getOp2Byte(1), ARMCondition(cond)); } void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest) { - m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0)); - m_assembler.mov_r(dest, ARMAssembler::getOp2Byte(0)); - m_assembler.mov_r(dest, ARMAssembler::getOp2Byte(1), ARMCondition(cond)); + m_assembler.cmp(left, m_assembler.getImm(right.m_value, ARMRegisters::S0)); + m_assembler.mov(dest, ARMAssembler::getOp2Byte(0)); + m_assembler.mov(dest, ARMAssembler::getOp2Byte(1), ARMCondition(cond)); } void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest) @@ -830,11 +830,11 @@ public: void test32(ResultCondition cond, RegisterID reg, TrustedImm32 mask, RegisterID dest) { if (mask.m_value == -1) - m_assembler.cmp_r(0, reg); + m_assembler.cmp(0, reg); else - m_assembler.tst_r(reg, m_assembler.getImm(mask.m_value, ARMRegisters::S0)); - m_assembler.mov_r(dest, ARMAssembler::getOp2Byte(0)); - m_assembler.mov_r(dest, ARMAssembler::getOp2Byte(1), ARMCondition(cond)); + m_assembler.tst(reg, m_assembler.getImm(mask.m_value, ARMRegisters::S0)); + m_assembler.mov(dest, ARMAssembler::getOp2Byte(0)); + m_assembler.mov(dest, ARMAssembler::getOp2Byte(1), ARMCondition(cond)); } void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest) @@ -851,31 +851,31 @@ public: void add32(TrustedImm32 imm, RegisterID src, RegisterID dest) { - m_assembler.add_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); + m_assembler.add(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } void add32(TrustedImm32 imm, AbsoluteAddress address) { - m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast<ARMWord>(address.m_ptr)); - m_assembler.dtr_u(ARMAssembler::LoadUint32, ARMRegisters::S1, ARMRegisters::S1, 0); + m_assembler.ldrUniqueImmediate(ARMRegisters::S1, reinterpret_cast<ARMWord>(address.m_ptr)); + m_assembler.dtrUp(ARMAssembler::LoadUint32, ARMRegisters::S1, ARMRegisters::S1, 0); add32(imm, ARMRegisters::S1); - m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address.m_ptr)); - m_assembler.dtr_u(ARMAssembler::StoreUint32, ARMRegisters::S1, ARMRegisters::S0, 0); + m_assembler.ldrUniqueImmediate(ARMRegisters::S0, reinterpret_cast<ARMWord>(address.m_ptr)); + m_assembler.dtrUp(ARMAssembler::StoreUint32, ARMRegisters::S1, ARMRegisters::S0, 0); } void sub32(TrustedImm32 imm, AbsoluteAddress address) { - m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast<ARMWord>(address.m_ptr)); - m_assembler.dtr_u(ARMAssembler::LoadUint32, ARMRegisters::S1, ARMRegisters::S1, 0); + m_assembler.ldrUniqueImmediate(ARMRegisters::S1, reinterpret_cast<ARMWord>(address.m_ptr)); + m_assembler.dtrUp(ARMAssembler::LoadUint32, ARMRegisters::S1, ARMRegisters::S1, 0); sub32(imm, ARMRegisters::S1); - m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address.m_ptr)); - m_assembler.dtr_u(ARMAssembler::StoreUint32, ARMRegisters::S1, ARMRegisters::S0, 0); + m_assembler.ldrUniqueImmediate(ARMRegisters::S0, reinterpret_cast<ARMWord>(address.m_ptr)); + m_assembler.dtrUp(ARMAssembler::StoreUint32, ARMRegisters::S1, ARMRegisters::S0, 0); } void load32(const void* address, RegisterID dest) { - m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address)); - m_assembler.dtr_u(ARMAssembler::LoadUint32, dest, ARMRegisters::S0, 0); + m_assembler.ldrUniqueImmediate(ARMRegisters::S0, reinterpret_cast<ARMWord>(address)); + m_assembler.dtrUp(ARMAssembler::LoadUint32, dest, ARMRegisters::S0, 0); } Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right) @@ -893,10 +893,10 @@ public: void relativeTableJump(RegisterID index, int scale) { ASSERT(scale >= 0 && scale <= 31); - m_assembler.add_r(ARMRegisters::pc, ARMRegisters::pc, m_assembler.lsl(index, scale)); + m_assembler.add(ARMRegisters::pc, ARMRegisters::pc, m_assembler.lsl(index, scale)); // NOP the default prefetching - m_assembler.mov_r(ARMRegisters::r0, ARMRegisters::r0); + m_assembler.mov(ARMRegisters::r0, ARMRegisters::r0); } Call call() @@ -919,7 +919,7 @@ public: DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest) { DataLabelPtr dataLabel(this); - m_assembler.ldr_un_imm(dest, reinterpret_cast<ARMWord>(initialValue.m_value)); + m_assembler.ldrUniqueImmediate(dest, reinterpret_cast<ARMWord>(initialValue.m_value)); return dataLabel; } @@ -985,7 +985,7 @@ public: void loadDouble(const void* address, FPRegisterID dest) { move(TrustedImm32(reinterpret_cast<ARMWord>(address)), ARMRegisters::S0); - m_assembler.fdtr_u(ARMAssembler::LoadDouble, dest, ARMRegisters::S0, 0); + m_assembler.doubleDtrUp(ARMAssembler::LoadDouble, dest, ARMRegisters::S0, 0); } void storeFloat(FPRegisterID src, BaseIndex address) @@ -1012,17 +1012,17 @@ public: void moveDouble(FPRegisterID src, FPRegisterID dest) { if (src != dest) - m_assembler.vmov_f64_r(dest, src); + m_assembler.vmov_f64(dest, src); } void addDouble(FPRegisterID src, FPRegisterID dest) { - m_assembler.vadd_f64_r(dest, dest, src); + m_assembler.vadd_f64(dest, dest, src); } void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest) { - m_assembler.vadd_f64_r(dest, op1, op2); + m_assembler.vadd_f64(dest, op1, op2); } void addDouble(Address src, FPRegisterID dest) @@ -1039,12 +1039,12 @@ public: void divDouble(FPRegisterID src, FPRegisterID dest) { - m_assembler.vdiv_f64_r(dest, dest, src); + m_assembler.vdiv_f64(dest, dest, src); } void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest) { - m_assembler.vdiv_f64_r(dest, op1, op2); + m_assembler.vdiv_f64(dest, op1, op2); } void divDouble(Address src, FPRegisterID dest) @@ -1056,12 +1056,12 @@ public: void subDouble(FPRegisterID src, FPRegisterID dest) { - m_assembler.vsub_f64_r(dest, dest, src); + m_assembler.vsub_f64(dest, dest, src); } void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest) { - m_assembler.vsub_f64_r(dest, op1, op2); + m_assembler.vsub_f64(dest, op1, op2); } void subDouble(Address src, FPRegisterID dest) @@ -1072,7 +1072,7 @@ public: void mulDouble(FPRegisterID src, FPRegisterID dest) { - m_assembler.vmul_f64_r(dest, dest, src); + m_assembler.vmul_f64(dest, dest, src); } void mulDouble(Address src, FPRegisterID dest) @@ -1083,28 +1083,28 @@ public: void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest) { - m_assembler.vmul_f64_r(dest, op1, op2); + m_assembler.vmul_f64(dest, op1, op2); } void sqrtDouble(FPRegisterID src, FPRegisterID dest) { - m_assembler.vsqrt_f64_r(dest, src); + m_assembler.vsqrt_f64(dest, src); } void absDouble(FPRegisterID src, FPRegisterID dest) { - m_assembler.vabs_f64_r(dest, src); + m_assembler.vabs_f64(dest, src); } void negateDouble(FPRegisterID src, FPRegisterID dest) { - m_assembler.vneg_f64_r(dest, src); + m_assembler.vneg_f64(dest, src); } void convertInt32ToDouble(RegisterID src, FPRegisterID dest) { - m_assembler.vmov_vfp32_r(dest << 1, src); - m_assembler.vcvt_f64_s32_r(dest, dest << 1); + m_assembler.vmov_vfp32(dest << 1, src); + m_assembler.vcvt_f64_s32(dest, dest << 1); } void convertInt32ToDouble(Address src, FPRegisterID dest) @@ -1122,20 +1122,20 @@ public: void convertFloatToDouble(FPRegisterID src, FPRegisterID dst) { - m_assembler.vcvt_f64_f32_r(dst, src); + m_assembler.vcvt_f64_f32(dst, src); } void convertDoubleToFloat(FPRegisterID src, FPRegisterID dst) { - m_assembler.vcvt_f32_f64_r(dst, src); + m_assembler.vcvt_f32_f64(dst, src); } Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) { - m_assembler.vcmp_f64_r(left, right); + m_assembler.vcmp_f64(left, right); m_assembler.vmrs_apsr(); if (cond & DoubleConditionBitSpecial) - m_assembler.cmp_r(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::VS); + m_assembler.cmp(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::VS); return Jump(m_assembler.jmp(static_cast<ARMAssembler::Condition>(cond & ~DoubleConditionMask))); } @@ -1148,12 +1148,12 @@ public: { truncateDoubleToInt32(src, dest); - m_assembler.add_r(ARMRegisters::S0, dest, ARMAssembler::getOp2Byte(1)); - m_assembler.bic_r(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Byte(1)); + m_assembler.add(ARMRegisters::S0, dest, ARMAssembler::getOp2Byte(1)); + m_assembler.bic(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Byte(1)); ARMWord w = ARMAssembler::getOp2(0x80000000); ASSERT(w != ARMAssembler::InvalidImmediate); - m_assembler.cmp_r(ARMRegisters::S0, w); + m_assembler.cmp(ARMRegisters::S0, w); return Jump(m_assembler.jmp(branchType == BranchIfTruncateFailed ? ARMAssembler::EQ : ARMAssembler::NE)); } @@ -1161,24 +1161,24 @@ public: { truncateDoubleToUint32(src, dest); - m_assembler.add_r(ARMRegisters::S0, dest, ARMAssembler::getOp2Byte(1)); - m_assembler.bic_r(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Byte(1)); + m_assembler.add(ARMRegisters::S0, dest, ARMAssembler::getOp2Byte(1)); + m_assembler.bic(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Byte(1)); - m_assembler.cmp_r(ARMRegisters::S0, ARMAssembler::getOp2Byte(0)); + m_assembler.cmp(ARMRegisters::S0, ARMAssembler::getOp2Byte(0)); return Jump(m_assembler.jmp(branchType == BranchIfTruncateFailed ? ARMAssembler::EQ : ARMAssembler::NE)); } // Result is undefined if the value is outside of the integer range. void truncateDoubleToInt32(FPRegisterID src, RegisterID dest) { - m_assembler.vcvt_s32_f64_r(ARMRegisters::SD0 << 1, src); - m_assembler.vmov_arm32_r(dest, ARMRegisters::SD0 << 1); + m_assembler.vcvt_s32_f64(ARMRegisters::SD0 << 1, src); + m_assembler.vmov_arm32(dest, ARMRegisters::SD0 << 1); } void truncateDoubleToUint32(FPRegisterID src, RegisterID dest) { - m_assembler.vcvt_u32_f64_r(ARMRegisters::SD0 << 1, src); - m_assembler.vmov_arm32_r(dest, ARMRegisters::SD0 << 1); + m_assembler.vcvt_u32_f64(ARMRegisters::SD0 << 1, src); + m_assembler.vmov_arm32(dest, ARMRegisters::SD0 << 1); } // Convert 'src' to an integer, and places the resulting 'dest'. @@ -1187,11 +1187,11 @@ public: // (specifically, in this case, 0). void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp) { - m_assembler.vcvt_s32_f64_r(ARMRegisters::SD0 << 1, src); - m_assembler.vmov_arm32_r(dest, ARMRegisters::SD0 << 1); + m_assembler.vcvt_s32_f64(ARMRegisters::SD0 << 1, src); + m_assembler.vmov_arm32(dest, ARMRegisters::SD0 << 1); // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump. - m_assembler.vcvt_f64_s32_r(ARMRegisters::SD0, ARMRegisters::SD0 << 1); + m_assembler.vcvt_f64_s32(ARMRegisters::SD0, ARMRegisters::SD0 << 1); failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, ARMRegisters::SD0)); // If the result is zero, it might have been -0.0, and 0.0 equals to -0.0 @@ -1200,14 +1200,14 @@ public: Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch) { - m_assembler.mov_r(ARMRegisters::S0, ARMAssembler::getOp2Byte(0)); + m_assembler.mov(ARMRegisters::S0, ARMAssembler::getOp2Byte(0)); convertInt32ToDouble(ARMRegisters::S0, scratch); return branchDouble(DoubleNotEqual, reg, scratch); } Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch) { - m_assembler.mov_r(ARMRegisters::S0, ARMAssembler::getOp2Byte(0)); + m_assembler.mov(ARMRegisters::S0, ARMAssembler::getOp2Byte(0)); convertInt32ToDouble(ARMRegisters::S0, scratch); return branchDouble(DoubleEqualOrUnordered, reg, scratch); } diff --git a/Source/JavaScriptCore/bytecode/ArrayProfile.cpp b/Source/JavaScriptCore/bytecode/ArrayProfile.cpp new file mode 100644 index 000000000..6b97f7806 --- /dev/null +++ b/Source/JavaScriptCore/bytecode/ArrayProfile.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ArrayProfile.h" + +namespace JSC { + +void ArrayProfile::computeUpdatedPrediction(OperationInProgress operation) +{ + if (m_lastSeenStructure) { + m_observedArrayModes |= arrayModeFromStructure(m_lastSeenStructure); + if (!m_structureIsPolymorphic) { + if (!m_expectedStructure) + m_expectedStructure = m_lastSeenStructure; + else if (m_expectedStructure != m_lastSeenStructure) { + m_expectedStructure = 0; + m_structureIsPolymorphic = true; + } + } + m_lastSeenStructure = 0; + } + + if (operation == Collection + && m_expectedStructure + && !Heap::isMarked(m_expectedStructure)) { + m_expectedStructure = 0; + m_structureIsPolymorphic = true; + } +} + +} // namespace JSC + diff --git a/Source/JavaScriptCore/bytecode/ArrayProfile.h b/Source/JavaScriptCore/bytecode/ArrayProfile.h new file mode 100644 index 000000000..5a656e2dd --- /dev/null +++ b/Source/JavaScriptCore/bytecode/ArrayProfile.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ArrayProfile_h +#define ArrayProfile_h + +#include "JSArray.h" +#include "Structure.h" +#include <wtf/HashMap.h> +#include <wtf/SegmentedVector.h> + +namespace JSC { + +class LLIntOffsetsExtractor; + +typedef unsigned ArrayModes; + +static const unsigned IsNotArray = 1; +static const unsigned IsJSArray = 2; + +inline ArrayModes arrayModeFromStructure(Structure* structure) +{ + if (structure->classInfo() == &JSArray::s_info) + return IsJSArray; + return IsNotArray; +} + +class ArrayProfile { +public: + ArrayProfile() + : m_bytecodeOffset(std::numeric_limits<unsigned>::max()) + , m_lastSeenStructure(0) + , m_expectedStructure(0) + , m_structureIsPolymorphic(false) + , m_observedArrayModes(0) + { + } + + ArrayProfile(unsigned bytecodeOffset) + : m_bytecodeOffset(bytecodeOffset) + , m_lastSeenStructure(0) + , m_expectedStructure(0) + , m_structureIsPolymorphic(false) + , m_observedArrayModes(0) + { + } + + unsigned bytecodeOffset() const { return m_bytecodeOffset; } + + Structure** addressOfLastSeenStructure() { return &m_lastSeenStructure; } + + void observeStructure(Structure* structure) + { + m_lastSeenStructure = structure; + } + + void computeUpdatedPrediction(OperationInProgress operation = NoOperation); + + Structure* expectedStructure() const { return m_expectedStructure; } + bool structureIsPolymorphic() const { return m_structureIsPolymorphic; } + bool hasDefiniteStructure() const + { + return !structureIsPolymorphic() && m_expectedStructure; + } + ArrayModes observedArrayModes() const { return m_observedArrayModes; } + +private: + friend class LLIntOffsetsExtractor; + + unsigned m_bytecodeOffset; + Structure* m_lastSeenStructure; + Structure* m_expectedStructure; + bool m_structureIsPolymorphic; + ArrayModes m_observedArrayModes; +}; + +typedef SegmentedVector<ArrayProfile, 4, 0> ArrayProfileVector; + +} // namespace JSC + +#endif // ArrayProfile_h + diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp index 0e2a98bc5..2ea969fcf 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp @@ -1155,6 +1155,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& dataLog("[%4d] get_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); dumpBytecodeCommentAndNewLine(location); it++; + it++; break; } case op_get_argument_by_val: { @@ -1164,6 +1165,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& dataLog("[%4d] get_argument_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); dumpBytecodeCommentAndNewLine(location); ++it; + ++it; break; } case op_get_by_pname: { @@ -1183,6 +1185,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r2 = (++it)->u.operand; dataLog("[%4d] put_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); dumpBytecodeCommentAndNewLine(location); + ++it; break; } case op_del_by_val: { @@ -2577,6 +2580,60 @@ void CodeBlock::unlinkIncomingCalls() m_incomingCalls.begin()->unlink(*m_globalData, repatchBuffer); } +#if ENABLE(LLINT) +Instruction* CodeBlock::adjustPCIfAtCallSite(Instruction* potentialReturnPC) +{ + ASSERT(potentialReturnPC); + + unsigned returnPCOffset = potentialReturnPC - instructions().begin(); + Instruction* adjustedPC; + unsigned opcodeLength; + + // If we are at a callsite, the LLInt stores the PC after the call + // instruction rather than the PC of the call instruction. This requires + // some correcting. If so, we can rely on the fact that the preceding + // instruction must be one of the call instructions, so either it's a + // call_varargs or it's a call, construct, or eval. + // + // If we are not at a call site, then we need to guard against the + // possibility of peeking past the start of the bytecode range for this + // codeBlock. Hence, we do a bounds check before we peek at the + // potential "preceding" instruction. + // The bounds check is done by comparing the offset of the potential + // returnPC with the length of the opcode. If there is room for a call + // instruction before the returnPC, then the offset of the returnPC must + // be greater than the size of the call opcode we're looking for. + + // The determination of the call instruction present (if we are at a + // callsite) depends on the following assumptions. So, assert that + // they are still true: + ASSERT(OPCODE_LENGTH(op_call_varargs) <= OPCODE_LENGTH(op_call)); + ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct)); + ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval)); + + // Check for the case of a preceeding op_call_varargs: + opcodeLength = OPCODE_LENGTH(op_call_varargs); + adjustedPC = potentialReturnPC - opcodeLength; + if ((returnPCOffset >= opcodeLength) + && (adjustedPC->u.pointer == bitwise_cast<void*>(llint_op_call_varargs))) { + return adjustedPC; + } + + // Check for the case of the other 3 call instructions: + opcodeLength = OPCODE_LENGTH(op_call); + adjustedPC = potentialReturnPC - opcodeLength; + if ((returnPCOffset >= opcodeLength) + && (adjustedPC->u.pointer == bitwise_cast<void*>(llint_op_call) + || adjustedPC->u.pointer == bitwise_cast<void*>(llint_op_construct) + || adjustedPC->u.pointer == bitwise_cast<void*>(llint_op_call_eval))) { + return adjustedPC; + } + + // Not a call site. No need to adjust PC. Just return the original. + return potentialReturnPC; +} +#endif + unsigned CodeBlock::bytecodeOffset(ExecState* exec, ReturnAddressPtr returnAddress) { #if ENABLE(LLINT) @@ -2587,28 +2644,8 @@ unsigned CodeBlock::bytecodeOffset(ExecState* exec, ReturnAddressPtr returnAddre ASSERT(JITCode::isBaselineCode(getJITType())); Instruction* instruction = exec->currentVPC(); ASSERT(instruction); - - // The LLInt stores the PC after the call instruction rather than the PC of - // the call instruction. This requires some correcting. We rely on the fact - // that the preceding instruction must be one of the call instructions, so - // either it's a call_varargs or it's a call, construct, or eval. - ASSERT(OPCODE_LENGTH(op_call_varargs) <= OPCODE_LENGTH(op_call)); - ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct)); - ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval)); - if (instruction[-OPCODE_LENGTH(op_call_varargs)].u.pointer == bitwise_cast<void*>(llint_op_call_varargs)) { - // We know that the preceding instruction must be op_call_varargs because there is no way that - // the pointer to the call_varargs could be an operand to the call. - instruction -= OPCODE_LENGTH(op_call_varargs); - ASSERT(instruction[-OPCODE_LENGTH(op_call)].u.pointer != bitwise_cast<void*>(llint_op_call) - && instruction[-OPCODE_LENGTH(op_call)].u.pointer != bitwise_cast<void*>(llint_op_construct) - && instruction[-OPCODE_LENGTH(op_call)].u.pointer != bitwise_cast<void*>(llint_op_call_eval)); - } else { - // Must be that the last instruction was some op_call. - ASSERT(instruction[-OPCODE_LENGTH(op_call)].u.pointer == bitwise_cast<void*>(llint_op_call) - || instruction[-OPCODE_LENGTH(op_call)].u.pointer == bitwise_cast<void*>(llint_op_construct) - || instruction[-OPCODE_LENGTH(op_call)].u.pointer == bitwise_cast<void*>(llint_op_call_eval)); - instruction -= OPCODE_LENGTH(op_call); - } + + instruction = adjustPCIfAtCallSite(instruction); return bytecodeOffset(instruction); } @@ -2684,27 +2721,27 @@ CodeBlock* FunctionCodeBlock::replacement() return &static_cast<FunctionExecutable*>(ownerExecutable())->generatedBytecodeFor(m_isConstructor ? CodeForConstruct : CodeForCall); } -JSObject* ProgramCodeBlock::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode) +JSObject* ProgramCodeBlock::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode, unsigned bytecodeIndex) { if (replacement()->getJITType() == JITCode::nextTierJIT(getJITType())) return 0; - JSObject* error = static_cast<ProgramExecutable*>(ownerExecutable())->compileOptimized(exec, scopeChainNode); + JSObject* error = static_cast<ProgramExecutable*>(ownerExecutable())->compileOptimized(exec, scopeChainNode, bytecodeIndex); return error; } -JSObject* EvalCodeBlock::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode) +JSObject* EvalCodeBlock::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode, unsigned bytecodeIndex) { if (replacement()->getJITType() == JITCode::nextTierJIT(getJITType())) return 0; - JSObject* error = static_cast<EvalExecutable*>(ownerExecutable())->compileOptimized(exec, scopeChainNode); + JSObject* error = static_cast<EvalExecutable*>(ownerExecutable())->compileOptimized(exec, scopeChainNode, bytecodeIndex); return error; } -JSObject* FunctionCodeBlock::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode) +JSObject* FunctionCodeBlock::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode, unsigned bytecodeIndex) { if (replacement()->getJITType() == JITCode::nextTierJIT(getJITType())) return 0; - JSObject* error = static_cast<FunctionExecutable*>(ownerExecutable())->compileOptimizedFor(exec, scopeChainNode, m_isConstructor ? CodeForConstruct : CodeForCall); + JSObject* error = static_cast<FunctionExecutable*>(ownerExecutable())->compileOptimizedFor(exec, scopeChainNode, bytecodeIndex, m_isConstructor ? CodeForConstruct : CodeForCall); return error; } @@ -2769,6 +2806,23 @@ bool FunctionCodeBlock::jitCompileImpl(ExecState* exec) #endif #if ENABLE(VALUE_PROFILER) +ArrayProfile* CodeBlock::getArrayProfile(unsigned bytecodeOffset) +{ + for (unsigned i = 0; i < m_arrayProfiles.size(); ++i) { + if (m_arrayProfiles[i].bytecodeOffset() == bytecodeOffset) + return &m_arrayProfiles[i]; + } + return 0; +} + +ArrayProfile* CodeBlock::getOrAddArrayProfile(unsigned bytecodeOffset) +{ + ArrayProfile* result = getArrayProfile(bytecodeOffset); + if (result) + return result; + return addArrayProfile(bytecodeOffset); +} + void CodeBlock::updateAllPredictionsAndCountLiveness( OperationInProgress operation, unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles) { @@ -2792,6 +2846,12 @@ void CodeBlock::updateAllPredictionsAndCountLiveness( #if ENABLE(DFG_JIT) m_lazyOperandValueProfiles.computeUpdatedPredictions(operation); #endif + + // Don't count the array profiles towards statistics, since each array profile + // site also has a value profile site - so we already know whether or not it's + // live. + for (unsigned i = m_arrayProfiles.size(); i--;) + m_arrayProfiles[i].computeUpdatedPrediction(operation); } void CodeBlock::updateAllPredictions(OperationInProgress operation) diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h index 2a7d2120a..a8b2a5871 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.h +++ b/Source/JavaScriptCore/bytecode/CodeBlock.h @@ -30,6 +30,7 @@ #ifndef CodeBlock_h #define CodeBlock_h +#include "ArrayProfile.h" #include "BytecodeConventions.h" #include "CallLinkInfo.h" #include "CallReturnOffsetToBytecodeOffset.h" @@ -229,6 +230,9 @@ namespace JSC { return *(binarySearch<MethodCallLinkInfo, unsigned, getMethodCallLinkInfoBytecodeIndex>(m_methodCallLinkInfos.begin(), m_methodCallLinkInfos.size(), bytecodeIndex)); } +#if ENABLE(LLINT) + Instruction* adjustPCIfAtCallSite(Instruction*); +#endif unsigned bytecodeOffset(ExecState*, ReturnAddressPtr); unsigned bytecodeOffsetForCallAtIndex(unsigned index) @@ -441,7 +445,7 @@ namespace JSC { MacroAssemblerCodePtr getJITCodeWithArityCheck() { return m_jitCodeWithArityCheck; } JITCode::JITType getJITType() { return m_jitCode.jitType(); } ExecutableMemoryHandle* executableMemory() { return getJITCode().getExecutableMemory(); } - virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*) = 0; + virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*, unsigned bytecodeIndex) = 0; virtual void jettison() = 0; enum JITCompilationResult { AlreadyCompiled, CouldNotCompile, CompiledSuccessfully }; JITCompilationResult jitCompile(ExecState* exec) @@ -751,8 +755,18 @@ namespace JSC { } unsigned executionEntryCount() const { return m_executionEntryCount; } -#endif + unsigned numberOfArrayProfiles() const { return m_arrayProfiles.size(); } + const ArrayProfileVector& arrayProfiles() { return m_arrayProfiles; } + ArrayProfile* addArrayProfile(unsigned bytecodeOffset) + { + m_arrayProfiles.append(ArrayProfile(bytecodeOffset)); + return &m_arrayProfiles.last(); + } + ArrayProfile* getArrayProfile(unsigned bytecodeOffset); + ArrayProfile* getOrAddArrayProfile(unsigned bytecodeOffset); +#endif + unsigned globalResolveInfoCount() const { #if ENABLE(JIT) @@ -1333,6 +1347,7 @@ namespace JSC { SegmentedVector<ValueProfile, 8> m_valueProfiles; SegmentedVector<RareCaseProfile, 8> m_rareCaseProfiles; SegmentedVector<RareCaseProfile, 8> m_specialFastCaseProfiles; + ArrayProfileVector m_arrayProfiles; unsigned m_executionEntryCount; #endif @@ -1436,7 +1451,7 @@ namespace JSC { #if ENABLE(JIT) protected: - virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*); + virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*, unsigned bytecodeIndex); virtual void jettison(); virtual bool jitCompileImpl(ExecState*); virtual CodeBlock* replacement(); @@ -1471,7 +1486,7 @@ namespace JSC { #if ENABLE(JIT) protected: - virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*); + virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*, unsigned bytecodeIndex); virtual void jettison(); virtual bool jitCompileImpl(ExecState*); virtual CodeBlock* replacement(); @@ -1509,7 +1524,7 @@ namespace JSC { #if ENABLE(JIT) protected: - virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*); + virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*, unsigned bytecodeIndex); virtual void jettison(); virtual bool jitCompileImpl(ExecState*); virtual CodeBlock* replacement(); diff --git a/Source/JavaScriptCore/bytecode/Instruction.h b/Source/JavaScriptCore/bytecode/Instruction.h index 2e94b452c..6c1260abc 100644 --- a/Source/JavaScriptCore/bytecode/Instruction.h +++ b/Source/JavaScriptCore/bytecode/Instruction.h @@ -46,6 +46,7 @@ namespace JSC { // curently actually use PolymorphicAccessStructureLists, which we should). Anyway, this seems like the best // solution for now - will need to something smarter if/when we actually want mixed-mode operation. + class ArrayProfile; class JSCell; class Structure; class StructureChain; @@ -190,6 +191,7 @@ namespace JSC { Instruction(LLIntCallLinkInfo* callLinkInfo) { u.callLinkInfo = callLinkInfo; } Instruction(ValueProfile* profile) { u.profile = profile; } + Instruction(ArrayProfile* profile) { u.arrayProfile = profile; } Instruction(WriteBarrier<Unknown>* registerPointer) { u.registerPointer = registerPointer; } @@ -205,6 +207,7 @@ namespace JSC { PropertySlot::GetValueFunc getterFunc; LLIntCallLinkInfo* callLinkInfo; ValueProfile* profile; + ArrayProfile* arrayProfile; void* pointer; bool* predicatePointer; } u; diff --git a/Source/JavaScriptCore/bytecode/Opcode.h b/Source/JavaScriptCore/bytecode/Opcode.h index 4308e79df..777b4876f 100644 --- a/Source/JavaScriptCore/bytecode/Opcode.h +++ b/Source/JavaScriptCore/bytecode/Opcode.h @@ -132,10 +132,10 @@ namespace JSC { macro(op_put_by_id_replace, 9) \ macro(op_put_by_id_generic, 9) \ macro(op_del_by_id, 4) \ - macro(op_get_by_val, 5) /* has value profiling */ \ - macro(op_get_argument_by_val, 5) /* must be the same size as op_get_by_val */ \ + macro(op_get_by_val, 6) /* has value profiling */ \ + macro(op_get_argument_by_val, 6) /* must be the same size as op_get_by_val */ \ macro(op_get_by_pname, 7) \ - macro(op_put_by_val, 4) \ + macro(op_put_by_val, 5) \ macro(op_del_by_val, 4) \ macro(op_put_by_index, 4) \ macro(op_put_getter_setter, 5) \ diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp index 14a69b530..c8cfa74b6 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp @@ -708,6 +708,15 @@ void BytecodeGenerator::prependComment(const char* string) } #endif +ArrayProfile* BytecodeGenerator::newArrayProfile() +{ +#if ENABLE(VALUE_PROFILER) + return m_codeBlock->addArrayProfile(instructions().size()); +#else + return 0; +#endif +} + ValueProfile* BytecodeGenerator::emitProfiledOpcode(OpcodeID opcodeID) { #if ENABLE(VALUE_PROFILER) @@ -1455,9 +1464,7 @@ RegisterID* BytecodeGenerator::emitResolveWithBase(RegisterID* baseDst, Register #if ENABLE(JIT) m_codeBlock->addGlobalResolveInfo(instructions().size()); #endif -#if ENABLE(CLASSIC_INTERPRETER) m_codeBlock->addGlobalResolveInstruction(instructions().size()); -#endif ValueProfile* profile = emitProfiledOpcode(op_resolve_global); instructions().append(propDst->index()); instructions().append(addConstant(property)); @@ -1669,11 +1676,13 @@ RegisterID* BytecodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base, RegisterID* BytecodeGenerator::emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property) { + ArrayProfile* arrayProfile = newArrayProfile(); ValueProfile* profile = emitProfiledOpcode(op_get_argument_by_val); instructions().append(dst->index()); ASSERT(base->index() == m_codeBlock->argumentsRegister()); instructions().append(base->index()); instructions().append(property->index()); + instructions().append(arrayProfile); instructions().append(profile); return dst; } @@ -1693,20 +1702,24 @@ RegisterID* BytecodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, R return dst; } } + ArrayProfile* arrayProfile = newArrayProfile(); ValueProfile* profile = emitProfiledOpcode(op_get_by_val); instructions().append(dst->index()); instructions().append(base->index()); instructions().append(property->index()); + instructions().append(arrayProfile); instructions().append(profile); return dst; } RegisterID* BytecodeGenerator::emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value) { + ArrayProfile* arrayProfile = newArrayProfile(); emitOpcode(op_put_by_val); instructions().append(base->index()); instructions().append(property->index()); instructions().append(value->index()); + instructions().append(arrayProfile); return value; } diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h index 490991fa7..9c094414d 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h @@ -555,6 +555,7 @@ namespace JSC { #endif void emitOpcode(OpcodeID); + ArrayProfile* newArrayProfile(); ValueProfile* emitProfiledOpcode(OpcodeID); void retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index); void retrieveLastUnaryOp(int& dstIndex, int& srcIndex); diff --git a/Source/JavaScriptCore/config.h b/Source/JavaScriptCore/config.h index 1e49c96bf..7f7eda0f1 100644 --- a/Source/JavaScriptCore/config.h +++ b/Source/JavaScriptCore/config.h @@ -69,12 +69,7 @@ #include <wtf/FastMalloc.h> #endif -// this breaks compilation of <QFontDatabase>, at least, so turn it off for now -// Also generates errors on wx on Windows and QNX, because these functions -// are used from wx and QNX headers. -#if !PLATFORM(QT) && !PLATFORM(WX) && !OS(QNX) #include <wtf/DisallowCType.h> -#endif #if COMPILER(MSVC) #define SKIP_STATIC_CONSTRUCTORS_ON_MSVC 1 diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp index 4f02ee793..5c53f6d78 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp +++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp @@ -62,13 +62,13 @@ void AbstractState::beginBasicBlock(BasicBlock* basicBlock) m_variables = basicBlock->valuesAtHead; m_haveStructures = false; for (size_t i = 0; i < m_variables.numberOfArguments(); ++i) { - if (m_variables.argument(i).m_structure.isNeitherClearNorTop()) { + if (m_variables.argument(i).m_currentKnownStructure.isNeitherClearNorTop()) { m_haveStructures = true; break; } } for (size_t i = 0; i < m_variables.numberOfLocals(); ++i) { - if (m_variables.local(i).m_structure.isNeitherClearNorTop()) { + if (m_variables.local(i).m_currentKnownStructure.isNeitherClearNorTop()) { m_haveStructures = true; break; } @@ -106,8 +106,6 @@ void AbstractState::initialize(Graph& graph) SpeculatedType prediction = node.variableAccessData()->prediction(); if (isInt32Speculation(prediction)) root->valuesAtHead.argument(i).set(SpecInt32); - else if (isArraySpeculation(prediction)) - root->valuesAtHead.argument(i).set(SpecArray); else if (isBooleanSpeculation(prediction)) root->valuesAtHead.argument(i).set(SpecBoolean); else if (isInt8ArraySpeculation(prediction)) @@ -160,6 +158,16 @@ void AbstractState::initialize(Graph& graph) block->valuesAtHead.local(i).clear(); block->valuesAtTail.local(i).clear(); } + if (!block->isOSRTarget) + continue; + if (block->bytecodeBegin != graph.m_osrEntryBytecodeIndex) + continue; + for (size_t i = 0; i < graph.m_mustHandleValues.size(); ++i) { + AbstractValue value; + value.setMostSpecific(graph.m_mustHandleValues[i]); + block->valuesAtHead.operand(graph.m_mustHandleValues.operandForIndex(i)).merge(value); + } + block->cfaShouldRevisit = true; } } @@ -290,10 +298,7 @@ bool AbstractState::execute(unsigned indexInBlock) SpeculatedType predictedType = node.variableAccessData()->argumentAwarePrediction(); if (isInt32Speculation(predictedType)) speculateInt32Unary(node); - else if (isArraySpeculation(predictedType)) { - node.setCanExit(!isArraySpeculation(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(SpecArray); - } else if (isCellSpeculation(predictedType)) { + else if (isCellSpeculation(predictedType)) { node.setCanExit(!isCellSpeculation(forNode(node.child1()).m_type)); forNode(node.child1()).filter(SpecCell); } else if (isBooleanSpeculation(predictedType)) @@ -867,7 +872,7 @@ bool AbstractState::execute(unsigned indexInBlock) m_isValid = false; break; } - if (!isActionableArraySpeculation(m_graph[node.child1()].prediction()) || !m_graph[node.child2()].shouldSpeculateInteger()) { + if (!m_graph[node.child2()].shouldSpeculateInteger() || (!node.child3() && !m_graph[node.child1()].shouldSpeculateArguments())) { clobberWorld(node.codeOrigin, indexInBlock); forNode(nodeIndex).makeTop(); break; @@ -942,8 +947,7 @@ bool AbstractState::execute(unsigned indexInBlock) forNode(nodeIndex).set(SpecDouble); break; } - ASSERT(m_graph[node.child1()].shouldSpeculateArray()); - forNode(node.child1()).filter(SpecArray); + forNode(node.child1()).filter(SpecCell); forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).makeTop(); break; @@ -962,7 +966,7 @@ bool AbstractState::execute(unsigned indexInBlock) m_isValid = false; break; } - if (!m_graph[child2].shouldSpeculateInteger() || !isActionableMutableArraySpeculation(m_graph[child1].prediction()) + if (!m_graph[child2].shouldSpeculateInteger() #if USE(JSVALUE32_64) || m_graph[child1].shouldSpeculateArguments() #endif @@ -1053,8 +1057,7 @@ bool AbstractState::execute(unsigned indexInBlock) forNode(child3).filter(SpecNumber); break; } - ASSERT(m_graph[child1].shouldSpeculateArray()); - forNode(child1).filter(SpecArray); + forNode(child1).filter(SpecCell); forNode(child2).filter(SpecInt32); if (node.op() == PutByValSafe) clobberWorld(node.codeOrigin, indexInBlock); @@ -1063,13 +1066,13 @@ bool AbstractState::execute(unsigned indexInBlock) case ArrayPush: node.setCanExit(true); - forNode(node.child1()).filter(SpecArray); + forNode(node.child1()).filter(SpecCell); forNode(nodeIndex).set(SpecNumber); break; case ArrayPop: node.setCanExit(true); - forNode(node.child1()).filter(SpecArray); + forNode(node.child1()).filter(SpecCell); forNode(nodeIndex).makeTop(); break; @@ -1354,7 +1357,7 @@ bool AbstractState::execute(unsigned indexInBlock) case GetArrayLength: node.setCanExit(true); - forNode(node.child1()).filter(SpecArray); + forNode(node.child1()).filter(SpecCell); forNode(nodeIndex).set(SpecInt32); break; @@ -1420,19 +1423,52 @@ bool AbstractState::execute(unsigned indexInBlock) case ForwardCheckStructure: { // FIXME: We should be able to propagate the structure sets of constants (i.e. prototypes). AbstractValue& value = forNode(node.child1()); + // If this structure check is attempting to prove knowledge already held in + // the futurePossibleStructure set then the constant folding phase should + // turn this into a watchpoint instead. + StructureSet& set = node.structureSet(); + if (value.m_futurePossibleStructure.isSubsetOf(set)) + m_foundConstants = true; node.setCanExit( - !value.m_structure.isSubsetOf(node.structureSet()) + !value.m_currentKnownStructure.isSubsetOf(set) || !isCellSpeculation(value.m_type)); - value.filter(node.structureSet()); + value.filter(set); + // This is likely to be unnecessary, but it's conservative, and that's a good thing. + // This is trying to avoid situations where the CFA proves that this structure check + // must fail due to a future structure proof. We have two options at that point. We + // can either compile all subsequent code as we would otherwise, or we can ensure + // that the subsequent code is never reachable. The former is correct because the + // Proof Is Infallible (TM) -- hence even if we don't force the subsequent code to + // be unreachable, it must be unreachable nonetheless. But imagine what would happen + // if the proof was borked. In the former case, we'd get really bizarre bugs where + // we assumed that the structure of this object was known even though it wasn't. In + // the latter case, we'd have a slight performance pathology because this would be + // turned into an OSR exit unnecessarily. Which would you rather have? + if (value.m_currentKnownStructure.isClear() + || value.m_futurePossibleStructure.isClear()) + m_isValid = false; m_haveStructures = true; break; } - case StructureTransitionWatchpoint: { - // FIXME: Turn CheckStructure into StructureTransitionWatchpoint when possible! + case StructureTransitionWatchpoint: + case ForwardStructureTransitionWatchpoint: { AbstractValue& value = forNode(node.child1()); + + // It's only valid to issue a structure transition watchpoint if we already + // know that the watchpoint covers a superset of the structures known to + // belong to the set of future structures that this value may have. + // Currently, we only issue singleton watchpoints (that check one structure) + // and our futurePossibleStructure set can only contain zero, one, or an + // infinity of structures. + ASSERT(value.m_futurePossibleStructure.isSubsetOf(StructureSet(node.structure()))); + ASSERT(value.isClear() || isCellSpeculation(value.m_type)); // Value could be clear if we've proven must-exit due to a speculation statically known to be bad. value.filter(node.structure()); + // See comment in CheckStructure for why this is here. + if (value.m_currentKnownStructure.isClear() + || value.m_futurePossibleStructure.isClear()) + m_isValid = false; m_haveStructures = true; node.setCanExit(true); break; @@ -1453,12 +1489,9 @@ bool AbstractState::execute(unsigned indexInBlock) forNode(nodeIndex).clear(); // The result is not a JS value. break; case GetIndexedPropertyStorage: { + ASSERT(m_graph[node.child1()].prediction()); + ASSERT(m_graph[node.child2()].shouldSpeculateInteger()); node.setCanExit(true); // Lies, but this is (almost) always followed by GetByVal, which does exit. So no point in trying to be more precise. - SpeculatedType basePrediction = m_graph[node.child2()].prediction(); - if (!(basePrediction & SpecInt32) && basePrediction) { - forNode(nodeIndex).clear(); - break; - } if (m_graph[node.child1()].shouldSpeculateArguments()) { ASSERT_NOT_REACHED(); break; @@ -1514,7 +1547,7 @@ bool AbstractState::execute(unsigned indexInBlock) forNode(nodeIndex).clear(); break; } - forNode(node.child1()).filter(SpecArray); + forNode(node.child1()).filter(SpecCell); forNode(nodeIndex).clear(); break; } diff --git a/Source/JavaScriptCore/dfg/DFGAbstractValue.h b/Source/JavaScriptCore/dfg/DFGAbstractValue.h index 402fd0fcd..ff1c6d205 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractValue.h +++ b/Source/JavaScriptCore/dfg/DFGAbstractValue.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2012 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,283 +30,13 @@ #if ENABLE(DFG_JIT) +#include "DFGStructureAbstractValue.h" #include "JSCell.h" #include "SpeculatedType.h" #include "StructureSet.h" namespace JSC { namespace DFG { -class StructureAbstractValue { -public: - StructureAbstractValue() - : m_structure(0) - { - } - - StructureAbstractValue(Structure* structure) - : m_structure(structure) - { - } - - StructureAbstractValue(const StructureSet& set) - { - switch (set.size()) { - case 0: - m_structure = 0; - break; - - case 1: - m_structure = set[0]; - break; - - default: - m_structure = topValue(); - break; - } - } - - void clear() - { - m_structure = 0; - } - - void makeTop() - { - m_structure = topValue(); - } - - static StructureAbstractValue top() - { - StructureAbstractValue value; - value.makeTop(); - return value; - } - - void add(Structure* structure) - { - ASSERT(!contains(structure) && !isTop()); - if (m_structure) - makeTop(); - else - m_structure = structure; - } - - bool addAll(const StructureSet& other) - { - if (isTop() || !other.size()) - return false; - if (other.size() > 1) { - makeTop(); - return true; - } - if (!m_structure) { - m_structure = other[0]; - return true; - } - if (m_structure == other[0]) - return false; - makeTop(); - return true; - } - - bool addAll(const StructureAbstractValue& other) - { - if (!other.m_structure) - return false; - if (isTop()) - return false; - if (other.isTop()) { - makeTop(); - return true; - } - if (m_structure) { - if (m_structure == other.m_structure) - return false; - makeTop(); - return true; - } - m_structure = other.m_structure; - return true; - } - - bool contains(Structure* structure) const - { - if (isTop()) - return true; - if (m_structure == structure) - return true; - return false; - } - - bool isSubsetOf(const StructureSet& other) const - { - if (isTop()) - return false; - if (!m_structure) - return true; - return other.contains(m_structure); - } - - bool doesNotContainAnyOtherThan(Structure* structure) const - { - if (isTop()) - return false; - if (!m_structure) - return true; - return m_structure == structure; - } - - bool isSupersetOf(const StructureSet& other) const - { - if (isTop()) - return true; - if (!other.size()) - return true; - if (other.size() > 1) - return false; - return m_structure == other[0]; - } - - bool isSubsetOf(const StructureAbstractValue& other) const - { - if (other.isTop()) - return true; - if (isTop()) - return false; - if (m_structure) { - if (other.m_structure) - return m_structure == other.m_structure; - return false; - } - return true; - } - - bool isSupersetOf(const StructureAbstractValue& other) const - { - return other.isSubsetOf(*this); - } - - void filter(const StructureSet& other) - { - if (!m_structure) - return; - - if (isTop()) { - switch (other.size()) { - case 0: - m_structure = 0; - return; - - case 1: - m_structure = other[0]; - return; - - default: - return; - } - } - - if (other.contains(m_structure)) - return; - - m_structure = 0; - } - - void filter(const StructureAbstractValue& other) - { - if (isTop()) { - m_structure = other.m_structure; - return; - } - if (m_structure == other.m_structure) - return; - if (other.isTop()) - return; - m_structure = 0; - } - - void filter(SpeculatedType other) - { - if (!(other & SpecCell)) { - clear(); - return; - } - - if (isClearOrTop()) - return; - - if (!(speculationFromStructure(m_structure) & other)) - m_structure = 0; - } - - bool isClear() const - { - return !m_structure; - } - - bool isTop() const { return m_structure == topValue(); } - - bool isClearOrTop() const { return m_structure <= topValue(); } - bool isNeitherClearNorTop() const { return !isClearOrTop(); } - - size_t size() const - { - ASSERT(!isTop()); - return !!m_structure; - } - - Structure* at(size_t i) const - { - ASSERT(!isTop()); - ASSERT(m_structure); - ASSERT_UNUSED(i, !i); - return m_structure; - } - - Structure* operator[](size_t i) const - { - return at(i); - } - - Structure* last() const - { - return at(0); - } - - SpeculatedType speculationFromStructures() const - { - if (isTop()) - return SpecCell; - if (isClear()) - return SpecNone; - return speculationFromStructure(m_structure); - } - - bool operator==(const StructureAbstractValue& other) const - { - return m_structure == other.m_structure; - } - - void dump(FILE* out) const - { - if (isTop()) { - fprintf(out, "TOP"); - return; - } - - fprintf(out, "["); - if (m_structure) - fprintf(out, "%p", m_structure); - fprintf(out, "]"); - } - -private: - static Structure* topValue() { return reinterpret_cast<Structure*>(1); } - - // This can only remember one structure at a time. - Structure* m_structure; -}; - struct AbstractValue { AbstractValue() : m_type(SpecNone) @@ -316,15 +46,15 @@ struct AbstractValue { void clear() { m_type = SpecNone; - m_structure.clear(); - m_unclobberedStructure.clear(); + m_currentKnownStructure.clear(); + m_futurePossibleStructure.clear(); m_value = JSValue(); checkConsistency(); } bool isClear() const { - bool result = m_type == SpecNone && m_structure.isClear() && m_unclobberedStructure.isClear(); + bool result = m_type == SpecNone && m_currentKnownStructure.isClear() && m_futurePossibleStructure.isClear(); if (result) ASSERT(!m_value); return result; @@ -333,8 +63,8 @@ struct AbstractValue { void makeTop() { m_type = SpecTop; - m_structure.makeTop(); - m_unclobberedStructure.makeTop(); + m_currentKnownStructure.makeTop(); + m_futurePossibleStructure.makeTop(); m_value = JSValue(); checkConsistency(); } @@ -342,9 +72,9 @@ struct AbstractValue { void clobberStructures() { if (m_type & SpecCell) - m_structure.makeTop(); + m_currentKnownStructure.makeTop(); else - ASSERT(m_structure.isClear()); + ASSERT(m_currentKnownStructure.isClear()); checkConsistency(); } @@ -355,7 +85,7 @@ struct AbstractValue { bool isTop() const { - return m_type == SpecTop && m_structure.isTop() && m_unclobberedStructure.isTop(); + return m_type == SpecTop && m_currentKnownStructure.isTop() && m_futurePossibleStructure.isTop(); } bool valueIsTop() const @@ -375,20 +105,29 @@ struct AbstractValue { return result; } - void set(JSValue value) + void setFuturePossibleStructure(Structure* structure) + { + if (structure->transitionWatchpointSetIsStillValid()) + m_futurePossibleStructure = structure; + else + m_futurePossibleStructure.makeTop(); + } + + void filterFuturePossibleStructure(Structure* structure) + { + if (structure->transitionWatchpointSetIsStillValid()) + m_futurePossibleStructure.filter(StructureAbstractValue(structure)); + } + + void setMostSpecific(JSValue value) { if (!!value && value.isCell()) { - // Have to be careful here! It's tempting to set the structure to the - // value's structure, but that would be wrong, since that would - // constitute a proof that this value will always have the same - // structure. The whole point of a value having a structure is that - // it may change in the future - for example between when we compile - // the code and when we run it. - m_structure.makeTop(); - m_unclobberedStructure.makeTop(); // FIXME: Consider not clobbering this. + Structure* structure = value.asCell()->structure(); + m_currentKnownStructure = structure; + setFuturePossibleStructure(structure); } else { - m_structure.clear(); - m_unclobberedStructure.clear(); + m_currentKnownStructure.clear(); + m_futurePossibleStructure.clear(); } m_type = speculationFromValue(value); @@ -397,14 +136,26 @@ struct AbstractValue { checkConsistency(); } - void set(Structure* structure) + void set(JSValue value) { - m_structure.clear(); - m_structure.add(structure); + if (!!value && value.isCell()) { + m_currentKnownStructure.makeTop(); + setFuturePossibleStructure(value.asCell()->structure()); + } else { + m_currentKnownStructure.clear(); + m_futurePossibleStructure.clear(); + } - m_unclobberedStructure.clear(); - m_unclobberedStructure.add(structure); + m_type = speculationFromValue(value); + m_value = value; + checkConsistency(); + } + + void set(Structure* structure) + { + m_currentKnownStructure = structure; + setFuturePossibleStructure(structure); m_type = speculationFromStructure(structure); m_value = JSValue(); @@ -414,11 +165,11 @@ struct AbstractValue { void set(SpeculatedType type) { if (type & SpecCell) { - m_structure.makeTop(); - m_unclobberedStructure.makeTop(); + m_currentKnownStructure.makeTop(); + m_futurePossibleStructure.makeTop(); } else { - m_structure.clear(); - m_unclobberedStructure.clear(); + m_currentKnownStructure.clear(); + m_futurePossibleStructure.clear(); } m_type = type; m_value = JSValue(); @@ -428,8 +179,8 @@ struct AbstractValue { bool operator==(const AbstractValue& other) const { return m_type == other.m_type - && m_structure == other.m_structure - && m_unclobberedStructure == other.m_unclobberedStructure + && m_currentKnownStructure == other.m_currentKnownStructure + && m_futurePossibleStructure == other.m_futurePossibleStructure && m_value == other.m_value; } bool operator!=(const AbstractValue& other) const @@ -448,8 +199,8 @@ struct AbstractValue { result = !other.isClear(); } else { result |= mergeSpeculation(m_type, other.m_type); - result |= m_structure.addAll(other.m_structure); - result |= m_unclobberedStructure.addAll(other.m_unclobberedStructure); + result |= m_currentKnownStructure.addAll(other.m_currentKnownStructure); + result |= m_futurePossibleStructure.addAll(other.m_futurePossibleStructure); if (m_value != other.m_value) { result |= !!m_value; m_value = JSValue(); @@ -465,8 +216,8 @@ struct AbstractValue { mergeSpeculation(m_type, type); if (type & SpecCell) { - m_structure.makeTop(); - m_unclobberedStructure.makeTop(); + m_currentKnownStructure.makeTop(); + m_futurePossibleStructure.makeTop(); } m_value = JSValue(); @@ -476,19 +227,21 @@ struct AbstractValue { void filter(const StructureSet& other) { m_type &= other.speculationFromStructures(); - m_structure.filter(other); - m_unclobberedStructure.filter(other); + m_currentKnownStructure.filter(other); + if (m_currentKnownStructure.isClear()) + m_futurePossibleStructure.clear(); + else if (m_currentKnownStructure.hasSingleton()) + filterFuturePossibleStructure(m_currentKnownStructure.singleton()); // It's possible that prior to the above two statements we had (Foo, TOP), where // Foo is a SpeculatedType that is disjoint with the passed StructureSet. In that // case, we will now have (None, [someStructure]). In general, we need to make // sure that new information gleaned from the SpeculatedType needs to be fed back // into the information gleaned from the StructureSet. - m_structure.filter(m_type); - m_unclobberedStructure.filter(m_type); + m_currentKnownStructure.filter(m_type); + m_futurePossibleStructure.filter(m_type); - if (!!m_value && !validateIgnoringValue(m_value)) - clear(); + filterValueByType(); checkConsistency(); } @@ -503,47 +256,38 @@ struct AbstractValue { // the passed type is Array. At this point we'll have (None, TOP). The best way // to ensure that the structure filtering does the right thing is to filter on // the new type (None) rather than the one passed (Array). - m_structure.filter(m_type); - m_unclobberedStructure.filter(m_type); + m_currentKnownStructure.filter(m_type); + m_futurePossibleStructure.filter(m_type); - if (!!m_value && !validateIgnoringValue(m_value)) - clear(); + filterValueByType(); checkConsistency(); } - bool validateIgnoringValue(JSValue value) const + // We could go further, and ensure that if the futurePossibleStructure contravenes + // the value, then we could clear both of those things. But that's unlikely to help + // in any realistic scenario, so we don't do it. Simpler is better. + void filterValueByType() { - if (isTop()) - return true; - - if (mergeSpeculations(m_type, speculationFromValue(value)) != m_type) - return false; - - if (value.isEmpty()) { - ASSERT(m_type & SpecEmpty); - return true; - } - - if (m_structure.isTop()) - return true; - - if (!!value && value.isCell()) { - ASSERT(m_type & SpecCell); - return m_structure.contains(value.asCell()->structure()); + if (!!m_type) { + // The type is still non-empty. This implies that regardless of what filtering + // was done, we either didn't have a value to begin with, or that value is still + // valid. + ASSERT(!m_value || validateType(m_value)); + return; } - return true; + // The type has been rendered empty. That means that the value must now be invalid, + // as well. + ASSERT(!m_value || !validateType(m_value)); + m_value = JSValue(); } - bool validate(JSValue value) const + bool validateType(JSValue value) const { if (isTop()) return true; - if (!!m_value && m_value != value) - return false; - if (mergeSpeculations(m_type, speculationFromValue(value)) != m_type) return false; @@ -552,18 +296,10 @@ struct AbstractValue { return true; } - if (m_structure.isTop()) - return true; - - if (!!value && value.isCell()) { - ASSERT(m_type & SpecCell); - return m_structure.contains(value.asCell()->structure()); - } - return true; } - bool validateForEntry(JSValue value) const + bool validate(JSValue value) const { if (isTop()) return true; @@ -579,12 +315,11 @@ struct AbstractValue { return true; } - if (m_unclobberedStructure.isTop()) - return true; - if (!!value && value.isCell()) { ASSERT(m_type & SpecCell); - return m_unclobberedStructure.contains(value.asCell()->structure()); + Structure* structure = value.asCell()->structure(); + return m_currentKnownStructure.contains(structure) + && m_futurePossibleStructure.contains(structure); } return true; @@ -593,8 +328,8 @@ struct AbstractValue { void checkConsistency() const { if (!(m_type & SpecCell)) { - ASSERT(m_structure.isClear()); - ASSERT(m_unclobberedStructure.isClear()); + ASSERT(m_currentKnownStructure.isClear()); + ASSERT(m_futurePossibleStructure.isClear()); } if (isClear()) @@ -612,17 +347,102 @@ struct AbstractValue { void dump(FILE* out) const { fprintf(out, "(%s, ", speculationToString(m_type)); - m_structure.dump(out); + m_currentKnownStructure.dump(out); dataLog(", "); - m_unclobberedStructure.dump(out); + m_futurePossibleStructure.dump(out); if (!!m_value) fprintf(out, ", %s", m_value.description()); fprintf(out, ")"); } + + // A great way to think about the difference between m_currentKnownStructure and + // m_futurePossibleStructure is to consider these four examples: + // + // 1) x = foo(); + // + // In this case x's m_currentKnownStructure and m_futurePossibleStructure will + // both be TOP, since we don't know anything about x for sure, yet. + // + // 2) x = foo(); + // y = x.f; + // + // Where x will later have a new property added to it, 'g'. Because of the + // known but not-yet-executed property addition, x's currently structure will + // not be watchpointable; hence we have no way of statically bounding the set + // of possible structures that x may have if a clobbering event happens. So, + // x's m_currentKnownStructure will be whatever structure we check to get + // property 'f', and m_futurePossibleStructure will be TOP. + // + // 3) x = foo(); + // y = x.f; + // + // Where x has a terminal structure that is still watchpointable. In this case, + // x's m_currentKnownStructure and m_futurePossibleStructure will both be + // whatever structure we checked for when getting 'f'. + // + // 4) x = foo(); + // y = x.f; + // bar(); + // + // Where x has a terminal structure that is still watchpointable. In this + // case, m_currentKnownStructure will be TOP because bar() may potentially + // change x's structure and we have no way of proving otherwise, but + // x's m_futurePossibleStructure will be whatever structure we had checked + // when getting property 'f'. - StructureAbstractValue m_structure; - StructureAbstractValue m_unclobberedStructure; + // This is a proven constraint on the structures that this value can have right + // now. The structure of the current value must belong to this set. The set may + // be TOP, indicating that it is the set of all possible structures, in which + // case the current value can have any structure. The set may be BOTTOM (empty) + // in which case this value cannot be a cell. This is all subject to change + // anytime a new value is assigned to this one, anytime there is a control flow + // merge, or most crucially, anytime a side-effect or structure check happens. + // In case of a side-effect, we typically must assume that any value may have + // had its structure changed, hence contravening our proof. We make the proof + // valid again by switching this to TOP (i.e. claiming that we have proved that + // this value may have any structure). Of note is that the proof represented by + // this field is not subject to structure transition watchpoints - even if one + // fires, we can be sure that this proof is still valid. + StructureAbstractValue m_currentKnownStructure; + + // This is a proven constraint on the structures that this value can have now + // or any time in the future subject to the structure transition watchpoints of + // all members of this set not having fired. This set is impervious to side- + // effects; even if one happens the side-effect can only cause the value to + // change to at worst another structure that is also a member of this set. But, + // the theorem being proved by this field is predicated upon there not being + // any new structure transitions introduced into any members of this set. In + // cases where there is no way for us to guard this happening, the set must be + // TOP. But in cases where we can guard new structure transitions (all members + // of the set have still-valid structure transition watchpoints) then this set + // will be finite. Anytime that we make use of the finite nature of this set, + // we must first issue a structure transition watchpoint, which will effectively + // result in m_currentKnownStructure being filtered according to + // m_futurePossibleStructure. + StructureAbstractValue m_futurePossibleStructure; + + // This is a proven constraint on the possible types that this value can have + // now or any time in the future, unless it is reassigned. This field is + // impervious to side-effects unless the side-effect can reassign the value + // (for example if we're talking about a captured variable). The relationship + // between this field, and the structure fields above, is as follows. The + // fields above constraint the structures that a cell may have, but they say + // nothing about whether or not the value is known to be a cell. More formally, + // the m_currentKnownStructure is itself an abstract value that consists of the + // union of the set of all non-cell values and the set of cell values that have + // the given structure. This abstract value is then the intersection of the + // m_currentKnownStructure and the set of values whose type is m_type. So, for + // example if m_type is SpecFinal|SpecInt32 and m_currentKnownStructure is + // [0x12345] then this abstract value corresponds to the set of all integers + // unified with the set of all objects with structure 0x12345. SpeculatedType m_type; + + // This is a proven constraint on the possible values that this value can + // have now or any time in the future, unless it is reassigned. Note that this + // implies nothing about the structure. Oddly, JSValue() (i.e. the empty value) + // means either BOTTOM or TOP depending on the state of m_type: if m_type is + // BOTTOM then JSValue() means BOTTOM; if m_type is not BOTTOM then JSValue() + // means TOP. JSValue m_value; }; diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp index 9208cde1b..000e1a938 100644 --- a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp @@ -317,6 +317,17 @@ public: // PhantomArguments and OSR exit will still do the right things. break; + case CheckStructure: + case ForwardCheckStructure: + case StructureTransitionWatchpoint: + case ForwardStructureTransitionWatchpoint: + // We don't care about these because if we get uses of the relevant + // variable then we can safely get rid of these, too. This of course + // relies on there not being any information transferred by the CFA + // from a CheckStructure on one variable to the information about the + // structures of another variable. + break; + default: observeBadArgumentsUses(node); break; @@ -471,6 +482,19 @@ public: break; } + case CheckStructure: + case ForwardCheckStructure: + case StructureTransitionWatchpoint: + case ForwardStructureTransitionWatchpoint: { + // We can just get rid of this node, if it references a phantom argument. + if (!isOKToOptimize(m_graph[node.child1()])) + break; + m_graph.deref(node.child1()); + node.setOpAndDefaultFlags(Phantom); + node.children.setChild1(Edge()); + break; + } + case GetByVal: { if (!node.prediction() || !m_graph[node.child1()].prediction() diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp index b7f48aa4b..f7536f87f 100644 --- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp +++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp @@ -118,7 +118,7 @@ private: template<PhiStackType stackType> void processPhiStack(); - void fixVariableAccessSpeculations(); + void fixVariableAccessPredictions(); // Add spill locations to nodes. void allocateVirtualRegisters(); @@ -2149,6 +2149,10 @@ bool ByteCodeParser::parseBlock(unsigned limit) NodeIndex base = get(currentInstruction[2].u.operand); NodeIndex property = get(currentInstruction[3].u.operand); + ArrayProfile* profile = currentInstruction[4].u.arrayProfile; + profile->computeUpdatedPrediction(); + if (profile->hasDefiniteStructure()) + addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(profile->expectedStructure())), base); NodeIndex propertyStorage = addToGraph(GetIndexedPropertyStorage, base, property); NodeIndex getByVal = addToGraph(GetByVal, OpInfo(0), OpInfo(prediction), base, property, propertyStorage); set(currentInstruction[1].u.operand, getByVal); @@ -2160,6 +2164,15 @@ bool ByteCodeParser::parseBlock(unsigned limit) NodeIndex base = get(currentInstruction[1].u.operand); NodeIndex property = get(currentInstruction[2].u.operand); NodeIndex value = get(currentInstruction[3].u.operand); + + ArrayProfile* profile = currentInstruction[4].u.arrayProfile; + profile->computeUpdatedPrediction(); + if (profile->hasDefiniteStructure()) + addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(profile->expectedStructure())), base); + +#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) + dataLog("Slow case profile for bc#%u: %u\n", m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter); +#endif bool makeSafe = m_inlineStackTop->m_profiledBlock->couldTakeSlowCase(m_currentIndex) @@ -3017,7 +3030,7 @@ void ByteCodeParser::processPhiStack() } } -void ByteCodeParser::fixVariableAccessSpeculations() +void ByteCodeParser::fixVariableAccessPredictions() { for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) { VariableAccessData* data = &m_graph.m_variableAccessData[i]; @@ -3349,7 +3362,27 @@ bool ByteCodeParser::parse() m_graph.m_blocks[blockIndex].clear(); } - fixVariableAccessSpeculations(); + fixVariableAccessPredictions(); + + for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) { + BasicBlock* block = m_graph.m_blocks[blockIndex].get(); + if (!block) + continue; + if (!block->isOSRTarget) + continue; + if (block->bytecodeBegin != m_graph.m_osrEntryBytecodeIndex) + continue; + for (size_t i = 0; i < m_graph.m_mustHandleValues.size(); ++i) { + NodeIndex nodeIndex = block->variablesAtHead.operand( + m_graph.m_mustHandleValues.operandForIndex(i)); + if (nodeIndex == NoNode) + continue; + Node& node = m_graph[nodeIndex]; + ASSERT(node.hasLocal()); + node.variableAccessData()->predict( + speculationFromValue(m_graph.m_mustHandleValues[i])); + } + } m_graph.m_preservedVars = m_preservedVars; m_graph.m_localVars = m_numLocals; diff --git a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp index dc1632dc4..f054707e2 100644 --- a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp @@ -613,7 +613,9 @@ private: ASSERT(node.shouldGenerate()); Node& possibleLocalOp = m_graph[node.child1()]; - if (possibleLocalOp.hasLocal() && !possibleLocalOp.variableAccessData()->isCaptured()) { + if (possibleLocalOp.op() != GetLocal + && possibleLocalOp.hasLocal() + && !possibleLocalOp.variableAccessData()->isCaptured()) { NodeIndex setLocalIndex = firstBlock->variablesAtTail.operand(possibleLocalOp.local()); Node& setLocal = m_graph[setLocalIndex]; diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp index e9b1e0d8b..b78ddc89d 100644 --- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp @@ -345,6 +345,7 @@ private: break; case StructureTransitionWatchpoint: + case ForwardStructureTransitionWatchpoint: if (node.child1() == child1 && structureSet.contains(node.structure())) return true; @@ -418,6 +419,7 @@ private: return false; case StructureTransitionWatchpoint: + case ForwardStructureTransitionWatchpoint: if (node.structure() == structure && node.child1() == child1) return true; break; @@ -843,6 +845,8 @@ private: // At this point we will eliminate all references to this node. m_replacements[m_compileIndex] = replacement; + m_changed = true; + return true; } @@ -856,6 +860,8 @@ private: ASSERT(node.refCount() == 1); ASSERT(node.mustGenerate()); node.setOpAndDefaultFlags(Phantom); + + m_changed = true; } void eliminate(NodeIndex nodeIndex, NodeType phantomType = Phantom) @@ -867,6 +873,8 @@ private: return; ASSERT(node.mustGenerate()); node.setOpAndDefaultFlags(phantomType); + + m_changed = true; } void performNodeCSE(Node& node) @@ -944,7 +952,7 @@ private: case GetLocal: { VariableAccessData* variableAccessData = node.variableAccessData(); - if (m_fixpointState == FixpointNotConverged && !variableAccessData->isCaptured()) + if (!variableAccessData->isCaptured()) break; NodeIndex relevantLocalOp; NodeIndex possibleReplacement = getLocalLoadElimination(variableAccessData->local(), relevantLocalOp, variableAccessData->isCaptured()); @@ -982,7 +990,7 @@ private: case GetLocalUnlinked: { NodeIndex relevantLocalOpIgnored; - m_changed |= setReplacement(getLocalLoadElimination(node.unlinkedLocal(), relevantLocalOpIgnored, true)); + setReplacement(getLocalLoadElimination(node.unlinkedLocal(), relevantLocalOpIgnored, true)); break; } @@ -1117,6 +1125,7 @@ private: break; case StructureTransitionWatchpoint: + case ForwardStructureTransitionWatchpoint: if (structureTransitionWatchpointElimination(node.structure(), node.child1().index())) eliminate(); break; diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp index a8eb9ee5c..68d5534e0 100644 --- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp @@ -91,7 +91,16 @@ private: break; } - // FIXME: This would be a great place to remove CheckStructure's. + case CheckStructure: + case ForwardCheckStructure: { + AbstractValue& value = m_state.forNode(node.child1()); + StructureAbstractValue& structureValue = value.m_futurePossibleStructure; + if (structureValue.isSubsetOf(node.structureSet()) + && structureValue.hasSingleton() + && isCellSpeculation(value.m_type)) + node.convertToStructureTransitionWatchpoint(structureValue.singleton()); + break; + } default: break; @@ -103,9 +112,7 @@ private: } m_state.execute(indexInBlock); - if (!node.shouldGenerate() - || m_state.didClobber() - || node.hasConstant()) + if (!node.shouldGenerate() || m_state.didClobber() || node.hasConstant()) continue; JSValue value = m_state.forNode(nodeIndex).value(); if (!value) diff --git a/Source/JavaScriptCore/dfg/DFGDriver.cpp b/Source/JavaScriptCore/dfg/DFGDriver.cpp index ddad4f864..ccef65208 100644 --- a/Source/JavaScriptCore/dfg/DFGDriver.cpp +++ b/Source/JavaScriptCore/dfg/DFGDriver.cpp @@ -26,6 +26,10 @@ #include "config.h" #include "DFGDriver.h" +#include "JSObject.h" +#include "JSString.h" +#include "ScopeChain.h" + #if ENABLE(DFG_JIT) #include "DFGArgumentsSimplificationPhase.h" @@ -53,7 +57,7 @@ unsigned getNumCompilations() } enum CompileMode { CompileFunction, CompileOther }; -inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr* jitCodeWithArityCheck) +inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr* jitCodeWithArityCheck, unsigned osrEntryBytecodeIndex) { SamplingRegion samplingRegion("DFG Compilation (Driver)"); @@ -62,6 +66,8 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo ASSERT(codeBlock); ASSERT(codeBlock->alternative()); ASSERT(codeBlock->alternative()->getJITType() == JITCode::BaselineJIT); + + ASSERT(osrEntryBytecodeIndex != UINT_MAX); if (!Options::useDFGJIT()) return false; @@ -70,7 +76,30 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo dataLog("DFG compiling code block %p(%p) for executable %p, number of instructions = %u.\n", codeBlock, codeBlock->alternative(), codeBlock->ownerExecutable(), codeBlock->instructionCount()); #endif - Graph dfg(exec->globalData(), codeBlock); + // Derive our set of must-handle values. The compilation must be at least conservative + // enough to allow for OSR entry with these values. + unsigned numVarsWithValues; + if (osrEntryBytecodeIndex) + numVarsWithValues = codeBlock->m_numVars; + else + numVarsWithValues = 0; + Operands<JSValue> mustHandleValues(codeBlock->numParameters(), numVarsWithValues); + for (size_t i = 0; i < mustHandleValues.size(); ++i) { + int operand = mustHandleValues.operandForIndex(i); + if (operandIsArgument(operand) + && !operandToArgument(operand) + && compileMode == CompileFunction + && codeBlock->specializationKind() == CodeForConstruct) { + // Ugh. If we're in a constructor, the 'this' argument may hold garbage. It will + // also never be used. It doesn't matter what we put into the value for this, + // but it has to be an actual value that can be grokked by subsequent DFG passes, + // so we sanitize it here by turning it into Undefined. + mustHandleValues[i] = jsUndefined(); + } else + mustHandleValues[i] = exec->uncheckedR(operand).jsValue(); + } + + Graph dfg(exec->globalData(), codeBlock, osrEntryBytecodeIndex, mustHandleValues); if (!parse(exec, dfg)) return false; @@ -86,6 +115,7 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo validate(dfg); performPredictionPropagation(dfg); performFixup(dfg); + performStructureCheckHoisting(dfg); unsigned cnt = 1; for (;; ++cnt) { #if DFG_ENABLE(DEBUG_VERBOSE) @@ -102,10 +132,7 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo dfg.resetExitStates(); performFixup(dfg); } - bool shouldRedoCFA = performStructureCheckHoisting(dfg); performCSE(dfg, FixpointConverged); - if (shouldRedoCFA) - performCFA(dfg); #if DFG_ENABLE(DEBUG_VERBOSE) dataLog("DFG optimization fixpoint converged in %u iterations.\n", cnt); #endif @@ -135,14 +162,14 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo return result; } -bool tryCompile(ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode) +bool tryCompile(ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode, unsigned bytecodeIndex) { - return compile(CompileOther, exec, codeBlock, jitCode, 0); + return compile(CompileOther, exec, codeBlock, jitCode, 0, bytecodeIndex); } -bool tryCompileFunction(ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck) +bool tryCompileFunction(ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck, unsigned bytecodeIndex) { - return compile(CompileFunction, exec, codeBlock, jitCode, &jitCodeWithArityCheck); + return compile(CompileFunction, exec, codeBlock, jitCode, &jitCodeWithArityCheck, bytecodeIndex); } } } // namespace JSC::DFG diff --git a/Source/JavaScriptCore/dfg/DFGDriver.h b/Source/JavaScriptCore/dfg/DFGDriver.h index a6e82fef5..1964ec34a 100644 --- a/Source/JavaScriptCore/dfg/DFGDriver.h +++ b/Source/JavaScriptCore/dfg/DFGDriver.h @@ -41,11 +41,11 @@ namespace DFG { JS_EXPORT_PRIVATE unsigned getNumCompilations(); #if ENABLE(DFG_JIT) -bool tryCompile(ExecState*, CodeBlock*, JITCode&); -bool tryCompileFunction(ExecState*, CodeBlock*, JITCode&, MacroAssemblerCodePtr& jitCodeWithArityCheck); +bool tryCompile(ExecState*, CodeBlock*, JITCode&, unsigned bytecodeIndex); +bool tryCompileFunction(ExecState*, CodeBlock*, JITCode&, MacroAssemblerCodePtr& jitCodeWithArityCheck, unsigned bytecodeIndex); #else -inline bool tryCompile(ExecState*, CodeBlock*, JITCode&) { return false; } -inline bool tryCompileFunction(ExecState*, CodeBlock*, JITCode&, MacroAssemblerCodePtr&) { return false; } +inline bool tryCompile(ExecState*, CodeBlock*, JITCode&, unsigned) { return false; } +inline bool tryCompileFunction(ExecState*, CodeBlock*, JITCode&, MacroAssemblerCodePtr&, unsigned) { return false; } #endif } } // namespace JSC::DFG diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp index 4e3cd5782..f7b10fc43 100644 --- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp @@ -96,9 +96,29 @@ private: #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLog(" @%u -> %s", m_compileIndex, isArray ? "GetArrayLength" : "GetStringLength"); #endif - if (isArray) + if (isArray) { node.setOp(GetArrayLength); - else if (isArguments) + ASSERT(node.flags() & NodeMustGenerate); + node.clearFlags(NodeMustGenerate); + m_graph.deref(m_compileIndex); + + ArrayProfile* arrayProfile = + m_graph.baselineCodeBlockFor(node.codeOrigin)->getArrayProfile( + node.codeOrigin.bytecodeIndex); + if (!arrayProfile) + break; + arrayProfile->computeUpdatedPrediction(); + if (!arrayProfile->hasDefiniteStructure()) + break; + m_graph.ref(node.child1()); + Node checkStructure(CheckStructure, node.codeOrigin, OpInfo(m_graph.addStructureSet(arrayProfile->expectedStructure())), node.child1().index()); + checkStructure.ref(); + NodeIndex checkStructureIndex = m_graph.size(); + m_graph.append(checkStructure); + m_insertionSet.append(m_indexInBlock, checkStructureIndex); + break; + } + if (isArguments) node.setOp(GetArgumentsLength); else if (isString) node.setOp(GetStringLength); @@ -129,10 +149,9 @@ private: break; } case GetIndexedPropertyStorage: { - SpeculatedType basePrediction = m_graph[node.child2()].prediction(); - if ((!(basePrediction & SpecInt32) && basePrediction) - || m_graph[node.child1()].shouldSpeculateArguments() - || !isActionableArraySpeculation(m_graph[node.child1()].prediction())) { + if (!m_graph[node.child1()].prediction() + || !m_graph[node.child2()].shouldSpeculateInteger() + || m_graph[node.child1()].shouldSpeculateArguments()) { node.setOpAndDefaultFlags(Nop); m_graph.clearAndDerefChild1(node); m_graph.clearAndDerefChild2(node); diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h index fdb78cf9b..8d164a299 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.h +++ b/Source/JavaScriptCore/dfg/DFGGraph.h @@ -76,11 +76,13 @@ struct ResolveGlobalData { // Nodes that are 'dead' remain in the vector with refCount 0. class Graph : public Vector<Node, 64> { public: - Graph(JSGlobalData& globalData, CodeBlock* codeBlock) + Graph(JSGlobalData& globalData, CodeBlock* codeBlock, unsigned osrEntryBytecodeIndex, const Operands<JSValue>& mustHandleValues) : m_globalData(globalData) , m_codeBlock(codeBlock) , m_profiledBlock(codeBlock->alternative()) , m_hasArguments(false) + , m_osrEntryBytecodeIndex(osrEntryBytecodeIndex) + , m_mustHandleValues(mustHandleValues) { ASSERT(m_profiledBlock); } @@ -137,6 +139,20 @@ public: edge = newEdge; } + void compareAndSwap(Edge& edge, NodeIndex oldIndex, NodeIndex newIndex, bool changeRef) + { + if (edge.index() != oldIndex) + return; + changeIndex(edge, newIndex, changeRef); + } + + void compareAndSwap(Edge& edge, Edge oldEdge, Edge newEdge, bool changeRef) + { + if (edge != oldEdge) + return; + changeEdge(edge, newEdge, changeRef); + } + void clearAndDerefChild1(Node& node) { if (!node.child1()) @@ -614,6 +630,69 @@ public: vote(node.child3(), ballot); } + template<typename T> // T = NodeIndex or Edge + void substitute(BasicBlock& block, unsigned startIndexInBlock, T oldThing, T newThing) + { + for (unsigned indexInBlock = startIndexInBlock; indexInBlock < block.size(); ++indexInBlock) { + NodeIndex nodeIndex = block[indexInBlock]; + Node& node = at(nodeIndex); + if (node.flags() & NodeHasVarArgs) { + for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); ++childIdx) + compareAndSwap(m_varArgChildren[childIdx], oldThing, newThing, node.shouldGenerate()); + continue; + } + if (!node.child1()) + continue; + compareAndSwap(node.children.child1(), oldThing, newThing, node.shouldGenerate()); + if (!node.child2()) + continue; + compareAndSwap(node.children.child2(), oldThing, newThing, node.shouldGenerate()); + if (!node.child3()) + continue; + compareAndSwap(node.children.child3(), oldThing, newThing, node.shouldGenerate()); + } + } + + // Use this if you introduce a new GetLocal and you know that you introduced it *before* + // any GetLocals in the basic block. + // FIXME: it may be appropriate, in the future, to generalize this to handle GetLocals + // introduced anywhere in the basic block. + void substituteGetLocal(BasicBlock& block, unsigned startIndexInBlock, VariableAccessData* variableAccessData, NodeIndex newGetLocal) + { + if (variableAccessData->isCaptured()) { + // Let CSE worry about this one. + return; + } + for (unsigned indexInBlock = startIndexInBlock; indexInBlock < block.size(); ++indexInBlock) { + NodeIndex nodeIndex = block[indexInBlock]; + Node& node = at(nodeIndex); + bool shouldContinue = true; + switch (node.op()) { + case SetLocal: { + if (node.local() == variableAccessData->local()) + shouldContinue = false; + break; + } + + case GetLocal: { + if (node.variableAccessData() != variableAccessData) + continue; + substitute(block, indexInBlock, nodeIndex, newGetLocal); + NodeIndex oldTailIndex = block.variablesAtTail.operand(variableAccessData->local()); + if (oldTailIndex == nodeIndex) + block.variablesAtTail.operand(variableAccessData->local()) = newGetLocal; + shouldContinue = false; + break; + } + + default: + break; + } + if (!shouldContinue) + break; + } + } + JSGlobalData& m_globalData; CodeBlock* m_codeBlock; CodeBlock* m_profiledBlock; @@ -633,6 +712,8 @@ public: Dominators m_dominators; unsigned m_localVars; unsigned m_parameterSlots; + unsigned m_osrEntryBytecodeIndex; + Operands<JSValue> m_mustHandleValues; private: void handleSuccessor(Vector<BlockIndex, 16>& worklist, BlockIndex blockIndex, BlockIndex successorIndex); diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h index 60cdd4b50..dac855be0 100644 --- a/Source/JavaScriptCore/dfg/DFGNode.h +++ b/Source/JavaScriptCore/dfg/DFGNode.h @@ -245,11 +245,19 @@ struct Node { children.reset(); } + void convertToStructureTransitionWatchpoint(Structure* structure) + { + ASSERT(m_op == CheckStructure || m_op == ForwardCheckStructure); + m_opInfo = bitwise_cast<uintptr_t>(structure); + if (m_op == CheckStructure) + m_op = StructureTransitionWatchpoint; + else + m_op = ForwardStructureTransitionWatchpoint; + } + void convertToStructureTransitionWatchpoint() { - ASSERT(m_op == CheckStructure); - m_opInfo = bitwise_cast<uintptr_t>(structureSet().singletonStructure()); - m_op = StructureTransitionWatchpoint; + convertToStructureTransitionWatchpoint(structureSet().singletonStructure()); } JSCell* weakConstant() @@ -675,7 +683,13 @@ struct Node { bool hasStructure() { - return op() == StructureTransitionWatchpoint; + switch (op()) { + case StructureTransitionWatchpoint: + case ForwardStructureTransitionWatchpoint: + return true; + default: + return false; + } } Structure* structure() diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h index 7657663a9..f0f8cb1d0 100644 --- a/Source/JavaScriptCore/dfg/DFGNodeType.h +++ b/Source/JavaScriptCore/dfg/DFGNodeType.h @@ -133,6 +133,7 @@ namespace JSC { namespace DFG { /* the object's structure does not need to be rechecked due to side-effecting */\ /* (clobbering) operations. */\ macro(StructureTransitionWatchpoint, NodeMustGenerate) \ + macro(ForwardStructureTransitionWatchpoint, NodeMustGenerate) \ macro(PutStructure, NodeMustGenerate) \ macro(PhantomPutStructure, NodeMustGenerate | NodeDoesNotExit) \ macro(AllocatePropertyStorage, NodeMustGenerate | NodeDoesNotExit | NodeResultStorage) \ diff --git a/Source/JavaScriptCore/dfg/DFGOSREntry.cpp b/Source/JavaScriptCore/dfg/DFGOSREntry.cpp index 97061bfb2..9a7bc96cc 100644 --- a/Source/JavaScriptCore/dfg/DFGOSREntry.cpp +++ b/Source/JavaScriptCore/dfg/DFGOSREntry.cpp @@ -99,7 +99,7 @@ void* prepareOSREntry(ExecState* exec, CodeBlock* codeBlock, unsigned bytecodeIn else value = exec->argument(argument - 1); - if (!entry->m_expectedValues.argument(argument).validateForEntry(value)) { + if (!entry->m_expectedValues.argument(argument).validate(value)) { #if ENABLE(JIT_VERBOSE_OSR) dataLog(" OSR failed because argument %zu is %s, expected ", argument, value.description()); entry->m_expectedValues.argument(argument).dump(WTF::dataFile()); @@ -119,7 +119,7 @@ void* prepareOSREntry(ExecState* exec, CodeBlock* codeBlock, unsigned bytecodeIn } continue; } - if (!entry->m_expectedValues.local(local).validateForEntry(exec->registers()[local].jsValue())) { + if (!entry->m_expectedValues.local(local).validate(exec->registers()[local].jsValue())) { #if ENABLE(JIT_VERBOSE_OSR) dataLog(" OSR failed because variable %zu is %s, expected ", local, exec->registers()[local].jsValue().description()); entry->m_expectedValues.local(local).dump(WTF::dataFile()); diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp index 94f69abc2..1247528e8 100644 --- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp @@ -675,6 +675,7 @@ private: case CheckStructure: case ForwardCheckStructure: case StructureTransitionWatchpoint: + case ForwardStructureTransitionWatchpoint: case CheckFunction: case PutStructure: case TearOffActivation: diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp index f17e2d7e4..6c6615716 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp @@ -119,11 +119,8 @@ JumpReplacementWatchpoint* SpeculativeJIT::speculationWatchpoint(ExitKind kind) return speculationWatchpoint(kind, JSValueSource(), NoNode); } -void SpeculativeJIT::forwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, MacroAssembler::Jump jumpToFail, const ValueRecovery& valueRecovery) +void SpeculativeJIT::convertLastOSRExitToForward(const ValueRecovery& valueRecovery) { - ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes); - speculationCheck(kind, jsValueSource, nodeIndex, jumpToFail); - #if !ASSERT_DISABLED if (!valueRecovery) { // Check that the preceding node was a SetLocal with the same code origin. @@ -155,6 +152,10 @@ void SpeculativeJIT::forwardSpeculationCheck(ExitKind kind, JSValueSource jsValu ASSERT(setLocal->codeOrigin == at(m_compileIndex).codeOrigin); Node* nextNode = &at(m_jit.graph().m_blocks[m_block]->at(setLocalIndexInBlock + 1)); + if (nextNode->op() == Jump && nextNode->codeOrigin == at(m_compileIndex).codeOrigin) { + // We're at an inlined return. Use a backward speculation instead. + return; + } ASSERT(nextNode->codeOrigin != at(m_compileIndex).codeOrigin); OSRExit& exit = m_jit.codeBlock()->lastOSRExit(); @@ -167,6 +168,28 @@ void SpeculativeJIT::forwardSpeculationCheck(ExitKind kind, JSValueSource jsValu new ValueRecoveryOverride(setLocal->local(), valueRecovery)); } +JumpReplacementWatchpoint* SpeculativeJIT::forwardSpeculationWatchpoint(ExitKind kind) +{ + JumpReplacementWatchpoint* result = speculationWatchpoint(kind); + convertLastOSRExitToForward(); + return result; +} + +JumpReplacementWatchpoint* SpeculativeJIT::speculationWatchpointWithConditionalDirection(ExitKind kind, bool isForward) +{ + JumpReplacementWatchpoint* result = speculationWatchpoint(kind); + if (isForward) + convertLastOSRExitToForward(); + return result; +} + +void SpeculativeJIT::forwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, MacroAssembler::Jump jumpToFail, const ValueRecovery& valueRecovery) +{ + ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes); + speculationCheck(kind, jsValueSource, nodeIndex, jumpToFail); + convertLastOSRExitToForward(valueRecovery); +} + void SpeculativeJIT::forwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, MacroAssembler::JumpList& jumpsToFail, const ValueRecovery& valueRecovery) { ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes); @@ -246,6 +269,24 @@ void SpeculativeJIT::clearGenerationInfo() m_fprs = RegisterBank<FPRInfo>(); } +void SpeculativeJIT::speculateArray(Edge edge, GPRReg baseReg) +{ + AbstractValue& arrayValue = m_state.forNode(edge); + if (arrayValue.m_currentKnownStructure.hasSingleton() + && arrayValue.m_currentKnownStructure.singleton()->classInfo() == &JSArray::s_info) + return; + + GPRTemporary temp(this); + m_jit.loadPtr( + MacroAssembler::Address(baseReg, JSCell::structureOffset()), temp.gpr()); + speculationCheck( + Uncountable, JSValueRegs(), NoNode, + m_jit.branchPtr( + MacroAssembler::NotEqual, + MacroAssembler::Address(temp.gpr(), Structure::classInfoOffset()), + MacroAssembler::TrustedImmPtr(&JSArray::s_info))); +} + GPRReg SpeculativeJIT::fillStorage(NodeIndex nodeIndex) { Node& node = m_jit.graph()[nodeIndex]; @@ -1220,7 +1261,7 @@ void SpeculativeJIT::compile(BasicBlock& block) valueSource = ValueSource(DoubleInRegisterFile); else if (isInt32Speculation(argumentPosition.prediction())) valueSource = ValueSource(Int32InRegisterFile); - else if (isArraySpeculation(argumentPosition.prediction()) || isCellSpeculation(argumentPosition.prediction())) + else if (isCellSpeculation(argumentPosition.prediction())) valueSource = ValueSource(CellInRegisterFile); else if (isBooleanSpeculation(argumentPosition.prediction())) valueSource = ValueSource(BooleanInRegisterFile); @@ -1343,12 +1384,7 @@ void SpeculativeJIT::checkArgumentTypes() #if USE(JSVALUE64) if (isInt32Speculation(predictedType)) speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::Below, JITCompiler::addressFor(virtualRegister), GPRInfo::tagTypeNumberRegister)); - else if (isArraySpeculation(predictedType)) { - GPRTemporary temp(this); - m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr()); - speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister)); - speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); - } else if (isBooleanSpeculation(predictedType)) { + else if (isBooleanSpeculation(predictedType)) { GPRTemporary temp(this); m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr()); m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), temp.gpr()); @@ -1403,13 +1439,7 @@ void SpeculativeJIT::checkArgumentTypes() #else if (isInt32Speculation(predictedType)) speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag))); - else if (isArraySpeculation(predictedType)) { - GPRTemporary temp(this); - m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr()); - speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag))); - m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr()); - speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); - } else if (isBooleanSpeculation(predictedType)) + else if (isBooleanSpeculation(predictedType)) speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::BooleanTag))); else if (isInt8ArraySpeculation(predictedType)) { GPRTemporary temp(this); @@ -1591,7 +1621,6 @@ void SpeculativeJIT::compileGetByValOnString(Node& node) GPRReg storageReg = storage.gpr(); if (!isStringSpeculation(m_state.forNode(node.child1()).m_type)) { - ASSERT(!(at(node.child1()).prediction() & SpecString)); terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); noResult(m_compileIndex); return; @@ -3037,22 +3066,12 @@ bool SpeculativeJIT::compileStrictEq(Node& node) void SpeculativeJIT::compileGetIndexedPropertyStorage(Node& node) { - if (!node.prediction() || !at(node.child1()).prediction() || !at(node.child2()).prediction()) { - terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode); - return; - } + ASSERT(at(node.child1()).prediction()); + ASSERT(at(node.child2()).shouldSpeculateInteger()); SpeculateCellOperand base(this, node.child1()); GPRReg baseReg = base.gpr(); - SpeculatedType basePrediction = at(node.child2()).prediction(); - if (!(basePrediction & SpecInt32) && basePrediction) { - ASSERT_NOT_REACHED(); - terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); - noResult(m_compileIndex); - return; - } - GPRTemporary storage(this); GPRReg storageReg = storage.gpr(); if (at(node.child1()).shouldSpeculateArguments()) { @@ -3113,8 +3132,7 @@ void SpeculativeJIT::compileGetIndexedPropertyStorage(Node& node) speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); } else { - if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); + speculateArray(node.child1(), baseReg); m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); } storageResult(storageReg, m_compileIndex); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h index 96f2fec0a..073dbb42c 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h @@ -2181,6 +2181,10 @@ public: // act of firing a watchpoint invalidates it. So, future recompilations will not // attempt to set this watchpoint again. JumpReplacementWatchpoint* speculationWatchpoint(ExitKind = UncountableWatchpoint); + + // It is generally a good idea to not use this directly. + void convertLastOSRExitToForward(const ValueRecovery& = ValueRecovery()); + // Note: not specifying the valueRecovery argument (leaving it as ValueRecovery()) implies // that you've ensured that there exists a MovHint prior to your use of forwardSpeculationCheck(). void forwardSpeculationCheck(ExitKind, JSValueSource, NodeIndex, MacroAssembler::Jump jumpToFail, const ValueRecovery& = ValueRecovery()); @@ -2190,6 +2194,12 @@ public: void terminateSpeculativeExecution(ExitKind, JSValueRegs, NodeIndex); void terminateSpeculativeExecution(ExitKind, JSValueRegs, Edge); void terminateSpeculativeExecutionWithConditionalDirection(ExitKind, JSValueRegs, NodeIndex, bool isForward); + // Issue a forward speculation watchpoint, which will exit to the next instruction rather + // than the current one. + JumpReplacementWatchpoint* forwardSpeculationWatchpoint(ExitKind = UncountableWatchpoint); + JumpReplacementWatchpoint* speculationWatchpointWithConditionalDirection(ExitKind, bool isForward); + + void speculateArray(Edge baseEdge, GPRReg baseReg); template<bool strict> GPRReg fillSpeculateIntInternal(NodeIndex, DataFormat& returnFormat); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp index bf3503d6d..7a9ba1e41 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp @@ -1530,7 +1530,7 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality( // We know that within this branch, rightChild must not be a cell. Check if that is enough to // prove that it is either null or undefined. - if (!isOtherSpeculation(m_state.forNode(rightChild).m_type & ~SpecCell)) { + if (!isOtherOrEmptySpeculation(m_state.forNode(rightChild).m_type & ~SpecCell)) { m_jit.move(op2TagGPR, resultGPR); m_jit.or32(TrustedImm32(1), resultGPR); @@ -1602,7 +1602,7 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality( // We know that within this branch, rightChild must not be a cell. Check if that is enough to // prove that it is either null or undefined. - if (isOtherSpeculation(m_state.forNode(rightChild).m_type & ~SpecCell)) + if (isOtherOrEmptySpeculation(m_state.forNode(rightChild).m_type & ~SpecCell)) rightNotCell.link(&m_jit); else { jump(notTaken, ForceJump); @@ -1918,7 +1918,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isArraySpeculation(value.m_type) || isCellSpeculation(value.m_type)) { + if (isCellSpeculation(value.m_type)) { GPRTemporary result(this); m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr()); @@ -2036,16 +2036,6 @@ void SpeculativeJIT::compile(Node& node) recordSetLocal(node.local(), ValueSource(Int32InRegisterFile)); break; } - if (isArraySpeculation(predictedType)) { - SpeculateCellOperand cell(this, node.child1()); - GPRReg cellGPR = cell.gpr(); - if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(cellGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(cellGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); - m_jit.storePtr(cellGPR, JITCompiler::payloadFor(node.local())); - noResult(m_compileIndex); - recordSetLocal(node.local(), ValueSource(CellInRegisterFile)); - break; - } if (isCellSpeculation(predictedType)) { SpeculateCellOperand cell(this, node.child1()); GPRReg cellGPR = cell.gpr(); @@ -2356,7 +2346,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (!at(node.child2()).shouldSpeculateInteger() || !isActionableArraySpeculation(at(node.child1()).prediction())) { + if (!at(node.child2()).shouldSpeculateInteger() || (!node.child3() && !at(node.child1()).shouldSpeculateArguments())) { SpeculateCellOperand base(this, node.child1()); // Save a register, speculate cell. We'll probably be right. JSValueOperand property(this, node.child2()); GPRReg baseGPR = base.gpr(); @@ -2449,8 +2439,6 @@ void SpeculativeJIT::compile(Node& node) break; } - ASSERT(at(node.child1()).shouldSpeculateArray()); - SpeculateStrictInt32Operand property(this, node.child2()); StorageOperand storage(this, node.child3()); GPRReg propertyReg = property.gpr(); @@ -2464,17 +2452,13 @@ void SpeculativeJIT::compile(Node& node) { SpeculateCellOperand base(this, node.child1()); GPRReg baseReg = base.gpr(); - if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); + // We've already speculated that it's some kind of array, at this point. speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()))); } GPRTemporary resultTag(this); GPRTemporary resultPayload(this); - // FIXME: In cases where there are subsequent by_val accesses to the same base it might help to cache - // the storage pointer - especially if there happens to be another register free right now. If we do so, - // then we'll need to allocate a new temporary for result. m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag.gpr()); speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::Equal, resultTag.gpr(), TrustedImm32(JSValue::EmptyValueTag))); m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload.gpr()); @@ -2495,7 +2479,6 @@ void SpeculativeJIT::compile(Node& node) } if (!at(child2).shouldSpeculateInteger() - || !isActionableMutableArraySpeculation(at(child1).prediction()) || at(child1).shouldSpeculateArguments()) { SpeculateCellOperand base(this, child1); // Save a register, speculate cell. We'll probably be right. JSValueOperand property(this, child2); @@ -2578,27 +2561,23 @@ void SpeculativeJIT::compile(Node& node) break; } - ASSERT(at(child1).shouldSpeculateArray()); - JSValueOperand value(this, child3); - GPRTemporary scratch(this); - // Map base, property & value into registers, allocate a scratch register. GPRReg baseReg = base.gpr(); GPRReg propertyReg = property.gpr(); GPRReg valueTagReg = value.tagGPR(); GPRReg valuePayloadReg = value.payloadGPR(); - GPRReg scratchReg = scratch.gpr(); if (!m_compileOkay) return; - - writeBarrier(baseReg, valueTagReg, child3, WriteBarrierForPropertyAccess, scratchReg); - // Check that base is an array, and that property is contained within m_vector (< m_vectorLength). - // If we have predicted the base to be type array, we can skip the check. - if (!isArraySpeculation(m_state.forNode(child1).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), child1, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); + { + GPRTemporary scratch(this); + GPRReg scratchReg = scratch.gpr(); + writeBarrier(baseReg, valueTagReg, child3, WriteBarrierForPropertyAccess, scratchReg); + } + + speculateArray(child1, baseReg); MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())); if (node.op() == PutByVal) @@ -2609,7 +2588,8 @@ void SpeculativeJIT::compile(Node& node) value.use(); // Get the array storage. - GPRReg storageReg = scratchReg; + GPRTemporary storage(this); + GPRReg storageReg = storage.gpr(); m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); // Check if we're writing to a hole; if so increment m_numValuesInVector. @@ -2795,20 +2775,23 @@ void SpeculativeJIT::compile(Node& node) case ArrayPush: { SpeculateCellOperand base(this, node.child1()); JSValueOperand value(this, node.child2()); - GPRTemporary storage(this); GPRTemporary storageLength(this); GPRReg baseGPR = base.gpr(); GPRReg valueTagGPR = value.tagGPR(); GPRReg valuePayloadGPR = value.payloadGPR(); - GPRReg storageGPR = storage.gpr(); GPRReg storageLengthGPR = storageLength.gpr(); - writeBarrier(baseGPR, valueTagGPR, node.child2(), WriteBarrierForPropertyAccess, storageGPR, storageLengthGPR); + { + GPRTemporary scratch(this); + writeBarrier(baseGPR, valueTagGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR); + } - if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); + speculateArray(node.child1(), baseGPR); + GPRTemporary storage(this); + GPRReg storageGPR = storage.gpr(); + m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR); m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR); @@ -2844,8 +2827,7 @@ void SpeculativeJIT::compile(Node& node) GPRReg storageGPR = storage.gpr(); GPRReg storageLengthGPR = storageLength.gpr(); - if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); + speculateArray(node.child1(), baseGPR); m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR); m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR); @@ -3395,8 +3377,7 @@ void SpeculativeJIT::compile(Node& node) SpeculateCellOperand base(this, node.child1()); GPRReg baseGPR = base.gpr(); - if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); + speculateArray(node.child1(), baseGPR); GPRTemporary result(this); GPRReg resultGPR = result.gpr(); @@ -3478,7 +3459,7 @@ void SpeculativeJIT::compile(Node& node) case CheckStructure: case ForwardCheckStructure: { AbstractValue& value = m_state.forNode(node.child1()); - if (value.m_structure.isSubsetOf(node.structureSet()) + if (value.m_currentKnownStructure.isSubsetOf(node.structureSet()) && isCellSpeculation(value.m_type)) { noResult(m_compileIndex); break; @@ -3519,9 +3500,12 @@ void SpeculativeJIT::compile(Node& node) break; } - case StructureTransitionWatchpoint: { + case StructureTransitionWatchpoint: + case ForwardStructureTransitionWatchpoint: { m_jit.addWeakReference(node.structure()); - node.structure()->addTransitionWatchpoint(speculationWatchpoint(BadCache)); + node.structure()->addTransitionWatchpoint( + speculationWatchpointWithConditionalDirection( + BadCache, node.op() == ForwardStructureTransitionWatchpoint)); #if !ASSERT_DISABLED SpeculateCellOperand op1(this, node.child1()); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp index 5541113f2..c2151088c 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp @@ -2072,16 +2072,6 @@ void SpeculativeJIT::compile(Node& node) recordSetLocal(node.local(), ValueSource(Int32InRegisterFile)); break; } - if (isArraySpeculation(predictedType)) { - SpeculateCellOperand cell(this, node.child1()); - GPRReg cellGPR = cell.gpr(); - if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueRegs(cellGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(cellGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); - m_jit.storePtr(cellGPR, JITCompiler::addressFor(node.local())); - noResult(m_compileIndex); - recordSetLocal(node.local(), ValueSource(CellInRegisterFile)); - break; - } if (isCellSpeculation(predictedType)) { SpeculateCellOperand cell(this, node.child1()); GPRReg cellGPR = cell.gpr(); @@ -2389,7 +2379,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (!at(node.child2()).shouldSpeculateInteger() || !isActionableArraySpeculation(at(node.child1()).prediction())) { + if (!at(node.child2()).shouldSpeculateInteger() || (!node.child3() && !at(node.child1()).shouldSpeculateArguments())) { JSValueOperand base(this, node.child1()); JSValueOperand property(this, node.child2()); GPRReg baseGPR = base.gpr(); @@ -2480,8 +2470,6 @@ void SpeculativeJIT::compile(Node& node) break; } - ASSERT(at(node.child1()).shouldSpeculateArray()); - SpeculateCellOperand base(this, node.child1()); SpeculateStrictInt32Operand property(this, node.child2()); StorageOperand storage(this, node.child3()); @@ -2493,13 +2481,11 @@ void SpeculativeJIT::compile(Node& node) if (!m_compileOkay) return; - if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueRegs(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); + // We will have already speculated that the base is some kind of array, + // at this point. + speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()))); - // FIXME: In cases where there are subsequent by_val accesses to the same base it might help to cache - // the storage pointer - especially if there happens to be another register free right now. If we do so, - // then we'll need to allocate a new temporary for result. GPRTemporary result(this); m_jit.loadPtr(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), result.gpr()); speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branchTestPtr(MacroAssembler::Zero, result.gpr())); @@ -2519,7 +2505,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (!at(child2).shouldSpeculateInteger() || !isActionableMutableArraySpeculation(at(child1).prediction())) { + if (!at(child2).shouldSpeculateInteger()) { JSValueOperand arg1(this, child1); JSValueOperand arg2(this, child2); JSValueOperand arg3(this, child3); @@ -2537,9 +2523,8 @@ void SpeculativeJIT::compile(Node& node) SpeculateCellOperand base(this, child1); SpeculateStrictInt32Operand property(this, child2); if (at(child1).shouldSpeculateArguments()) { + dataLog(" in here "); JSValueOperand value(this, child3); - SpeculateCellOperand base(this, child1); - SpeculateStrictInt32Operand property(this, child2); GPRTemporary scratch(this); GPRTemporary scratch2(this); @@ -2656,8 +2641,6 @@ void SpeculativeJIT::compile(Node& node) break; } - ASSERT(at(child1).shouldSpeculateArray()); - JSValueOperand value(this, child3); GPRTemporary scratch(this); @@ -2672,11 +2655,8 @@ void SpeculativeJIT::compile(Node& node) writeBarrier(baseReg, value.gpr(), child3, WriteBarrierForPropertyAccess, scratchReg); - // Check that base is an array, and that property is contained within m_vector (< m_vectorLength). - // If we have predicted the base to be type array, we can skip the check. - if (!isArraySpeculation(m_state.forNode(child1).m_type)) - speculationCheck(BadType, JSValueRegs(baseReg), child1, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); - + speculateArray(child1, baseReg); + MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())); if (node.op() == PutByVal) speculationCheck(OutOfBounds, JSValueRegs(), NoNode, beyondArrayBounds); @@ -2879,9 +2859,8 @@ void SpeculativeJIT::compile(Node& node) writeBarrier(baseGPR, valueGPR, node.child2(), WriteBarrierForPropertyAccess, storageGPR, storageLengthGPR); - if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueRegs(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); - + speculateArray(node.child1(), baseGPR); + m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR); m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR); @@ -2917,9 +2896,8 @@ void SpeculativeJIT::compile(Node& node) GPRReg storageGPR = storage.gpr(); GPRReg storageLengthGPR = storageLength.gpr(); - if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueRegs(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); - + speculateArray(node.child1(), baseGPR); + m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR); m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR); @@ -3415,9 +3393,8 @@ void SpeculativeJIT::compile(Node& node) GPRReg baseGPR = base.gpr(); GPRReg resultGPR = result.gpr(); - if (!isArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueRegs(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info))); - + speculateArray(node.child1(), baseGPR); + m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), resultGPR); m_jit.load32(MacroAssembler::Address(resultGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), resultGPR); @@ -3493,7 +3470,7 @@ void SpeculativeJIT::compile(Node& node) case CheckStructure: case ForwardCheckStructure: { AbstractValue& value = m_state.forNode(node.child1()); - if (value.m_structure.isSubsetOf(node.structureSet()) + if (value.m_currentKnownStructure.isSubsetOf(node.structureSet()) && isCellSpeculation(value.m_type)) { noResult(m_compileIndex); break; @@ -3534,9 +3511,12 @@ void SpeculativeJIT::compile(Node& node) break; } - case StructureTransitionWatchpoint: { + case StructureTransitionWatchpoint: + case ForwardStructureTransitionWatchpoint: { m_jit.addWeakReference(node.structure()); - node.structure()->addTransitionWatchpoint(speculationWatchpoint(BadCache)); + node.structure()->addTransitionWatchpoint( + speculationWatchpointWithConditionalDirection( + BadCache, node.op() == ForwardStructureTransitionWatchpoint)); #if !ASSERT_DISABLED SpeculateCellOperand op1(this, node.child1()); diff --git a/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h b/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h new file mode 100644 index 000000000..b3082de1a --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h @@ -0,0 +1,327 @@ +/* + * 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DFGStructureAbstractValue_h +#define DFGStructureAbstractValue_h + +#include <wtf/Platform.h> + +#if ENABLE(DFG_JIT) + +#include "JSCell.h" +#include "SpeculatedType.h" +#include "StructureSet.h" + +namespace JSC { namespace DFG { + +class StructureAbstractValue { +public: + StructureAbstractValue() + : m_structure(0) + { + } + + StructureAbstractValue(Structure* structure) + : m_structure(structure) + { + } + + StructureAbstractValue(const StructureSet& set) + { + switch (set.size()) { + case 0: + m_structure = 0; + break; + + case 1: + m_structure = set[0]; + break; + + default: + m_structure = topValue(); + break; + } + } + + void clear() + { + m_structure = 0; + } + + void makeTop() + { + m_structure = topValue(); + } + + static StructureAbstractValue top() + { + StructureAbstractValue value; + value.makeTop(); + return value; + } + + void add(Structure* structure) + { + ASSERT(!contains(structure) && !isTop()); + if (m_structure) + makeTop(); + else + m_structure = structure; + } + + bool addAll(const StructureSet& other) + { + if (isTop() || !other.size()) + return false; + if (other.size() > 1) { + makeTop(); + return true; + } + if (!m_structure) { + m_structure = other[0]; + return true; + } + if (m_structure == other[0]) + return false; + makeTop(); + return true; + } + + bool addAll(const StructureAbstractValue& other) + { + if (!other.m_structure) + return false; + if (isTop()) + return false; + if (other.isTop()) { + makeTop(); + return true; + } + if (m_structure) { + if (m_structure == other.m_structure) + return false; + makeTop(); + return true; + } + m_structure = other.m_structure; + return true; + } + + bool contains(Structure* structure) const + { + if (isTop()) + return true; + if (m_structure == structure) + return true; + return false; + } + + bool isSubsetOf(const StructureSet& other) const + { + if (isTop()) + return false; + if (!m_structure) + return true; + return other.contains(m_structure); + } + + bool doesNotContainAnyOtherThan(Structure* structure) const + { + if (isTop()) + return false; + if (!m_structure) + return true; + return m_structure == structure; + } + + bool isSupersetOf(const StructureSet& other) const + { + if (isTop()) + return true; + if (!other.size()) + return true; + if (other.size() > 1) + return false; + return m_structure == other[0]; + } + + bool isSubsetOf(const StructureAbstractValue& other) const + { + if (other.isTop()) + return true; + if (isTop()) + return false; + if (m_structure) { + if (other.m_structure) + return m_structure == other.m_structure; + return false; + } + return true; + } + + bool isSupersetOf(const StructureAbstractValue& other) const + { + return other.isSubsetOf(*this); + } + + void filter(const StructureSet& other) + { + if (!m_structure) + return; + + if (isTop()) { + switch (other.size()) { + case 0: + m_structure = 0; + return; + + case 1: + m_structure = other[0]; + return; + + default: + return; + } + } + + if (other.contains(m_structure)) + return; + + m_structure = 0; + } + + void filter(const StructureAbstractValue& other) + { + if (isTop()) { + m_structure = other.m_structure; + return; + } + if (m_structure == other.m_structure) + return; + if (other.isTop()) + return; + m_structure = 0; + } + + void filter(SpeculatedType other) + { + if (!(other & SpecCell)) { + clear(); + return; + } + + if (isClearOrTop()) + return; + + if (!(speculationFromStructure(m_structure) & other)) + m_structure = 0; + } + + bool isClear() const + { + return !m_structure; + } + + bool isTop() const { return m_structure == topValue(); } + + bool isClearOrTop() const { return m_structure <= topValue(); } + bool isNeitherClearNorTop() const { return !isClearOrTop(); } + + size_t size() const + { + ASSERT(!isTop()); + return !!m_structure; + } + + Structure* at(size_t i) const + { + ASSERT(!isTop()); + ASSERT(m_structure); + ASSERT_UNUSED(i, !i); + return m_structure; + } + + Structure* operator[](size_t i) const + { + return at(i); + } + + Structure* last() const + { + return at(0); + } + + SpeculatedType speculationFromStructures() const + { + if (isTop()) + return SpecCell; + if (isClear()) + return SpecNone; + return speculationFromStructure(m_structure); + } + + bool hasSingleton() const + { + return isNeitherClearNorTop(); + } + + Structure* singleton() const + { + ASSERT(isNeitherClearNorTop()); + return m_structure; + } + + bool operator==(const StructureAbstractValue& other) const + { + return m_structure == other.m_structure; + } + + void dump(FILE* out) const + { + if (isTop()) { + fprintf(out, "TOP"); + return; + } + + fprintf(out, "["); + if (m_structure) + fprintf(out, "%p", m_structure); + fprintf(out, "]"); + } + +private: + static Structure* topValue() { return reinterpret_cast<Structure*>(1); } + + // This can only remember one structure at a time. + Structure* m_structure; +}; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGStructureAbstractValue_h + + diff --git a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp index e86c57dff..68627f95c 100644 --- a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp @@ -82,6 +82,7 @@ public: } case ForwardCheckStructure: + case ForwardStructureTransitionWatchpoint: // We currently rely on the fact that we're the only ones who would // insert this node. ASSERT_NOT_REACHED(); @@ -94,6 +95,12 @@ public: case AllocatePropertyStorage: case ReallocatePropertyStorage: case GetPropertyStorage: + case GetByVal: + case PutByVal: + case PutByValAlias: + case PutByValSafe: + case GetArrayLength: + case Phantom: // Don't count these uses. break; @@ -215,17 +222,22 @@ public: break; case PutByVal: - case PutByValAlias: { + case PutByValAlias: + case PutByValSafe: { Edge child1 = m_graph.varArgChild(node, 0); Edge child2 = m_graph.varArgChild(node, 1); if (!m_graph[child1].prediction() || !m_graph[child2].prediction()) break; - if (!m_graph[child2].shouldSpeculateInteger() || !isActionableMutableArraySpeculation(m_graph[child1].prediction())) { + if (!m_graph[child2].shouldSpeculateInteger() +#if USE(JSVALUE32_64) + || m_graph[child1].shouldSpeculateArguments() +#endif + ) { clobber(live); break; } - if (node.op() == PutByValAlias) + if (node.op() != PutByValSafe) break; if (m_graph[child1].shouldSpeculateArguments()) break; @@ -291,7 +303,7 @@ public: dataLog("Hoisting checks for %s\n", m_graph.nameOfVariableAccessData(it->first)); } #endif // DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) - + // Make changes: // 1) If a variable's live range does not span a clobber, then inject structure // checks before the SetLocal. @@ -348,6 +360,8 @@ public: if (block->variablesAtTail.operand(variable->local()) == nodeIndex) block->variablesAtTail.operand(variable->local()) = getLocalIndex; + m_graph.substituteGetLocal(*block, indexInBlock, variable, getLocalIndex); + changed = true; break; } diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp index 51f22bedd..a9118f43b 100644 --- a/Source/JavaScriptCore/interpreter/Interpreter.cpp +++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp @@ -712,7 +712,7 @@ bool Interpreter::isOpcode(Opcode opcode) #if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) || ENABLE(LLINT) #if !ENABLE(LLINT) if (!m_classicEnabled) - return opcode >= 0 && static_cast<OpcodeID>(bitwise_cast<uintptr_t>(opcode)) <= op_end; + return static_cast<OpcodeID>(bitwise_cast<uintptr_t>(opcode)) <= op_end; #endif return opcode != HashTraits<Opcode>::emptyValue() && !HashTraits<Opcode>::isDeletedValue(opcode) diff --git a/Source/JavaScriptCore/jit/JITDriver.h b/Source/JavaScriptCore/jit/JITDriver.h index 6c50f4bd1..7b5cc28eb 100644 --- a/Source/JavaScriptCore/jit/JITDriver.h +++ b/Source/JavaScriptCore/jit/JITDriver.h @@ -38,7 +38,7 @@ namespace JSC { template<typename CodeBlockType> -inline bool jitCompileIfAppropriate(ExecState* exec, OwnPtr<CodeBlockType>& codeBlock, JITCode& jitCode, JITCode::JITType jitType, JITCompilationEffort effort) +inline bool jitCompileIfAppropriate(ExecState* exec, OwnPtr<CodeBlockType>& codeBlock, JITCode& jitCode, JITCode::JITType jitType, unsigned bytecodeIndex, JITCompilationEffort effort) { JSGlobalData& globalData = exec->globalData(); @@ -54,7 +54,7 @@ inline bool jitCompileIfAppropriate(ExecState* exec, OwnPtr<CodeBlockType>& code bool dfgCompiled = false; if (jitType == JITCode::DFGJIT) - dfgCompiled = DFG::tryCompile(exec, codeBlock.get(), jitCode); + dfgCompiled = DFG::tryCompile(exec, codeBlock.get(), jitCode, bytecodeIndex); if (dfgCompiled) { if (codeBlock->alternative()) codeBlock->alternative()->unlinkIncomingCalls(); @@ -75,7 +75,7 @@ inline bool jitCompileIfAppropriate(ExecState* exec, OwnPtr<CodeBlockType>& code return true; } -inline bool jitCompileFunctionIfAppropriate(ExecState* exec, OwnPtr<FunctionCodeBlock>& codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck, SharedSymbolTable*& symbolTable, JITCode::JITType jitType, JITCompilationEffort effort) +inline bool jitCompileFunctionIfAppropriate(ExecState* exec, OwnPtr<FunctionCodeBlock>& codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck, SharedSymbolTable*& symbolTable, JITCode::JITType jitType, unsigned bytecodeIndex, JITCompilationEffort effort) { JSGlobalData& globalData = exec->globalData(); @@ -92,7 +92,7 @@ inline bool jitCompileFunctionIfAppropriate(ExecState* exec, OwnPtr<FunctionCode bool dfgCompiled = false; if (jitType == JITCode::DFGJIT) - dfgCompiled = DFG::tryCompileFunction(exec, codeBlock.get(), jitCode, jitCodeWithArityCheck); + dfgCompiled = DFG::tryCompileFunction(exec, codeBlock.get(), jitCode, jitCodeWithArityCheck, bytecodeIndex); if (dfgCompiled) { if (codeBlock->alternative()) codeBlock->alternative()->unlinkIncomingCalls(); diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp index dfb2dc8ec..16af9125b 100644 --- a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp +++ b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp @@ -110,7 +110,11 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction) zeroExtend32ToPtr(regT1, regT1); emitJumpSlowCaseIfNotJSCell(regT0, base); - addSlowCase(branchPtr(NotEqual, Address(regT0, JSCell::classInfoOffset()), TrustedImmPtr(&JSArray::s_info))); + loadPtr(Address(regT0, JSCell::structureOffset()), regT2); +#if ENABLE(VALUE_PROFILER) + storePtr(regT2, currentInstruction[4].u.arrayProfile->addressOfLastSeenStructure()); +#endif + addSlowCase(branchPtr(NotEqual, Address(regT2, Structure::classInfoOffset()), TrustedImmPtr(&JSArray::s_info))); loadPtr(Address(regT0, JSArray::storageOffset()), regT2); addSlowCase(branch32(AboveOrEqual, regT1, Address(regT0, JSArray::vectorLengthOffset()))); @@ -231,7 +235,11 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction) // See comment in op_get_by_val. zeroExtend32ToPtr(regT1, regT1); emitJumpSlowCaseIfNotJSCell(regT0, base); - addSlowCase(branchPtr(NotEqual, Address(regT0, JSCell::classInfoOffset()), TrustedImmPtr(&JSArray::s_info))); + loadPtr(Address(regT0, JSCell::structureOffset()), regT2); +#if ENABLE(VALUE_PROFILER) + storePtr(regT2, currentInstruction[4].u.arrayProfile->addressOfLastSeenStructure()); +#endif + addSlowCase(branchPtr(NotEqual, Address(regT2, Structure::classInfoOffset()), TrustedImmPtr(&JSArray::s_info))); addSlowCase(branch32(AboveOrEqual, regT1, Address(regT0, JSArray::vectorLengthOffset()))); loadPtr(Address(regT0, JSArray::storageOffset()), regT2); @@ -645,7 +653,11 @@ void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress) StructureStubInfo* stubInfo = &m_codeBlock->getStubInfo(returnAddress); // Check eax is an array - Jump failureCases1 = branchPtr(NotEqual, Address(regT0, JSCell::classInfoOffset()), TrustedImmPtr(&JSArray::s_info)); + loadPtr(Address(regT0, JSCell::structureOffset()), regT3); +#if ENABLE(VALUE_PROFILER) + storePtr(regT3, m_codeBlock->getOrAddArrayProfile(stubInfo->bytecodeIndex)->addressOfLastSeenStructure()); +#endif + Jump failureCases1 = branchPtr(NotEqual, Address(regT3, Structure::classInfoOffset()), TrustedImmPtr(&JSArray::s_info)); // Checks out okay! - get the length from the storage loadPtr(Address(regT0, JSArray::storageOffset()), regT3); diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp index b506f4ecb..6ef25046f 100644 --- a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp +++ b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp @@ -209,7 +209,11 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction) addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag))); emitJumpSlowCaseIfNotJSCell(base, regT1); - addSlowCase(branchPtr(NotEqual, Address(regT0, JSCell::classInfoOffset()), TrustedImmPtr(&JSArray::s_info))); + loadPtr(Address(regT0, JSCell::structureOffset()), regT1); +#if ENABLE(VALUE_PROFILER) + storePtr(regT1, currentInstruction[4].u.arrayProfile->addressOfLastSeenStructure()); +#endif + addSlowCase(branchPtr(NotEqual, Address(regT1, JSCell::classInfoOffset()), TrustedImmPtr(&JSArray::s_info))); loadPtr(Address(regT0, JSArray::storageOffset()), regT3); addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, JSArray::vectorLengthOffset()))); @@ -264,7 +268,11 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction) addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag))); emitJumpSlowCaseIfNotJSCell(base, regT1); - addSlowCase(branchPtr(NotEqual, Address(regT0, JSCell::classInfoOffset()), TrustedImmPtr(&JSArray::s_info))); + loadPtr(Address(regT0, JSCell::structureOffset()), regT1); +#if ENABLE(VALUE_PROFILER) + storePtr(regT1, currentInstruction[4].u.arrayProfile->addressOfLastSeenStructure()); +#endif + addSlowCase(branchPtr(NotEqual, Address(regT1, Structure::classInfoOffset()), TrustedImmPtr(&JSArray::s_info))); addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, JSArray::vectorLengthOffset()))); emitWriteBarrier(regT0, regT1, regT1, regT3, UnconditionalWriteBarrier, WriteBarrierForPropertyAccess); @@ -608,7 +616,11 @@ void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress) // regT0 holds a JSCell* // Check for array - Jump failureCases1 = branchPtr(NotEqual, Address(regT0, JSCell::classInfoOffset()), TrustedImmPtr(&JSArray::s_info)); + loadPtr(Address(regT0, JSCell::structureOffset()), regT2); +#if ENABLE(VALUE_PROFILER) + storePtr(regT2, m_codeBlock->getOrAddArrayProfile(stubInfo->bytecodeIndex)->addressOfLastSeenStructure()); +#endif + Jump failureCases1 = branchPtr(NotEqual, Address(regT2, Structure::classInfoOffset()), TrustedImmPtr(&JSArray::s_info)); // Checks out okay! - get the length from the storage loadPtr(Address(regT0, JSArray::storageOffset()), regT2); diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp index 8b8546994..cb5adc2fa 100644 --- a/Source/JavaScriptCore/jit/JITStubs.cpp +++ b/Source/JavaScriptCore/jit/JITStubs.cpp @@ -2022,8 +2022,7 @@ DEFINE_STUB_FUNCTION(void, optimize) } ScopeChainNode* scopeChain = callFrame->scopeChain(); - - JSObject* error = codeBlock->compileOptimized(callFrame, scopeChain); + JSObject* error = codeBlock->compileOptimized(callFrame, scopeChain, bytecodeIndex); #if ENABLE(JIT_VERBOSE_OSR) if (error) dataLog("WARNING: optimized compilation failed.\n"); diff --git a/Source/JavaScriptCore/llint/LLIntExceptions.cpp b/Source/JavaScriptCore/llint/LLIntExceptions.cpp index 20b0db3d9..a915c42e3 100644 --- a/Source/JavaScriptCore/llint/LLIntExceptions.cpp +++ b/Source/JavaScriptCore/llint/LLIntExceptions.cpp @@ -37,6 +37,14 @@ namespace JSC { namespace LLInt { +static void fixupPCforExceptionIfNeeded(ExecState* exec) +{ + CodeBlock* codeBlock = exec->codeBlock(); + ASSERT(!!codeBlock); + Instruction* pc = exec->currentVPC(); + exec->setCurrentVPC(codeBlock->adjustPCIfAtCallSite(pc)); +} + void interpreterThrowInCaller(ExecState* exec, ReturnAddressPtr pc) { JSGlobalData* globalData = &exec->globalData(); @@ -44,6 +52,7 @@ void interpreterThrowInCaller(ExecState* exec, ReturnAddressPtr pc) #if LLINT_SLOW_PATH_TRACING dataLog("Throwing exception %s.\n", globalData->exception.description()); #endif + fixupPCforExceptionIfNeeded(exec); genericThrow( globalData, exec, globalData->exception, exec->codeBlock()->bytecodeOffset(exec, pc)); @@ -61,6 +70,7 @@ Instruction* returnToThrow(ExecState* exec, Instruction* pc) #if LLINT_SLOW_PATH_TRACING dataLog("Throwing exception %s (returnToThrow).\n", globalData->exception.description()); #endif + fixupPCforExceptionIfNeeded(exec); genericThrow(globalData, exec, globalData->exception, pc - exec->codeBlock()->instructions().begin()); return globalData->llintData.exceptionInstructions(); @@ -73,6 +83,7 @@ void* callToThrow(ExecState* exec, Instruction* pc) #if LLINT_SLOW_PATH_TRACING dataLog("Throwing exception %s (callToThrow).\n", globalData->exception.description()); #endif + fixupPCforExceptionIfNeeded(exec); genericThrow(globalData, exec, globalData->exception, pc - exec->codeBlock()->instructions().begin()); return bitwise_cast<void*>(&llint_throw_during_call_trampoline); diff --git a/Source/JavaScriptCore/llint/LLIntOffsetsExtractor.cpp b/Source/JavaScriptCore/llint/LLIntOffsetsExtractor.cpp index f863cb218..cbb4258d0 100644 --- a/Source/JavaScriptCore/llint/LLIntOffsetsExtractor.cpp +++ b/Source/JavaScriptCore/llint/LLIntOffsetsExtractor.cpp @@ -25,6 +25,7 @@ #include "config.h" +#include "ArrayProfile.h" #include "CodeBlock.h" #include "Executable.h" #include "Heap.h" diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm index b8115dd6b..5f280ce1b 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm @@ -1255,14 +1255,19 @@ _llint_op_put_by_id_transition_normal_out_of_line: _llint_op_get_by_val: traceExecution() - loadp CodeBlock[cfr], t1 loadi 8[PC], t2 loadi 12[PC], t3 - loadp CodeBlock::m_globalData[t1], t1 loadConstantOrVariablePayload(t2, CellTag, t0, .opGetByValSlow) - loadp JSGlobalData::jsArrayClassInfo[t1], t2 loadConstantOrVariablePayload(t3, Int32Tag, t1, .opGetByValSlow) - bpneq [t0], t2, .opGetByValSlow + loadp JSCell::m_structure[t0], t3 + loadp 16[PC], t2 + if VALUE_PROFILER + storep t3, ArrayProfile::m_lastSeenStructure[t2] + end + loadp CodeBlock[cfr], t2 + loadp CodeBlock::m_globalData[t2], t2 + loadp JSGlobalData::jsArrayClassInfo[t2], t2 + bpneq Structure::m_classInfo[t3], t2, .opGetByValSlow loadp JSArray::m_storage[t0], t3 biaeq t1, JSArray::m_vectorLength[t0], .opGetByValSlow loadi 4[PC], t0 @@ -1271,16 +1276,18 @@ _llint_op_get_by_val: bieq t2, EmptyValueTag, .opGetByValSlow storei t2, TagOffset[cfr, t0, 8] storei t1, PayloadOffset[cfr, t0, 8] - loadi 16[PC], t0 + loadi 20[PC], t0 valueProfile(t2, t1, t0) - dispatch(5) + dispatch(6) .opGetByValSlow: callSlowPath(_llint_slow_path_get_by_val) - dispatch(5) + dispatch(6) _llint_op_get_argument_by_val: + # FIXME: At some point we should array profile this. Right now it isn't necessary + # since the DFG will never turn a get_argument_by_val into a GetByVal. traceExecution() loadi 8[PC], t0 loadi 12[PC], t1 @@ -1293,15 +1300,15 @@ _llint_op_get_argument_by_val: loadi 4[PC], t3 loadi ThisArgumentOffset + TagOffset[cfr, t2, 8], t0 loadi ThisArgumentOffset + PayloadOffset[cfr, t2, 8], t1 - loadi 16[PC], t2 + loadi 20[PC], t2 storei t0, TagOffset[cfr, t3, 8] storei t1, PayloadOffset[cfr, t3, 8] valueProfile(t0, t1, t2) - dispatch(5) + dispatch(6) .opGetArgumentByValSlow: callSlowPath(_llint_slow_path_get_argument_by_val) - dispatch(5) + dispatch(6) _llint_op_get_by_pname: @@ -1338,10 +1345,15 @@ _llint_op_put_by_val: loadConstantOrVariablePayload(t0, CellTag, t1, .opPutByValSlow) loadi 8[PC], t0 loadConstantOrVariablePayload(t0, Int32Tag, t2, .opPutByValSlow) + loadp JSCell::m_structure[t1], t3 + loadp 16[PC], t0 + if VALUE_PROFILER + storep t3, ArrayProfile::m_lastSeenStructure[t0] + end loadp CodeBlock[cfr], t0 loadp CodeBlock::m_globalData[t0], t0 loadp JSGlobalData::jsArrayClassInfo[t0], t0 - bpneq [t1], t0, .opPutByValSlow + bpneq Structure::m_classInfo[t3], t0, .opPutByValSlow biaeq t2, JSArray::m_vectorLength[t1], .opPutByValSlow loadp JSArray::m_storage[t1], t0 bieq ArrayStorage::m_vector + TagOffset[t0, t2, 8], EmptyValueTag, .opPutByValEmpty @@ -1351,7 +1363,7 @@ _llint_op_put_by_val: writeBarrier(t1, t3) storei t1, ArrayStorage::m_vector + TagOffset[t0, t2, 8] storei t3, ArrayStorage::m_vector + PayloadOffset[t0, t2, 8] - dispatch(4) + dispatch(5) .opPutByValEmpty: addi 1, ArrayStorage::m_numValuesInVector[t0] @@ -1362,7 +1374,7 @@ _llint_op_put_by_val: .opPutByValSlow: callSlowPath(_llint_slow_path_put_by_val) - dispatch(4) + dispatch(5) _llint_op_loop: diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm index 6e752a6d0..f1a7e2998 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm @@ -1099,31 +1099,38 @@ _llint_op_put_by_id_transition_normal_out_of_line: _llint_op_get_by_val: traceExecution() - loadp CodeBlock[cfr], t1 loadis 16[PB, PC, 8], t2 loadis 24[PB, PC, 8], t3 - loadp CodeBlock::m_globalData[t1], t1 loadConstantOrVariableCell(t2, t0, .opGetByValSlow) - loadp JSGlobalData::jsArrayClassInfo[t1], t2 loadConstantOrVariableInt32(t3, t1, .opGetByValSlow) sxi2p t1, t1 - bpneq [t0], t2, .opGetByValSlow + loadp JSCell::m_structure[t0], t3 + loadp 32[PB, PC, 8], t2 + if VALUE_PROFILER + storep t3, ArrayProfile::m_lastSeenStructure[t2] + end + loadp CodeBlock[cfr], t2 + loadp CodeBlock::m_globalData[t2], t2 + loadp JSGlobalData::jsArrayClassInfo[t2], t2 + bpneq Structure::m_classInfo[t3], t2, .opGetByValSlow loadp JSArray::m_storage[t0], t3 biaeq t1, JSArray::m_vectorLength[t0], .opGetByValSlow loadis 8[PB, PC, 8], t0 loadp ArrayStorage::m_vector[t3, t1, 8], t2 btpz t2, .opGetByValSlow storep t2, [cfr, t0, 8] - loadp 32[PB, PC, 8], t0 + loadp 40[PB, PC, 8], t0 valueProfile(t2, t0) - dispatch(5) + dispatch(6) .opGetByValSlow: callSlowPath(_llint_slow_path_get_by_val) - dispatch(5) + dispatch(6) _llint_op_get_argument_by_val: + # FIXME: At some point we should array profile this. Right now it isn't necessary + # since the DFG will never turn a get_argument_by_val into a GetByVal. traceExecution() loadis 16[PB, PC, 8], t0 loadis 24[PB, PC, 8], t1 @@ -1139,11 +1146,11 @@ _llint_op_get_argument_by_val: loadp ThisArgumentOffset[cfr, t2, 8], t0 storep t0, [cfr, t3, 8] valueProfile(t0, t1) - dispatch(5) + dispatch(6) .opGetArgumentByValSlow: callSlowPath(_llint_slow_path_get_argument_by_val) - dispatch(5) + dispatch(6) _llint_op_get_by_pname: @@ -1182,10 +1189,15 @@ _llint_op_put_by_val: loadis 16[PB, PC, 8], t0 loadConstantOrVariableInt32(t0, t2, .opPutByValSlow) sxi2p t2, t2 + loadp JSCell::m_structure[t1], t3 + loadp 32[PB, PC, 8], t0 + if VALUE_PROFILER + storep t3, ArrayProfile::m_lastSeenStructure[t0] + end loadp CodeBlock[cfr], t0 loadp CodeBlock::m_globalData[t0], t0 loadp JSGlobalData::jsArrayClassInfo[t0], t0 - bpneq [t1], t0, .opPutByValSlow + bpneq Structure::m_classInfo[t3], t0, .opPutByValSlow biaeq t2, JSArray::m_vectorLength[t1], .opPutByValSlow loadp JSArray::m_storage[t1], t0 btpz ArrayStorage::m_vector[t0, t2, 8], .opPutByValEmpty @@ -1194,7 +1206,7 @@ _llint_op_put_by_val: loadConstantOrVariable(t3, t1) writeBarrier(t1) storep t1, ArrayStorage::m_vector[t0, t2, 8] - dispatch(4) + dispatch(5) .opPutByValEmpty: addi 1, ArrayStorage::m_numValuesInVector[t0] @@ -1205,7 +1217,7 @@ _llint_op_put_by_val: .opPutByValSlow: callSlowPath(_llint_slow_path_put_by_val) - dispatch(4) + dispatch(5) _llint_op_loop: diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp index 73b4b6c4f..50bb5ffae 100644 --- a/Source/JavaScriptCore/runtime/Executable.cpp +++ b/Source/JavaScriptCore/runtime/Executable.cpp @@ -160,13 +160,13 @@ void FunctionExecutable::destroy(JSCell* cell) static_cast<FunctionExecutable*>(cell)->FunctionExecutable::~FunctionExecutable(); } -JSObject* EvalExecutable::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode) +JSObject* EvalExecutable::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode, unsigned bytecodeIndex) { ASSERT(exec->globalData().dynamicGlobalObject); ASSERT(!!m_evalCodeBlock); JSObject* error = 0; if (m_evalCodeBlock->getJITType() != JITCode::topTierJIT()) - error = compileInternal(exec, scopeChainNode, JITCode::nextTierJIT(m_evalCodeBlock->getJITType())); + error = compileInternal(exec, scopeChainNode, JITCode::nextTierJIT(m_evalCodeBlock->getJITType()), bytecodeIndex); ASSERT(!!m_evalCodeBlock); return error; } @@ -174,7 +174,7 @@ JSObject* EvalExecutable::compileOptimized(ExecState* exec, ScopeChainNode* scop #if ENABLE(JIT) bool EvalExecutable::jitCompile(ExecState* exec) { - return jitCompileIfAppropriate(exec, m_evalCodeBlock, m_jitCodeForCall, JITCode::bottomTierJIT(), JITCompilationCanFail); + return jitCompileIfAppropriate(exec, m_evalCodeBlock, m_jitCodeForCall, JITCode::bottomTierJIT(), UINT_MAX, JITCompilationCanFail); } #endif @@ -193,12 +193,13 @@ inline const char* samplingDescription(JITCode::JITType jitType) } } -JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType) +JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType, unsigned bytecodeIndex) { SamplingRegion samplingRegion(samplingDescription(jitType)); #if !ENABLE(JIT) UNUSED_PARAM(jitType); + UNUSED_PARAM(bytecodeIndex); #endif JSObject* exception = 0; JSGlobalData* globalData = &exec->globalData(); @@ -235,7 +236,7 @@ JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scope } #if ENABLE(JIT) - if (!prepareForExecution(exec, m_evalCodeBlock, m_jitCodeForCall, jitType)) + if (!prepareForExecution(exec, m_evalCodeBlock, m_jitCodeForCall, jitType, bytecodeIndex)) return 0; #endif @@ -301,13 +302,13 @@ JSObject* ProgramExecutable::checkSyntax(ExecState* exec) return exception; } -JSObject* ProgramExecutable::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode) +JSObject* ProgramExecutable::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode, unsigned bytecodeIndex) { ASSERT(exec->globalData().dynamicGlobalObject); ASSERT(!!m_programCodeBlock); JSObject* error = 0; if (m_programCodeBlock->getJITType() != JITCode::topTierJIT()) - error = compileInternal(exec, scopeChainNode, JITCode::nextTierJIT(m_programCodeBlock->getJITType())); + error = compileInternal(exec, scopeChainNode, JITCode::nextTierJIT(m_programCodeBlock->getJITType()), bytecodeIndex); ASSERT(!!m_programCodeBlock); return error; } @@ -315,16 +316,17 @@ JSObject* ProgramExecutable::compileOptimized(ExecState* exec, ScopeChainNode* s #if ENABLE(JIT) bool ProgramExecutable::jitCompile(ExecState* exec) { - return jitCompileIfAppropriate(exec, m_programCodeBlock, m_jitCodeForCall, JITCode::bottomTierJIT(), JITCompilationCanFail); + return jitCompileIfAppropriate(exec, m_programCodeBlock, m_jitCodeForCall, JITCode::bottomTierJIT(), UINT_MAX, JITCompilationCanFail); } #endif -JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType) +JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType, unsigned bytecodeIndex) { SamplingRegion samplingRegion(samplingDescription(jitType)); #if !ENABLE(JIT) UNUSED_PARAM(jitType); + UNUSED_PARAM(bytecodeIndex); #endif JSObject* exception = 0; JSGlobalData* globalData = &exec->globalData(); @@ -359,7 +361,7 @@ JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* sc } #if ENABLE(JIT) - if (!prepareForExecution(exec, m_programCodeBlock, m_jitCodeForCall, jitType)) + if (!prepareForExecution(exec, m_programCodeBlock, m_jitCodeForCall, jitType, bytecodeIndex)) return 0; #endif @@ -431,24 +433,24 @@ FunctionCodeBlock* FunctionExecutable::baselineCodeBlockFor(CodeSpecializationKi return result; } -JSObject* FunctionExecutable::compileOptimizedForCall(ExecState* exec, ScopeChainNode* scopeChainNode) +JSObject* FunctionExecutable::compileOptimizedForCall(ExecState* exec, ScopeChainNode* scopeChainNode, unsigned bytecodeIndex) { ASSERT(exec->globalData().dynamicGlobalObject); ASSERT(!!m_codeBlockForCall); JSObject* error = 0; if (m_codeBlockForCall->getJITType() != JITCode::topTierJIT()) - error = compileForCallInternal(exec, scopeChainNode, JITCode::nextTierJIT(m_codeBlockForCall->getJITType())); + error = compileForCallInternal(exec, scopeChainNode, JITCode::nextTierJIT(m_codeBlockForCall->getJITType()), bytecodeIndex); ASSERT(!!m_codeBlockForCall); return error; } -JSObject* FunctionExecutable::compileOptimizedForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode) +JSObject* FunctionExecutable::compileOptimizedForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode, unsigned bytecodeIndex) { ASSERT(exec->globalData().dynamicGlobalObject); ASSERT(!!m_codeBlockForConstruct); JSObject* error = 0; if (m_codeBlockForConstruct->getJITType() != JITCode::topTierJIT()) - error = compileForConstructInternal(exec, scopeChainNode, JITCode::nextTierJIT(m_codeBlockForConstruct->getJITType())); + error = compileForConstructInternal(exec, scopeChainNode, JITCode::nextTierJIT(m_codeBlockForConstruct->getJITType()), bytecodeIndex); ASSERT(!!m_codeBlockForConstruct); return error; } @@ -456,12 +458,12 @@ JSObject* FunctionExecutable::compileOptimizedForConstruct(ExecState* exec, Scop #if ENABLE(JIT) bool FunctionExecutable::jitCompileForCall(ExecState* exec) { - return jitCompileFunctionIfAppropriate(exec, m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, m_symbolTable, JITCode::bottomTierJIT(), JITCompilationCanFail); + return jitCompileFunctionIfAppropriate(exec, m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, m_symbolTable, JITCode::bottomTierJIT(), UINT_MAX, JITCompilationCanFail); } bool FunctionExecutable::jitCompileForConstruct(ExecState* exec) { - return jitCompileFunctionIfAppropriate(exec, m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, m_symbolTable, JITCode::bottomTierJIT(), JITCompilationCanFail); + return jitCompileFunctionIfAppropriate(exec, m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, m_symbolTable, JITCode::bottomTierJIT(), UINT_MAX, JITCompilationCanFail); } #endif @@ -502,7 +504,7 @@ PassOwnPtr<FunctionCodeBlock> FunctionExecutable::produceCodeBlockFor(ScopeChain return result.release(); } -JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType) +JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType, unsigned bytecodeIndex) { SamplingRegion samplingRegion(samplingDescription(jitType)); @@ -510,6 +512,7 @@ JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChain UNUSED_PARAM(exec); UNUSED_PARAM(jitType); UNUSED_PARAM(exec); + UNUSED_PARAM(bytecodeIndex); #endif ASSERT((jitType == JITCode::bottomTierJIT()) == !m_codeBlockForCall); JSObject* exception; @@ -526,7 +529,7 @@ JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChain m_symbolTable = m_codeBlockForCall->sharedSymbolTable(); #if ENABLE(JIT) - if (!prepareFunctionForExecution(exec, m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, m_symbolTable, jitType, CodeForCall)) + if (!prepareFunctionForExecution(exec, m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, m_symbolTable, jitType, bytecodeIndex, CodeForCall)) return 0; #endif @@ -544,13 +547,14 @@ JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChain return 0; } -JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType) +JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType, unsigned bytecodeIndex) { SamplingRegion samplingRegion(samplingDescription(jitType)); #if !ENABLE(JIT) UNUSED_PARAM(jitType); UNUSED_PARAM(exec); + UNUSED_PARAM(bytecodeIndex); #endif ASSERT((jitType == JITCode::bottomTierJIT()) == !m_codeBlockForConstruct); @@ -568,7 +572,7 @@ JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, Scope m_symbolTable = m_codeBlockForConstruct->sharedSymbolTable(); #if ENABLE(JIT) - if (!prepareFunctionForExecution(exec, m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, m_symbolTable, jitType, CodeForConstruct)) + if (!prepareFunctionForExecution(exec, m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, m_symbolTable, jitType, bytecodeIndex, CodeForConstruct)) return 0; #endif diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h index 2f6c6a253..2e5ba28ca 100644 --- a/Source/JavaScriptCore/runtime/Executable.h +++ b/Source/JavaScriptCore/runtime/Executable.h @@ -377,7 +377,7 @@ namespace JSC { return error; } - JSObject* compileOptimized(ExecState*, ScopeChainNode*); + JSObject* compileOptimized(ExecState*, ScopeChainNode*, unsigned bytecodeIndex); #if ENABLE(JIT) void jettisonOptimizedCode(JSGlobalData&); @@ -418,7 +418,7 @@ namespace JSC { static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags; EvalExecutable(ExecState*, const SourceCode&, bool); - JSObject* compileInternal(ExecState*, ScopeChainNode*, JITCode::JITType); + JSObject* compileInternal(ExecState*, ScopeChainNode*, JITCode::JITType, unsigned bytecodeIndex = UINT_MAX); static void visitChildren(JSCell*, SlotVisitor&); OwnPtr<EvalCodeBlock> m_evalCodeBlock; @@ -448,7 +448,7 @@ namespace JSC { return error; } - JSObject* compileOptimized(ExecState*, ScopeChainNode*); + JSObject* compileOptimized(ExecState*, ScopeChainNode*, unsigned bytecodeIndex); #if ENABLE(JIT) void jettisonOptimizedCode(JSGlobalData&); @@ -485,7 +485,7 @@ namespace JSC { static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags; ProgramExecutable(ExecState*, const SourceCode&); - JSObject* compileInternal(ExecState*, ScopeChainNode*, JITCode::JITType); + JSObject* compileInternal(ExecState*, ScopeChainNode*, JITCode::JITType, unsigned bytecodeIndex = UINT_MAX); static void visitChildren(JSCell*, SlotVisitor&); OwnPtr<ProgramCodeBlock> m_programCodeBlock; @@ -543,7 +543,7 @@ namespace JSC { return error; } - JSObject* compileOptimizedForCall(ExecState*, ScopeChainNode*); + JSObject* compileOptimizedForCall(ExecState*, ScopeChainNode*, unsigned bytecodeIndex); #if ENABLE(JIT) void jettisonOptimizedCodeForCall(JSGlobalData&); @@ -571,7 +571,7 @@ namespace JSC { return error; } - JSObject* compileOptimizedForConstruct(ExecState*, ScopeChainNode*); + JSObject* compileOptimizedForConstruct(ExecState*, ScopeChainNode*, unsigned bytecodeIndex); #if ENABLE(JIT) void jettisonOptimizedCodeForConstruct(JSGlobalData&); @@ -601,16 +601,16 @@ namespace JSC { return compileForConstruct(exec, scopeChainNode); } - JSObject* compileOptimizedFor(ExecState* exec, ScopeChainNode* scopeChainNode, CodeSpecializationKind kind) + JSObject* compileOptimizedFor(ExecState* exec, ScopeChainNode* scopeChainNode, unsigned bytecodeIndex, CodeSpecializationKind kind) { ASSERT(exec->callee()); ASSERT(exec->callee()->inherits(&JSFunction::s_info)); ASSERT(jsCast<JSFunction*>(exec->callee())->jsExecutable() == this); if (kind == CodeForCall) - return compileOptimizedForCall(exec, scopeChainNode); + return compileOptimizedForCall(exec, scopeChainNode, bytecodeIndex); ASSERT(kind == CodeForConstruct); - return compileOptimizedForConstruct(exec, scopeChainNode); + return compileOptimizedForConstruct(exec, scopeChainNode, bytecodeIndex); } #if ENABLE(JIT) @@ -691,8 +691,8 @@ namespace JSC { FunctionExecutable(JSGlobalData&, const Identifier& name, const Identifier& inferredName, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool); FunctionExecutable(ExecState*, const Identifier& name, const Identifier& inferredName, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool); - JSObject* compileForCallInternal(ExecState*, ScopeChainNode*, JITCode::JITType); - JSObject* compileForConstructInternal(ExecState*, ScopeChainNode*, JITCode::JITType); + JSObject* compileForCallInternal(ExecState*, ScopeChainNode*, JITCode::JITType, unsigned bytecodeIndex = UINT_MAX); + JSObject* compileForConstructInternal(ExecState*, ScopeChainNode*, JITCode::JITType, unsigned bytecodeIndex = UINT_MAX); OwnPtr<FunctionCodeBlock>& codeBlockFor(CodeSpecializationKind kind) { diff --git a/Source/JavaScriptCore/runtime/ExecutionHarness.h b/Source/JavaScriptCore/runtime/ExecutionHarness.h index 4cc37f3b7..3a876402e 100644 --- a/Source/JavaScriptCore/runtime/ExecutionHarness.h +++ b/Source/JavaScriptCore/runtime/ExecutionHarness.h @@ -36,7 +36,7 @@ namespace JSC { template<typename CodeBlockType> -inline bool prepareForExecution(ExecState* exec, OwnPtr<CodeBlockType>& codeBlock, JITCode& jitCode, JITCode::JITType jitType) +inline bool prepareForExecution(ExecState* exec, OwnPtr<CodeBlockType>& codeBlock, JITCode& jitCode, JITCode::JITType jitType, unsigned bytecodeIndex) { #if ENABLE(LLINT) if (JITCode::isBaselineCode(jitType)) { @@ -46,10 +46,10 @@ inline bool prepareForExecution(ExecState* exec, OwnPtr<CodeBlockType>& codeBloc return true; } #endif // ENABLE(LLINT) - return jitCompileIfAppropriate(exec, codeBlock, jitCode, jitType, JITCode::isBaselineCode(jitType) ? JITCompilationMustSucceed : JITCompilationCanFail); + return jitCompileIfAppropriate(exec, codeBlock, jitCode, jitType, bytecodeIndex, JITCode::isBaselineCode(jitType) ? JITCompilationMustSucceed : JITCompilationCanFail); } -inline bool prepareFunctionForExecution(ExecState* exec, OwnPtr<FunctionCodeBlock>& codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck, SharedSymbolTable*& symbolTable, JITCode::JITType jitType, CodeSpecializationKind kind) +inline bool prepareFunctionForExecution(ExecState* exec, OwnPtr<FunctionCodeBlock>& codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck, SharedSymbolTable*& symbolTable, JITCode::JITType jitType, unsigned bytecodeIndex, CodeSpecializationKind kind) { #if ENABLE(LLINT) if (JITCode::isBaselineCode(jitType)) { @@ -61,7 +61,7 @@ inline bool prepareFunctionForExecution(ExecState* exec, OwnPtr<FunctionCodeBloc #else UNUSED_PARAM(kind); #endif // ENABLE(LLINT) - return jitCompileFunctionIfAppropriate(exec, codeBlock, jitCode, jitCodeWithArityCheck, symbolTable, jitType, JITCode::isBaselineCode(jitType) ? JITCompilationMustSucceed : JITCompilationCanFail); + return jitCompileFunctionIfAppropriate(exec, codeBlock, jitCode, jitCodeWithArityCheck, symbolTable, jitType, bytecodeIndex, JITCode::isBaselineCode(jitType) ? JITCompilationMustSucceed : JITCompilationCanFail); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h index ee0b573d9..0b9c92210 100644 --- a/Source/JavaScriptCore/runtime/Structure.h +++ b/Source/JavaScriptCore/runtime/Structure.h @@ -322,6 +322,11 @@ namespace JSC { { return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::typeOffset(); } + + static ptrdiff_t classInfoOffset() + { + return OBJECT_OFFSETOF(Structure, m_classInfo); + } static Structure* createStructure(JSGlobalData&); diff --git a/Source/JavaScriptCore/shell/PlatformEfl.cmake b/Source/JavaScriptCore/shell/PlatformEfl.cmake index c35af2d51..53755727b 100644 --- a/Source/JavaScriptCore/shell/PlatformEfl.cmake +++ b/Source/JavaScriptCore/shell/PlatformEfl.cmake @@ -1,5 +1,5 @@ LIST(APPEND JSC_LIBRARIES - ${Glib_LIBRARIES} + ${GLIB_LIBRARIES} ${ECORE_LIBRARIES} ${CMAKE_DL_LIBS} ) |