diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-06-20 13:01:08 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-06-20 13:01:08 +0200 |
commit | 49233e234e5c787396cadb2cea33b31ae0cd65c1 (patch) | |
tree | 5410cb9a8fd53168bb60d62c54b654d86f03c38d /Source/JavaScriptCore | |
parent | b211c645d8ab690f713515dfdc84d80b11c27d2c (diff) | |
download | qtwebkit-49233e234e5c787396cadb2cea33b31ae0cd65c1.tar.gz |
Imported WebKit commit 3a8c29f35d00659d2ce7a0ccdfa8304f14e82327 (http://svn.webkit.org/repository/webkit/trunk@120813)
New snapshot with Windows build fixes
Diffstat (limited to 'Source/JavaScriptCore')
199 files changed, 22630 insertions, 4169 deletions
diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt index dc00849e3..24e67b940 100644 --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt @@ -7,6 +7,7 @@ SET(JavaScriptCore_INCLUDE_DIRECTORIES "${JAVASCRIPTCORE_DIR}/bytecode" "${JAVASCRIPTCORE_DIR}/bytecompiler" "${JAVASCRIPTCORE_DIR}/dfg" + "${JAVASCRIPTCORE_DIR}/disassembler" "${JAVASCRIPTCORE_DIR}/heap" "${JAVASCRIPTCORE_DIR}/debugger" "${JAVASCRIPTCORE_DIR}/interpreter" @@ -35,6 +36,8 @@ SET(JavaScriptCore_SOURCES API/JSValueRef.cpp API/JSWeakObjectMapRefPrivate.cpp API/OpaqueJSString.cpp + + assembler/LinkBuffer.cpp bytecode/CallLinkInfo.cpp bytecode/CallLinkStatus.cpp @@ -49,10 +52,11 @@ SET(JavaScriptCore_SOURCES bytecode/MethodOfGettingAValueProfile.cpp bytecode/Opcode.cpp bytecode/PolymorphicPutByIdList.cpp - bytecode/PredictedType.cpp + bytecode/SpeculatedType.cpp bytecode/PutByIdStatus.cpp bytecode/SamplingTool.cpp bytecode/StructureStubInfo.cpp + bytecode/Watchpoint.cpp bytecompiler/BytecodeGenerator.cpp bytecompiler/NodesCodegen.cpp @@ -97,6 +101,7 @@ SET(JavaScriptCore_SOURCES heap/HandleSet.cpp heap/HandleStack.cpp heap/Heap.cpp + heap/HeapTimer.cpp heap/IncrementalSweeper.cpp heap/MachineStackMarker.cpp heap/MarkedAllocator.cpp @@ -186,9 +191,11 @@ SET(JavaScriptCore_SOURCES runtime/JSObject.cpp runtime/JSONObject.cpp runtime/JSPropertyNameIterator.cpp + runtime/JSSegmentedVariableObject.cpp runtime/JSStaticScopeObject.cpp runtime/JSString.cpp runtime/JSStringJoiner.cpp + runtime/JSSymbolTableObject.cpp runtime/JSValue.cpp runtime/JSVariableObject.cpp runtime/JSWrapperObject.cpp @@ -229,6 +236,7 @@ SET(JavaScriptCore_SOURCES runtime/StringRecursionChecker.cpp runtime/Structure.cpp runtime/StructureChain.cpp + runtime/SymbolTable.cpp runtime/TimeoutChecker.cpp runtime/UString.cpp diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog index 807d83297..aafc84dca 100644 --- a/Source/JavaScriptCore/ChangeLog +++ b/Source/JavaScriptCore/ChangeLog @@ -1,3 +1,3143 @@ +2012-06-19 Filip Pizlo <fpizlo@apple.com> + + JSC should be able to show disassembly for all generated JIT code + https://bugs.webkit.org/show_bug.cgi?id=89536 + + Reviewed by Gavin Barraclough. + + Now instead of doing linkBuffer.finalizeCode(), you do + FINALIZE_CODE(linkBuffer, (... explanation ...)). FINALIZE_CODE() then + prints your explanation and the disassembled code, if + Options::showDisassembly is set to true. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * Target.pri: + * assembler/LinkBuffer.cpp: Added. + (JSC): + (JSC::LinkBuffer::finalizeCodeWithoutDisassembly): + (JSC::LinkBuffer::finalizeCodeWithDisassembly): + (JSC::LinkBuffer::linkCode): + (JSC::LinkBuffer::performFinalization): + (JSC::LinkBuffer::dumpLinkStatistics): + (JSC::LinkBuffer::dumpCode): + * assembler/LinkBuffer.h: + (LinkBuffer): + (JSC): + * assembler/MacroAssemblerCodeRef.h: + (JSC::MacroAssemblerCodeRef::tryToDisassemble): + (MacroAssemblerCodeRef): + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::compile): + (JSC::DFG::JITCompiler::compileFunction): + * dfg/DFGOSRExitCompiler.cpp: + * dfg/DFGRepatch.cpp: + (JSC::DFG::generateProtoChainAccessStub): + (JSC::DFG::tryCacheGetByID): + (JSC::DFG::tryBuildGetByIDList): + (JSC::DFG::emitPutReplaceStub): + (JSC::DFG::emitPutTransitionStub): + * dfg/DFGThunks.cpp: + (JSC::DFG::osrExitGenerationThunkGenerator): + * disassembler/Disassembler.h: + (JSC): + (JSC::tryToDisassemble): + * disassembler/UDis86Disassembler.cpp: + (JSC::tryToDisassemble): + * jit/JIT.cpp: + (JSC::JIT::privateCompile): + * jit/JITCode.h: + (JSC::JITCode::tryToDisassemble): + * jit/JITOpcodes.cpp: + (JSC::JIT::privateCompileCTIMachineTrampolines): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::privateCompileCTIMachineTrampolines): + (JSC::JIT::privateCompileCTINativeCall): + * jit/JITPropertyAccess.cpp: + (JSC::JIT::stringGetByValStubGenerator): + (JSC::JIT::privateCompilePutByIdTransition): + (JSC::JIT::privateCompilePatchGetArrayLength): + (JSC::JIT::privateCompileGetByIdProto): + (JSC::JIT::privateCompileGetByIdSelfList): + (JSC::JIT::privateCompileGetByIdProtoList): + (JSC::JIT::privateCompileGetByIdChainList): + (JSC::JIT::privateCompileGetByIdChain): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::stringGetByValStubGenerator): + (JSC::JIT::privateCompilePutByIdTransition): + (JSC::JIT::privateCompilePatchGetArrayLength): + (JSC::JIT::privateCompileGetByIdProto): + (JSC::JIT::privateCompileGetByIdSelfList): + (JSC::JIT::privateCompileGetByIdProtoList): + (JSC::JIT::privateCompileGetByIdChainList): + (JSC::JIT::privateCompileGetByIdChain): + * jit/SpecializedThunkJIT.h: + (JSC::SpecializedThunkJIT::finalize): + * jit/ThunkGenerators.cpp: + (JSC::charCodeAtThunkGenerator): + (JSC::charAtThunkGenerator): + (JSC::fromCharCodeThunkGenerator): + (JSC::sqrtThunkGenerator): + (JSC::floorThunkGenerator): + (JSC::ceilThunkGenerator): + (JSC::roundThunkGenerator): + (JSC::expThunkGenerator): + (JSC::logThunkGenerator): + (JSC::absThunkGenerator): + (JSC::powThunkGenerator): + * llint/LLIntThunks.cpp: + (JSC::LLInt::generateThunkWithJumpTo): + (JSC::LLInt::functionForCallEntryThunkGenerator): + (JSC::LLInt::functionForConstructEntryThunkGenerator): + (JSC::LLInt::functionForCallArityCheckThunkGenerator): + (JSC::LLInt::functionForConstructArityCheckThunkGenerator): + (JSC::LLInt::evalEntryThunkGenerator): + (JSC::LLInt::programEntryThunkGenerator): + * runtime/Options.cpp: + (Options): + (JSC::Options::initializeOptions): + * runtime/Options.h: + (Options): + * yarr/YarrJIT.cpp: + (JSC::Yarr::YarrGenerator::compile): + +2012-06-19 Mark Hahnenberg <mhahnenberg@apple.com> + + [Qt][Mac] REGRESSION(r120742): It broke the build + https://bugs.webkit.org/show_bug.cgi?id=89516 + + Reviewed by Geoffrey Garen. + + Removing GCActivityCallbackCF.cpp because it doesn't mesh well with cross-platform + code on Darwin (e.g. Qt). We now use plain ol' vanilla ifdefs to handle platforms + without CF support. These if-defs will probably disappear in the future when we + use cross-platform timers in HeapTimer. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * runtime/GCActivityCallback.cpp: + (JSC): + (JSC::DefaultGCActivityCallback::DefaultGCActivityCallback): + (JSC::DefaultGCActivityCallback::doWork): + (JSC::DefaultGCActivityCallback::scheduleTimer): + (JSC::DefaultGCActivityCallback::cancelTimer): + (JSC::DefaultGCActivityCallback::didAllocate): + (JSC::DefaultGCActivityCallback::willCollect): + (JSC::DefaultGCActivityCallback::cancel): + * runtime/GCActivityCallbackCF.cpp: Removed. + +2012-06-19 Filip Pizlo <fpizlo@apple.com> + + DFG CFA forgets to notify subsequent phases of found constants if it proves LogicalNot to be a constant + https://bugs.webkit.org/show_bug.cgi?id=89511 + <rdar://problem/11700089> + + Reviewed by Geoffrey Garen. + + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::execute): + +2012-06-19 Mark Lam <mark.lam@apple.com> + + CodeBlock::needsCallReturnIndices() is no longer needed. + https://bugs.webkit.org/show_bug.cgi?id=89490 + + Reviewed by Geoffrey Garen. + + * bytecode/CodeBlock.h: + (JSC::CodeBlock::needsCallReturnIndices): removed. + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::link): + * jit/JIT.cpp: + (JSC::JIT::privateCompile): + +2012-06-19 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, try to fix Windows build. + + * JavaScriptCore.vcproj/JavaScriptCore/copy-files.cmd: + +2012-06-17 Filip Pizlo <fpizlo@apple.com> + + It should be possible to look at disassembly + https://bugs.webkit.org/show_bug.cgi?id=89319 + + Reviewed by Sam Weinig. + + This imports the udis86 disassembler library. The library is placed + behind an abstraction in disassembler/Disassembler.h, so that we can + in the future use other disassemblers (for other platforms) whenever + appropriate. As a first step, the disassembler is being invoked for + DFG verbose dumps. + + If we ever want to merge a new version of udis86 in the future, I've + made notes about changes I made to the library in + disassembler/udis86/differences.txt. + + * CMakeLists.txt: + * DerivedSources.make: + * GNUmakefile.list.am: + * JavaScriptCore.pri: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCommon.vsprops: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::compile): + (JSC::DFG::JITCompiler::compileFunction): + * disassembler: Added. + * disassembler/Disassembler.h: Added. + (JSC): + (JSC::tryToDisassemble): + * disassembler/UDis86Disassembler.cpp: Added. + (JSC): + (JSC::tryToDisassemble): + * disassembler/udis86: Added. + * disassembler/udis86/differences.txt: Added. + * disassembler/udis86/itab.py: Added. + (UdItabGenerator): + (UdItabGenerator.__init__): + (UdItabGenerator.toGroupId): + (UdItabGenerator.genLookupTable): + (UdItabGenerator.genLookupTableList): + (UdItabGenerator.genInsnTable): + (genItabH): + (genItabH.UD_ITAB_H): + (genItabC): + (genItab): + (main): + * disassembler/udis86/optable.xml: Added. + * disassembler/udis86/ud_opcode.py: Added. + (UdOpcodeTables): + (UdOpcodeTables.sizeOfTable): + (UdOpcodeTables.nameOfTable): + (UdOpcodeTables.updateTable): + (UdOpcodeTables.Insn): + (UdOpcodeTables.Insn.__init__): + (UdOpcodeTables.Insn.__init__.opcode): + (UdOpcodeTables.parse): + (UdOpcodeTables.addInsnDef): + (UdOpcodeTables.print_table): + (UdOpcodeTables.print_tree): + * disassembler/udis86/ud_optable.py: Added. + (UdOptableXmlParser): + (UdOptableXmlParser.parseDef): + (UdOptableXmlParser.parse): + (printFn): + (parse): + (main): + * disassembler/udis86/udis86.c: Added. + (ud_init): + (ud_disassemble): + (ud_set_mode): + (ud_set_vendor): + (ud_set_pc): + (ud): + (ud_insn_asm): + (ud_insn_off): + (ud_insn_hex): + (ud_insn_ptr): + (ud_insn_len): + * disassembler/udis86/udis86.h: Added. + * disassembler/udis86/udis86_decode.c: Added. + (eff_adr_mode): + (ud_lookup_mnemonic): + (decode_prefixes): + (modrm): + (resolve_operand_size): + (resolve_mnemonic): + (decode_a): + (decode_gpr): + (resolve_gpr64): + (resolve_gpr32): + (resolve_reg): + (decode_imm): + (decode_modrm_reg): + (decode_modrm_rm): + (decode_o): + (decode_operand): + (decode_operands): + (clear_insn): + (resolve_mode): + (gen_hex): + (decode_insn): + (decode_3dnow): + (decode_ssepfx): + (decode_ext): + (decode_opcode): + (ud_decode): + * disassembler/udis86/udis86_decode.h: Added. + (ud_itab_entry_operand): + (ud_itab_entry): + (ud_lookup_table_list_entry): + (sse_pfx_idx): + (mode_idx): + (modrm_mod_idx): + (vendor_idx): + (is_group_ptr): + (group_idx): + * disassembler/udis86/udis86_extern.h: Added. + * disassembler/udis86/udis86_input.c: Added. + (inp_buff_hook): + (inp_file_hook): + (ud): + (ud_set_user_opaque_data): + (ud_get_user_opaque_data): + (ud_set_input_buffer): + (ud_set_input_file): + (ud_input_skip): + (ud_input_end): + (ud_inp_next): + (ud_inp_back): + (ud_inp_peek): + (ud_inp_move): + (ud_inp_uint8): + (ud_inp_uint16): + (ud_inp_uint32): + (ud_inp_uint64): + * disassembler/udis86/udis86_input.h: Added. + * disassembler/udis86/udis86_itab_holder.c: Added. + * disassembler/udis86/udis86_syn-att.c: Added. + (opr_cast): + (gen_operand): + (ud_translate_att): + * disassembler/udis86/udis86_syn-intel.c: Added. + (opr_cast): + (gen_operand): + (ud_translate_intel): + * disassembler/udis86/udis86_syn.c: Added. + * disassembler/udis86/udis86_syn.h: Added. + (mkasm): + * disassembler/udis86/udis86_types.h: Added. + (ud_operand): + (ud): + * jit/JITCode.h: + (JITCode): + (JSC::JITCode::tryToDisassemble): + +2012-06-19 Mark Hahnenberg <mhahnenberg@apple.com> + + GCActivityCallback and IncrementalSweeper should share code + https://bugs.webkit.org/show_bug.cgi?id=89400 + + Reviewed by Geoffrey Garen. + + A lot of functionality is duplicated between GCActivityCallback and IncrementalSweeper. + We should extract the common functionality out into a separate class that both of them + can inherit from. This refactoring will be an even greater boon when we add the ability + to shut these two agents down in a thread-safe fashion + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * Target.pri: + * heap/Heap.cpp: + (JSC::Heap::Heap): Move initialization down so that the JSGlobalData has a valid Heap when + we're initializing the GCActivityCallback and the IncrementalSweeper. + * heap/Heap.h: + (Heap): + * heap/HeapTimer.cpp: Added. + (JSC): + (JSC::HeapTimer::HeapTimer): Initialize the various base class data that + DefaultGCActivityCallback::commonConstructor() used to do. + (JSC::HeapTimer::~HeapTimer): Call to invalidate(). + (JSC::HeapTimer::synchronize): Same functionality as the old DefaultGCActivityCallback::synchronize(). + Virtual so that non-CF subclasses can override. + (JSC::HeapTimer::invalidate): Tears down the runloop timer to prevent any future firing. + (JSC::HeapTimer::timerDidFire): Callback to pass to the timer function. Casts and calls the virtual doWork(). + * heap/HeapTimer.h: Added. This is the class that serves as the common base class for + both GCActivityCallback and IncrementalSweeper. It handles setting up and tearing down run loops and synchronizing + across threads for its subclasses. + (JSC): + (HeapTimer): + * heap/IncrementalSweeper.cpp: Changes to accomodate the extraction of common functionality + between IncrementalSweeper and GCActivityCallback into a common ancestor. + (JSC): + (JSC::IncrementalSweeper::doWork): + (JSC::IncrementalSweeper::IncrementalSweeper): + (JSC::IncrementalSweeper::cancelTimer): + (JSC::IncrementalSweeper::create): + * heap/IncrementalSweeper.h: + (IncrementalSweeper): + * runtime/GCActivityCallback.cpp: + (JSC::DefaultGCActivityCallback::DefaultGCActivityCallback): + (JSC::DefaultGCActivityCallback::doWork): + * runtime/GCActivityCallback.h: + (GCActivityCallback): + (JSC::GCActivityCallback::willCollect): + (JSC::GCActivityCallback::GCActivityCallback): + (JSC): + (DefaultGCActivityCallback): Remove the platform data struct. The platform data should be kept in + the class itself so as to be accessible by doWork(). Most of the platform data for CF is kept in + HeapTimer anyways, so we only need the m_delay field now. + * runtime/GCActivityCallbackBlackBerry.cpp: + (JSC): + (JSC::DefaultGCActivityCallback::DefaultGCActivityCallback): + (JSC::DefaultGCActivityCallback::doWork): + (JSC::DefaultGCActivityCallback::didAllocate): + * runtime/GCActivityCallbackCF.cpp: + (JSC): + (JSC::DefaultGCActivityCallback::DefaultGCActivityCallback): + (JSC::DefaultGCActivityCallback::doWork): + (JSC::DefaultGCActivityCallback::scheduleTimer): + (JSC::DefaultGCActivityCallback::cancelTimer): + (JSC::DefaultGCActivityCallback::didAllocate): + (JSC::DefaultGCActivityCallback::willCollect): + (JSC::DefaultGCActivityCallback::cancel): + + +2012-06-19 Mike West <mkwst@chromium.org> + + Introduce ENABLE_CSP_NEXT configuration flag. + https://bugs.webkit.org/show_bug.cgi?id=89300 + + Reviewed by Adam Barth. + + The 1.0 draft of the Content Security Policy spec is just about to + move to Last Call. We'll hide work on the upcoming 1.1 spec behind + this ENABLE flag, disabled by default. + + Spec: https://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html + + * Configurations/FeatureDefines.xcconfig: + +2012-06-18 Mark Lam <mark.lam@apple.com> + + Changed JSC to always record line number information so that error.stack + and window.onerror() can report proper line numbers. + https://bugs.webkit.org/show_bug.cgi?id=89410 + + Reviewed by Geoffrey Garen. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::lineNumberForBytecodeOffset): + (JSC::CodeBlock::shrinkToFit): m_lineInfo is now available unconditionally. + + * bytecode/CodeBlock.h: + (JSC::CodeBlock::addLineInfo): + (JSC::CodeBlock::hasLineInfo): Unused. Now removed. + (JSC::CodeBlock::needsCallReturnIndices): + (CodeBlock): + (RareData): Hoisted m_lineInfo out of m_rareData. m_lineInfo is now + filled in unconditionally. + + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::addLineInfo): + +2012-06-18 Andy Estes <aestes@apple.com> + + Fix r120663, which didn't land the change that was reviewed. + +2012-06-18 Andy Estes <aestes@apple.com> + + [JSC] In JSGlobalData.cpp, enableAssembler() sometimes leaks two CF objects + https://bugs.webkit.org/show_bug.cgi?id=89415 + + Reviewed by Sam Weinig. + + In the case where canUseJIT was a non-NULL CFBooleanRef, + enableAssembler() would leak both canUseJITKey and canUseJIT by + returning before calling CFRelease. Fix this by using RetainPtr. + + * runtime/JSGlobalData.cpp: + (JSC::enableAssembler): + +2012-06-17 Geoffrey Garen <ggaren@apple.com> + + GC copy phase spends needless cycles zero-filling blocks + https://bugs.webkit.org/show_bug.cgi?id=89128 + + Reviewed by Gavin Barraclough. + + We only need to zero-fill when we're allocating memory that might not + get fully initialized before GC. + + * heap/CopiedBlock.h: + (JSC::CopiedBlock::createNoZeroFill): + (JSC::CopiedBlock::create): Added a way to create without zero-filling. + This is our optimization. + + (JSC::CopiedBlock::zeroFillToEnd): + (JSC::CopiedBlock::CopiedBlock): Split zero-filling out from creation, + so we can sometimes create without zero-filling. + + * heap/CopiedSpace.cpp: + (JSC::CopiedSpace::init): + (JSC::CopiedSpace::tryAllocateSlowCase): + (JSC::CopiedSpace::doneCopying): Renamed addNewBlock to allocateBlock() + to clarify that the new block is always newly-allocated. + + (JSC::CopiedSpace::doneFillingBlock): Make sure to zero-fill to the end + of a block that might be used in the future for allocation. (Most of the + time, this is a no-op, since we've already filled the block completely.) + + (JSC::CopiedSpace::getFreshBlock): Removed this function because the + abstraction of "allocation must succeed" is no longer useful. + + * heap/CopiedSpace.h: Updated declarations to match. + + * heap/CopiedSpaceInlineMethods.h: + (JSC::CopiedSpace::allocateBlockForCopyingPhase): New function, which + knows that it can skip zero-filling. + + Added tighter scoping to our lock, to improve parallelism. + + (JSC::CopiedSpace::allocateBlock): Folded getFreshBlock functionality + into this function, for simplicity. + + * heap/MarkStack.cpp: + (JSC::SlotVisitor::startCopying): + (JSC::SlotVisitor::allocateNewSpace): Use our new zero-fill-free helper + function for great good. + +2012-06-17 Filip Pizlo <fpizlo@apple.com> + + DFG should attempt to use structure watchpoints for all inlined get_by_id's and put_by_id's + https://bugs.webkit.org/show_bug.cgi?id=89316 + + Reviewed by Oliver Hunt. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::addStructureTransitionCheck): + (ByteCodeParser): + (JSC::DFG::ByteCodeParser::handleGetById): + (JSC::DFG::ByteCodeParser::parseBlock): + +2012-06-15 Yong Li <yoli@rim.com> + + [BlackBerry] Put platform-specific GC policy in GCActivityCallback + https://bugs.webkit.org/show_bug.cgi?id=89236 + + Reviewed by Rob Buis. + + Add GCActivityCallbackBlackBerry.cpp and implement platform-specific + low memory GC policy there. + + * PlatformBlackBerry.cmake: + * heap/Heap.h: + (JSC::Heap::isSafeToCollect): Added. + * runtime/GCActivityCallbackBlackBerry.cpp: Added. + (JSC): + (JSC::DefaultGCActivityCallbackPlatformData::DefaultGCActivityCallbackPlatformData): + (DefaultGCActivityCallbackPlatformData): + (JSC::DefaultGCActivityCallback::DefaultGCActivityCallback): + (JSC::DefaultGCActivityCallback::~DefaultGCActivityCallback): + (JSC::DefaultGCActivityCallback::didAllocate): + (JSC::DefaultGCActivityCallback::willCollect): + (JSC::DefaultGCActivityCallback::synchronize): + (JSC::DefaultGCActivityCallback::cancel): + +2012-06-15 Filip Pizlo <fpizlo@apple.com> + + DFG should be able to set watchpoints on structure transitions in the + method check prototype chain + https://bugs.webkit.org/show_bug.cgi?id=89058 + + Adding the same assertion to 32-bit that I added to 64-bit. This change + does not affect correctness but it's a good thing for assertion coverage. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + +2012-06-13 Filip Pizlo <fpizlo@apple.com> + + DFG should be able to set watchpoints on structure transitions in the + method check prototype chain + https://bugs.webkit.org/show_bug.cgi?id=89058 + + Reviewed by Gavin Barraclough. + + This adds the ability to set watchpoints on Structures, and then does + the most modest thing we can do with this ability: the DFG now sets + watchpoints on structure transitions in the prototype chain of method + checks. + + This appears to be a >1% speed-up on V8. + + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeFromLLInt): + (JSC::PutByIdStatus::computeFor): + * bytecode/StructureSet.h: + (JSC::StructureSet::containsOnly): + (StructureSet): + * bytecode/Watchpoint.cpp: + (JSC::WatchpointSet::WatchpointSet): + (JSC::InlineWatchpointSet::add): + (JSC): + (JSC::InlineWatchpointSet::inflateSlow): + (JSC::InlineWatchpointSet::freeFat): + * bytecode/Watchpoint.h: + (WatchpointSet): + (JSC): + (InlineWatchpointSet): + (JSC::InlineWatchpointSet::InlineWatchpointSet): + (JSC::InlineWatchpointSet::~InlineWatchpointSet): + (JSC::InlineWatchpointSet::hasBeenInvalidated): + (JSC::InlineWatchpointSet::isStillValid): + (JSC::InlineWatchpointSet::startWatching): + (JSC::InlineWatchpointSet::notifyWrite): + (JSC::InlineWatchpointSet::isFat): + (JSC::InlineWatchpointSet::fat): + (JSC::InlineWatchpointSet::inflate): + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::execute): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::addStructureTransitionCheck): + (ByteCodeParser): + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::structureTransitionWatchpointElimination): + (CSEPhase): + (JSC::DFG::CSEPhase::performNodeCSE): + * dfg/DFGCommon.h: + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dump): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::isCellConstant): + * dfg/DFGJITCompiler.h: + (JSC::DFG::JITCompiler::addWeakReferences): + (JITCompiler): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasStructure): + (Node): + (JSC::DFG::Node::structure): + * dfg/DFGNodeType.h: + (DFG): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGRepatch.cpp: + (JSC::DFG::emitPutTransitionStub): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * jit/JITStubs.cpp: + (JSC::JITThunks::tryCachePutByID): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * runtime/Structure.cpp: + (JSC::Structure::Structure): + * runtime/Structure.h: + (JSC::Structure::transitionWatchpointSetHasBeenInvalidated): + (Structure): + (JSC::Structure::transitionWatchpointSetIsStillValid): + (JSC::Structure::addTransitionWatchpoint): + (JSC::Structure::notifyTransitionFromThisStructure): + (JSC::JSCell::setStructure): + * runtime/SymbolTable.cpp: + (JSC::SymbolTableEntry::attemptToWatch): + +2012-06-13 Filip Pizlo <fpizlo@apple.com> + + DFG should be able to set watchpoints on global variables + https://bugs.webkit.org/show_bug.cgi?id=88692 + + Reviewed by Geoffrey Garen. + + Rolling back in after fixing Windows build issues, and implementing + branchTest8 for the Qt port's strange assemblers. + + This implements global variable constant folding by allowing the optimizing + compiler to set a "watchpoint" on globals that it wishes to constant fold. + If the watchpoint fires, then an OSR exit is forced by overwriting the + machine code that the optimizing compiler generated with a jump. + + As such, this patch is adding quite a bit of stuff: + + - Jump replacement on those hardware targets supported by the optimizing + JIT. It is now possible to patch in a jump instruction over any recorded + watchpoint label. The jump must be "local" in the sense that it must be + within the range of the largest jump distance supported by a one + instruction jump. + + - WatchpointSets and Watchpoints. A Watchpoint is a doubly-linked list node + that records the location where a jump must be inserted and the + destination to which it should jump. Watchpoints can be added to a + WatchpointSet. The WatchpointSet can be fired all at once, which plants + all jumps. WatchpointSet also remembers if it had ever been invalidated, + which allows for monotonicity: we typically don't want to optimize using + watchpoints on something for which watchpoints had previously fired. The + act of notifying a WatchpointSet has a trivial fast path in case no + Watchpoints are registered (one-byte load+branch). + + - SpeculativeJIT::speculationWatchpoint(). It's like speculationCheck(), + except that you don't have to emit branches. But, you need to know what + WatchpointSet to add the resulting Watchpoint to. Not everything that + you could write a speculationCheck() for will have a WatchpointSet that + would get notified if the condition you were speculating against became + invalid. + + - SymbolTableEntry now has the ability to refer to a WatchpointSet. It can + do so without incurring any space overhead for those entries that don't + have WatchpointSets. + + - The bytecode generator infers all global function variables to be + watchable, and makes all stores perform the WatchpointSet's write check, + and marks all loads as being potentially watchable (i.e. you can compile + them to a watchpoint and a constant). + + Put together, this allows for fully sleazy inlining of calls to globally + declared functions. The inline prologue will no longer contain the load of + the function, or any checks of the function you're calling. I.e. it's + pretty much like the kind of inlining you would see in Java or C++. + Furthermore, the watchpointing functionality is built to be fairly general, + and should allow setting watchpoints on all sorts of interesting things + in the future. + + The sleazy inlining means that we will now sometimes inline in code paths + that have never executed. Previously, to inline we would have either had + to have executed the call (to read the call's inline cache) or have + executed the method check (to read the method check's inline cache). Now, + we might inline when the callee is a watched global variable. This + revealed some humorous bugs. First, constant folding disagreed with CFA + over what kinds of operations can clobber (example: code path A is dead + but stores a String into variable X, all other code paths store 0 into + X, and then you do CompareEq(X, 0) - CFA will say that this is a non- + clobbering constant, but constant folding thought it was clobbering + because it saw the String prediction). Second, inlining would crash if + the inline callee had not been compiled. This patch fixes both bugs, + since otherwise run-javascriptcore-tests would report regressions. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * Target.pri: + * assembler/ARMv7Assembler.h: + (ARMv7Assembler): + (JSC::ARMv7Assembler::ARMv7Assembler): + (JSC::ARMv7Assembler::labelForWatchpoint): + (JSC::ARMv7Assembler::label): + (JSC::ARMv7Assembler::replaceWithJump): + (JSC::ARMv7Assembler::maxJumpReplacementSize): + * assembler/AbstractMacroAssembler.h: + (JSC): + (AbstractMacroAssembler): + (Label): + (JSC::AbstractMacroAssembler::watchpointLabel): + (JSC::AbstractMacroAssembler::readPointer): + * assembler/AssemblerBuffer.h: + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::branchTest8): + (MacroAssemblerARM): + (JSC::MacroAssemblerARM::replaceWithJump): + (JSC::MacroAssemblerARM::maxJumpReplacementSize): + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::load8Signed): + (JSC::MacroAssemblerARMv7::load16Signed): + (MacroAssemblerARMv7): + (JSC::MacroAssemblerARMv7::replaceWithJump): + (JSC::MacroAssemblerARMv7::maxJumpReplacementSize): + (JSC::MacroAssemblerARMv7::branchTest8): + (JSC::MacroAssemblerARMv7::jump): + (JSC::MacroAssemblerARMv7::makeBranch): + * assembler/MacroAssemblerMIPS.h: + (JSC::MacroAssemblerMIPS::branchTest8): + (MacroAssemblerMIPS): + (JSC::MacroAssemblerMIPS::replaceWithJump): + (JSC::MacroAssemblerMIPS::maxJumpReplacementSize): + * assembler/MacroAssemblerSH4.h: + (JSC::MacroAssemblerSH4::branchTest8): + (MacroAssemblerSH4): + (JSC::MacroAssemblerSH4::replaceWithJump): + (JSC::MacroAssemblerSH4::maxJumpReplacementSize): + * assembler/MacroAssemblerX86.h: + (MacroAssemblerX86): + (JSC::MacroAssemblerX86::branchTest8): + * assembler/MacroAssemblerX86Common.h: + (JSC::MacroAssemblerX86Common::replaceWithJump): + (MacroAssemblerX86Common): + (JSC::MacroAssemblerX86Common::maxJumpReplacementSize): + * assembler/MacroAssemblerX86_64.h: + (MacroAssemblerX86_64): + (JSC::MacroAssemblerX86_64::branchTest8): + * assembler/X86Assembler.h: + (JSC::X86Assembler::X86Assembler): + (X86Assembler): + (JSC::X86Assembler::cmpb_im): + (JSC::X86Assembler::testb_im): + (JSC::X86Assembler::labelForWatchpoint): + (JSC::X86Assembler::label): + (JSC::X86Assembler::replaceWithJump): + (JSC::X86Assembler::maxJumpReplacementSize): + (JSC::X86Assembler::X86InstructionFormatter::memoryModRM): + * bytecode/CodeBlock.cpp: + (JSC): + (JSC::CodeBlock::printGetByIdCacheStatus): + (JSC::CodeBlock::dump): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::appendOSRExit): + (JSC::CodeBlock::appendSpeculationRecovery): + (CodeBlock): + (JSC::CodeBlock::appendWatchpoint): + (JSC::CodeBlock::numberOfWatchpoints): + (JSC::CodeBlock::watchpoint): + (DFGData): + * bytecode/DFGExitProfile.h: + (JSC::DFG::exitKindToString): + (JSC::DFG::exitKindIsCountable): + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeForChain): + * bytecode/Instruction.h: + (Instruction): + (JSC::Instruction::Instruction): + * bytecode/Opcode.h: + (JSC): + (JSC::padOpcodeName): + * bytecode/Watchpoint.cpp: Added. + (JSC): + (JSC::Watchpoint::~Watchpoint): + (JSC::Watchpoint::correctLabels): + (JSC::Watchpoint::fire): + (JSC::WatchpointSet::WatchpointSet): + (JSC::WatchpointSet::~WatchpointSet): + (JSC::WatchpointSet::add): + (JSC::WatchpointSet::notifyWriteSlow): + (JSC::WatchpointSet::fireAllWatchpoints): + * bytecode/Watchpoint.h: Added. + (JSC): + (Watchpoint): + (JSC::Watchpoint::Watchpoint): + (JSC::Watchpoint::setDestination): + (WatchpointSet): + (JSC::WatchpointSet::isStillValid): + (JSC::WatchpointSet::hasBeenInvalidated): + (JSC::WatchpointSet::startWatching): + (JSC::WatchpointSet::notifyWrite): + (JSC::WatchpointSet::addressOfIsWatched): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::ResolveResult::checkValidity): + (JSC::BytecodeGenerator::addGlobalVar): + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::resolve): + (JSC::BytecodeGenerator::emitResolve): + (JSC::BytecodeGenerator::emitResolveWithBase): + (JSC::BytecodeGenerator::emitResolveWithThis): + (JSC::BytecodeGenerator::emitGetStaticVar): + (JSC::BytecodeGenerator::emitPutStaticVar): + * bytecompiler/BytecodeGenerator.h: + (BytecodeGenerator): + * bytecompiler/NodesCodegen.cpp: + (JSC::FunctionCallResolveNode::emitBytecode): + (JSC::PostfixResolveNode::emitBytecode): + (JSC::PrefixResolveNode::emitBytecode): + (JSC::ReadModifyResolveNode::emitBytecode): + (JSC::AssignResolveNode::emitBytecode): + (JSC::ConstDeclNode::emitCodeSingle): + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::execute): + (JSC::DFG::AbstractState::clobberStructures): + * dfg/DFGAbstractState.h: + (AbstractState): + (JSC::DFG::AbstractState::didClobber): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleInlining): + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCCallHelpers.h: + (CCallHelpers): + (JSC::DFG::CCallHelpers::setupArguments): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::globalVarWatchpointElimination): + (CSEPhase): + (JSC::DFG::CSEPhase::globalVarStoreElimination): + (JSC::DFG::CSEPhase::performNodeCSE): + * dfg/DFGCapabilities.h: + (JSC::DFG::canCompileOpcode): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::run): + * dfg/DFGCorrectableJumpPoint.h: + (JSC::DFG::CorrectableJumpPoint::isSet): + (CorrectableJumpPoint): + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::linkOSRExits): + (JSC::DFG::JITCompiler::link): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasIdentifierNumberForCheck): + (Node): + (JSC::DFG::Node::identifierNumberForCheck): + (JSC::DFG::Node::hasRegisterPointer): + * dfg/DFGNodeType.h: + (DFG): + * dfg/DFGOSRExit.cpp: + (JSC::DFG::OSRExit::OSRExit): + * dfg/DFGOSRExit.h: + (OSRExit): + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::callOperation): + (JSC::DFG::SpeculativeJIT::appendCall): + (SpeculativeJIT): + (JSC::DFG::SpeculativeJIT::speculationWatchpoint): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + (JSC::JIT::privateCompileSlowCases): + * jit/JIT.h: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_put_global_var_check): + (JSC): + (JSC::JIT::emitSlow_op_put_global_var_check): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emit_op_put_global_var_check): + (JSC): + (JSC::JIT::emitSlow_op_put_global_var_check): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + (JSC): + * jit/JITStubs.h: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + (LLInt): + * llint/LLIntSlowPaths.h: + (LLInt): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/JSObject.cpp: + (JSC::JSObject::removeDirect): + * runtime/JSObject.h: + (JSObject): + * runtime/JSSymbolTableObject.h: + (JSC::symbolTableGet): + (JSC::symbolTablePut): + (JSC::symbolTablePutWithAttributes): + * runtime/SymbolTable.cpp: Added. + (JSC): + (JSC::SymbolTableEntry::copySlow): + (JSC::SymbolTableEntry::freeFatEntrySlow): + (JSC::SymbolTableEntry::couldBeWatched): + (JSC::SymbolTableEntry::attemptToWatch): + (JSC::SymbolTableEntry::addressOfIsWatched): + (JSC::SymbolTableEntry::addWatchpoint): + (JSC::SymbolTableEntry::notifyWriteSlow): + (JSC::SymbolTableEntry::inflateSlow): + * runtime/SymbolTable.h: + (JSC): + (SymbolTableEntry): + (Fast): + (JSC::SymbolTableEntry::Fast::Fast): + (JSC::SymbolTableEntry::Fast::isNull): + (JSC::SymbolTableEntry::Fast::getIndex): + (JSC::SymbolTableEntry::Fast::isReadOnly): + (JSC::SymbolTableEntry::Fast::getAttributes): + (JSC::SymbolTableEntry::Fast::isFat): + (JSC::SymbolTableEntry::SymbolTableEntry): + (JSC::SymbolTableEntry::~SymbolTableEntry): + (JSC::SymbolTableEntry::operator=): + (JSC::SymbolTableEntry::isNull): + (JSC::SymbolTableEntry::getIndex): + (JSC::SymbolTableEntry::getFast): + (JSC::SymbolTableEntry::getAttributes): + (JSC::SymbolTableEntry::isReadOnly): + (JSC::SymbolTableEntry::watchpointSet): + (JSC::SymbolTableEntry::notifyWrite): + (FatEntry): + (JSC::SymbolTableEntry::FatEntry::FatEntry): + (JSC::SymbolTableEntry::isFat): + (JSC::SymbolTableEntry::fatEntry): + (JSC::SymbolTableEntry::inflate): + (JSC::SymbolTableEntry::bits): + (JSC::SymbolTableEntry::freeFatEntry): + (JSC::SymbolTableEntry::pack): + (JSC::SymbolTableEntry::isValidIndex): + +2012-06-13 Sheriff Bot <webkit.review.bot@gmail.com> + + Unreviewed, rolling out r120172. + http://trac.webkit.org/changeset/120172 + https://bugs.webkit.org/show_bug.cgi?id=88976 + + The patch causes compilation failures on Gtk, Qt and Apple Win + bots (Requested by zdobersek on #webkit). + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * Target.pri: + * assembler/ARMv7Assembler.h: + (JSC::ARMv7Assembler::nop): + (JSC::ARMv7Assembler::label): + (JSC::ARMv7Assembler::readPointer): + (ARMv7Assembler): + * assembler/AbstractMacroAssembler.h: + (JSC): + (AbstractMacroAssembler): + (Label): + * assembler/AssemblerBuffer.h: + * assembler/MacroAssemblerARM.h: + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::nop): + (JSC::MacroAssemblerARMv7::jump): + (JSC::MacroAssemblerARMv7::makeBranch): + * assembler/MacroAssemblerMIPS.h: + * assembler/MacroAssemblerSH4.h: + * assembler/MacroAssemblerX86.h: + (MacroAssemblerX86): + (JSC::MacroAssemblerX86::moveWithPatch): + * assembler/MacroAssemblerX86Common.h: + * assembler/MacroAssemblerX86_64.h: + (JSC::MacroAssemblerX86_64::branchTest8): + * assembler/X86Assembler.h: + (JSC::X86Assembler::cmpb_im): + (JSC::X86Assembler::codeSize): + (JSC::X86Assembler::label): + (JSC::X86Assembler::X86InstructionFormatter::memoryModRM): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::appendOSRExit): + (JSC::CodeBlock::appendSpeculationRecovery): + (DFGData): + * bytecode/DFGExitProfile.h: + (JSC::DFG::exitKindToString): + (JSC::DFG::exitKindIsCountable): + * bytecode/Instruction.h: + * bytecode/Opcode.h: + (JSC): + (JSC::padOpcodeName): + * bytecode/Watchpoint.cpp: Removed. + * bytecode/Watchpoint.h: Removed. + * bytecompiler/BytecodeGenerator.cpp: + (JSC::ResolveResult::checkValidity): + (JSC::BytecodeGenerator::addGlobalVar): + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::resolve): + (JSC::BytecodeGenerator::emitResolve): + (JSC::BytecodeGenerator::emitResolveWithBase): + (JSC::BytecodeGenerator::emitResolveWithThis): + (JSC::BytecodeGenerator::emitGetStaticVar): + (JSC::BytecodeGenerator::emitPutStaticVar): + * bytecompiler/BytecodeGenerator.h: + (BytecodeGenerator): + * bytecompiler/NodesCodegen.cpp: + (JSC::FunctionCallResolveNode::emitBytecode): + (JSC::PostfixResolveNode::emitBytecode): + (JSC::PrefixResolveNode::emitBytecode): + (JSC::ReadModifyResolveNode::emitBytecode): + (JSC::AssignResolveNode::emitBytecode): + (JSC::ConstDeclNode::emitCodeSingle): + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::execute): + (JSC::DFG::AbstractState::clobberStructures): + * dfg/DFGAbstractState.h: + (AbstractState): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleInlining): + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCCallHelpers.h: + (JSC::DFG::CCallHelpers::setupArguments): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::globalVarStoreElimination): + (JSC::DFG::CSEPhase::performNodeCSE): + * dfg/DFGCapabilities.h: + (JSC::DFG::canCompileOpcode): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::run): + * dfg/DFGCorrectableJumpPoint.h: + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::linkOSRExits): + (JSC::DFG::JITCompiler::link): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasRegisterPointer): + * dfg/DFGNodeType.h: + (DFG): + * dfg/DFGOSRExit.cpp: + (JSC::DFG::OSRExit::OSRExit): + * dfg/DFGOSRExit.h: + (OSRExit): + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::callOperation): + (JSC::DFG::SpeculativeJIT::appendCallSetResult): + (JSC::DFG::SpeculativeJIT::speculationCheck): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + (JSC::JIT::privateCompileSlowCases): + * jit/JIT.h: + * jit/JITPropertyAccess.cpp: + * jit/JITPropertyAccess32_64.cpp: + * jit/JITStubs.cpp: + * jit/JITStubs.h: + * llint/LLIntSlowPaths.cpp: + * llint/LLIntSlowPaths.h: + (LLInt): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/JSObject.cpp: + (JSC::JSObject::removeDirect): + * runtime/JSObject.h: + (JSObject): + * runtime/JSSymbolTableObject.h: + (JSC::symbolTableGet): + (JSC::symbolTablePut): + (JSC::symbolTablePutWithAttributes): + * runtime/SymbolTable.cpp: Removed. + * runtime/SymbolTable.h: + (JSC): + (JSC::SymbolTableEntry::isNull): + (JSC::SymbolTableEntry::getIndex): + (SymbolTableEntry): + (JSC::SymbolTableEntry::getAttributes): + (JSC::SymbolTableEntry::isReadOnly): + (JSC::SymbolTableEntry::pack): + (JSC::SymbolTableEntry::isValidIndex): + +2012-06-12 Filip Pizlo <fpizlo@apple.com> + + DFG should be able to set watchpoints on global variables + https://bugs.webkit.org/show_bug.cgi?id=88692 + + Reviewed by Geoffrey Garen. + + This implements global variable constant folding by allowing the optimizing + compiler to set a "watchpoint" on globals that it wishes to constant fold. + If the watchpoint fires, then an OSR exit is forced by overwriting the + machine code that the optimizing compiler generated with a jump. + + As such, this patch is adding quite a bit of stuff: + + - Jump replacement on those hardware targets supported by the optimizing + JIT. It is now possible to patch in a jump instruction over any recorded + watchpoint label. The jump must be "local" in the sense that it must be + within the range of the largest jump distance supported by a one + instruction jump. + + - WatchpointSets and Watchpoints. A Watchpoint is a doubly-linked list node + that records the location where a jump must be inserted and the + destination to which it should jump. Watchpoints can be added to a + WatchpointSet. The WatchpointSet can be fired all at once, which plants + all jumps. WatchpointSet also remembers if it had ever been invalidated, + which allows for monotonicity: we typically don't want to optimize using + watchpoints on something for which watchpoints had previously fired. The + act of notifying a WatchpointSet has a trivial fast path in case no + Watchpoints are registered (one-byte load+branch). + + - SpeculativeJIT::speculationWatchpoint(). It's like speculationCheck(), + except that you don't have to emit branches. But, you need to know what + WatchpointSet to add the resulting Watchpoint to. Not everything that + you could write a speculationCheck() for will have a WatchpointSet that + would get notified if the condition you were speculating against became + invalid. + + - SymbolTableEntry now has the ability to refer to a WatchpointSet. It can + do so without incurring any space overhead for those entries that don't + have WatchpointSets. + + - The bytecode generator infers all global function variables to be + watchable, and makes all stores perform the WatchpointSet's write check, + and marks all loads as being potentially watchable (i.e. you can compile + them to a watchpoint and a constant). + + Put together, this allows for fully sleazy inlining of calls to globally + declared functions. The inline prologue will no longer contain the load of + the function, or any checks of the function you're calling. I.e. it's + pretty much like the kind of inlining you would see in Java or C++. + Furthermore, the watchpointing functionality is built to be fairly general, + and should allow setting watchpoints on all sorts of interesting things + in the future. + + The sleazy inlining means that we will now sometimes inline in code paths + that have never executed. Previously, to inline we would have either had + to have executed the call (to read the call's inline cache) or have + executed the method check (to read the method check's inline cache). Now, + we might inline when the callee is a watched global variable. This + revealed some humorous bugs. First, constant folding disagreed with CFA + over what kinds of operations can clobber (example: code path A is dead + but stores a String into variable X, all other code paths store 0 into + X, and then you do CompareEq(X, 0) - CFA will say that this is a non- + clobbering constant, but constant folding thought it was clobbering + because it saw the String prediction). Second, inlining would crash if + the inline callee had not been compiled. This patch fixes both bugs, + since otherwise run-javascriptcore-tests would report regressions. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * Target.pri: + * assembler/ARMv7Assembler.h: + (ARMv7Assembler): + (JSC::ARMv7Assembler::ARMv7Assembler): + (JSC::ARMv7Assembler::labelForWatchpoint): + (JSC::ARMv7Assembler::label): + (JSC::ARMv7Assembler::replaceWithJump): + (JSC::ARMv7Assembler::maxJumpReplacementSize): + * assembler/AbstractMacroAssembler.h: + (JSC): + (AbstractMacroAssembler): + (Label): + (JSC::AbstractMacroAssembler::watchpointLabel): + * assembler/AssemblerBuffer.h: + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::replaceWithJump): + (MacroAssemblerARM): + (JSC::MacroAssemblerARM::maxJumpReplacementSize): + * assembler/MacroAssemblerARMv7.h: + (MacroAssemblerARMv7): + (JSC::MacroAssemblerARMv7::replaceWithJump): + (JSC::MacroAssemblerARMv7::maxJumpReplacementSize): + (JSC::MacroAssemblerARMv7::branchTest8): + (JSC::MacroAssemblerARMv7::jump): + (JSC::MacroAssemblerARMv7::makeBranch): + * assembler/MacroAssemblerMIPS.h: + (JSC::MacroAssemblerMIPS::replaceWithJump): + (MacroAssemblerMIPS): + (JSC::MacroAssemblerMIPS::maxJumpReplacementSize): + * assembler/MacroAssemblerSH4.h: + (JSC::MacroAssemblerSH4::replaceWithJump): + (MacroAssemblerSH4): + (JSC::MacroAssemblerSH4::maxJumpReplacementSize): + * assembler/MacroAssemblerX86.h: + (MacroAssemblerX86): + (JSC::MacroAssemblerX86::branchTest8): + * assembler/MacroAssemblerX86Common.h: + (JSC::MacroAssemblerX86Common::replaceWithJump): + (MacroAssemblerX86Common): + (JSC::MacroAssemblerX86Common::maxJumpReplacementSize): + * assembler/MacroAssemblerX86_64.h: + (MacroAssemblerX86_64): + (JSC::MacroAssemblerX86_64::branchTest8): + * assembler/X86Assembler.h: + (JSC::X86Assembler::X86Assembler): + (X86Assembler): + (JSC::X86Assembler::cmpb_im): + (JSC::X86Assembler::testb_im): + (JSC::X86Assembler::labelForWatchpoint): + (JSC::X86Assembler::label): + (JSC::X86Assembler::replaceWithJump): + (JSC::X86Assembler::maxJumpReplacementSize): + (JSC::X86Assembler::X86InstructionFormatter::memoryModRM): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::appendOSRExit): + (JSC::CodeBlock::appendSpeculationRecovery): + (CodeBlock): + (JSC::CodeBlock::appendWatchpoint): + (JSC::CodeBlock::numberOfWatchpoints): + (JSC::CodeBlock::watchpoint): + (DFGData): + * bytecode/DFGExitProfile.h: + (JSC::DFG::exitKindToString): + (JSC::DFG::exitKindIsCountable): + * bytecode/Instruction.h: + (Instruction): + (JSC::Instruction::Instruction): + * bytecode/Opcode.h: + (JSC): + (JSC::padOpcodeName): + * bytecode/Watchpoint.cpp: Added. + (JSC): + (JSC::Watchpoint::~Watchpoint): + (JSC::Watchpoint::correctLabels): + (JSC::Watchpoint::fire): + (JSC::WatchpointSet::WatchpointSet): + (JSC::WatchpointSet::~WatchpointSet): + (JSC::WatchpointSet::add): + (JSC::WatchpointSet::notifyWriteSlow): + (JSC::WatchpointSet::fireAllWatchpoints): + * bytecode/Watchpoint.h: Added. + (JSC): + (Watchpoint): + (JSC::Watchpoint::Watchpoint): + (JSC::Watchpoint::setDestination): + (WatchpointSet): + (JSC::WatchpointSet::isStillValid): + (JSC::WatchpointSet::hasBeenInvalidated): + (JSC::WatchpointSet::startWatching): + (JSC::WatchpointSet::notifyWrite): + (JSC::WatchpointSet::addressOfIsWatched): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::ResolveResult::checkValidity): + (JSC::BytecodeGenerator::addGlobalVar): + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::resolve): + (JSC::BytecodeGenerator::emitResolve): + (JSC::BytecodeGenerator::emitResolveWithBase): + (JSC::BytecodeGenerator::emitResolveWithThis): + (JSC::BytecodeGenerator::emitGetStaticVar): + (JSC::BytecodeGenerator::emitPutStaticVar): + * bytecompiler/BytecodeGenerator.h: + (BytecodeGenerator): + * bytecompiler/NodesCodegen.cpp: + (JSC::FunctionCallResolveNode::emitBytecode): + (JSC::PostfixResolveNode::emitBytecode): + (JSC::PrefixResolveNode::emitBytecode): + (JSC::ReadModifyResolveNode::emitBytecode): + (JSC::AssignResolveNode::emitBytecode): + (JSC::ConstDeclNode::emitCodeSingle): + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::execute): + (JSC::DFG::AbstractState::clobberStructures): + * dfg/DFGAbstractState.h: + (AbstractState): + (JSC::DFG::AbstractState::didClobber): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleInlining): + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCCallHelpers.h: + (CCallHelpers): + (JSC::DFG::CCallHelpers::setupArguments): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::globalVarWatchpointElimination): + (CSEPhase): + (JSC::DFG::CSEPhase::globalVarStoreElimination): + (JSC::DFG::CSEPhase::performNodeCSE): + * dfg/DFGCapabilities.h: + (JSC::DFG::canCompileOpcode): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::run): + * dfg/DFGCorrectableJumpPoint.h: + (JSC::DFG::CorrectableJumpPoint::isSet): + (CorrectableJumpPoint): + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::linkOSRExits): + (JSC::DFG::JITCompiler::link): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasIdentifierNumberForCheck): + (Node): + (JSC::DFG::Node::identifierNumberForCheck): + (JSC::DFG::Node::hasRegisterPointer): + * dfg/DFGNodeType.h: + (DFG): + * dfg/DFGOSRExit.cpp: + (JSC::DFG::OSRExit::OSRExit): + * dfg/DFGOSRExit.h: + (OSRExit): + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::callOperation): + (JSC::DFG::SpeculativeJIT::appendCall): + (SpeculativeJIT): + (JSC::DFG::SpeculativeJIT::speculationWatchpoint): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + (JSC::JIT::privateCompileSlowCases): + * jit/JIT.h: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_put_global_var_check): + (JSC): + (JSC::JIT::emitSlow_op_put_global_var_check): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emit_op_put_global_var_check): + (JSC): + (JSC::JIT::emitSlow_op_put_global_var_check): + * jit/JITStubs.cpp: + (JSC::JITThunks::JITThunks): + (JSC::DEFINE_STUB_FUNCTION): + (JSC): + * jit/JITStubs.h: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + (LLInt): + * llint/LLIntSlowPaths.h: + (LLInt): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/JSObject.cpp: + (JSC::JSObject::removeDirect): + * runtime/JSObject.h: + (JSObject): + * runtime/JSSymbolTableObject.h: + (JSC::symbolTableGet): + (JSC::symbolTablePut): + (JSC::symbolTablePutWithAttributes): + * runtime/SymbolTable.cpp: Added. + (JSC): + (JSC::SymbolTableEntry::copySlow): + (JSC::SymbolTableEntry::freeFatEntrySlow): + (JSC::SymbolTableEntry::couldBeWatched): + (JSC::SymbolTableEntry::attemptToWatch): + (JSC::SymbolTableEntry::addressOfIsWatched): + (JSC::SymbolTableEntry::addWatchpoint): + (JSC::SymbolTableEntry::notifyWriteSlow): + (JSC::SymbolTableEntry::inflateSlow): + * runtime/SymbolTable.h: + (JSC): + (SymbolTableEntry): + (Fast): + (JSC::SymbolTableEntry::Fast::Fast): + (JSC::SymbolTableEntry::Fast::isNull): + (JSC::SymbolTableEntry::Fast::getIndex): + (JSC::SymbolTableEntry::Fast::isReadOnly): + (JSC::SymbolTableEntry::Fast::getAttributes): + (JSC::SymbolTableEntry::Fast::isFat): + (JSC::SymbolTableEntry::SymbolTableEntry): + (JSC::SymbolTableEntry::~SymbolTableEntry): + (JSC::SymbolTableEntry::operator=): + (JSC::SymbolTableEntry::isNull): + (JSC::SymbolTableEntry::getIndex): + (JSC::SymbolTableEntry::getFast): + (JSC::SymbolTableEntry::getAttributes): + (JSC::SymbolTableEntry::isReadOnly): + (JSC::SymbolTableEntry::watchpointSet): + (JSC::SymbolTableEntry::notifyWrite): + (FatEntry): + (JSC::SymbolTableEntry::FatEntry::FatEntry): + (JSC::SymbolTableEntry::isFat): + (JSC::SymbolTableEntry::fatEntry): + (JSC::SymbolTableEntry::inflate): + (JSC::SymbolTableEntry::bits): + (JSC::SymbolTableEntry::freeFatEntry): + (JSC::SymbolTableEntry::pack): + (JSC::SymbolTableEntry::isValidIndex): + +2012-06-12 Filip Pizlo <fpizlo@apple.com> + + Unreviewed build fix for ARMv7 debug builds. + + * jit/JITStubs.cpp: + (JSC::JITThunks::JITThunks): + +2012-06-12 Geoffrey Garen <ggaren@apple.com> + + Build fix for case-sensitive file systems: use the right case. + + * heap/ListableHandler.h: + +2012-06-11 Geoffrey Garen <ggaren@apple.com> + + GC should be 1.7X faster + https://bugs.webkit.org/show_bug.cgi?id=88840 + + Reviewed by Oliver Hunt. + + I profiled, and removed anything that showed up as a concurrency + bottleneck. Then, I added 3 threads to our max thread count, since we + can scale up to more threads now. + + * heap/BlockAllocator.cpp: + (JSC::BlockAllocator::BlockAllocator): + (JSC::BlockAllocator::~BlockAllocator): + (JSC::BlockAllocator::releaseFreeBlocks): + (JSC::BlockAllocator::waitForRelativeTimeWhileHoldingLock): + (JSC::BlockAllocator::waitForRelativeTime): + (JSC::BlockAllocator::blockFreeingThreadMain): + * heap/BlockAllocator.h: + (BlockAllocator): + (JSC::BlockAllocator::allocate): + (JSC::BlockAllocator::deallocate): Use a spin lock for the common case + where we're just popping a linked list. (A pthread mutex would sleep our + thread even if the lock were only contended for a microsecond.) + + Scope the lock to avoid holding it while allocating VM, since that's a + slow activity and it doesn't modify any of our data structures. + + We still use a pthread mutex to handle our condition variable since we + have to, and it's not a hot path. + + * heap/CopiedSpace.cpp: + (JSC::CopiedSpace::CopiedSpace): + (JSC::CopiedSpace::doneFillingBlock): + * heap/CopiedSpace.h: + (JSC::CopiedSpace::CopiedSpace): Use a spin lock for the to space lock, + since it just guards linked list and hash table manipulation. + + * heap/MarkStack.cpp: + (JSC::MarkStackSegmentAllocator::MarkStackSegmentAllocator): + (JSC::MarkStackSegmentAllocator::allocate): + (JSC::MarkStackSegmentAllocator::release): + (JSC::MarkStackSegmentAllocator::shrinkReserve): Use a spin lock, since + we're just managing a linked list. + + (JSC::MarkStackArray::donateSomeCellsTo): Changed donation to be proportional + to our current stack size. This fixes cases where we used to donate too + much. Interestingly, donating too much was starving the donor (when it + ran out of work later) *and* the recipient (since it had to wait on a + long donation operation to complete before it could acquire the lock). + + In the worst case, we're still guaranteed to donate N cells in roughly log N time. + + This change also fixes cases where we used to donate too little, since + we would always keep a fixed minimum number of cells. In the worst case, + with N marking threads, would could have N large object graph roots in + our stack for the duration of GC, and scale to only 1 thread. + + It's an interesting observation that a single object in the mark stack + might represent an arbitrarily large object graph -- and only the act + of marking can find out. + + (JSC::MarkStackArray::stealSomeCellsFrom): Steal in proportion to idle + threads. Once again, this fixes cases where constants could cause us + to steal too much or too little. + + (JSC::SlotVisitor::donateKnownParallel): Always wake up other threads + if they're idle. We can afford to do this because we're conservative + about when we donate. + + (JSC::SlotVisitor::drainFromShared): + * heap/MarkStack.h: + (MarkStackSegmentAllocator): + (MarkStackArray): + (JSC): + * heap/SlotVisitor.h: Merged the "should I donate?" decision into a + single function, for simplicity. + + * runtime/Options.cpp: + (minimumNumberOfScansBetweenRebalance): Reduced the delay before donation + a lot. We can afford to do this because, in the common case, donation is + a single branch that decides not to donate. + + (cpusToUse): Use more CPUs now, since we scale better now. + + * runtime/Options.h: + (Options): Removed now-unused variables. + +2012-06-12 Filip Pizlo <fpizlo@apple.com> + + REGRESSION(120121): inspector tests crash in DFG + https://bugs.webkit.org/show_bug.cgi?id=88941 + + Reviewed by Geoffrey Garen. + + The CFG simplifier has two different ways of fixing up GetLocal, Phantom, and Flush. If we've + already fixed up the node one way, we shouldn't try the other way. The reason why we shouldn't + is that the second way depends on the node referring to other nodes in the to-be-jettisoned + block. After fixup they potentially will refer to nodes in the block being merged to. + + * dfg/DFGCFGSimplificationPhase.cpp: + (JSC::DFG::CFGSimplificationPhase::fixPossibleGetLocal): + (JSC::DFG::CFGSimplificationPhase::mergeBlocks): + +2012-06-12 Leo Yang <leo.yang@torchmobile.com.cn> + + Dynamic hash table in DOMObjectHashTableMap is wrong in multiple threads + https://bugs.webkit.org/show_bug.cgi?id=87334 + + Reviewed by Geoffrey Garen. + + Add a copy member function to JSC::HasTable. This function will copy all data + members except for *table* which contains thread specific data that prevents + up copying it. When you want to copy a JSC::HashTable that was constructed + on another thread you should call JSC::HashTable::copy(). + + * runtime/Lookup.h: + (JSC::HashTable::copy): + (HashTable): + +2012-06-12 Filip Pizlo <fpizlo@apple.com> + + DFG should not ASSERT if you have a double use of a variable that is not revealed to be a double + until after CFG simplification + https://bugs.webkit.org/show_bug.cgi?id=88927 + <rdar://problem/11513971> + + Reviewed by Geoffrey Garen. + + Speculation fixup needs to run if simplification did things, because simplification can change + predictions - particularly if you had a control flow path that stored weird things into a + variable, but that path got axed by the simplifier. + + Running fixup in the fixpoint requires making it idempotent, which it previously wasn't. Only + one place needed to be changed, namely the un-MustGenerate-ion of ValueToInt32. + + * dfg/DFGDriver.cpp: + (JSC::DFG::compile): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + +2012-06-12 Filip Pizlo <fpizlo@apple.com> + + REGRESSION (r119779): Javascript TypeError: 'undefined' is not an object + https://bugs.webkit.org/show_bug.cgi?id=88783 + <rdar://problem/11640299> + + Reviewed by Geoffrey Garen. + + If you don't keep alive the base of an object access over the various checks + you do for the prototype chain, you're going to have a bad time. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleGetById): + +2012-06-12 Hojong Han <hojong.han@samsung.com> + + Property names of the built-in object cannot be retrieved + after trying to delete one of its properties + https://bugs.webkit.org/show_bug.cgi?id=86461 + + Reviewed by Gavin Barraclough. + + * runtime/JSObject.cpp: + (JSC::getClassPropertyNames): + (JSC::JSObject::getOwnPropertyNames): + +2012-06-11 Gyuyoung Kim <gyuyoung.kim@samsung.com> + + [CMAKE][EFL] Remove duplicated executable output path + https://bugs.webkit.org/show_bug.cgi?id=88765 + + Reviewed by Daniel Bates. + + CMake files for EFL port have redefined executable output path. However, EFL port doesn't + need to define again because it is already defined in top-level CMake file. + + * shell/CMakeLists.txt: + +2012-06-11 Carlos Garcia Campos <cgarcia@igalia.com> + + Unreviewed. Fix make distcheck issues. + + * GNUmakefile.list.am: Remove non existent header file. + +2012-06-10 Patrick Gansterer <paroga@webkit.org> + + Unreviewed. Build fix for !ENABLE(JIT) after r119844 and r119925. + + * runtime/Executable.h: + (ExecutableBase): + (JSC::ExecutableBase::clearCodeVirtual): + +2012-06-10 Patrick Gansterer <paroga@webkit.org> + + Unreviewed. Build fix for !ENABLE(JIT) after r119844. + + * runtime/Executable.h: + (ExecutableBase): + (JSC): + +2012-06-09 Dominic Cooney <dominicc@chromium.org> + + [Chromium] Remove JavaScriptCore dependencies from gyp + https://bugs.webkit.org/show_bug.cgi?id=88510 + + Reviewed by Adam Barth. + + Chromium doesn't support JSC any more and there doesn't seem to be + a strong interest in using GYP as the common build system in other + ports. + + * JavaScriptCore.gyp/JavaScriptCore.gyp: WebCore still depends on YARR interpreter. + * JavaScriptCore.gypi: Only include YARR source. + * gyp/JavaScriptCore.gyp: Removed. + * gyp/gtk.gyp: Removed. + +2012-06-09 Geoffrey Garen <ggaren@apple.com> + + Unreviewed, rolling back in part2 of r118646. + + This patch removes eager finalization. + + Weak pointer finalization should be lazy + https://bugs.webkit.org/show_bug.cgi?id=87599 + + Reviewed by Sam Weinig. + + * heap/Heap.cpp: + (JSC::Heap::collect): Don't finalize eagerly -- we'll do it lazily. + + * heap/MarkedBlock.cpp: + (JSC::MarkedBlock::sweep): Do sweep weak sets when sweeping a block, + since we won't get another chance. + + * heap/MarkedBlock.h: + (JSC::MarkedBlock::sweepWeakSet): + * heap/MarkedSpace.cpp: + (MarkedSpace::WeakSetSweep): + * heap/MarkedSpace.h: + (JSC::MarkedSpace::sweepWeakSets): Removed now-unused code. + +2012-06-09 Sukolsak Sakshuwong <sukolsak@google.com> + + Add UNDO_MANAGER flag + https://bugs.webkit.org/show_bug.cgi?id=87908 + + Reviewed by Tony Chang. + + * Configurations/FeatureDefines.xcconfig: + +2012-06-08 Geoffrey Garen <ggaren@apple.com> + + Unreviewed, rolling back in part1 of r118646. + + This patch includes everything necessary for lazy finalization, but + keeps eager finalization enabled for the time being. + + Weak pointer finalization should be lazy + https://bugs.webkit.org/show_bug.cgi?id=87599 + + Reviewed by Sam Weinig. + + * heap/MarkedBlock.cpp: + * heap/MarkedBlock.h: + (JSC::MarkedBlock::resetAllocator): + * heap/MarkedSpace.cpp: + (JSC::MarkedSpace::resetAllocators): + * heap/MarkedSpace.h: + (JSC::MarkedSpace::resetAllocators): Don't force allocator reset anymore. + It will happen automatically when a weak set is swept. It's simpler to + have only one canonical way for this to happen, and it wasn't buying + us anything to do it eagerly. + * heap/WeakBlock.cpp: + (JSC::WeakBlock::sweep): Don't short-circuit a sweep unless we know + the sweep would be a no-op. If even one finalizer is pending, we need to + run it, since we won't get another chance. + * heap/WeakSet.cpp: + (JSC::WeakSet::sweep): This loop can be simpler now that + WeakBlock::sweep() does what we mean. + Reset our allocator after a sweep because this is the optimal time to + start trying to recycle old weak pointers. + (JSC::WeakSet::tryFindAllocator): Don't sweep when searching for an + allocator because we've swept already, and forcing a new sweep would be + wasteful. + * heap/WeakSet.h: + (JSC::WeakSet::shrink): Be sure to reset our allocator after a shrink + because the shrink may have removed the block the allocator was going to + allocate out of. + +2012-06-08 Gavin Barraclough <barraclough@apple.com> + + Unreviewed roll out r119795. + + This broke jquery/core.html + + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::emitAllocateBasicJSObject): + * jit/JITInlineMethods.h: + (JSC::JIT::emitAllocateBasicJSObject): + * llint/LowLevelInterpreter.asm: + * runtime/JSGlobalData.h: + (JSGlobalData): + * runtime/JSGlobalThis.cpp: + (JSC::JSGlobalThis::setUnwrappedObject): + * runtime/JSObject.cpp: + (JSC::JSObject::visitChildren): + (JSC::JSObject::createInheritorID): + * runtime/JSObject.h: + (JSObject): + (JSC::JSObject::resetInheritorID): + (JSC): + (JSC::JSObject::offsetOfInheritorID): + (JSC::JSObject::inheritorID): + +2012-06-08 Filip Pizlo <fpizlo@apple.com> + + PredictedType should be called SpeculatedType + https://bugs.webkit.org/show_bug.cgi?id=88477 + + Unreviewed, fix a renaming goof from http://trac.webkit.org/changeset/119660. + I accidentally renamed ByteCodeParser::getPrediction to + ByteCodeParser::getSpeculation. That was not the intent. This changes it + back. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::addCall): + (JSC::DFG::ByteCodeParser::getPredictionWithoutOSRExit): + (JSC::DFG::ByteCodeParser::getPrediction): + (JSC::DFG::ByteCodeParser::handleCall): + (JSC::DFG::ByteCodeParser::parseBlock): + +2012-06-08 Andy Wingo <wingo@igalia.com> + + Explictly mark stubs called by JIT as being internal + https://bugs.webkit.org/show_bug.cgi?id=88552 + + Reviewed by Filip Pizlo. + + * dfg/DFGOSRExitCompiler.h: + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * jit/HostCallReturnValue.h: + * jit/JITStubs.cpp: + * jit/JITStubs.h: + * jit/ThunkGenerators.cpp: + * llint/LLIntSlowPaths.h: Mark a bunch of stubs as being + WTF_INTERNAL. Change most calls to SYMBOL_STRING_RELOCATION to + LOCAL_REFERENCE, or GLOBAL_REFERENCE in the case of the wrappers + to truly global symbols. + * offlineasm/asm.rb: Generate LOCAL_REFERENCE instead of + SYMBOL_STRING_RELOCATION. + +2012-06-08 Geoffrey Garen <ggaren@apple.com> + + Don't rely on weak pointers for eager CodeBlock finalization + https://bugs.webkit.org/show_bug.cgi?id=88465 + + Reviewed by Gavin Barraclough. + + This is incompatible with lazy weak pointer finalization. + + I considered just making CodeBlock finalization lazy-friendly, but it + turns out that the heap is already way up in CodeBlock's business when + it comes to finalization, so I decided to finish the job and move full + responsibility for CodeBlock finalization into the heap. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: Maybe this + will build. + + * debugger/Debugger.cpp: Updated for rename. + + * heap/Heap.cpp: + (JSC::Heap::deleteAllCompiledCode): Renamed for consistency. Fixed a bug + where we would not delete code for a code block that had been previously + jettisoned. I don't know if this happens in practice -- I mostly did + this to improve consistency with deleteUnmarkedCompiledCode. + + (JSC::Heap::deleteUnmarkedCompiledCode): New function, responsible for + eager finalization of unmarked code blocks. + + (JSC::Heap::collect): Updated for rename. Updated to call + deleteUnmarkedCompiledCode(), which takes care of jettisoned DFG code + blocks too. + + (JSC::Heap::addCompiledCode): Renamed, since this points to all code + now, not just functions. + + * heap/Heap.h: + (Heap): Keep track of all user code, not just functions. This is a + negligible additional overhead, since most code is function code. + + * runtime/Executable.cpp: + (JSC::*::finalize): Removed these functions, since we don't rely on + weak pointer finalization anymore. + + (JSC::FunctionExecutable::FunctionExecutable): Moved linked-list stuff + into base class so all executables can be in the list. + + (JSC::EvalExecutable::clearCode): + (JSC::ProgramExecutable::clearCode): + (JSC::FunctionExecutable::clearCode): All we need to do is delete our + CodeBlock -- that will delete all of its internal data structures. + + (JSC::FunctionExecutable::clearCodeIfNotCompiling): Factored out a helper + function to improve clarity. + + * runtime/Executable.h: + (JSC::ExecutableBase): Moved linked-list stuff + into base class so all executables can be in the list. + + (JSC::NativeExecutable::create): + (NativeExecutable): + (ScriptExecutable): + (JSC::ScriptExecutable::finishCreation): + (JSC::EvalExecutable::create): + (EvalExecutable): + (JSC::ProgramExecutable::create): + (ProgramExecutable): + (FunctionExecutable): + (JSC::FunctionExecutable::create): Don't use a finalizer -- the heap + will call us back to destroy our code block. + + (JSC::FunctionExecutable::discardCode): Renamed to clearCodeIfNotCompiling() + for clarity. + + (JSC::FunctionExecutable::isCompiling): New helper function, for clarity. + + (JSC::ScriptExecutable::clearCodeVirtual): New helper function, since + the heap needs to make polymorphic calls to clear code. + + * runtime/JSGlobalData.cpp: + (JSC::StackPreservingRecompiler::operator()): + * runtime/JSGlobalObject.cpp: + (JSC::DynamicGlobalObjectScope::DynamicGlobalObjectScope): Updated for + renames. + +2012-06-07 Filip Pizlo <fpizlo@apple.com> + + DFG should inline prototype chain accesses, and do the right things if the + specific function optimization is available + https://bugs.webkit.org/show_bug.cgi?id=88594 + + Reviewed by Gavin Barraclough. + + Looks like a 3% win on V8. + + * bytecode/CodeBlock.h: + (JSC::Structure::prototypeForLookup): + (JSC): + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeFromLLInt): + (JSC): + (JSC::GetByIdStatus::computeForChain): + (JSC::GetByIdStatus::computeFor): + * bytecode/GetByIdStatus.h: + (JSC::GetByIdStatus::GetByIdStatus): + (JSC::GetByIdStatus::isSimple): + (JSC::GetByIdStatus::chain): + (JSC::GetByIdStatus::specificValue): + (GetByIdStatus): + * bytecode/StructureSet.h: + (StructureSet): + (JSC::StructureSet::singletonStructure): + * bytecode/StructureStubInfo.h: + (JSC::StructureStubInfo::initGetByIdProto): + (JSC::StructureStubInfo::initGetByIdChain): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleGetById): + * dfg/DFGRepatch.cpp: + (JSC::DFG::tryCacheGetByID): + * jit/JITStubs.cpp: + (JSC::JITThunks::tryCacheGetByID): + * runtime/JSGlobalObject.h: + (JSC::Structure::prototypeForLookup): + (JSC): + * runtime/Structure.h: + (Structure): + +2012-06-07 Gavin Barraclough <barraclough@apple.com> + + Remove JSObject::m_inheritorID + https://bugs.webkit.org/show_bug.cgi?id=88378 + + Reviewed by Geoff Garen. + + This is rarely used, and not performance critical (the commonly accessed copy is cached on JSFunction), + and most objects don't need an inheritorID (this value is only used if the object is used as a prototype). + Instead use a private named value in the object's property storage. + + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::emitAllocateBasicJSObject): + - No need m_inheritorID to initialize! + * jit/JITInlineMethods.h: + (JSC::JIT::emitAllocateBasicJSObject): + - No need m_inheritorID to initialize! + * llint/LowLevelInterpreter.asm: + - No need m_inheritorID to initialize! + * runtime/JSGlobalData.h: + (JSGlobalData): + - Added private name 'm_inheritorIDKey'. + * runtime/JSGlobalThis.cpp: + (JSC::JSGlobalThis::setUnwrappedObject): + - resetInheritorID is now passed a JSGlobalData&. + * runtime/JSObject.cpp: + (JSC::JSObject::visitChildren): + - No m_inheritorID to be marked. + (JSC::JSObject::createInheritorID): + - Store the newly created inheritorID in the property map. + * runtime/JSObject.h: + (JSC::JSObject::resetInheritorID): + - Remove the inheritorID from property storage. + (JSC::JSObject::inheritorID): + - Read the inheritorID from property storage. + +2012-06-07 Gavin Barraclough <barraclough@apple.com> + + Math.pow on iOS does not support denormal numbers. + https://bugs.webkit.org/show_bug.cgi?id=88592 + + Reviewed by Filip Pizlo. + + Import an implementation from fdlibm, detect cases where it is safe to use the system + implementation & where we should fall back to fdlibm. + + * runtime/MathObject.cpp: + (JSC::isDenormal): + (JSC::isEdgeCase): + (JSC::mathPow): + - On iOS, detect cases where denormal support may be required & use fdlibm in these cases. + (JSC::mathProtoFuncPow): + - Changed to use mathPow. + (JSC::fdlibmScalbn): + (JSC::fdlibmPow): + - These functions imported from fdlibm; original style retained to ease future merging. + +2012-06-07 Patrick Gansterer <paroga@webkit.org> + + Unreviewed. Build fix for !ENABLE(JIT) after r119441. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + +2012-06-07 Andy Wingo <wingo@igalia.com> + + Unreviewed build fix after r119593. + + * llint/LLIntOfflineAsmConfig.h (OFFLINE_ASM_GLOBAL_LABEL): Fix + uses of "name" to be "label", the macro's parameter. Otherwise we + serialize mentions of the literal symbol "name" into the objcode. + Causes a build error using GNU ld (not gold). + +2012-06-06 Ryosuke Niwa <rniwa@webkit.org> + + Chromium build fix attempt. Why do we need to list these files in gyp!? + + * JavaScriptCore.gypi: + +2012-06-06 Filip Pizlo <fpizlo@apple.com> + + PredictedType should be called SpeculatedType + https://bugs.webkit.org/show_bug.cgi?id=88477 + + Rubber stamped by Gavin Barraclough. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * Target.pri: + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::shouldOptimizeNow): + (JSC::CodeBlock::dumpValueProfiles): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::valueProfilePredictionForBytecodeOffset): + * bytecode/LazyOperandValueProfile.cpp: + (JSC::LazyOperandValueProfileParser::prediction): + * bytecode/LazyOperandValueProfile.h: + (LazyOperandValueProfileParser): + * bytecode/PredictedType.cpp: Removed. + * bytecode/PredictedType.h: Removed. + * bytecode/SpeculatedType.cpp: Copied from Source/JavaScriptCore/bytecode/PredictedType.cpp. + (JSC::speculationToString): + (JSC::speculationToAbbreviatedString): + (JSC::speculationFromClassInfo): + (JSC::speculationFromStructure): + (JSC::speculationFromCell): + (JSC::speculationFromValue): + * bytecode/SpeculatedType.h: Copied from Source/JavaScriptCore/bytecode/PredictedType.h. + (JSC): + (JSC::isAnySpeculation): + (JSC::isCellSpeculation): + (JSC::isObjectSpeculation): + (JSC::isFinalObjectSpeculation): + (JSC::isFinalObjectOrOtherSpeculation): + (JSC::isFixedIndexedStorageObjectSpeculation): + (JSC::isStringSpeculation): + (JSC::isArraySpeculation): + (JSC::isFunctionSpeculation): + (JSC::isInt8ArraySpeculation): + (JSC::isInt16ArraySpeculation): + (JSC::isInt32ArraySpeculation): + (JSC::isUint8ArraySpeculation): + (JSC::isUint8ClampedArraySpeculation): + (JSC::isUint16ArraySpeculation): + (JSC::isUint32ArraySpeculation): + (JSC::isFloat32ArraySpeculation): + (JSC::isFloat64ArraySpeculation): + (JSC::isArgumentsSpeculation): + (JSC::isActionableIntMutableArraySpeculation): + (JSC::isActionableFloatMutableArraySpeculation): + (JSC::isActionableTypedMutableArraySpeculation): + (JSC::isActionableMutableArraySpeculation): + (JSC::isActionableArraySpeculation): + (JSC::isArrayOrOtherSpeculation): + (JSC::isMyArgumentsSpeculation): + (JSC::isInt32Speculation): + (JSC::isDoubleRealSpeculation): + (JSC::isDoubleSpeculation): + (JSC::isNumberSpeculation): + (JSC::isBooleanSpeculation): + (JSC::isOtherSpeculation): + (JSC::isEmptySpeculation): + (JSC::mergeSpeculations): + (JSC::mergeSpeculation): + * bytecode/StructureSet.h: + (JSC::StructureSet::speculationFromStructures): + * bytecode/ValueProfile.h: + (JSC::ValueProfileBase::ValueProfileBase): + (JSC::ValueProfileBase::dump): + (JSC::ValueProfileBase::computeUpdatedPrediction): + (ValueProfileBase): + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::initialize): + (JSC::DFG::AbstractState::execute): + (JSC::DFG::AbstractState::mergeStateAtTail): + * dfg/DFGAbstractState.h: + (JSC::DFG::AbstractState::speculateInt32Unary): + (JSC::DFG::AbstractState::speculateNumberUnary): + (JSC::DFG::AbstractState::speculateBooleanUnary): + (JSC::DFG::AbstractState::speculateInt32Binary): + (JSC::DFG::AbstractState::speculateNumberBinary): + * dfg/DFGAbstractValue.h: + (JSC::DFG::StructureAbstractValue::filter): + (JSC::DFG::StructureAbstractValue::speculationFromStructures): + (JSC::DFG::AbstractValue::AbstractValue): + (JSC::DFG::AbstractValue::clear): + (JSC::DFG::AbstractValue::isClear): + (JSC::DFG::AbstractValue::makeTop): + (JSC::DFG::AbstractValue::clobberStructures): + (JSC::DFG::AbstractValue::isTop): + (JSC::DFG::AbstractValue::set): + (JSC::DFG::AbstractValue::merge): + (JSC::DFG::AbstractValue::filter): + (JSC::DFG::AbstractValue::validateIgnoringValue): + (JSC::DFG::AbstractValue::validate): + (JSC::DFG::AbstractValue::checkConsistency): + (JSC::DFG::AbstractValue::dump): + (AbstractValue): + * dfg/DFGArgumentPosition.h: + (JSC::DFG::ArgumentPosition::ArgumentPosition): + (JSC::DFG::ArgumentPosition::mergeArgumentAwareness): + (JSC::DFG::ArgumentPosition::prediction): + (ArgumentPosition): + * dfg/DFGArgumentsSimplificationPhase.cpp: + (JSC::DFG::ArgumentsSimplificationPhase::run): + * dfg/DFGByteCodeParser.cpp: + (ByteCodeParser): + (JSC::DFG::ByteCodeParser::injectLazyOperandSpeculation): + (JSC::DFG::ByteCodeParser::getLocal): + (JSC::DFG::ByteCodeParser::getArgument): + (JSC::DFG::ByteCodeParser::addCall): + (JSC::DFG::ByteCodeParser::getSpeculationWithoutOSRExit): + (JSC::DFG::ByteCodeParser::getSpeculation): + (InlineStackEntry): + (JSC::DFG::ByteCodeParser::handleCall): + (JSC::DFG::ByteCodeParser::handleIntrinsic): + (JSC::DFG::ByteCodeParser::handleGetById): + (JSC::DFG::ByteCodeParser::parseBlock): + (JSC::DFG::ByteCodeParser::fixVariableAccessSpeculations): + (JSC::DFG::ByteCodeParser::parse): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::getIndexedPropertyStorageLoadElimination): + (JSC::DFG::CSEPhase::performNodeCSE): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::run): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::fixDoubleEdge): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::nameOfVariableAccessData): + (JSC::DFG::Graph::dump): + (JSC::DFG::Graph::predictArgumentTypes): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::getJSConstantSpeculation): + (JSC::DFG::Graph::isPredictedNumerical): + (JSC::DFG::Graph::byValIsPure): + * dfg/DFGJITCompiler.h: + (JSC::DFG::JITCompiler::getSpeculation): + * dfg/DFGNode.h: + (JSC::DFG::Node::Node): + (JSC::DFG::Node::getHeapPrediction): + (JSC::DFG::Node::predictHeap): + (JSC::DFG::Node::prediction): + (JSC::DFG::Node::predict): + (JSC::DFG::Node::shouldSpeculateInteger): + (JSC::DFG::Node::shouldSpeculateDouble): + (JSC::DFG::Node::shouldSpeculateNumber): + (JSC::DFG::Node::shouldSpeculateBoolean): + (JSC::DFG::Node::shouldSpeculateFinalObject): + (JSC::DFG::Node::shouldSpeculateFinalObjectOrOther): + (JSC::DFG::Node::shouldSpeculateArray): + (JSC::DFG::Node::shouldSpeculateArguments): + (JSC::DFG::Node::shouldSpeculateInt8Array): + (JSC::DFG::Node::shouldSpeculateInt16Array): + (JSC::DFG::Node::shouldSpeculateInt32Array): + (JSC::DFG::Node::shouldSpeculateUint8Array): + (JSC::DFG::Node::shouldSpeculateUint8ClampedArray): + (JSC::DFG::Node::shouldSpeculateUint16Array): + (JSC::DFG::Node::shouldSpeculateUint32Array): + (JSC::DFG::Node::shouldSpeculateFloat32Array): + (JSC::DFG::Node::shouldSpeculateFloat64Array): + (JSC::DFG::Node::shouldSpeculateArrayOrOther): + (JSC::DFG::Node::shouldSpeculateObject): + (JSC::DFG::Node::shouldSpeculateCell): + (Node): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::setPrediction): + (JSC::DFG::PredictionPropagationPhase::mergePrediction): + (JSC::DFG::PredictionPropagationPhase::propagate): + (JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::fillStorage): + (JSC::DFG::SpeculativeJIT::writeBarrier): + (JSC::DFG::GPRTemporary::GPRTemporary): + (JSC::DFG::FPRTemporary::FPRTemporary): + (JSC::DFG::SpeculativeJIT::compilePeepHoleDoubleBranch): + (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectEquality): + (JSC::DFG::SpeculativeJIT::compilePeepHoleBranch): + (JSC::DFG::SpeculativeJIT::compile): + (JSC::DFG::SpeculativeJIT::checkArgumentTypes): + (JSC::DFG::SpeculativeJIT::compileGetCharCodeAt): + (JSC::DFG::SpeculativeJIT::compileGetByValOnString): + (JSC::DFG::SpeculativeJIT::compileValueToInt32): + (JSC::DFG::SpeculativeJIT::compileDoubleAsInt32): + (JSC::DFG::SpeculativeJIT::compileInt32ToDouble): + (JSC::DFG::SpeculativeJIT::compileGetTypedArrayLength): + (JSC::DFG::SpeculativeJIT::compileGetByValOnIntTypedArray): + (JSC::DFG::SpeculativeJIT::compilePutByValForIntTypedArray): + (JSC::DFG::SpeculativeJIT::compileGetByValOnFloatTypedArray): + (JSC::DFG::SpeculativeJIT::compilePutByValForFloatTypedArray): + (JSC::DFG::SpeculativeJIT::compileInstanceOf): + (JSC::DFG::SpeculativeJIT::compileAdd): + (JSC::DFG::SpeculativeJIT::compileArithSub): + (JSC::DFG::SpeculativeJIT::compileArithNegate): + (JSC::DFG::SpeculativeJIT::compileArithMul): + (JSC::DFG::SpeculativeJIT::compileArithMod): + (JSC::DFG::SpeculativeJIT::compare): + (JSC::DFG::SpeculativeJIT::compileStrictEq): + (JSC::DFG::SpeculativeJIT::compileGetIndexedPropertyStorage): + (JSC::DFG::SpeculativeJIT::compileGetByValOnArguments): + (JSC::DFG::SpeculativeJIT::compileGetArgumentsLength): + (JSC::DFG::SpeculativeJIT::compileRegExpExec): + * dfg/DFGSpeculativeJIT.h: + (DFG): + (JSC::DFG::ValueSource::forSpeculation): + (SpeculativeJIT): + (GPRTemporary): + (FPRTemporary): + (JSC::DFG::SpecDoubleOperand::SpecDoubleOperand): + (JSC::DFG::SpecDoubleOperand::~SpecDoubleOperand): + (JSC::DFG::SpecDoubleOperand::fpr): + (JSC::DFG::SpecCellOperand::SpecCellOperand): + (JSC::DFG::SpecCellOperand::~SpecCellOperand): + (JSC::DFG::SpecCellOperand::gpr): + (JSC::DFG::SpecBooleanOperand::SpecBooleanOperand): + (JSC::DFG::SpecBooleanOperand::~SpecBooleanOperand): + (JSC::DFG::SpecBooleanOperand::gpr): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::fillSpeculateIntInternal): + (JSC::DFG::SpeculativeJIT::fillSpecDouble): + (JSC::DFG::SpeculativeJIT::fillSpecCell): + (JSC::DFG::SpeculativeJIT::fillSpecBoolean): + (JSC::DFG::SpeculativeJIT::compileObjectEquality): + (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compileDoubleCompare): + (JSC::DFG::SpeculativeJIT::compileLogicalNot): + (JSC::DFG::SpeculativeJIT::emitBranch): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::fillSpeculateIntInternal): + (JSC::DFG::SpeculativeJIT::fillSpecDouble): + (JSC::DFG::SpeculativeJIT::fillSpecCell): + (JSC::DFG::SpeculativeJIT::fillSpecBoolean): + (JSC::DFG::SpeculativeJIT::compileObjectEquality): + (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compileDoubleCompare): + (JSC::DFG::SpeculativeJIT::compileLogicalNot): + (JSC::DFG::SpeculativeJIT::emitBranch): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGVariableAccessData.h: + (JSC::DFG::VariableAccessData::VariableAccessData): + (JSC::DFG::VariableAccessData::predict): + (JSC::DFG::VariableAccessData::nonUnifiedPrediction): + (JSC::DFG::VariableAccessData::prediction): + (JSC::DFG::VariableAccessData::argumentAwarePrediction): + (JSC::DFG::VariableAccessData::mergeArgumentAwarePrediction): + (JSC::DFG::VariableAccessData::shouldUseDoubleFormatAccordingToVote): + (JSC::DFG::VariableAccessData::makePredictionForDoubleFormat): + (VariableAccessData): + +2012-06-06 Filip Pizlo <fpizlo@apple.com> + + Global object variable accesses should not require an extra load + https://bugs.webkit.org/show_bug.cgi?id=88385 + + Reviewed by Gavin Barraclough and Geoffrey Garen. + + Previously, if you wanted to access a global variable, you'd first have + to load the register array from the appropriate global object and then + either load or store at an offset to the register array. This is because + JSGlobalObject inherited from JSVariableObject, and JSVariableObject is + designed with the pessimistic assumption that its register array may + point into the call stack. This is never the case for global objects. + Hence, even though the global object may add more registers at any time, + it does not need to store them in a contiguous array. It can use a + SegmentedVector or similar. + + This patch refactors global objects and variable objects as follows: + + - The functionality to track variables in an indexable array using a + SymbolTable to map names to indices is moved into JSSymbolTableObject, + which is now a supertype of JSVariableObject. JSVariableObject is now + just a holder for a registers array and implements the registerAt() + method that is left abstract in JSSymbolTableObject. Because all users + of JSVariableObject know whether they are a JSStaticScopeObject, + JSActivation, or JSGlobalObject, this "abstract" method is not virtual; + instead the utility methods that would call registerAt() are now + template functions that require you to know statically what subtype of + JSSymbolTableObject you're using (JSVariableObject or something else), + so that registerAt() can be statically bound. + + - A new class is added called JSSegmentedVariableObject, which only + differs from JSVariableObject in how it allocates registers. It uses a + SegmentedVector instead of manually managing a pointer to a contiguous + slab of registers. This changes the interface somewhat; for example + with JSVariableObject if you wanted to add a register you had to do + it yourself since the JSVariableObject didn't know how the registers + array ought to be allocated. With JSSegmentedVariableObject you can + just call addRegisters(). JSSegmentedVariableObject preserves the + invariant that once you get a pointer into a register, that pointer + will continue to be valid so long as the JSSegmentedVariableObject is + alive. This allows the JITs and interpreters to skip the extra load. + + - JSGlobalObject now inherits from JSSegmentedVariableObject. For now + (and possibly forever) it is the only subtype of this new class. + + - The bytecode format is changed so that get_global_var and + put_global_var have a pointer to the register directly rather than + having an index. A convenience method is provided in + JSSegmentedVariableObject to get the index given a a pointer, which is + used for assertions and debug dumps. + + This appears to be a 1% across the board win. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * Target.pri: + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + * bytecode/Instruction.h: + (Instruction): + (JSC::Instruction::Instruction): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::ResolveResult::registerPointer): + (JSC): + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::retrieveLastUnaryOp): + (JSC::BytecodeGenerator::resolve): + (JSC::BytecodeGenerator::resolveConstDecl): + (JSC::BytecodeGenerator::emitGetStaticVar): + (JSC::BytecodeGenerator::emitPutStaticVar): + * bytecompiler/BytecodeGenerator.h: + (ResolveResult): + (BytecodeGenerator): + * dfg/DFGAssemblyHelpers.h: + (AssemblyHelpers): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::globalVarLoadElimination): + (JSC::DFG::CSEPhase::globalVarStoreElimination): + (JSC::DFG::CSEPhase::performNodeCSE): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dump): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::globalObjectFor): + (Graph): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasVarNumber): + (Node): + (JSC::DFG::Node::hasRegisterPointer): + (JSC::DFG::Node::registerPointer): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * heap/Heap.h: + (Heap): + (JSC::Heap::isWriteBarrierEnabled): + (JSC): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): + (JSC::Interpreter::privateExecute): + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_get_global_var): + (JSC::JIT::emit_op_put_global_var): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emit_op_get_global_var): + (JSC::JIT::emit_op_put_global_var): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/JSGlobalObject.cpp: + (JSC): + (JSC::JSGlobalObject::put): + (JSC::JSGlobalObject::putDirectVirtual): + (JSC::JSGlobalObject::defineOwnProperty): + (JSC::JSGlobalObject::visitChildren): + (JSC::JSGlobalObject::addStaticGlobals): + (JSC::JSGlobalObject::getOwnPropertySlot): + (JSC::JSGlobalObject::getOwnPropertyDescriptor): + * runtime/JSGlobalObject.h: + (JSGlobalObject): + (JSC::JSGlobalObject::JSGlobalObject): + (JSC): + (JSC::JSGlobalObject::hasOwnPropertyForWrite): + * runtime/JSSegmentedVariableObject.cpp: Added. + (JSC): + (JSC::JSSegmentedVariableObject::findRegisterIndex): + (JSC::JSSegmentedVariableObject::addRegisters): + (JSC::JSSegmentedVariableObject::visitChildren): + * runtime/JSSegmentedVariableObject.h: Added. + (JSC): + (JSSegmentedVariableObject): + (JSC::JSSegmentedVariableObject::registerAt): + (JSC::JSSegmentedVariableObject::assertRegisterIsInThisObject): + (JSC::JSSegmentedVariableObject::JSSegmentedVariableObject): + (JSC::JSSegmentedVariableObject::finishCreation): + * runtime/JSStaticScopeObject.cpp: + (JSC::JSStaticScopeObject::put): + (JSC::JSStaticScopeObject::putDirectVirtual): + (JSC::JSStaticScopeObject::getOwnPropertySlot): + * runtime/JSSymbolTableObject.cpp: Added. + (JSC): + (JSC::JSSymbolTableObject::destroy): + (JSC::JSSymbolTableObject::deleteProperty): + (JSC::JSSymbolTableObject::getOwnPropertyNames): + (JSC::JSSymbolTableObject::putDirectVirtual): + (JSC::JSSymbolTableObject::isDynamicScope): + * runtime/JSSymbolTableObject.h: Added. + (JSC): + (JSSymbolTableObject): + (JSC::JSSymbolTableObject::symbolTable): + (JSC::JSSymbolTableObject::JSSymbolTableObject): + (JSC::JSSymbolTableObject::finishCreation): + (JSC::symbolTableGet): + (JSC::symbolTablePut): + (JSC::symbolTablePutWithAttributes): + * runtime/JSVariableObject.cpp: + (JSC): + * runtime/JSVariableObject.h: + (JSVariableObject): + (JSC::JSVariableObject::JSVariableObject): + (JSC::JSVariableObject::finishCreation): + (JSC): + * runtime/WriteBarrier.h: + +2012-06-06 Filip Pizlo <fpizlo@apple.com> + + DFG arguments access slow path should not crash if the arguments haven't been created + https://bugs.webkit.org/show_bug.cgi?id=88471 + + Reviewed by Gavin Barraclough. + + * dfg/DFGCCallHelpers.h: + (JSC::DFG::CCallHelpers::setupArgumentsWithExecState): + (CCallHelpers): + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::callOperation): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + +2012-06-06 Michael Saboff <msaboff@apple.com> + + ENH: Add Logging to GC Marking Phase + https://bugs.webkit.org/show_bug.cgi?id=88364 + + Reviewed by Filip Pizlo. + + Log GC marking to stderr or a file. The logging in controlled + with the define ENABLE_OBJECT_MARK_LOGGING in wtf/Platform.h. + If DATA_LOG_TO_FILE in wtf/DataLog.cpp is set to 1, output is + logged to a file otherwise it is logged to stderr. + + When logging is enabled, the GC is built single threaded since the + log output from the various threads isn't buffered and output in a + thread safe manner. + + * heap/Heap.cpp: + (JSC::Heap::markRoots): + * heap/MarkStack.cpp: + (JSC::MarkStackThreadSharedData::resetChildren): + (JSC::MarkStackThreadSharedData::childVisitCount): + (JSC::MarkStackThreadSharedData::markingThreadMain): + (JSC::MarkStackThreadSharedData::markingThreadStartFunc): + (JSC::MarkStackThreadSharedData::MarkStackThreadSharedData): + (JSC::MarkStackThreadSharedData::reset): + * heap/MarkStack.h: + (MarkStackThreadSharedData): + (MarkStack): + (JSC::MarkStack::sharedData): + (JSC::MarkStack::resetChildCount): + (JSC::MarkStack::childCount): + (JSC::MarkStack::incrementChildCount): + * runtime/JSArray.cpp: + (JSC::JSArray::visitChildren): + * runtime/JSCell.cpp: + (JSC::JSCell::className): + * runtime/JSCell.h: + (JSCell): + (JSC::JSCell::visitChildren): + * runtime/JSString.cpp: + (JSC::JSString::visitChildren): + * runtime/JSString.h: + (JSString): + * runtime/Structure.h: + (JSC::MarkStack::internalAppend): + +2012-06-06 Gavin Barraclough <barraclough@apple.com> + + Assigning to a static property should not change iteration order + https://bugs.webkit.org/show_bug.cgi?id=88401 + + Reviewed by Geoff Garen. + + A specific iteration order is not defined by the spec, but test-262 somewhat tenuously + requires that it is at least stable, e.g. ch10/10.4/10.4.2/S10.4.2_A1.1_T1.js + + Whilst it is not clear that this behavior really arises from the specification, it + would seem like common sense to conform to this. + + The problem here is that we allow properties in the structure to shadow those in the + static table, and we iterate the properties in the structure first - which means that + as values of existing properties are modified, their iteration order changes too. + + The easy fix is to iterate the properties from the static table first. This has a + further benefit, since it will mean that user added properties will come after those + present in the static table (respected the expected insertion-order). + + * runtime/JSObject.cpp: + (JSC::JSObject::getOwnPropertyNames): + - Iterate static properties first. + +2012-06-06 Andy Wingo <wingo@igalia.com> + + Ensure consistent order of evaluation in LLInt slow paths + https://bugs.webkit.org/show_bug.cgi?id=88409 + + Reviewed by Geoffrey Garen. + + * llint/LLIntSlowPaths.cpp: + (slow_path_mul) + (slow_path_sub) + (slow_path_div) + (slow_path_mod) + (slow_path_lshift) + (slow_path_rshift) + (slow_path_urshift) + (slow_path_bitand) + (slow_path_bitor) + (slow_path_bitxor): Avoid calling toNumber, toInt32, or toUInt32 + multiple times without intervening sequence points. Fixes + fast/js/exception-sequencing-binops.html with GCC 4.7 on x86-64 + Linux, which reordered evaluation of the arguments to fmod. + +2012-06-06 Andy Wingo <wingo@igalia.com> + + [GTK] Enable the LLInt + https://bugs.webkit.org/show_bug.cgi?id=88315 + + Reviewed by Filip Pizlo. + + * GNUmakefile.am: Add rules to generate LLIntDesiredOffsets.h and + LLIntAssembly.h. + * GNUmakefile.list.am: Add offlineasm and llint files to the + dist. Add LLInt source files to the build. + * llint/LowLevelInterpreter.asm (crash): Generate a store of + 0xbbadbeef to a register, not to a constant. Otherwise, gas was + failing to assemble result. + * offlineasm/asm.rb (labelReference): Generate a + SYMBOL_STRING_RELOCATION instead of a SYMBOL_STRING, so that we go + through the PLT on ELF systems. + +2012-06-06 Andy Wingo <wingo@igalia.com> + + REGRESSION (r106478): None of the Paper.js JavaScript examples work + https://bugs.webkit.org/show_bug.cgi?id=87158 + + Reviewed by Michael Saboff. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::resolve): If we have to bail out to + dynamicResolve(), only skip static scopes from the head of the + scope chain. Before, we were also skipping activations with + direct eval as well, which was incorrect. + +2012-06-06 Dan Bernstein <mitz@apple.com> + + Reverted r119567, the fix for <http://webkit.org/b/88378>, because it broke the 32-bit build. + + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::emitAllocateBasicJSObject): + * jit/JITInlineMethods.h: + (JSC::JIT::emitAllocateBasicJSObject): + * llint/LowLevelInterpreter.asm: + * runtime/JSGlobalData.h: + (JSGlobalData): + * runtime/JSGlobalThis.cpp: + (JSC::JSGlobalThis::setUnwrappedObject): + * runtime/JSObject.cpp: + (JSC::JSObject::visitChildren): + (JSC::JSObject::createInheritorID): + * runtime/JSObject.h: + (JSObject): + (JSC::JSObject::resetInheritorID): + (JSC): + (JSC::JSObject::offsetOfInheritorID): + (JSC::JSObject::inheritorID): + +2012-06-05 Yuqiang Xian <yuqiang.xian@intel.com> + + Improve Math.round and Math.floor intrinsic + https://bugs.webkit.org/show_bug.cgi?id=88314 + + Reviewed by Filip Pizlo. + + Currently we call a native function from the JIT code to complete the + "round" and "floor" operations. We could inline some fast paths + especially for those positive values on the platforms where floating + point truncation is supported. + This brings 3% gain on Kraken, especially 32% on audio-oscillator, + and slight win on SunSpider, measured on IA32. + + * jit/ThunkGenerators.cpp: + (JSC::floorThunkGenerator): + (JSC): + (JSC::roundThunkGenerator): + +2012-06-05 Gavin Barraclough <barraclough@apple.com> + + Remove JSObject::m_inheritorID + https://bugs.webkit.org/show_bug.cgi?id=88378 + + Reviewed by Geoff Garen. + + This is rarely used, and not performance critical (the commonly accessed copy is cached on JSFunction), + and most objects don't need an inheritorID (this value is only used if the object is used as a prototype). + Instead use a private named value in the object's property storage. + + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::emitAllocateBasicJSObject): + - No need m_inheritorID to initialize! + * jit/JITInlineMethods.h: + (JSC::JIT::emitAllocateBasicJSObject): + - No need m_inheritorID to initialize! + * llint/LowLevelInterpreter.asm: + - No need m_inheritorID to initialize! + * runtime/JSGlobalData.h: + (JSGlobalData): + - Added private name 'm_inheritorIDKey'. + * runtime/JSGlobalThis.cpp: + (JSC::JSGlobalThis::setUnwrappedObject): + - resetInheritorID is now passed a JSGlobalData&. + * runtime/JSObject.cpp: + (JSC::JSObject::visitChildren): + - No m_inheritorID to be marked. + (JSC::JSObject::createInheritorID): + - Store the newly created inheritorID in the property map. + * runtime/JSObject.h: + (JSC::JSObject::resetInheritorID): + - Remove the inheritorID from property storage. + (JSC::JSObject::inheritorID): + - Read the inheritorID from property storage. + +2012-06-05 Filip Pizlo <fpizlo@apple.com> + + DFG CFG simplification should not attempt to deref nodes inside of an unreachable subgraph + https://bugs.webkit.org/show_bug.cgi?id=88362 + + Reviewed by Gavin Barraclough. + + * dfg/DFGCFGSimplificationPhase.cpp: + (JSC::DFG::CFGSimplificationPhase::fixPhis): + (JSC::DFG::CFGSimplificationPhase::removePotentiallyDeadPhiReference): + +2012-06-05 Mark Hahnenberg <mhahnenberg@apple.com> + + Entry into JSC should CRASH() if the Heap is busy + https://bugs.webkit.org/show_bug.cgi?id=88355 + + Reviewed by Geoffrey Garen. + + Interpreter::execute() returns jsNull() right now if we try to enter it while + the Heap is busy (e.g. with a collection), which is okay, but some code paths + that call Interpreter::execute() allocate objects before checking if the Heap + is busy. Attempting to execute JS code while the Heap is busy should not be + allowed and should be enforced by a release-mode CRASH() to prevent vague, + unhelpful backtraces later on if somebody makes a mistake. Normally, recursively + executing JS code is okay, e.g. for evals, but it should not occur during a + Heap allocation or collection because the Heap is not guaranteed to be in a + consistent state (especially during collections). We are protected from + executing JS on the same Heap concurrently on two separate threads because + they must each take a JSLock first. However, we are not protected from reentrant + execution of JS on the same thread because JSLock allows reentrancy. Therefore, + we should fail early if we detect an entrance into JS code while the Heap is busy. + + * heap/Heap.cpp: Changed Heap::collect so that it sets the m_operationInProgress field + at the beginning of collection and then unsets it at the end so that it is set at all + times throughout the duration of a collection rather than sporadically during various + phases. There is no reason to unset during a collection because our collector does + not currently support running additional JS between the phases of a collection. + (JSC::Heap::getConservativeRegisterRoots): + (JSC::Heap::markRoots): + (JSC::Heap::collect): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): Crash if the Heap is busy. + * runtime/Completion.cpp: Crash if the Heap is busy. We do it here before we call + Interpreter::execute() because we do some allocation prior to calling execute() which + could cause Heap corruption if, for example, that allocation caused a collection. + (JSC::evaluate): + +2012-06-05 Dongwoo Im <dw.im@samsung.com> + + Add 'isProtocolHandlerRegistered' and 'unregisterProtocolHandler'. + https://bugs.webkit.org/show_bug.cgi?id=73176 + + Reviewed by Adam Barth. + + Two more APIs are added in Custom Scheme Handler specification. + http://dev.w3.org/html5/spec/Overview.html#custom-handlers + One is 'isProtocolHandlerRegistered' to query whether the specific URL + is registered or not. + The other is 'unregisterProtocolHandler' to remove the registered URL. + + * Configurations/FeatureDefines.xcconfig: Add a macro 'ENABLE_CUSTOM_SCHEME_HANDLER'. + +2012-06-04 Filip Pizlo <fpizlo@apple.com> + + DFG CFG simplification should correct the variables at the head of the predecessor block + https://bugs.webkit.org/show_bug.cgi?id=88284 + + Reviewed by Geoffrey Garen. + + * dfg/DFGCFGSimplificationPhase.cpp: + (JSC::DFG::CFGSimplificationPhase::mergeBlocks): + +2012-06-04 Geoffrey Garen <ggaren@apple.com> + + Unreviewed. + + Rolled out r119364 because it's still causing crashes (when running + v8-earley in release builds of DRT) + + This time for sure! + + * heap/Heap.cpp: + (JSC::Heap::collect): + * heap/MarkedBlock.cpp: + (JSC::MarkedBlock::sweep): + * heap/MarkedBlock.h: + (JSC::MarkedBlock::resetAllocator): + (JSC): + * heap/MarkedSpace.cpp: + (JSC::ResetAllocator::operator()): + (JSC): + (JSC::MarkedSpace::resetAllocators): + (JSC::MarkedSpace::sweepWeakSets): + * heap/MarkedSpace.h: + (MarkedSpace): + * heap/WeakBlock.cpp: + (JSC::WeakBlock::sweep): + * heap/WeakSet.cpp: + (JSC::WeakSet::sweep): + (JSC::WeakSet::tryFindAllocator): + * heap/WeakSet.h: + (JSC::WeakSet::shrink): + +2012-06-04 Filip Pizlo <fpizlo@apple.com> + + DFG arguments simplification should have rationalized handling of TearOffArguments + https://bugs.webkit.org/show_bug.cgi?id=88206 + + Reviewed by Geoffrey Garen. + + - Accesses to the unmodified arguments register ought to have the same effect on + alias/escape analysis of arguments as accesses to the mutable arguments register. + + - The existence of TearOffArguments should not get in the way of arguments aliasing. + + - TearOffArguments should be eliminated if CreateArguments is eliminated. + + * dfg/DFGArgumentsSimplificationPhase.cpp: + (JSC::DFG::ArgumentsSimplificationPhase::run): + (JSC::DFG::ArgumentsSimplificationPhase::observeBadArgumentsUse): + +2012-06-04 Gavin Barraclough <barraclough@apple.com> + + Remove enabledProfilerReference + https://bugs.webkit.org/show_bug.cgi?id=88258 + + Reviewed by Michael Saboff. + + Make the enabled profiler a member of JSGlobalData, and switch code that accesses it to do so directly + via the JSGlobalData, rather than holding a Profiler** reference to it. Do not pass the Profiler** + reference to JIT code. This patch does not change the stack layout on entry into JIT code (passing an + unused void* instead), since this is an intrusive change better handled in a separate patch. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::throwException): + (JSC::Interpreter::execute): + (JSC::Interpreter::executeCall): + (JSC::Interpreter::executeConstruct): + (JSC::Interpreter::privateExecute): + * jit/JITCode.h: + (JSC::JITCode::execute): + - Don't pass Profiler** to JIT code. + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_profile_will_call): + (JSC::JIT::emit_op_profile_did_call): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_profile_will_call): + (JSC::JIT::emit_op_profile_did_call): + * jit/JITStubs.cpp: + (JSC): + (JSC::ctiTrampoline): + (JSC::ctiVMThrowTrampoline): + (JSC::ctiOpThrowNotCaught): + (JSC::JITThunks::JITThunks): + (JSC::DEFINE_STUB_FUNCTION): + - For ARM_THUMB2, rename ENABLE_PROFILER_REFERENCE_OFFSET to FIRST_STACK_ARGUMENT (which is how it is being used). + - For MIPS, remove ENABLE_PROFILER_REFERENCE_OFFSET. + * jit/JITStubs.h: + (JITStackFrame): + (JSC): + - Renamed enabledProfilerReference to unusedX. + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LowLevelInterpreter.asm: + * profiler/Profiler.cpp: + (JSC): + (JSC::Profiler::startProfiling): + (JSC::Profiler::stopProfiling): + * profiler/Profiler.h: + (Profiler): + - Removed s_sharedEnabledProfilerReference, enabledProfilerReference(). + * runtime/JSGlobalData.cpp: + (JSC::JSGlobalData::JSGlobalData): + * runtime/JSGlobalData.h: + (JSC): + (JSC::JSGlobalData::enabledProfiler): + (JSGlobalData): + - Added m_enabledProfiler, enabledProfiler(). + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::~JSGlobalObject): + +2012-06-04 Filip Pizlo <fpizlo@apple.com> + + get_argument_by_val should be profiled everywhere + https://bugs.webkit.org/show_bug.cgi?id=88205 + + Reviewed by Geoffrey Garen. + + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emitSlow_op_get_argument_by_val): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + +2012-06-04 Filip Pizlo <fpizlo@apple.com> + + DFG arguments simplification takes unkindly to direct accesses to the arguments register + https://bugs.webkit.org/show_bug.cgi?id=88261 + + Reviewed by Geoffrey Garen. + + Fixed arguments simplification for direct accesses to the arguments register, which may + arise if CSE had not run. Fixed CSE so that it does run prior to arguments simplification, + by making it a full-fledged member of the fixpoint. Fixed other issues in arguments + simplification, like realizing that it needs to bail if there is a direct assignment to + the arguments register, and failing to turn CreateArguments into PhantomArguments. Also + fixed CSE's handling of store elimination of captured locals in the presence of a + GetMyArgumentByVal (or one of its friends), and fixed CSE to correctly fixup variables at + tail if the Flush it removes is the last operation on a local in a basic block. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + * dfg/DFGArgumentsSimplificationPhase.cpp: + (JSC::DFG::ArgumentsSimplificationPhase::run): + (JSC::DFG::ArgumentsSimplificationPhase::isOKToOptimize): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::run): + (JSC::DFG::CSEPhase::setLocalStoreElimination): + (JSC::DFG::CSEPhase::performNodeCSE): + (CSEPhase): + * dfg/DFGDriver.cpp: + (JSC::DFG::compile): + +2012-06-04 Anders Carlsson <andersca@apple.com> + + Fix a struct/class mismatch. + + * heap/Handle.h: + (Handle): + +2012-06-04 David Kilzer <ddkilzer@apple.com> + + BUILD FIX: FeatureDefines.xcconfig should match across projects + + * Configurations/FeatureDefines.xcconfig: + - Add missing ENABLE_LEGACY_CSS_VENDOR_PREFIXES. + +2012-06-02 Geoffrey Garen <ggaren@apple.com> + + Weak pointer finalization should be lazy + https://bugs.webkit.org/show_bug.cgi?id=87599 + + Reviewed by Sam Weinig. + + This time for sure! + + * heap/Heap.cpp: + (JSC::Heap::collect): Don't sweep eagerly -- we'll sweep lazily instead. + + * heap/MarkedBlock.cpp: + (JSC::MarkedBlock::sweep): Sweep our weak set before we sweep our other + destructors -- this is our last chance to run weak set finalizers before + we recycle our memory. + + * heap/MarkedBlock.h: + (JSC::MarkedBlock::resetAllocator): + * heap/MarkedSpace.cpp: + (JSC::MarkedSpace::resetAllocators): + * heap/MarkedSpace.h: + (JSC::MarkedSpace::resetAllocators): Don't force allocator reset anymore. + It will happen automatically when a weak set is swept. It's simpler to + have only one canonical way for this to happen, and it wasn't buying + us anything to do it eagerly. + + * heap/WeakBlock.cpp: + (JSC::WeakBlock::sweep): Don't short-circuit a sweep unless we know + the sweep would be a no-op. If even one finalizer is pending, we need to + run it, since we won't get another chance. + + * heap/WeakSet.cpp: + (JSC::WeakSet::sweep): This loop can be simpler now that + WeakBlock::sweep() does what we mean. + + Reset our allocator after a sweep because this is the optimal time to + start trying to recycle old weak pointers. + + (JSC::WeakSet::tryFindAllocator): Don't sweep when searching for an + allocator because we've swept already, and forcing a new sweep would be + wasteful. + + * heap/WeakSet.h: + (JSC::WeakSet::shrink): Be sure to reset our allocator after a shrink + because the shrink may have removed the block the allocator was going to + allocate out of. + +2012-06-02 Filip Pizlo <fpizlo@apple.com> + + If the DFG bytecode parser detects that op_method_check has gone polymorphic, it + shouldn't revert all the way to GetById/GetByIdFlush + https://bugs.webkit.org/show_bug.cgi?id=88176 + + Reviewed by Geoffrey Garen. + + Refactored the code so that the op_method_check case of the parser gracefully falls + through to all of the goodness of the normal op_get_by_id case. + + * dfg/DFGByteCodeParser.cpp: + (ByteCodeParser): + (JSC::DFG::ByteCodeParser::handleGetById): + (DFG): + (JSC::DFG::ByteCodeParser::parseBlock): + +2012-06-02 Filip Pizlo <fpizlo@apple.com> + + DFG CSE should be able to eliminate unnecessary flushes of arguments and captured variables + https://bugs.webkit.org/show_bug.cgi?id=87929 + + Reviewed by Geoffrey Garen. + + Slight speed-up on V8. Big win (up to 50%) on programs that inline very small functions. + + This required a bunch of changes: + + - The obvious change is making CSE essentially ignore whether or not the set of + operations between the Flush and the SetLocal can exit, and instead focus on whether or + not that set of operations can clobber the world or access local variables. This code + is now refactored to return a set of flags indicating any of these events, and the CSE + decides what to do based on those flags. If the set of operations is non-clobbering + and non-accessing, then the Flush is turned into a Phantom on the child of the + SetLocal. This expands the liveness of the relevant variable but virtually guarantees + that it will be register allocated and not flushed to the stack. So, yeah, this patch + is a lot of work to save a few stores to the stack. + + - Previously, CheckArgumentsNotCreated was optimized "lazily" in that you only knew if + it was a no-op if you were holding onto a CFA abstract state. But this would make the + CSE act pessimistically, since it doesn't use the CFA. Hence, this patch changes the + constant folding phase into something more broad; it now fixes up + CheckArgumentsNotCreated nodes by turning them into phantoms if it knows that they are + no-ops. + + - Arguments simplification was previously relying on this very strange PhantomArguments + node, which had two different meanings: for normal execution it meant the empty value + but for OSR exit it meant that the arguments should be reified. This produces problems + when set SetLocals to the captured arguments registers are CSE'd away, since we'd be + triggering reification of arguments without having initialized the arguments registers + to empty. The cleanest solution was to fix PhantomArguments to have one meaning: + namely, arguments reification on OSR exit. Hence, this patch changes arguments + simplification to change SetLocal of CreateArguments on the arguments registers to be + a SetLocal of Empty. + + - Argument value recoveries were previously derived from the value source of the + arguments at the InlineStart. But that relies on all SetLocals to arguments having + been flushed. It's possible that we could have elided the SetLocal to the arguments + at the callsite because there were subsequent SetLocals to the arguments inside of the + callee, in which case the InlineStart would get the wrong information. Hence, this + patch changes argument value recovery computation to operate over the ArgumentPositions + directly. + + - But that doesn't actually work, because previously, there was no way to link an + InlineStart back to the corresponding ArgumentPositions, at least not without some + ugliness. So this patch instates the rule that the m_argumentPositions vector consists + of disjoint subsequences such that each subsequence corresponds to an inline callsite + and can be identified by its first index, and within each subsequence are the + ArgumentPositions of all of the arguments ordered by argument index. This required + flipping the order in which ArgumentPositions are added to the vector, and giving + InlineStart an operand that indicates the start of that inline callsite's + ArgumentPosition subsequence. + + - This patch also revealed a nasty bug in the reification of arguments in inline call + frames on OSR exit. Since the reification was happening after the values of virtual + registers were recovered, the value recoveries of the inline arguments were wrong. + Hence using operationCreateInlinedArguments is wrong. For example a value recovery + might say that you have to box a double, but if we had already boxed it then boxing + it a second time will result in garbage. The specific case of this bug was this patch + uncovered was that now it is possible for an inline call frame to not have any valid + value recoveries for any inline arguments, if the optimization elides all argument + flushes, while at the same time optimizing away arguments creation. Then OSR exit + would try to recover the arguments using the inline call frame, which had bogus + information, and humorous crashes would ensue. This patch fixes this issue by moving + arguments reification to after call frame reification, so that arguments reification + can always use operationCreateArguments instead of operationCreateInlinedArguments. + + - This patch may turn a Flush into a Phantom. That's kind of the whole point. But that + broke forward speculation checks, which knew to look for a Flush prior to a SetLocal + but didn't know that there could alternatively be a Phantom in place of the Flush. + This patch fixes that by augmenting the forward speculation check logic. + + - Finally, in the process of having fun with all of the above, I realized that my DFG + validation was not actually running on every phase like I had originally designed it + to. In fact it was only running just after bytecode parsing. I initially tried to + make it run in every phase but found that this causes some tests to timeout + (specifically the evil fuzzing ones), so I decided on a compromise where: (i) in + release mode validation never runs, (ii) in debug mode validation will run just + after parsing and just before the backend, and (iii) it's possible with a simple + switch to enable validation to run on every phase. + + Luckily all of the above issues were already covered by the 77 or so DFG-specific + layout tests. Hence, this patch does not introduce any new tests despite being so + meaty. + + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::execute): + * dfg/DFGArgumentPosition.h: + (JSC::DFG::ArgumentPosition::prediction): + (JSC::DFG::ArgumentPosition::doubleFormatState): + (JSC::DFG::ArgumentPosition::shouldUseDoubleFormat): + (ArgumentPosition): + * dfg/DFGArgumentsSimplificationPhase.cpp: + (JSC::DFG::ArgumentsSimplificationPhase::run): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleInlining): + (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::SetLocalStoreEliminationResult::SetLocalStoreEliminationResult): + (SetLocalStoreEliminationResult): + (JSC::DFG::CSEPhase::setLocalStoreElimination): + (JSC::DFG::CSEPhase::performNodeCSE): + * dfg/DFGCommon.h: + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::run): + * dfg/DFGDriver.cpp: + (JSC::DFG::compile): + * dfg/DFGNode.h: + (Node): + (JSC::DFG::Node::hasArgumentPositionStart): + (JSC::DFG::Node::argumentPositionStart): + * dfg/DFGOSRExitCompiler32_64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * dfg/DFGOSRExitCompiler64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * dfg/DFGPhase.cpp: + (DFG): + * dfg/DFGPhase.h: + (Phase): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::forwardSpeculationCheck): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + +2012-06-02 Geoffrey Garen <ggaren@apple.com> + + DOM string cache should hash pointers, not characters + https://bugs.webkit.org/show_bug.cgi?id=88175 + + Reviewed by Phil Pizlo and Sam Weinig. + + * heap/Weak.h: + (JSC::weakAdd): + (JSC::weakRemove): Made these function templates slightly more generic + to accommodate new client types. + +2012-06-01 Filip Pizlo <fpizlo@apple.com> + + DFG CFA should know that PutByVal can clobber the world + https://bugs.webkit.org/show_bug.cgi?id=88155 + + Reviewed by Gavin Barraclough. + + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::execute): + +2012-06-01 Filip Pizlo <fpizlo@apple.com> + + DFG CFA should mark basic blocks as having constants if local accesses yield constants + https://bugs.webkit.org/show_bug.cgi?id=88153 + + Reviewed by Gavin Barraclough. + + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::execute): + +2012-06-01 Filip Pizlo <fpizlo@apple.com> + + DFG arguments simplification phase uses a node.codeOrigin after appending a node + https://bugs.webkit.org/show_bug.cgi?id=88151 + + Reviewed by Geoffrey Garen. + + The right thing to do is to save the CodeOrigin before appending to the graph. + + * dfg/DFGArgumentsSimplificationPhase.cpp: + (JSC::DFG::ArgumentsSimplificationPhase::run): + +2012-06-01 Filip Pizlo <fpizlo@apple.com> + + DFG should not emit unnecessary speculation checks when performing an int32 to double conversion on + a value that is proved to be a number, predicted to be an int32, but not proved to be an int32 + https://bugs.webkit.org/show_bug.cgi?id=88146 + + Reviewed by Gavin Barraclough. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileInt32ToDouble): + +2012-06-01 Filip Pizlo <fpizlo@apple.com> + + DFG constant folding search for the last local access skips the immediately previous local access + https://bugs.webkit.org/show_bug.cgi?id=88141 + + Reviewed by Michael Saboff. + + If you use a loop in the style of: + + for (i = start; i--;) + + then you need to remember that the first value of 'i' that the loop body will see is 'start - 1'. + Hence the following is probably wrong: + + for (i = start - 1; i--;) + + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::run): + +2012-06-01 Filip Pizlo <fpizlo@apple.com> + + DFG constant folding should be OK with GetLocal of captured variables having a constant + https://bugs.webkit.org/show_bug.cgi?id=88137 + + Reviewed by Gavin Barraclough. + + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::run): + 2012-05-31 Mark Hahnenberg <mhahnenberg@apple.com> JSGlobalObject does not mark m_privateNameStructure diff --git a/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig b/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig index 76440b0a6..b96b21db3 100644 --- a/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig +++ b/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig @@ -36,12 +36,14 @@ ENABLE_ACCELERATED_2D_CANVAS = ; ENABLE_ANIMATION_API = ; ENABLE_BLOB = ENABLE_BLOB; ENABLE_CHANNEL_MESSAGING = ENABLE_CHANNEL_MESSAGING; +ENABLE_CSP_NEXT = ; ENABLE_CSS3_FLEXBOX = ENABLE_CSS3_FLEXBOX; ENABLE_CSS_EXCLUSIONS = ENABLE_CSS_EXCLUSIONS; ENABLE_CSS_FILTERS = ENABLE_CSS_FILTERS; ENABLE_CSS_IMAGE_RESOLUTION = ; ENABLE_CSS_REGIONS = ENABLE_CSS_REGIONS; ENABLE_CSS_VARIABLES = ; +ENABLE_CUSTOM_SCHEME_HANDLER = ; ENABLE_DASHBOARD_SUPPORT = $(ENABLE_DASHBOARD_SUPPORT_$(REAL_PLATFORM_NAME)); ENABLE_DASHBOARD_SUPPORT_macosx = ENABLE_DASHBOARD_SUPPORT; ENABLE_DATALIST = ; @@ -82,6 +84,7 @@ ENABLE_INPUT_TYPE_WEEK = $(ENABLE_INPUT_TYPE_WEEK_$(REAL_PLATFORM_NAME)); ENABLE_INPUT_TYPE_WEEK_iphoneos = ENABLE_INPUT_TYPE_WEEK; ENABLE_INPUT_TYPE_WEEK_iphonesimulator = ENABLE_INPUT_TYPE_WEEK; ENABLE_JAVASCRIPT_DEBUGGER = ENABLE_JAVASCRIPT_DEBUGGER; +ENABLE_LEGACY_CSS_VENDOR_PREFIXES = ENABLE_LEGACY_CSS_VENDOR_PREFIXES; ENABLE_LEGACY_NOTIFICATIONS = $(ENABLE_LEGACY_NOTIFICATIONS_$(REAL_PLATFORM_NAME)); ENABLE_LEGACY_NOTIFICATIONS_macosx = $(ENABLE_LEGACY_NOTIFICATIONS_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)); ENABLE_LEGACY_NOTIFICATIONS_macosx_1070 = ; @@ -117,6 +120,7 @@ ENABLE_SVG_DOM_OBJC_BINDINGS_macosx = ENABLE_SVG_DOM_OBJC_BINDINGS; ENABLE_SVG_FONTS = ENABLE_SVG_FONTS; ENABLE_TEXT_NOTIFICATIONS_ONLY = ENABLE_TEXT_NOTIFICATIONS_ONLY; ENABLE_TOUCH_ICON_LOADING = ; +ENABLE_UNDO_MANAGER = ; ENABLE_VIDEO = ENABLE_VIDEO; ENABLE_VIDEO_TRACK = $(ENABLE_VIDEO_TRACK_$(REAL_PLATFORM_NAME)); ENABLE_VIDEO_TRACK_macosx = ENABLE_VIDEO_TRACK; @@ -127,4 +131,4 @@ ENABLE_WEB_TIMING = ; 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_CSS3_FLEXBOX) $(ENABLE_CSS_EXCLUSIONS) $(ENABLE_CSS_FILTERS) $(ENABLE_CSS_IMAGE_RESOLUTION) $(ENABLE_CSS_REGIONS) $(ENABLE_CSS_SHADERS) $(ENABLE_CSS_VARIABLES) $(ENABLE_DASHBOARD_SUPPORT) $(ENABLE_DATALIST) $(ENABLE_DATA_TRANSFER_ITEMS) $(ENABLE_DETAILS) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DIRECTORY_UPLOAD) $(ENABLE_FILE_SYSTEM) $(ENABLE_FILTERS) $(ENABLE_FONT_BOOSTING) $(ENABLE_FULLSCREEN_API) $(ENABLE_GAMEPAD) $(ENABLE_GEOLOCATION) $(ENABLE_HIGH_DPI_CANVAS) $(ENABLE_ICONDATABASE) $(ENABLE_IFRAME_SEAMLESS) $(ENABLE_INDEXED_DATABASE) $(ENABLE_INPUT_TYPE_COLOR) $(ENABLE_INPUT_SPEECH) $(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_NOTIFICATIONS) $(ENABLE_LINK_PREFETCH) $(ENABLE_LINK_PRERENDER) $(ENABLE_MATHML) $(ENABLE_MEDIA_SOURCE) $(ENABLE_MEDIA_STATISTICS) $(ENABLE_METER_TAG) $(ENABLE_MICRODATA) $(ENABLE_MUTATION_OBSERVERS) $(ENABLE_NOTIFICATIONS) $(ENABLE_PAGE_VISIBILITY_API) $(ENABLE_PROGRESS_TAG) $(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_NOTIFICATIONS_ONLY) $(ENABLE_TOUCH_ICON_LOADING) $(ENABLE_VIDEO) $(ENABLE_VIDEO_TRACK) $(ENABLE_WEBGL) $(ENABLE_WEB_AUDIO) $(ENABLE_WEB_SOCKETS) $(ENABLE_WEB_TIMING) $(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_CSS3_FLEXBOX) $(ENABLE_CSS_EXCLUSIONS) $(ENABLE_CSS_FILTERS) $(ENABLE_CSS_IMAGE_RESOLUTION) $(ENABLE_CSS_REGIONS) $(ENABLE_CSS_SHADERS) $(ENABLE_CSS_VARIABLES) $(ENABLE_CUSTOM_SCHEME_HANDLER) $(ENABLE_DASHBOARD_SUPPORT) $(ENABLE_DATALIST) $(ENABLE_DATA_TRANSFER_ITEMS) $(ENABLE_DETAILS) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DIRECTORY_UPLOAD) $(ENABLE_FILE_SYSTEM) $(ENABLE_FILTERS) $(ENABLE_FONT_BOOSTING) $(ENABLE_FULLSCREEN_API) $(ENABLE_GAMEPAD) $(ENABLE_GEOLOCATION) $(ENABLE_HIGH_DPI_CANVAS) $(ENABLE_ICONDATABASE) $(ENABLE_IFRAME_SEAMLESS) $(ENABLE_INDEXED_DATABASE) $(ENABLE_INPUT_TYPE_COLOR) $(ENABLE_INPUT_SPEECH) $(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_TAG) $(ENABLE_MICRODATA) $(ENABLE_MUTATION_OBSERVERS) $(ENABLE_NOTIFICATIONS) $(ENABLE_PAGE_VISIBILITY_API) $(ENABLE_PROGRESS_TAG) $(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_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_WORKERS) $(ENABLE_XSLT); diff --git a/Source/JavaScriptCore/DerivedSources.make b/Source/JavaScriptCore/DerivedSources.make index fb60d30ca..b0b637e88 100644 --- a/Source/JavaScriptCore/DerivedSources.make +++ b/Source/JavaScriptCore/DerivedSources.make @@ -59,6 +59,7 @@ all : \ StringConstructor.lut.h \ StringPrototype.lut.h \ docs/bytecode.html \ + udis86_itab.h \ # # lookup tables for classes @@ -79,6 +80,11 @@ RegExpJitTables.h: create_regex_tables KeywordLookup.h: KeywordLookupGenerator.py Keywords.table python $^ > $@ +# udis86 instruction tables + +udis86_itab.h: $(JavaScriptCore)/disassembler/udis86/itab.py $(JavaScriptCore)/disassembler/udis86/optable.xml + (PYTHONPATH=$(JavaScriptCore)/disassembler/udis86 python $(JavaScriptCore)/disassembler/udis86/itab.py $(JavaScriptCore)/disassembler/udis86/optable.xml || exit 1) + # header detection ifeq ($(OS),MACOS) diff --git a/Source/JavaScriptCore/GNUmakefile.am b/Source/JavaScriptCore/GNUmakefile.am index 1ad42fd1c..96a23f288 100644 --- a/Source/JavaScriptCore/GNUmakefile.am +++ b/Source/JavaScriptCore/GNUmakefile.am @@ -51,6 +51,7 @@ javascriptcore_cppflags += \ -I$(srcdir)/Source/JavaScriptCore/bytecode \ -I$(srcdir)/Source/JavaScriptCore/bytecompiler \ -I$(srcdir)/Source/JavaScriptCore/dfg \ + -I$(srcdir)/Source/JavaScriptCore/disassembler \ -I$(srcdir)/Source/JavaScriptCore/heap \ -I$(srcdir)/Source/JavaScriptCore/debugger \ -I$(srcdir)/Source/JavaScriptCore/ForwardingHeaders \ @@ -89,6 +90,16 @@ DerivedSources/JavaScriptCore/RegExpJitTables.h: $(srcdir)/Source/JavaScriptCore DerivedSources/JavaScriptCore/KeywordLookup.h: $(srcdir)/Source/JavaScriptCore/KeywordLookupGenerator.py $(srcdir)/Source/JavaScriptCore/parser/Keywords.table $(AM_V_GEN)$(PYTHON) $^ > $@ +DerivedSources/JavaScriptCore/LLIntDesiredOffsets.h: $(javascriptcore_sources) $(llint_nosources) $(offlineasm_nosources) + $(AM_V_GEN)$(RUBY) $(srcdir)/Source/JavaScriptCore/offlineasm/generate_offset_extractor.rb $(srcdir)/Source/JavaScriptCore/llint/LowLevelInterpreter.asm $@ + +$(Programs_LLIntOffsetsExtractor_OBJECTS): DerivedSources/JavaScriptCore/LLIntDesiredOffsets.h + +DerivedSources/JavaScriptCore/LLIntAssembly.h: Programs/LLIntOffsetsExtractor$(EXEEXT) + $(AM_V_GEN)$(RUBY) $(srcdir)/Source/JavaScriptCore/offlineasm/asm.rb $(srcdir)/Source/JavaScriptCore/llint/LowLevelInterpreter.asm Programs/LLIntOffsetsExtractor$(EXEEXT) $@ + +$(libjavascriptcoregtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_OBJECTS): DerivedSources/JavaScriptCore/LLIntAssembly.h + jsc: $(javascriptcore_built_nosources) Programs/jsc$(EXEEXT) bin_PROGRAMS += \ @@ -96,7 +107,8 @@ bin_PROGRAMS += \ noinst_PROGRAMS += \ Programs/jsc \ - Programs/minidom + Programs/minidom \ + Programs/LLIntOffsetsExtractor Programs_minidom_CPPFLAGS = \ $(global_cppflags) \ @@ -119,6 +131,30 @@ Programs_minidom_LDFLAGS = \ -no-install \ -no-fast-install +Programs_LLIntOffsetsExtractor_CPPFLAGS = \ + $(global_cppflags) \ + $(javascriptcore_cppflags) + +Programs_LLIntOffsetsExtractor_CFLAGS = \ + -ansi \ + -fno-strict-aliasing \ + $(global_cflags) \ + $(GLOBALDEPS_CFLAGS) + +Programs_LLIntOffsetsExtractor_LDADD = \ + -lpthread \ + libWTF.la \ + $(UNICODE_LIBS) \ + $(GLIB_LIBS) \ + $(WINMM_LIBS) \ + -lm \ + -lpthread \ + -lstdc++ + +Programs_LLIntOffsetsExtractor_LDFLAGS = \ + -no-install \ + -no-fast-install + # jsc Programs/jsc$(EXEEXT): Programs/jsc-@WEBKITGTK_API_MAJOR_VERSION@$(EXEEXT) $(AM_V_GEN)cp -f Programs/jsc-@WEBKITGTK_API_MAJOR_VERSION@$(EXEEXT) Programs/jsc$(EXEEXT) @@ -151,12 +187,15 @@ EXTRA_DIST += \ Source/JavaScriptCore/icu/README \ Source/JavaScriptCore/KeywordLookupGenerator.py \ Source/JavaScriptCore/parser/Keywords.table \ - Source/JavaScriptCore/THANKS + Source/JavaScriptCore/THANKS \ + $(llint_nosources) \ + $(offlineasm_nosources) CLEANFILES += \ $(javascriptcore_built_nosources) \ Programs/jsc \ Programs/jsc-@WEBKITGTK_API_MAJOR_VERSION@ \ + Programs/LLIntOffsetsExtractor \ Programs/minidom DISTCLEANFILES += \ diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am index efd4b5fd8..77409fe93 100644 --- a/Source/JavaScriptCore/GNUmakefile.list.am +++ b/Source/JavaScriptCore/GNUmakefile.list.am @@ -20,7 +20,7 @@ javascriptcore_built_nosources += \ DerivedSources/JavaScriptCore/JSGlobalObject.lut.h \ DerivedSources/JavaScriptCore/JSONObject.lut.h \ DerivedSources/JavaScriptCore/MathObject.lut.h \ - DerivedSources/JavaScriptCore/NamePrototype.lut.h \ + DerivedSources/JavaScriptCore/NamePrototype.lut.h \ DerivedSources/JavaScriptCore/NumberConstructor.lut.h \ DerivedSources/JavaScriptCore/NumberPrototype.lut.h \ DerivedSources/JavaScriptCore/ObjectConstructor.lut.h \ @@ -29,7 +29,9 @@ javascriptcore_built_nosources += \ DerivedSources/JavaScriptCore/RegExpObject.lut.h \ DerivedSources/JavaScriptCore/RegExpPrototype.lut.h \ DerivedSources/JavaScriptCore/StringConstructor.lut.h \ - DerivedSources/JavaScriptCore/StringPrototype.lut.h + DerivedSources/JavaScriptCore/StringPrototype.lut.h \ + DerivedSources/JavaScriptCore/LLIntDesiredOffsets.h \ + DerivedSources/JavaScriptCore/LLIntAssembly.h javascriptcore_sources += \ Source/JavaScriptCore/API/APICast.h \ @@ -63,6 +65,7 @@ javascriptcore_sources += \ Source/JavaScriptCore/assembler/AssemblerBuffer.h \ Source/JavaScriptCore/assembler/AssemblerBufferWithConstantPool.h \ Source/JavaScriptCore/assembler/CodeLocation.h \ + Source/JavaScriptCore/assembler/LinkBuffer.cpp \ Source/JavaScriptCore/assembler/LinkBuffer.h \ Source/JavaScriptCore/assembler/MacroAssembler.h \ Source/JavaScriptCore/assembler/MacroAssemblerARM.cpp \ @@ -118,8 +121,8 @@ javascriptcore_sources += \ Source/JavaScriptCore/bytecode/Operands.h \ Source/JavaScriptCore/bytecode/PolymorphicPutByIdList.cpp \ Source/JavaScriptCore/bytecode/PolymorphicPutByIdList.h \ - Source/JavaScriptCore/bytecode/PredictedType.cpp \ - Source/JavaScriptCore/bytecode/PredictedType.h \ + Source/JavaScriptCore/bytecode/SpeculatedType.cpp \ + Source/JavaScriptCore/bytecode/SpeculatedType.h \ Source/JavaScriptCore/bytecode/PutByIdStatus.cpp \ Source/JavaScriptCore/bytecode/PutByIdStatus.h \ Source/JavaScriptCore/bytecode/PutKind.h \ @@ -131,6 +134,8 @@ javascriptcore_sources += \ Source/JavaScriptCore/bytecode/ValueProfile.h \ Source/JavaScriptCore/bytecode/ValueRecovery.h \ Source/JavaScriptCore/bytecode/VirtualRegister.h \ + Source/JavaScriptCore/bytecode/Watchpoint.cpp \ + Source/JavaScriptCore/bytecode/Watchpoint.h \ Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp \ Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h \ Source/JavaScriptCore/bytecompiler/Label.h \ @@ -217,6 +222,7 @@ javascriptcore_sources += \ Source/JavaScriptCore/dfg/DFGVariableAccessData.h \ Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp \ Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.h \ + Source/JavaScriptCore/disassembler/Disassembler.h \ Source/JavaScriptCore/heap/CopiedAllocator.h \ Source/JavaScriptCore/heap/CopiedBlock.h \ Source/JavaScriptCore/heap/CopiedSpace.cpp \ @@ -232,8 +238,10 @@ javascriptcore_sources += \ Source/JavaScriptCore/heap/HandleSet.cpp \ Source/JavaScriptCore/heap/HandleSet.h \ Source/JavaScriptCore/heap/HeapBlock.h \ - Source/JavaScriptCore/heap/IncrementalSweeper.h \ - Source/JavaScriptCore/heap/IncrementalSweeper.cpp \ + Source/JavaScriptCore/heap/HeapTimer.h \ + Source/JavaScriptCore/heap/HeapTimer.cpp \ + Source/JavaScriptCore/heap/IncrementalSweeper.h \ + Source/JavaScriptCore/heap/IncrementalSweeper.cpp \ Source/JavaScriptCore/heap/SlotVisitor.h \ Source/JavaScriptCore/heap/HandleStack.cpp \ Source/JavaScriptCore/heap/HandleStack.h \ @@ -357,9 +365,18 @@ javascriptcore_sources += \ Source/JavaScriptCore/jit/SpecializedThunkJIT.h \ Source/JavaScriptCore/jit/ThunkGenerators.cpp \ Source/JavaScriptCore/jit/ThunkGenerators.h \ + Source/JavaScriptCore/llint/LLIntCommon.h \ + Source/JavaScriptCore/llint/LLIntData.cpp \ Source/JavaScriptCore/llint/LLIntData.h \ Source/JavaScriptCore/llint/LLIntEntrypoints.cpp \ Source/JavaScriptCore/llint/LLIntEntrypoints.h \ + Source/JavaScriptCore/llint/LLIntExceptions.cpp \ + Source/JavaScriptCore/llint/LLIntExceptions.h \ + Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h \ + Source/JavaScriptCore/llint/LLIntSlowPaths.cpp \ + Source/JavaScriptCore/llint/LLIntSlowPaths.h \ + Source/JavaScriptCore/llint/LLIntThunks.cpp \ + Source/JavaScriptCore/llint/LLIntThunks.h \ Source/JavaScriptCore/llint/LowLevelInterpreter.cpp \ Source/JavaScriptCore/llint/LowLevelInterpreter.h \ Source/JavaScriptCore/os-win32/stdbool.h \ @@ -490,6 +507,8 @@ javascriptcore_sources += \ Source/JavaScriptCore/runtime/JSONObject.h \ Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp \ Source/JavaScriptCore/runtime/JSPropertyNameIterator.h \ + Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp \ + Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h \ Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp \ Source/JavaScriptCore/runtime/JSStaticScopeObject.h \ Source/JavaScriptCore/runtime/JSStringBuilder.h \ @@ -497,6 +516,8 @@ javascriptcore_sources += \ Source/JavaScriptCore/runtime/JSStringJoiner.h \ Source/JavaScriptCore/runtime/JSString.cpp \ Source/JavaScriptCore/runtime/JSString.h \ + Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp \ + Source/JavaScriptCore/runtime/JSSymbolTableObject.h \ Source/JavaScriptCore/runtime/JSType.h \ Source/JavaScriptCore/runtime/JSTypeInfo.h \ Source/JavaScriptCore/runtime/JSValue.cpp \ @@ -588,6 +609,7 @@ javascriptcore_sources += \ Source/JavaScriptCore/runtime/Structure.cpp \ Source/JavaScriptCore/runtime/Structure.h \ Source/JavaScriptCore/runtime/StructureTransitionTable.h \ + Source/JavaScriptCore/runtime/SymbolTable.cpp \ Source/JavaScriptCore/runtime/SymbolTable.h \ Source/JavaScriptCore/runtime/Terminator.h \ Source/JavaScriptCore/runtime/TimeoutChecker.cpp \ @@ -626,6 +648,27 @@ javascriptcore_sources += \ Source/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp endif +llint_nosources += \ + Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm \ + Source/JavaScriptCore/llint/LowLevelInterpreter64.asm \ + Source/JavaScriptCore/llint/LowLevelInterpreter.asm + +offlineasm_nosources += \ + Source/JavaScriptCore/offlineasm/armv7.rb \ + Source/JavaScriptCore/offlineasm/asm.rb \ + Source/JavaScriptCore/offlineasm/ast.rb \ + Source/JavaScriptCore/offlineasm/backends.rb \ + Source/JavaScriptCore/offlineasm/generate_offset_extractor.rb \ + Source/JavaScriptCore/offlineasm/instructions.rb \ + Source/JavaScriptCore/offlineasm/offsets.rb \ + Source/JavaScriptCore/offlineasm/opt.rb \ + Source/JavaScriptCore/offlineasm/parser.rb \ + Source/JavaScriptCore/offlineasm/registers.rb \ + Source/JavaScriptCore/offlineasm/self_hash.rb \ + Source/JavaScriptCore/offlineasm/settings.rb \ + Source/JavaScriptCore/offlineasm/transform.rb \ + Source/JavaScriptCore/offlineasm/x86.rb + # minidom Programs_minidom_SOURCES = \ Source/JavaScriptCore/API/tests/JSNode.c \ @@ -638,6 +681,9 @@ Programs_minidom_SOURCES = \ Source/JavaScriptCore/API/tests/NodeList.h \ Source/JavaScriptCore/API/tests/minidom.c +Programs_LLIntOffsetsExtractor_SOURCES = \ + Source/JavaScriptCore/llint/LLIntOffsetsExtractor.cpp + Programs_jsc_@WEBKITGTK_API_MAJOR_VERSION@_SOURCES = \ Source/JavaScriptCore/JSCTypedArrayStubs.h \ Source/JavaScriptCore/jsc.cpp diff --git a/Source/JavaScriptCore/JavaScriptCore.gyp/JavaScriptCore.gyp b/Source/JavaScriptCore/JavaScriptCore.gyp/JavaScriptCore.gyp index f0de2f073..8da950f5e 100644 --- a/Source/JavaScriptCore/JavaScriptCore.gyp/JavaScriptCore.gyp +++ b/Source/JavaScriptCore/JavaScriptCore.gyp/JavaScriptCore.gyp @@ -84,15 +84,7 @@ '../runtime', ], 'sources': [ - '<@(javascriptcore_files)', - ], - 'sources/': [ - # First exclude everything ... - ['exclude', '../'], - # ... Then include what we want. - ['include', '../yarr/'], - # The Yarr JIT isn't used in WebCore. - ['exclude', '../yarr/YarrJIT\\.(h|cpp)$'], + '<@(javascriptcore_yarr_files)', ], 'export_dependent_settings': [ '../../WTF/WTF.gyp/WTF.gyp:wtf', diff --git a/Source/JavaScriptCore/JavaScriptCore.gypi b/Source/JavaScriptCore/JavaScriptCore.gypi index 6f4598f41..1f1802bde 100644 --- a/Source/JavaScriptCore/JavaScriptCore.gypi +++ b/Source/JavaScriptCore/JavaScriptCore.gypi @@ -1,595 +1,14 @@ { 'variables': { 'project_dir': ['.'], - # These headers are part of JavaScriptCore's public API in the Apple Mac build. - 'javascriptcore_publicheader_files': [ - 'API/APICast.h', - 'API/APIShims.h', - 'API/JSBase.h', - 'API/JSContextRef.h', - 'API/JSContextRefPrivate.h', - 'API/JSObjectRef.h', - 'API/JSObjectRefPrivate.h', - 'API/JSRetainPtr.h', - 'API/JSStringRef.h', - 'API/JSStringRefBSTR.h', - 'API/JSStringRefCF.h', - 'API/JSValueRef.h', - 'API/JSWeakObjectMapRefInternal.h', - 'API/JSWeakObjectMapRefPrivate.h', - 'API/JavaScript.h', - 'API/JavaScriptCore.h', - 'API/OpaqueJSString.h', - 'API/WebKitAvailability.h', - ], - # These headers are part of JavaScriptCore's private API in the Apple Mac build. - 'javascriptcore_privateheader_files': [ - 'assembler/AbstractMacroAssembler.h', - 'assembler/ARMAssembler.h', - 'assembler/ARMv7Assembler.h', - 'assembler/AssemblerBuffer.h', - 'assembler/AssemblerBufferWithConstantPool.h', - 'assembler/CodeLocation.h', - 'assembler/LinkBuffer.h', - 'assembler/MacroAssembler.h', - 'assembler/MacroAssemblerARM.h', - 'assembler/MacroAssemblerARMv7.h', - 'assembler/MacroAssemblerCodeRef.h', - 'assembler/MacroAssemblerMIPS.h', - 'assembler/MacroAssemblerSH4.h', - 'assembler/MacroAssemblerX86.h', - 'assembler/MacroAssemblerX86Common.h', - 'assembler/MacroAssemblerX86_64.h', - 'assembler/MIPSAssembler.h', - 'assembler/RepatchBuffer.h', - 'assembler/SH4Assembler.h', - 'assembler/X86Assembler.h', - 'bytecode/BytecodeConventions.h', - 'bytecode/CallLinkInfo.h', - 'bytecode/CallLinkStatus.h', - 'bytecode/CallReturnOffsetToBytecodeOffset.h', - 'bytecode/CodeBlock.h', - 'bytecode/CodeOrigin.h', - 'bytecode/CodeType.h', - 'bytecode/DataFormat.h', - 'bytecode/DFGExitProfile.h', - 'bytecode/EvalCodeCache.h', - 'bytecode/ExecutionCounter.h', - 'bytecode/ExpressionRangeInfo.h', - 'bytecode/GetByIdStatus.h', - 'bytecode/GlobalResolveInfo.h', - 'bytecode/HandlerInfo.h', - 'bytecode/Instruction.h', - 'bytecode/JumpTable.h', - 'bytecode/LazyOperandValueProfile.h', - 'bytecode/LineInfo.h', - 'bytecode/LLIntCallLinkInfo.h', - 'bytecode/MethodCallLinkInfo.h', - 'bytecode/MethodCallLinkStatus.h', - 'bytecode/MethodOfGettingAValueProfile.h', - 'bytecode/Opcode.h', - 'bytecode/Operands.h', - 'bytecode/PolymorphicPutByIdList.h', - 'bytecode/PredictedType.h', - 'bytecode/PredictionTracker.h', - 'bytecode/PutByIdStatus.h', - 'bytecode/PutKind.h', - 'bytecode/SamplingTool.h', - 'bytecode/StructureSet.h', - 'bytecode/StructureStubInfo.h', - 'bytecode/ValueProfile.h', - 'bytecode/ValueRecovery.h', - 'bytecode/VirtualRegister.h', - 'dfg/DFGAbstractState.h', - 'dfg/DFGAbstractValue.h', - 'dfg/DFGAdjacencyList.h', - 'dfg/DFGAssemblyHelpers.h', - 'dfg/DFGBasicBlock.h', - 'dfg/DFGByteCodeCache.h', - 'dfg/DFGByteCodeParser.h', - 'dfg/DFGCapabilities.h', - 'dfg/DFGCCallHelpers.h', - 'dfg/DFGCFAPhase.h', - 'dfg/DFGCommon.h', - 'dfg/DFGCorrectableJumpPoint.h', - 'dfg/DFGCSEPhase.h', - 'dfg/DFGDriver.h', - 'dfg/DFGEdge.h', - 'dfg/DFGFixupPhase.h', - 'dfg/DFGFPRInfo.h', - 'dfg/DFGGenerationInfo.h', - 'dfg/DFGGPRInfo.h', - 'dfg/DFGGraph.h', - 'dfg/DFGInsertionSet.h', - 'dfg/DFGJITCompiler.h', - 'dfg/DFGNode.h', - 'dfg/DFGNodeFlags.h', - 'dfg/DFGNodeType.h', - 'dfg/DFGOperations.h', - 'dfg/DFGOSREntry.h', - 'dfg/DFGOSRExit.h', - 'dfg/DFGOSRExitCompiler.h', - 'dfg/DFGPhase.h', - 'dfg/DFGPredictionPropagationPhase.h', - 'dfg/DFGRedundantPhiEliminationPhase.h', - 'dfg/DFGRegisterBank.h', - 'dfg/DFGRepatch.h', - 'dfg/DFGScoreBoard.h', - 'dfg/DFGSpeculativeJIT.h', - 'dfg/DFGThunks.h', - 'dfg/DFGVariableAccessData.h', - 'dfg/DFGVirtualRegisterAllocationPhase.h', - 'heap/CardSet.h', - 'heap/ConservativeRoots.h', - 'heap/CopiedAllocator.h', - 'heap/CopiedBlock.h', - 'heap/CopiedSpace.h', - 'heap/CopiedSpaceInlineMethods.h', - 'heap/DFGCodeBlocks.h', - 'heap/GCAssertions.h', - 'heap/Handle.h', - 'heap/HandleSet.h', - 'heap/HandleStack.h', - 'heap/HandleTypes.h', - 'heap/Heap.h', - 'heap/HeapBlock.h', - 'heap/HeapRootVisitor.h', - 'heap/IncrementalSweeper.h', - 'heap/ListableHandler.h', - 'heap/Local.h', - 'heap/LocalScope.h', - 'heap/MachineStackMarker.h', - 'heap/MarkedAllocator.h', - 'heap/MarkedBlock.h', - 'heap/MarkedBlockSet.h', - 'heap/MarkedSpace.h', - 'heap/MarkStack.h', - 'heap/PassWeak.h', - 'heap/SlotVisitor.h', - 'heap/Strong.h', - 'heap/StrongInlines.h', - 'heap/TinyBloomFilter.h', - 'heap/UnconditionalFinalizer.h', - 'heap/VTableSpectrum.h', - 'heap/Weak.h', - 'heap/WeakBlock.h', - 'heap/WeakHandleOwner.h', - 'heap/WeakImpl.h', - 'heap/WeakReferenceHarvester.h', - 'heap/WeakSet.h', - 'heap/WeakSetInlines.h', - 'heap/WriteBarrierSupport.h', - 'debugger/Debugger.h', - 'debugger/DebuggerActivation.h', - 'debugger/DebuggerCallFrame.h', - 'interpreter/AbstractPC.h', - 'interpreter/CachedCall.h', - 'interpreter/CallFrame.h', - 'interpreter/CallFrameClosure.h', - 'interpreter/Interpreter.h', - 'interpreter/Register.h', - 'interpreter/RegisterFile.h', - 'jit/CompactJITCodeMap.h', - 'jit/ExecutableAllocator.h', - 'jit/HostCallReturnValue.h', - 'jit/JIT.h', - 'jit/JITCode.h', - 'jit/JITCompilationEffort.h', - 'jit/JITDriver.h', - 'jit/JITExceptions.h', - 'jit/JITInlineMethods.h', - 'jit/JITStubCall.h', - 'jit/JITStubs.h', - 'jit/JITWriteBarrier.h', - 'jit/JSInterfaceJIT.h', - 'jit/SpecializedThunkJIT.h', - 'jit/ThunkGenerators.h', - 'parser/ASTBuilder.h', - 'parser/Lexer.h', - 'parser/NodeConstructors.h', - 'parser/NodeInfo.h', - 'parser/Nodes.h', - 'parser/Parser.h', - 'parser/ParserArena.h', - 'parser/ParserTokens.h', - 'parser/ResultType.h', - 'parser/SourceCode.h', - 'parser/SourceProvider.h', - 'parser/SourceProviderCache.h', - 'parser/SourceProviderCacheItem.h', - 'parser/SyntaxChecker.h', - 'profiler/CallIdentifier.h', - 'profiler/Profile.h', - 'profiler/ProfileGenerator.h', - 'profiler/ProfileNode.h', - 'profiler/Profiler.h', - 'runtime/ArgList.h', - 'runtime/Arguments.h', - 'runtime/ArrayConstructor.h', - 'runtime/ArrayPrototype.h', - 'runtime/BatchedTransitionOptimizer.h', - 'runtime/BigInteger.h', - 'runtime/BooleanConstructor.h', - 'runtime/BooleanObject.h', - 'runtime/BooleanPrototype.h', - 'runtime/CachedTranscendentalFunction.h', - 'runtime/CallData.h', - 'runtime/ClassInfo.h', - 'runtime/CodeSpecializationKind.h', - 'runtime/CommonIdentifiers.h', - 'runtime/CommonSlowPaths.h', - 'runtime/Completion.h', - 'runtime/ConstructData.h', - 'runtime/DateConstructor.h', - 'runtime/DateConversion.h', - 'runtime/DateInstance.h', - 'runtime/DateInstanceCache.h', - 'runtime/DatePrototype.h', - 'runtime/Error.h', - 'runtime/ErrorConstructor.h', - 'runtime/ErrorInstance.h', - 'runtime/ErrorPrototype.h', - 'runtime/ExceptionHelpers.h', - 'runtime/Executable.h', - 'runtime/ExecutionHarness.h', - 'runtime/FunctionConstructor.h', - 'runtime/FunctionPrototype.h', - 'runtime/GCActivityCallback.h', - 'runtime/GetterSetter.h', - 'runtime/Identifier.h', - 'runtime/InitializeThreading.h', - 'runtime/InternalFunction.h', - 'runtime/Intrinsic.h', - 'runtime/JSActivation.h', - 'runtime/JSAPIValueWrapper.h', - 'runtime/JSArray.h', - 'runtime/JSBoundFunction.h', - 'runtime/JSCell.h', - 'runtime/JSChunk.h', - 'runtime/JSDateMath.h', - 'runtime/JSExportMacros.h', - 'runtime/JSFunction.h', - 'runtime/JSGlobalData.h', - 'runtime/JSGlobalObject.h', - 'runtime/JSGlobalObjectFunctions.h', - 'runtime/JSGlobalThis.h', - 'runtime/JSLock.h', - 'runtime/JSNotAnObject.h', - 'runtime/JSObject.h', - 'runtime/JSONObject.h', - 'runtime/JSPropertyNameIterator.h', - 'runtime/JSStaticScopeObject.h', - 'runtime/JSString.h', - 'runtime/JSStringBuilder.h', - 'runtime/JSStringJoiner.h', - 'runtime/JSType.h', - 'runtime/JSTypeInfo.h', - 'runtime/JSValue.h', - 'runtime/JSValueInlineMethods.h', - 'runtime/JSVariableObject.h', - 'runtime/JSWrapperObject.h', - 'runtime/LiteralParser.h', - 'runtime/Lookup.h', - 'runtime/MatchResult.h', - 'runtime/MathObject.h', - 'runtime/MemoryStatistics.h', - 'runtime/NameConstructor.h', - 'runtime/NameInstance.h', - 'runtime/NamePrototype.h', - 'runtime/NativeErrorConstructor.h', - 'runtime/NativeErrorPrototype.h', - 'runtime/NumberConstructor.h', - 'runtime/NumberObject.h', - 'runtime/NumberPrototype.h', - 'runtime/NumericStrings.h', - 'runtime/ObjectConstructor.h', - 'runtime/ObjectPrototype.h', - 'runtime/Operations.h', - 'runtime/Options.h', - 'runtime/PropertyDescriptor.h', - 'runtime/PropertyMapHashTable.h', - 'runtime/PropertyNameArray.h', - 'runtime/PropertySlot.h', - 'runtime/Protect.h', - 'runtime/PutPropertySlot.h', - 'runtime/RegExp.h', - 'runtime/RegExpCache.h', - 'runtime/RegExpCachedResult.h', - 'runtime/RegExpConstructor.h', - 'runtime/RegExpKey.h', - 'runtime/RegExpMatchesArray.h', - 'runtime/RegExpObject.h', - 'runtime/RegExpPrototype.h', - 'runtime/SamplingCounter.h', - 'runtime/ScopeChain.h', - 'runtime/ScopeChainMark.h', - 'runtime/SmallStrings.h', - 'runtime/StorageBarrier.h', - 'runtime/StrictEvalActivation.h', - 'runtime/StringConstructor.h', - 'runtime/StringObject.h', - 'runtime/StringPrototype.h', - 'runtime/StringRecursionChecker.h', - 'runtime/Structure.h', - 'runtime/StructureChain.h', - 'runtime/StructureTransitionTable.h', - 'runtime/SymbolTable.h', - 'runtime/Terminator.h', - 'runtime/TimeoutChecker.h', - 'runtime/Tracing.h', - 'runtime/Uint16WithFraction.h', - 'runtime/UString.h', - 'runtime/UStringBuilder.h', - 'runtime/UStringConcatenate.h', - 'runtime/WeakGCMap.h', - 'runtime/WeakRandom.h', - 'runtime/WriteBarrier.h', - 'yarr/Yarr.h', - 'yarr/YarrCanonicalizeUCS2.h', - 'yarr/YarrInterpreter.h', - 'yarr/YarrJIT.h', - 'yarr/YarrParser.h', - 'yarr/YarrPattern.h', - 'yarr/YarrSyntaxChecker.h', - ], - 'javascriptcore_files': [ - 'API/JSBase.cpp', - 'API/JSCallbackConstructor.cpp', - 'API/JSCallbackFunction.cpp', - 'API/JSCallbackObject.cpp', - 'API/JSClassRef.cpp', - 'API/JSContextRef.cpp', - 'API/JSObjectRef.cpp', - 'API/JSProfilerPrivate.cpp', - 'API/JSStringRef.cpp', - 'API/JSStringRefBSTR.cpp', - 'API/JSStringRefCF.cpp', - 'API/JSValueRef.cpp', - 'API/JSWeakObjectMapRefPrivate.cpp', - 'API/OpaqueJSString.cpp', - 'assembler/ARMAssembler.cpp', - 'assembler/ARMv7Assembler.cpp', - 'assembler/MacroAssemblerARM.cpp', - 'assembler/MacroAssemblerSH4.cpp', - 'bytecode/CallLinkInfo.cpp', - 'bytecode/CallLinkStatus.cpp', - 'bytecode/CodeBlock.cpp', - 'bytecode/DFGExitProfile.cpp', - 'bytecode/ExecutionCounter.cpp', - 'bytecode/GetByIdStatus.cpp', - 'bytecode/JumpTable.cpp', - 'bytecode/LazyOperandValueProfile.cpp', - 'bytecode/MethodCallLinkInfo.cpp', - 'bytecode/MethodCallLinkStatus.cpp', - 'bytecode/MethodOfGettingAValueProfile.cpp', - 'bytecode/Opcode.cpp', - 'bytecode/PolymorphicPutByIdList.cpp', - 'bytecode/PredictedType.cpp', - 'bytecode/PutByIdStatus.cpp', - 'bytecode/SamplingTool.cpp', - 'bytecode/StructureStubInfo.cpp', - 'bytecompiler/BytecodeGenerator.cpp', - 'bytecompiler/NodesCodegen.cpp', - 'debugger/Debugger.cpp', - 'debugger/DebuggerActivation.cpp', - 'debugger/DebuggerCallFrame.cpp', - 'dfg/DFGAbstractState.cpp', - 'dfg/DFGAssemblyHelpers.cpp', - 'dfg/DFGByteCodeParser.cpp', - 'dfg/DFGCapabilities.cpp', - 'dfg/DFGCFAPhase.cpp', - 'dfg/DFGCorrectableJumpPoint.cpp', - 'dfg/DFGCSEPhase.cpp', - 'dfg/DFGDriver.cpp', - 'dfg/DFGFixupPhase.cpp', - 'dfg/DFGGraph.cpp', - 'dfg/DFGJITCompiler.cpp', - 'dfg/DFGNodeFlags.cpp', - 'dfg/DFGOperations.cpp', - 'dfg/DFGOSREntry.cpp', - 'dfg/DFGOSRExit.cpp', - 'dfg/DFGOSRExitCompiler.cpp', - 'dfg/DFGOSRExitCompiler32_64.cpp', - 'dfg/DFGOSRExitCompiler64.cpp', - 'dfg/DFGPhase.cpp', - 'dfg/DFGPredictionPropagationPhase.cpp', - 'dfg/DFGRedundantPhiEliminationPhase.cpp', - 'dfg/DFGRepatch.cpp', - 'dfg/DFGSpeculativeJIT.cpp', - 'dfg/DFGSpeculativeJIT32_64.cpp', - 'dfg/DFGSpeculativeJIT64.cpp', - 'dfg/DFGThunks.cpp', - 'dfg/DFGVirtualRegisterAllocationPhase.cpp', - 'heap/ConservativeRoots.cpp', - 'heap/CopiedSpace.cpp', - 'heap/DFGCodeBlocks.cpp', - 'heap/HandleSet.cpp', - 'heap/HandleStack.cpp', - 'heap/BlockAllocator.cpp', - 'heap/Heap.cpp', - 'heap/IncrementalSweeper.cpp', - 'heap/MachineStackMarker.cpp', - 'heap/MarkedAllocator.cpp', - 'heap/MarkedBlock.cpp', - 'heap/MarkedSpace.cpp', - 'heap/MarkStack.cpp', - 'heap/VTableSpectrum.cpp', - 'heap/WeakBlock.cpp', - 'heap/WeakHandleOwner.cpp', - 'heap/WeakSet.cpp', - 'heap/WriteBarrierSupport.cpp', - 'interpreter/AbstractPC.cpp', - 'interpreter/CallFrame.cpp', - 'interpreter/Interpreter.cpp', - 'interpreter/RegisterFile.cpp', - 'jit/ExecutableAllocator.cpp', - 'jit/ExecutableAllocatorFixedVMPool.cpp', - 'jit/HostCallReturnValue.cpp', - 'jit/JIT.cpp', - 'jit/JITArithmetic.cpp', - 'jit/JITArithmetic32_64.cpp', - 'jit/JITCall.cpp', - 'jit/JITCall32_64.cpp', - 'jit/JITExceptions.cpp', - 'jit/JITOpcodes.cpp', - 'jit/JITOpcodes32_64.cpp', - 'jit/JITPropertyAccess.cpp', - 'jit/JITPropertyAccess32_64.cpp', - 'jit/JITStubs.cpp', - 'jit/ThunkGenerators.cpp', - 'parser/Lexer.cpp', - 'parser/Nodes.cpp', - 'parser/Parser.cpp', - 'parser/ParserArena.cpp', - 'parser/SourceProviderCache.cpp', - 'profiler/Profile.cpp', - 'profiler/ProfileGenerator.cpp', - 'profiler/ProfileNode.cpp', - 'profiler/Profiler.cpp', - 'runtime/ArgList.cpp', - 'runtime/Arguments.cpp', - 'runtime/ArrayConstructor.cpp', - 'runtime/ArrayPrototype.cpp', - 'runtime/BooleanConstructor.cpp', - 'runtime/BooleanObject.cpp', - 'runtime/BooleanPrototype.cpp', - 'runtime/CallData.cpp', - 'runtime/CommonIdentifiers.cpp', - 'runtime/Completion.cpp', - 'runtime/ConstructData.cpp', - 'runtime/DateConstructor.cpp', - 'runtime/DateConversion.cpp', - 'runtime/DateInstance.cpp', - 'runtime/DatePrototype.cpp', - 'runtime/Error.cpp', - 'runtime/ErrorConstructor.cpp', - 'runtime/ErrorInstance.cpp', - 'runtime/ErrorPrototype.cpp', - 'runtime/ExceptionHelpers.cpp', - 'runtime/Executable.cpp', - 'runtime/FunctionConstructor.cpp', - 'runtime/FunctionPrototype.cpp', - 'runtime/GCActivityCallback.cpp', - 'runtime/GCActivityCallbackCF.cpp', - 'runtime/GetterSetter.cpp', - 'runtime/Identifier.cpp', - 'runtime/InitializeThreading.cpp', - 'runtime/InternalFunction.cpp', - 'runtime/JSActivation.cpp', - 'runtime/JSAPIValueWrapper.cpp', - 'runtime/JSArray.cpp', - 'runtime/JSBoundFunction.cpp', - 'runtime/JSCell.cpp', - 'runtime/JSChunk.cpp', - 'runtime/JSDateMath.cpp', - 'runtime/JSFunction.cpp', - 'runtime/JSGlobalData.cpp', - 'runtime/JSGlobalObject.cpp', - 'runtime/JSGlobalObjectFunctions.cpp', - 'runtime/JSGlobalThis.cpp', - 'runtime/JSLock.cpp', - 'runtime/JSNotAnObject.cpp', - 'runtime/JSObject.cpp', - 'runtime/JSONObject.cpp', - 'runtime/JSPropertyNameIterator.cpp', - 'runtime/JSStaticScopeObject.cpp', - 'runtime/JSString.cpp', - 'runtime/JSStringJoiner.cpp', - 'runtime/JSValue.cpp', - 'runtime/JSVariableObject.cpp', - 'runtime/JSWrapperObject.cpp', - 'runtime/LiteralParser.cpp', - 'runtime/Lookup.cpp', - 'runtime/MathObject.cpp', - 'runtime/MemoryStatistics.cpp', - 'runtime/NameConstructor.cpp', - 'runtime/NameInstance.cpp', - 'runtime/NamePrototype.cpp', - 'runtime/NativeErrorConstructor.cpp', - 'runtime/NativeErrorPrototype.cpp', - 'runtime/NumberConstructor.cpp', - 'runtime/NumberObject.cpp', - 'runtime/NumberPrototype.cpp', - 'runtime/ObjectConstructor.cpp', - 'runtime/ObjectPrototype.cpp', - 'runtime/Operations.cpp', - 'runtime/Options.cpp', - 'runtime/PropertyDescriptor.cpp', - 'runtime/PropertyNameArray.cpp', - 'runtime/PropertySlot.cpp', - 'runtime/RegExp.cpp', - 'runtime/RegExpCache.cpp', - 'runtime/RegExpCachedResult.cpp', - 'runtime/RegExpConstructor.cpp', - 'runtime/RegExpMatchesArray.cpp', - 'runtime/RegExpObject.cpp', - 'runtime/RegExpPrototype.cpp', - 'runtime/SamplingCounter.cpp', - 'runtime/ScopeChain.cpp', - 'runtime/SmallStrings.cpp', - 'runtime/StrictEvalActivation.cpp', - 'runtime/StringConstructor.cpp', - 'runtime/StringObject.cpp', - 'runtime/StringPrototype.cpp', - 'runtime/StringRecursionChecker.cpp', - 'runtime/Structure.cpp', - 'runtime/StructureChain.cpp', - 'runtime/TimeoutChecker.cpp', - 'runtime/UString.cpp', - 'tools/CodeProfile.cpp', - 'tools/CodeProfiling.cpp', + 'javascriptcore_yarr_files': [ 'yarr/YarrCanonicalizeUCS2.cpp', 'yarr/YarrInterpreter.cpp', - 'yarr/YarrJIT.cpp', 'yarr/YarrPattern.cpp', 'yarr/YarrSyntaxChecker.cpp', ], 'javascriptcore_derived_source_files': [ - '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/Lexer.lut.h', '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/RegExpJitTables.h', - '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/TracingDtrace.h', - '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/ArrayConstructor.lut.h', - '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/ArrayPrototype.lut.h', - '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/BooleanPrototype.lut.h', - '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/DateConstructor.lut.h', - '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/DatePrototype.lut.h', - '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/ErrorPrototype.lut.h', - '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/JSGlobalObject.lut.h', - '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/JSONObject.lut.h', - '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/MathObject.lut.h', - '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/NamePrototype.lut.h', - '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/NumberConstructor.lut.h', - '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/NumberPrototype.lut.h', - '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/ObjectConstructor.lut.h', - '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/ObjectPrototype.lut.h', - '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/RegExpConstructor.lut.h', - '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/RegExpObject.lut.h', - '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/RegExpPrototype.lut.h', - '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/StringConstructor.lut.h', - '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore/StringPrototype.lut.h', - ], - 'minidom_files': [ - 'API/tests/JSNode.c', - 'API/tests/JSNode.h', - 'API/tests/JSNodeList.c', - 'API/tests/JSNodeList.h', - 'API/tests/Node.c', - 'API/tests/Node.h', - 'API/tests/NodeList.c', - 'API/tests/NodeList.h', - 'API/tests/minidom.c', - ], - 'minidom_support_files': [ - 'API/tests/minidom.js', - ], - 'testapi_files': [ - 'API/tests/testapi.c', - ], - 'testapi_support_files': [ - 'API/tests/testapi.js', - ], - 'jsc_files': [ - 'jsc.cpp', ], } } diff --git a/Source/JavaScriptCore/JavaScriptCore.pri b/Source/JavaScriptCore/JavaScriptCore.pri index 94b663a18..380bbaf1b 100644 --- a/Source/JavaScriptCore/JavaScriptCore.pri +++ b/Source/JavaScriptCore/JavaScriptCore.pri @@ -19,6 +19,7 @@ INCLUDEPATH += \ $$SOURCE_DIR/heap \ $$SOURCE_DIR/dfg \ $$SOURCE_DIR/debugger \ + $$SOURCE_DIR/disassembler \ $$SOURCE_DIR/interpreter \ $$SOURCE_DIR/jit \ $$SOURCE_DIR/llint \ diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def index 6d5828c44..365038cee 100755 --- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def +++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def @@ -140,7 +140,7 @@ EXPORTS ?deleteOwnedPtr@WTF@@YAXPAUHFONT__@@@Z ?deleteOwnedPtr@WTF@@YAXPAUHRGN__@@@Z ?deleteProperty@JSObject@JSC@@SA_NPAVJSCell@2@PAVExecState@2@VPropertyName@2@@Z - ?deleteProperty@JSVariableObject@JSC@@SA_NPAVJSCell@2@PAVExecState@2@VPropertyName@2@@Z + ?deleteProperty@JSSymbolTableObject@JSC@@SA_NPAVJSCell@2@PAVExecState@2@VPropertyName@2@@Z ?deletePropertyByIndex@JSObject@JSC@@SA_NPAVJSCell@2@PAVExecState@2@I@Z ?deleteTable@HashTable@JSC@@QBEXXZ ?despecifyDictionaryFunction@Structure@JSC@@QAEXAAVJSGlobalData@2@VPropertyName@2@@Z @@ -151,7 +151,7 @@ EXPORTS ?detach@Debugger@JSC@@UAEXPAVJSGlobalObject@2@@Z ?detachThread@WTF@@YAXI@Z ?didTimeOut@TimeoutChecker@JSC@@QAE_NPAVExecState@2@@Z - ?discardAllCompiledCode@Heap@JSC@@QAEXXZ + ?deleteAllCompiledCode@Heap@JSC@@QAEXXZ ?displayName@JSFunction@JSC@@QAE?BVUString@2@PAVExecState@2@@Z ?dtoa@WTF@@YAXQADNAA_NAAHAAI@Z ?dumpSampleData@JSGlobalData@JSC@@QAEXPAVExecState@2@@Z @@ -181,6 +181,7 @@ EXPORTS ?finishCreation@RegExpObject@JSC@@IAEXPAVJSGlobalObject@2@@Z ?finishCreation@StringObject@JSC@@IAEXAAVJSGlobalData@2@PAVJSString@2@@Z ?focus@Profile@JSC@@QAEXPBVProfileNode@2@@Z + ?freeFatEntrySlow@SymbolTableEntry@JSC@@AAEXXZ ?from@Identifier@JSC@@SA?AV12@PAVExecState@2@H@Z ?from@Identifier@JSC@@SA?AV12@PAVExecState@2@I@Z ?functionGetter@PropertySlot@JSC@@ABE?AVJSValue@2@PAVExecState@2@@Z @@ -194,7 +195,7 @@ EXPORTS ?getOwnPropertyDescriptor@JSGlobalObject@JSC@@SA_NPAVJSObject@2@PAVExecState@2@VPropertyName@2@AAVPropertyDescriptor@2@@Z ?getOwnPropertyDescriptor@JSObject@JSC@@SA_NPAV12@PAVExecState@2@VPropertyName@2@AAVPropertyDescriptor@2@@Z ?getOwnPropertyNames@JSObject@JSC@@SAXPAV12@PAVExecState@2@AAVPropertyNameArray@2@W4EnumerationMode@2@@Z - ?getOwnPropertyNames@JSVariableObject@JSC@@SAXPAVJSObject@2@PAVExecState@2@AAVPropertyNameArray@2@W4EnumerationMode@2@@Z + ?getOwnPropertyNames@JSSymbolTableObject@JSC@@SAXPAVJSObject@2@PAVExecState@2@AAVPropertyNameArray@2@W4EnumerationMode@2@@Z ?getOwnPropertySlot@JSGlobalObject@JSC@@SA_NPAVJSCell@2@PAVExecState@2@VPropertyName@2@AAVPropertySlot@2@@Z ?getOwnPropertySlotByIndex@JSArray@JSC@@SA_NPAVJSCell@2@PAVExecState@2@IAAVPropertySlot@2@@Z ?getOwnPropertySlotByIndex@JSObject@JSC@@SA_NPAVJSCell@2@PAVExecState@2@IAAVPropertySlot@2@@Z @@ -246,6 +247,7 @@ EXPORTS ?name@JSFunction@JSC@@QAEABVUString@2@PAVExecState@2@@Z ?neuter@ArrayBufferView@WTF@@MAEXXZ ?newUninitialized@CString@WTF@@SA?AV12@IAAPAD@Z + ?notifyWriteSlow@SymbolTableEntry@JSC@@AAEXXZ ?nullptr@@3Vnullptr_t@std@@A ?number@String@WTF@@SA?AV12@NII@Z ?number@UString@JSC@@SA?AV12@H@Z diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj index 21884df96..78ca7dd6e 100644 --- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj +++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj @@ -874,6 +874,14 @@ > </File> <File + RelativePath="..\..\runtime\JSSegmentedVariableObject.cpp" + > + </File> + <File + RelativePath="..\..\runtime\JSSegmentedVariableObject.h" + > + </File> + <File RelativePath="..\..\runtime\JSStaticScopeObject.cpp" > </File> @@ -898,6 +906,14 @@ > </File> <File + RelativePath="..\..\runtime\JSSymbolTableObject.cpp" + > + </File> + <File + RelativePath="..\..\runtime\JSSymbolTableObject.h" + > + </File> + <File RelativePath="..\..\runtime\JSType.h" > </File> @@ -1238,6 +1254,10 @@ > </File> <File + RelativePath="..\..\runtime\SymbolTable.cpp" + > + </File> + <File RelativePath="..\..\runtime\SymbolTable.h" > </File> @@ -1630,11 +1650,11 @@ > </File> <File - RelativePath="..\..\bytecode\PredictedType.cpp" + RelativePath="..\..\bytecode\SpeculatedType.cpp" > </File> <File - RelativePath="..\..\bytecode\PredictedType.h" + RelativePath="..\..\bytecode\SpeculatedType.h" > </File> <File @@ -1665,6 +1685,14 @@ RelativePath="..\..\bytecode\ValueProfile.h" > </File> + <File + RelativePath="..\..\bytecode\Watchpoint.cpp" + > + </File> + <File + RelativePath="..\..\bytecode\Watchpoint.h" + > + </File> </Filter> <Filter Name="debugger" @@ -1710,6 +1738,10 @@ > </File> <File + RelativePath="..\..\assembler\LinkBuffer.cpp" + > + </File> + <File RelativePath="..\..\assembler\LinkBuffer.h" > </File> @@ -1911,6 +1943,14 @@ </File> </Filter> <Filter + Name="disassembler" + > + <File + RelativePath="..\..\disassembler\Disassembler.h" + > + </File> + </Filter> + <Filter Name="interpreter" > <File @@ -2158,6 +2198,14 @@ > </File> <File + RelativePath="..\..\heap\HeapTimer.cpp" + > + </File> + <File + RelativePath="..\..\heap\HeapTimer.h" + > + </File> + <File RelativePath="..\..\heap\IncrementalSweeper.h" > </File> diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCommon.vsprops b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCommon.vsprops index fac0af564..df0724e7c 100644 --- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCommon.vsprops +++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCommon.vsprops @@ -6,7 +6,7 @@ > <Tool Name="VCCLCompilerTool" - AdditionalIncludeDirectories=""$(ConfigurationBuildDir)\obj\JavaScriptCore\DerivedSources\";../../;../../API/;../../parser/;../../bytecompiler/;../../dfg/;../../jit/;../../llint/;../../runtime/;../../tools/;../../bytecode/;../../interpreter/;../../wtf/;../../profiler;../../assembler/;../../debugger/;../../heap/;"$(WebKitLibrariesDir)\include";"$(WebKitLibrariesDir)\include\private";"$(ConfigurationBuildDir)\include";"$(ConfigurationBuildDir)\include\JavaScriptCore";"$(ConfigurationBuildDir)\include\private";"$(ConfigurationBuildDir)\include\private\JavaScriptCore";"$(WebKitLibrariesDir)\include\pthreads"" + AdditionalIncludeDirectories=""$(ConfigurationBuildDir)\obj\JavaScriptCore\DerivedSources\";../../;../../API/;../../parser/;../../bytecompiler/;../../dfg/;../../disassembler;../../jit/;../../llint/;../../runtime/;../../tools/;../../bytecode/;../../interpreter/;../../wtf/;../../profiler;../../assembler/;../../debugger/;../../heap/;"$(WebKitLibrariesDir)\include";"$(WebKitLibrariesDir)\include\private";"$(ConfigurationBuildDir)\include";"$(ConfigurationBuildDir)\include\JavaScriptCore";"$(ConfigurationBuildDir)\include\private";"$(ConfigurationBuildDir)\include\private\JavaScriptCore";"$(WebKitLibrariesDir)\include\pthreads"" PreprocessorDefinitions="__STD_C" ForcedIncludeFiles="ICUVersion.h" /> diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/copy-files.cmd b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/copy-files.cmd index 524e38037..0a32c319a 100755 --- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/copy-files.cmd +++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/copy-files.cmd @@ -39,6 +39,7 @@ for %%d in ( assembler
bytecode
dfg
+ disassembler
heap
debugger
interpreter
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj index 386fcd391..2ffc9e266 100644 --- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj +++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj @@ -135,6 +135,13 @@ 0F7B294B14C3CD2F007C3DB1 /* DFGCapabilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82E1F14172C2F00179C94 /* DFGCapabilities.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F7B294C14C3CD43007C3DB1 /* DFGByteCodeCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5F08CC146BE602000472A9 /* DFGByteCodeCache.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F7B294D14C3CD4C007C3DB1 /* DFGCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC0977E1469EBC400CF2442 /* DFGCommon.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F919D0C157EE09F004A4E7D /* JSSymbolTableObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F919D09157EE09D004A4E7D /* JSSymbolTableObject.cpp */; }; + 0F919D0D157EE0A2004A4E7D /* JSSymbolTableObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F919D0A157EE09D004A4E7D /* JSSymbolTableObject.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F919D10157F3329004A4E7D /* JSSegmentedVariableObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F919D0E157F3327004A4E7D /* JSSegmentedVariableObject.cpp */; }; + 0F919D11157F332C004A4E7D /* JSSegmentedVariableObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F919D0F157F3327004A4E7D /* JSSegmentedVariableObject.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F919D2515853CE0004A4E7D /* Watchpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F919D2215853CDE004A4E7D /* Watchpoint.cpp */; }; + 0F919D2615853CE3004A4E7D /* Watchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F919D2315853CDE004A4E7D /* Watchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F919D2815856773004A4E7D /* SymbolTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F919D2715856770004A4E7D /* SymbolTable.cpp */; }; 0F93329D14CA7DC30085F3C6 /* CallLinkStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F93329314CA7DC10085F3C6 /* CallLinkStatus.cpp */; }; 0F93329E14CA7DC50085F3C6 /* CallLinkStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93329414CA7DC10085F3C6 /* CallLinkStatus.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F93329F14CA7DCA0085F3C6 /* GetByIdStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F93329514CA7DC10085F3C6 /* GetByIdStatus.cpp */; }; @@ -180,12 +187,28 @@ 0FD81AD3154FB4F000983E72 /* DFGDominators.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD81AD0154FB4EB00983E72 /* DFGDominators.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FD82E2114172CE300179C94 /* DFGCapabilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD82E1E14172C2F00179C94 /* DFGCapabilities.cpp */; }; 0FD82E39141AB14D00179C94 /* CompactJITCodeMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82E37141AB14200179C94 /* CompactJITCodeMap.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 0FD82E54141DAEEE00179C94 /* PredictedType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82E4F141DAEA100179C94 /* PredictedType.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FD82E54141DAEEE00179C94 /* SpeculatedType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82E4F141DAEA100179C94 /* SpeculatedType.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FD82E56141DAF0800179C94 /* DFGOSREntry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD82E52141DAEDE00179C94 /* DFGOSREntry.cpp */; }; 0FD82E57141DAF1000179C94 /* DFGOSREntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82E53141DAEDE00179C94 /* DFGOSREntry.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 0FD82E86141F3FF100179C94 /* PredictedType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD82E84141F3FDA00179C94 /* PredictedType.cpp */; }; + 0FD82E86141F3FF100179C94 /* SpeculatedType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD82E84141F3FDA00179C94 /* SpeculatedType.cpp */; }; 0FE228ED1436AB2700196C48 /* Options.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE228EB1436AB2300196C48 /* Options.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FE228EE1436AB2C00196C48 /* Options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE228EA1436AB2300196C48 /* Options.cpp */; }; + 0FF42731158EBD54004CB9FF /* Disassembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF4272F158EBD44004CB9FF /* Disassembler.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FF42732158EBD58004CB9FF /* UDis86Disassembler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FF42730158EBD44004CB9FF /* UDis86Disassembler.cpp */; }; + 0FF42740158EBE8B004CB9FF /* udis86_decode.c in Sources */ = {isa = PBXBuildFile; fileRef = 0FF42734158EBD94004CB9FF /* udis86_decode.c */; }; + 0FF42741158EBE8D004CB9FF /* udis86_decode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF42735158EBD94004CB9FF /* udis86_decode.h */; }; + 0FF42742158EBE91004CB9FF /* udis86_extern.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF42736158EBD94004CB9FF /* udis86_extern.h */; }; + 0FF42743158EBE91004CB9FF /* udis86_input.c in Sources */ = {isa = PBXBuildFile; fileRef = 0FF42737158EBD94004CB9FF /* udis86_input.c */; }; + 0FF42744158EBE91004CB9FF /* udis86_input.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF42738158EBD94004CB9FF /* udis86_input.h */; }; + 0FF42745158EBE91004CB9FF /* udis86_syn-att.c in Sources */ = {isa = PBXBuildFile; fileRef = 0FF42739158EBD94004CB9FF /* udis86_syn-att.c */; }; + 0FF42746158EBE91004CB9FF /* udis86_syn-intel.c in Sources */ = {isa = PBXBuildFile; fileRef = 0FF4273A158EBD94004CB9FF /* udis86_syn-intel.c */; }; + 0FF42747158EBE91004CB9FF /* udis86_syn.c in Sources */ = {isa = PBXBuildFile; fileRef = 0FF4273B158EBD94004CB9FF /* udis86_syn.c */; }; + 0FF42748158EBE91004CB9FF /* udis86_syn.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF4273C158EBD94004CB9FF /* udis86_syn.h */; }; + 0FF42749158EBE91004CB9FF /* udis86_types.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF4273D158EBD94004CB9FF /* udis86_types.h */; }; + 0FF4274A158EBE91004CB9FF /* udis86.c in Sources */ = {isa = PBXBuildFile; fileRef = 0FF4273E158EBD94004CB9FF /* udis86.c */; }; + 0FF4274B158EBE91004CB9FF /* udis86.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF4273F158EBD94004CB9FF /* udis86.h */; }; + 0FF4274D158EBFE6004CB9FF /* udis86_itab_holder.c in Sources */ = {isa = PBXBuildFile; fileRef = 0FF4274C158EBFE1004CB9FF /* udis86_itab_holder.c */; }; + 0FF4275715914A20004CB9FF /* LinkBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FF4275615914A20004CB9FF /* LinkBuffer.cpp */; }; 0FF922D414F46B410041A24E /* LLIntOffsetsExtractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F4680A114BA7F8200BFE272 /* LLIntOffsetsExtractor.cpp */; }; 0FFFC95714EF90A000C72532 /* DFGCFAPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FFFC94B14EF909500C72532 /* DFGCFAPhase.cpp */; }; 0FFFC95814EF90A200C72532 /* DFGCFAPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFFC94C14EF909500C72532 /* DFGCFAPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -366,10 +389,10 @@ 7E4EE70F0EBB7A5B005934AA /* StructureChain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7E4EE70E0EBB7A5B005934AA /* StructureChain.cpp */; }; 7EFF00640EC05A9A00AA7C93 /* NodeInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 7EFF00630EC05A9A00AA7C93 /* NodeInfo.h */; }; 840480131021A1D9008E7F01 /* JSAPIValueWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = BC0894D60FAFBA2D00001865 /* JSAPIValueWrapper.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 860161E30F3A83C100F84710 /* AbstractMacroAssembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 860161DF0F3A83C100F84710 /* AbstractMacroAssembler.h */; }; - 860161E40F3A83C100F84710 /* MacroAssemblerX86.h in Headers */ = {isa = PBXBuildFile; fileRef = 860161E00F3A83C100F84710 /* MacroAssemblerX86.h */; }; - 860161E50F3A83C100F84710 /* MacroAssemblerX86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = 860161E10F3A83C100F84710 /* MacroAssemblerX86_64.h */; }; - 860161E60F3A83C100F84710 /* MacroAssemblerX86Common.h in Headers */ = {isa = PBXBuildFile; fileRef = 860161E20F3A83C100F84710 /* MacroAssemblerX86Common.h */; }; + 860161E30F3A83C100F84710 /* AbstractMacroAssembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 860161DF0F3A83C100F84710 /* AbstractMacroAssembler.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 860161E40F3A83C100F84710 /* MacroAssemblerX86.h in Headers */ = {isa = PBXBuildFile; fileRef = 860161E00F3A83C100F84710 /* MacroAssemblerX86.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 860161E50F3A83C100F84710 /* MacroAssemblerX86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = 860161E10F3A83C100F84710 /* MacroAssemblerX86_64.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 860161E60F3A83C100F84710 /* MacroAssemblerX86Common.h in Headers */ = {isa = PBXBuildFile; fileRef = 860161E20F3A83C100F84710 /* MacroAssemblerX86Common.h */; settings = {ATTRIBUTES = (Private, ); }; }; 8604F505143CE1C200B295F5 /* JSGlobalThis.h in Headers */ = {isa = PBXBuildFile; fileRef = 8604F503143CE1C100B295F5 /* JSGlobalThis.h */; settings = {ATTRIBUTES = (Private, ); }; }; 860BD801148EA6F200112B2F /* Intrinsic.h in Headers */ = {isa = PBXBuildFile; fileRef = 86BF642A148DB2B5004DE36A /* Intrinsic.h */; settings = {ATTRIBUTES = (Private, ); }; }; 8612E4CD152389EC00C836BE /* MatchResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 8612E4CB1522918400C836BE /* MatchResult.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -397,11 +420,11 @@ 869D04AF1193B54D00803475 /* CachedTranscendentalFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 869D04AE1193B54D00803475 /* CachedTranscendentalFunction.h */; settings = {ATTRIBUTES = (Private, ); }; }; 869EBCB70E8C6D4A008722CC /* ResultType.h in Headers */ = {isa = PBXBuildFile; fileRef = 869EBCB60E8C6D4A008722CC /* ResultType.h */; settings = {ATTRIBUTES = (Private, ); }; }; 86A90ED00EE7D51F00AB350D /* JITArithmetic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86A90ECF0EE7D51F00AB350D /* JITArithmetic.cpp */; }; - 86ADD1450FDDEA980006EEC2 /* ARMv7Assembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86ADD1430FDDEA980006EEC2 /* ARMv7Assembler.h */; }; - 86ADD1460FDDEA980006EEC2 /* MacroAssemblerARMv7.h in Headers */ = {isa = PBXBuildFile; fileRef = 86ADD1440FDDEA980006EEC2 /* MacroAssemblerARMv7.h */; }; + 86ADD1450FDDEA980006EEC2 /* ARMv7Assembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86ADD1430FDDEA980006EEC2 /* ARMv7Assembler.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 86ADD1460FDDEA980006EEC2 /* MacroAssemblerARMv7.h in Headers */ = {isa = PBXBuildFile; fileRef = 86ADD1440FDDEA980006EEC2 /* MacroAssemblerARMv7.h */; settings = {ATTRIBUTES = (Private, ); }; }; 86AE64A8135E5E1C00963012 /* MacroAssemblerSH4.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86AE64A5135E5E1C00963012 /* MacroAssemblerSH4.cpp */; }; - 86AE64A9135E5E1C00963012 /* MacroAssemblerSH4.h in Headers */ = {isa = PBXBuildFile; fileRef = 86AE64A6135E5E1C00963012 /* MacroAssemblerSH4.h */; }; - 86AE64AA135E5E1C00963012 /* SH4Assembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86AE64A7135E5E1C00963012 /* SH4Assembler.h */; }; + 86AE64A9135E5E1C00963012 /* MacroAssemblerSH4.h in Headers */ = {isa = PBXBuildFile; fileRef = 86AE64A6135E5E1C00963012 /* MacroAssemblerSH4.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 86AE64AA135E5E1C00963012 /* SH4Assembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86AE64A7135E5E1C00963012 /* SH4Assembler.h */; settings = {ATTRIBUTES = (Private, ); }; }; 86AE6C4D136A11E400963012 /* DFGFPRInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 86AE6C4B136A11E400963012 /* DFGFPRInfo.h */; }; 86AE6C4E136A11E400963012 /* DFGGPRInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 86AE6C4C136A11E400963012 /* DFGGPRInfo.h */; }; 86B5826714D2796C00A9C306 /* CodeProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86B5822E14D2373B00A9C306 /* CodeProfile.cpp */; }; @@ -410,8 +433,8 @@ 86BB09C1138E381B0056702F /* DFGRepatch.h in Headers */ = {isa = PBXBuildFile; fileRef = 86BB09BF138E381B0056702F /* DFGRepatch.h */; }; 86C36EEA0EE1289D00B3DF59 /* MacroAssembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C36EE90EE1289D00B3DF59 /* MacroAssembler.h */; settings = {ATTRIBUTES = (Private, ); }; }; 86C568E011A213EE0007F7F0 /* MacroAssemblerARM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86C568DD11A213EE0007F7F0 /* MacroAssemblerARM.cpp */; }; - 86C568E111A213EE0007F7F0 /* MacroAssemblerMIPS.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C568DE11A213EE0007F7F0 /* MacroAssemblerMIPS.h */; }; - 86C568E211A213EE0007F7F0 /* MIPSAssembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C568DF11A213EE0007F7F0 /* MIPSAssembler.h */; }; + 86C568E111A213EE0007F7F0 /* MacroAssemblerMIPS.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C568DE11A213EE0007F7F0 /* MacroAssemblerMIPS.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 86C568E211A213EE0007F7F0 /* MIPSAssembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C568DF11A213EE0007F7F0 /* MIPSAssembler.h */; settings = {ATTRIBUTES = (Private, ); }; }; 86CA032E1038E8440028A609 /* Executable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86CA032D1038E8440028A609 /* Executable.cpp */; }; 86CAFEE31035DDE60028A609 /* Executable.h in Headers */ = {isa = PBXBuildFile; fileRef = 86CAFEE21035DDE60028A609 /* Executable.h */; settings = {ATTRIBUTES = (Private, ); }; }; 86CC85A10EE79A4700288682 /* JITInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = 86CC85A00EE79A4700288682 /* JITInlineMethods.h */; }; @@ -419,13 +442,13 @@ 86CC85C40EE7A89400288682 /* JITPropertyAccess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86CC85C30EE7A89400288682 /* JITPropertyAccess.cpp */; }; 86CCEFDE0F413F8900FD7F9E /* JITCode.h in Headers */ = {isa = PBXBuildFile; fileRef = 86CCEFDD0F413F8900FD7F9E /* JITCode.h */; settings = {ATTRIBUTES = (Private, ); }; }; 86D3B2C310156BDE002865E7 /* ARMAssembler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86D3B2BF10156BDE002865E7 /* ARMAssembler.cpp */; }; - 86D3B2C410156BDE002865E7 /* ARMAssembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86D3B2C010156BDE002865E7 /* ARMAssembler.h */; }; - 86D3B2C510156BDE002865E7 /* AssemblerBufferWithConstantPool.h in Headers */ = {isa = PBXBuildFile; fileRef = 86D3B2C110156BDE002865E7 /* AssemblerBufferWithConstantPool.h */; }; - 86D3B2C610156BDE002865E7 /* MacroAssemblerARM.h in Headers */ = {isa = PBXBuildFile; fileRef = 86D3B2C210156BDE002865E7 /* MacroAssemblerARM.h */; }; - 86D3B3C310159D7F002865E7 /* LinkBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 86D3B3C110159D7F002865E7 /* LinkBuffer.h */; }; - 86D3B3C410159D7F002865E7 /* RepatchBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 86D3B3C210159D7F002865E7 /* RepatchBuffer.h */; }; + 86D3B2C410156BDE002865E7 /* ARMAssembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86D3B2C010156BDE002865E7 /* ARMAssembler.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 86D3B2C510156BDE002865E7 /* AssemblerBufferWithConstantPool.h in Headers */ = {isa = PBXBuildFile; fileRef = 86D3B2C110156BDE002865E7 /* AssemblerBufferWithConstantPool.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 86D3B2C610156BDE002865E7 /* MacroAssemblerARM.h in Headers */ = {isa = PBXBuildFile; fileRef = 86D3B2C210156BDE002865E7 /* MacroAssemblerARM.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 86D3B3C310159D7F002865E7 /* LinkBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 86D3B3C110159D7F002865E7 /* LinkBuffer.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 86D3B3C410159D7F002865E7 /* RepatchBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 86D3B3C210159D7F002865E7 /* RepatchBuffer.h */; settings = {ATTRIBUTES = (Private, ); }; }; 86DB64640F95C6FC00D7D921 /* ExecutableAllocatorFixedVMPool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86DB64630F95C6FC00D7D921 /* ExecutableAllocatorFixedVMPool.cpp */; }; - 86E116B10FE75AC800B512BC /* CodeLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = 86E116B00FE75AC800B512BC /* CodeLocation.h */; }; + 86E116B10FE75AC800B512BC /* CodeLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = 86E116B00FE75AC800B512BC /* CodeLocation.h */; settings = {ATTRIBUTES = (Private, ); }; }; 86E85539111B9968001AF51E /* JSStringBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 86E85538111B9968001AF51E /* JSStringBuilder.h */; }; 86EBF2FF1560F06A008E9222 /* NameConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86EBF2F91560F036008E9222 /* NameConstructor.cpp */; }; 86EBF3001560F06A008E9222 /* NameConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 86EBF2FA1560F036008E9222 /* NameConstructor.h */; }; @@ -471,8 +494,8 @@ 95F6E6950E5B5F970091E860 /* JSProfilerPrivate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95988BA90E477BEC00D28D4D /* JSProfilerPrivate.cpp */; }; 960097A60EBABB58007A7297 /* LabelScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 960097A50EBABB58007A7297 /* LabelScope.h */; }; 960626960FB8EC02009798AB /* JITStubCall.h in Headers */ = {isa = PBXBuildFile; fileRef = 960626950FB8EC02009798AB /* JITStubCall.h */; }; - 9688CB150ED12B4E001D649F /* AssemblerBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 9688CB130ED12B4E001D649F /* AssemblerBuffer.h */; }; - 9688CB160ED12B4E001D649F /* X86Assembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 9688CB140ED12B4E001D649F /* X86Assembler.h */; }; + 9688CB150ED12B4E001D649F /* AssemblerBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 9688CB130ED12B4E001D649F /* AssemblerBuffer.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 9688CB160ED12B4E001D649F /* X86Assembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 9688CB140ED12B4E001D649F /* X86Assembler.h */; settings = {ATTRIBUTES = (Private, ); }; }; 969A07230ED1CE3300F1F681 /* BytecodeGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 969A07210ED1CE3300F1F681 /* BytecodeGenerator.h */; }; 969A072A0ED1CE6900F1F681 /* Label.h in Headers */ = {isa = PBXBuildFile; fileRef = 969A07270ED1CE6900F1F681 /* Label.h */; }; 969A072B0ED1CE6900F1F681 /* RegisterID.h in Headers */ = {isa = PBXBuildFile; fileRef = 969A07280ED1CE6900F1F681 /* RegisterID.h */; }; @@ -644,10 +667,12 @@ C2C8D02D14A3C6E000578E65 /* CopiedSpaceInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C8D02B14A3C6B200578E65 /* CopiedSpaceInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; }; C2C8D03014A3CEFC00578E65 /* CopiedBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C8D02E14A3CEFC00578E65 /* CopiedBlock.h */; settings = {ATTRIBUTES = (Private, ); }; }; C2C8D03114A3CEFC00578E65 /* HeapBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C8D02F14A3CEFC00578E65 /* HeapBlock.h */; settings = {ATTRIBUTES = (Private, ); }; }; + C2D58C3415912FEE0021A844 /* GCActivityCallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D58C3315912FEE0021A844 /* GCActivityCallback.cpp */; }; + C2E526BD1590EF000054E48D /* HeapTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2E526BB1590EF000054E48D /* HeapTimer.cpp */; }; + C2E526BE1590EF000054E48D /* HeapTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E526BC1590EF000054E48D /* HeapTimer.h */; settings = {ATTRIBUTES = (Private, ); }; }; C2EAA3FA149A835E00FCE112 /* CopiedSpace.h in Headers */ = {isa = PBXBuildFile; fileRef = C2EAA3F8149A830800FCE112 /* CopiedSpace.h */; settings = {ATTRIBUTES = (Private, ); }; }; C2EAD2FC14F0249800A4B159 /* CopiedAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = C2EAD2FB14F0249800A4B159 /* CopiedAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; }; DDF7ABD411F60ED200108E36 /* GCActivityCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = DDF7ABD211F60ED200108E36 /* GCActivityCallback.h */; settings = {ATTRIBUTES = (Private, ); }; }; - DDF7ABD511F60ED200108E36 /* GCActivityCallbackCF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DDF7ABD311F60ED200108E36 /* GCActivityCallbackCF.cpp */; }; E124A8F70E555775003091F1 /* OpaqueJSString.h in Headers */ = {isa = PBXBuildFile; fileRef = E124A8F50E555775003091F1 /* OpaqueJSString.h */; settings = {ATTRIBUTES = (Private, ); }; }; E124A8F80E555775003091F1 /* OpaqueJSString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E124A8F60E555775003091F1 /* OpaqueJSString.cpp */; }; E178636D0D9BEEC300D74E75 /* InitializeThreading.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E178636C0D9BEEC300D74E75 /* InitializeThreading.cpp */; }; @@ -828,6 +853,13 @@ 0F77008E1402FDD60078EB39 /* SamplingCounter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SamplingCounter.h; sourceTree = "<group>"; }; 0F7700911402FF280078EB39 /* SamplingCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SamplingCounter.cpp; sourceTree = "<group>"; }; 0F7B294814C3CD23007C3DB1 /* DFGCCallHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCCallHelpers.h; path = dfg/DFGCCallHelpers.h; sourceTree = "<group>"; }; + 0F919D09157EE09D004A4E7D /* JSSymbolTableObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSymbolTableObject.cpp; sourceTree = "<group>"; }; + 0F919D0A157EE09D004A4E7D /* JSSymbolTableObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSSymbolTableObject.h; sourceTree = "<group>"; }; + 0F919D0E157F3327004A4E7D /* JSSegmentedVariableObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSegmentedVariableObject.cpp; sourceTree = "<group>"; }; + 0F919D0F157F3327004A4E7D /* JSSegmentedVariableObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSSegmentedVariableObject.h; sourceTree = "<group>"; }; + 0F919D2215853CDE004A4E7D /* Watchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Watchpoint.cpp; sourceTree = "<group>"; }; + 0F919D2315853CDE004A4E7D /* Watchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Watchpoint.h; sourceTree = "<group>"; }; + 0F919D2715856770004A4E7D /* SymbolTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolTable.cpp; sourceTree = "<group>"; }; 0F93329314CA7DC10085F3C6 /* CallLinkStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CallLinkStatus.cpp; sourceTree = "<group>"; }; 0F93329414CA7DC10085F3C6 /* CallLinkStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallLinkStatus.h; sourceTree = "<group>"; }; 0F93329514CA7DC10085F3C6 /* GetByIdStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetByIdStatus.cpp; sourceTree = "<group>"; }; @@ -875,12 +907,28 @@ 0FD82E1E14172C2F00179C94 /* DFGCapabilities.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCapabilities.cpp; path = dfg/DFGCapabilities.cpp; sourceTree = "<group>"; }; 0FD82E1F14172C2F00179C94 /* DFGCapabilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCapabilities.h; path = dfg/DFGCapabilities.h; sourceTree = "<group>"; }; 0FD82E37141AB14200179C94 /* CompactJITCodeMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CompactJITCodeMap.h; sourceTree = "<group>"; }; - 0FD82E4F141DAEA100179C94 /* PredictedType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PredictedType.h; sourceTree = "<group>"; }; + 0FD82E4F141DAEA100179C94 /* SpeculatedType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpeculatedType.h; sourceTree = "<group>"; }; 0FD82E52141DAEDE00179C94 /* DFGOSREntry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGOSREntry.cpp; path = dfg/DFGOSREntry.cpp; sourceTree = "<group>"; }; 0FD82E53141DAEDE00179C94 /* DFGOSREntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGOSREntry.h; path = dfg/DFGOSREntry.h; sourceTree = "<group>"; }; - 0FD82E84141F3FDA00179C94 /* PredictedType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PredictedType.cpp; sourceTree = "<group>"; }; + 0FD82E84141F3FDA00179C94 /* SpeculatedType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpeculatedType.cpp; sourceTree = "<group>"; }; 0FE228EA1436AB2300196C48 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Options.cpp; sourceTree = "<group>"; }; 0FE228EB1436AB2300196C48 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Options.h; sourceTree = "<group>"; }; + 0FF4272F158EBD44004CB9FF /* Disassembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Disassembler.h; path = disassembler/Disassembler.h; sourceTree = "<group>"; }; + 0FF42730158EBD44004CB9FF /* UDis86Disassembler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UDis86Disassembler.cpp; path = disassembler/UDis86Disassembler.cpp; sourceTree = "<group>"; }; + 0FF42734158EBD94004CB9FF /* udis86_decode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = udis86_decode.c; path = disassembler/udis86/udis86_decode.c; sourceTree = "<group>"; }; + 0FF42735158EBD94004CB9FF /* udis86_decode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = udis86_decode.h; path = disassembler/udis86/udis86_decode.h; sourceTree = "<group>"; }; + 0FF42736158EBD94004CB9FF /* udis86_extern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = udis86_extern.h; path = disassembler/udis86/udis86_extern.h; sourceTree = "<group>"; }; + 0FF42737158EBD94004CB9FF /* udis86_input.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = udis86_input.c; path = disassembler/udis86/udis86_input.c; sourceTree = "<group>"; }; + 0FF42738158EBD94004CB9FF /* udis86_input.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = udis86_input.h; path = disassembler/udis86/udis86_input.h; sourceTree = "<group>"; }; + 0FF42739158EBD94004CB9FF /* udis86_syn-att.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "udis86_syn-att.c"; path = "disassembler/udis86/udis86_syn-att.c"; sourceTree = "<group>"; }; + 0FF4273A158EBD94004CB9FF /* udis86_syn-intel.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "udis86_syn-intel.c"; path = "disassembler/udis86/udis86_syn-intel.c"; sourceTree = "<group>"; }; + 0FF4273B158EBD94004CB9FF /* udis86_syn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = udis86_syn.c; path = disassembler/udis86/udis86_syn.c; sourceTree = "<group>"; }; + 0FF4273C158EBD94004CB9FF /* udis86_syn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = udis86_syn.h; path = disassembler/udis86/udis86_syn.h; sourceTree = "<group>"; }; + 0FF4273D158EBD94004CB9FF /* udis86_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = udis86_types.h; path = disassembler/udis86/udis86_types.h; sourceTree = "<group>"; }; + 0FF4273E158EBD94004CB9FF /* udis86.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = udis86.c; path = disassembler/udis86/udis86.c; sourceTree = "<group>"; }; + 0FF4273F158EBD94004CB9FF /* udis86.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = udis86.h; path = disassembler/udis86/udis86.h; sourceTree = "<group>"; }; + 0FF4274C158EBFE1004CB9FF /* udis86_itab_holder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = udis86_itab_holder.c; path = disassembler/udis86/udis86_itab_holder.c; sourceTree = "<group>"; }; + 0FF4275615914A20004CB9FF /* LinkBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LinkBuffer.cpp; sourceTree = "<group>"; }; 0FF922CF14F46B130041A24E /* JSCLLIntOffsetsExtractor */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = JSCLLIntOffsetsExtractor; sourceTree = BUILT_PRODUCTS_DIR; }; 0FFFC94B14EF909500C72532 /* DFGCFAPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCFAPhase.cpp; path = dfg/DFGCFAPhase.cpp; sourceTree = "<group>"; }; 0FFFC94C14EF909500C72532 /* DFGCFAPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCFAPhase.h; path = dfg/DFGCFAPhase.h; sourceTree = "<group>"; }; @@ -1340,12 +1388,14 @@ C2C8D02B14A3C6B200578E65 /* CopiedSpaceInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopiedSpaceInlineMethods.h; sourceTree = "<group>"; }; C2C8D02E14A3CEFC00578E65 /* CopiedBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopiedBlock.h; sourceTree = "<group>"; }; C2C8D02F14A3CEFC00578E65 /* HeapBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapBlock.h; sourceTree = "<group>"; }; + C2D58C3315912FEE0021A844 /* GCActivityCallback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GCActivityCallback.cpp; sourceTree = "<group>"; }; + C2E526BB1590EF000054E48D /* HeapTimer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HeapTimer.cpp; sourceTree = "<group>"; }; + C2E526BC1590EF000054E48D /* HeapTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapTimer.h; sourceTree = "<group>"; }; C2EAA3F8149A830800FCE112 /* CopiedSpace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopiedSpace.h; sourceTree = "<group>"; }; C2EAD2FB14F0249800A4B159 /* CopiedAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopiedAllocator.h; sourceTree = "<group>"; }; D21202280AD4310C00ED79B6 /* DateConversion.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DateConversion.cpp; sourceTree = "<group>"; }; D21202290AD4310C00ED79B6 /* DateConversion.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DateConversion.h; sourceTree = "<group>"; }; DDF7ABD211F60ED200108E36 /* GCActivityCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCActivityCallback.h; sourceTree = "<group>"; }; - DDF7ABD311F60ED200108E36 /* GCActivityCallbackCF.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GCActivityCallbackCF.cpp; sourceTree = "<group>"; }; E124A8F50E555775003091F1 /* OpaqueJSString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpaqueJSString.h; sourceTree = "<group>"; }; E124A8F60E555775003091F1 /* OpaqueJSString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OpaqueJSString.cpp; sourceTree = "<group>"; }; E178633F0D9BEC0000D74E75 /* InitializeThreading.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InitializeThreading.h; sourceTree = "<group>"; }; @@ -1481,6 +1531,7 @@ 969A078F0ED1D3AE00F1F681 /* bytecode */, 7E39D81D0EC38EFA003AF11A /* bytecompiler */, 1480DB9A0DDC2231003CFDF2 /* debugger */, + 0FF4272E158EBCCE004CB9FF /* disassembler */, 86EC9DB31328DF44002B2AD7 /* dfg */, 142E312A134FF0A600AFADB5 /* heap */, 1429D77A0ED20D7300B89619 /* interpreter */, @@ -1542,6 +1593,36 @@ name = llint; sourceTree = "<group>"; }; + 0FF4272E158EBCCE004CB9FF /* disassembler */ = { + isa = PBXGroup; + children = ( + 0FF42733158EBD64004CB9FF /* udis86 */, + 0FF4272F158EBD44004CB9FF /* Disassembler.h */, + 0FF42730158EBD44004CB9FF /* UDis86Disassembler.cpp */, + ); + name = disassembler; + sourceTree = "<group>"; + }; + 0FF42733158EBD64004CB9FF /* udis86 */ = { + isa = PBXGroup; + children = ( + 0FF42734158EBD94004CB9FF /* udis86_decode.c */, + 0FF42735158EBD94004CB9FF /* udis86_decode.h */, + 0FF42736158EBD94004CB9FF /* udis86_extern.h */, + 0FF42737158EBD94004CB9FF /* udis86_input.c */, + 0FF42738158EBD94004CB9FF /* udis86_input.h */, + 0FF4274C158EBFE1004CB9FF /* udis86_itab_holder.c */, + 0FF42739158EBD94004CB9FF /* udis86_syn-att.c */, + 0FF4273A158EBD94004CB9FF /* udis86_syn-intel.c */, + 0FF4273B158EBD94004CB9FF /* udis86_syn.c */, + 0FF4273C158EBD94004CB9FF /* udis86_syn.h */, + 0FF4273D158EBD94004CB9FF /* udis86_types.h */, + 0FF4273E158EBD94004CB9FF /* udis86.c */, + 0FF4273F158EBD94004CB9FF /* udis86.h */, + ); + name = udis86; + sourceTree = "<group>"; + }; 141211000A48772600480255 /* tests */ = { isa = PBXGroup; children = ( @@ -1613,6 +1694,8 @@ 142E312A134FF0A600AFADB5 /* heap */ = { isa = PBXGroup; children = ( + C2E526BB1590EF000054E48D /* HeapTimer.cpp */, + C2E526BC1590EF000054E48D /* HeapTimer.h */, C25F8BCB157544A900245B71 /* IncrementalSweeper.cpp */, C25F8BCC157544A900245B71 /* IncrementalSweeper.h */, 14816E19154CC56C00B8054C /* BlockAllocator.cpp */, @@ -1838,6 +1921,7 @@ 7EF6E0BB0EB7A1EC0079AFAF /* runtime */ = { isa = PBXGroup; children = ( + C2D58C3315912FEE0021A844 /* GCActivityCallback.cpp */, BCF605110E203EF800B9A64D /* ArgList.cpp */, BCF605120E203EF800B9A64D /* ArgList.h */, BC257DE50E1F51C50016B6C9 /* Arguments.cpp */, @@ -1893,7 +1977,6 @@ F692A85C0255597D01FF60F7 /* FunctionPrototype.cpp */, F692A85D0255597D01FF60F7 /* FunctionPrototype.h */, DDF7ABD211F60ED200108E36 /* GCActivityCallback.h */, - DDF7ABD311F60ED200108E36 /* GCActivityCallbackCF.cpp */, BC02E9B80E184545000F9297 /* GetterSetter.cpp */, BC337BDE0E1AF0B80076918A /* GetterSetter.h */, 933A349D038AE80F008635CE /* Identifier.cpp */, @@ -1934,6 +2017,8 @@ A7F9935D0FD7325100A0B2D0 /* JSONObject.h */, A727FF660DA3053B00E548D7 /* JSPropertyNameIterator.cpp */, A727FF650DA3053B00E548D7 /* JSPropertyNameIterator.h */, + 0F919D0E157F3327004A4E7D /* JSSegmentedVariableObject.cpp */, + 0F919D0F157F3327004A4E7D /* JSSegmentedVariableObject.h */, A7E42C190E3938830065A544 /* JSStaticScopeObject.cpp */, A7E42C180E3938830065A544 /* JSStaticScopeObject.h */, BC02E9B60E1842FA000F9297 /* JSString.cpp */, @@ -1941,6 +2026,8 @@ 86E85538111B9968001AF51E /* JSStringBuilder.h */, 2600B5A4152BAAA70091EE5F /* JSStringJoiner.cpp */, 2600B5A5152BAAA70091EE5F /* JSStringJoiner.h */, + 0F919D09157EE09D004A4E7D /* JSSymbolTableObject.cpp */, + 0F919D0A157EE09D004A4E7D /* JSSymbolTableObject.h */, 14ABB454099C2A0F00E2A24F /* JSType.h */, 6507D2970E871E4A00D7D896 /* JSTypeInfo.h */, F692A8870255597D01FF60F7 /* JSValue.cpp */, @@ -2033,6 +2120,7 @@ 7E4EE70E0EBB7A5B005934AA /* StructureChain.cpp */, 7E4EE7080EBB7963005934AA /* StructureChain.h */, BC9041470EB9250900FE26FA /* StructureTransitionTable.h */, + 0F919D2715856770004A4E7D /* SymbolTable.cpp */, 14A396A60CD2933100B5B4FF /* SymbolTable.h */, 97F6903A1169DF7F00A6BB46 /* Terminator.h */, 14A42E3D0F4F60EE00599099 /* TimeoutChecker.cpp */, @@ -2209,6 +2297,7 @@ 9688CB130ED12B4E001D649F /* AssemblerBuffer.h */, 86D3B2C110156BDE002865E7 /* AssemblerBufferWithConstantPool.h */, 86E116B00FE75AC800B512BC /* CodeLocation.h */, + 0FF4275615914A20004CB9FF /* LinkBuffer.cpp */, 86D3B3C110159D7F002865E7 /* LinkBuffer.h */, 86C36EE90EE1289D00B3DF59 /* MacroAssembler.h */, 86C568DD11A213EE0007F7F0 /* MacroAssemblerARM.cpp */, @@ -2275,8 +2364,8 @@ BCFD8C910EEB2EE700283848 /* JumpTable.h */, 969A07940ED1D3AE00F1F681 /* Opcode.cpp */, 969A07950ED1D3AE00F1F681 /* Opcode.h */, - 0FD82E84141F3FDA00179C94 /* PredictedType.cpp */, - 0FD82E4F141DAEA100179C94 /* PredictedType.h */, + 0FD82E84141F3FDA00179C94 /* SpeculatedType.cpp */, + 0FD82E4F141DAEA100179C94 /* SpeculatedType.h */, 1429D8830ED21C3D00B89619 /* SamplingTool.cpp */, 1429D8840ED21C3D00B89619 /* SamplingTool.h */, BCCF0D0B0EF0B8A500413C8F /* StructureStubInfo.cpp */, @@ -2284,6 +2373,8 @@ 0F963B3613FC6FDE0002D9B2 /* ValueProfile.h */, 0F426A451460CBAB00131F8F /* ValueRecovery.h */, 0F426A461460CBAB00131F8F /* VirtualRegister.h */, + 0F919D2215853CDE004A4E7D /* Watchpoint.cpp */, + 0F919D2315853CDE004A4E7D /* Watchpoint.h */, ); path = bytecode; sourceTree = "<group>"; @@ -2316,6 +2407,7 @@ 86ADD1450FDDEA980006EEC2 /* ARMv7Assembler.h in Headers */, C2EAD2FC14F0249800A4B159 /* CopiedAllocator.h in Headers */, C2B916C214DA014E00CBAC86 /* MarkedAllocator.h in Headers */, + C2E526BE1590EF000054E48D /* HeapTimer.h in Headers */, C25F8BCE157544A900245B71 /* IncrementalSweeper.h in Headers */, BC18C3E60E16F5CD00B34460 /* ArrayConstructor.h in Headers */, BC18C3E70E16F5CD00B34460 /* ArrayPrototype.h in Headers */, @@ -2506,7 +2598,7 @@ BC18C44B0E16F5CD00B34460 /* Parser.h in Headers */, 93052C350FB792190048FDC3 /* ParserArena.h in Headers */, 65303D641447B9E100D3F904 /* ParserTokens.h in Headers */, - 0FD82E54141DAEEE00179C94 /* PredictedType.h in Headers */, + 0FD82E54141DAEEE00179C94 /* SpeculatedType.h in Headers */, BC18C4500E16F5CD00B34460 /* Profile.h in Headers */, BC18C4510E16F5CD00B34460 /* ProfileNode.h in Headers */, BC18C4520E16F5CD00B34460 /* Profiler.h in Headers */, @@ -2657,6 +2749,16 @@ 0F3B3A2C15475002003ED0FF /* DFGValidate.h in Headers */, 0FD81AD3154FB4F000983E72 /* DFGDominators.h in Headers */, 0F16015E156198C900C2587C /* DFGArgumentsSimplificationPhase.h in Headers */, + 0F919D0D157EE0A2004A4E7D /* JSSymbolTableObject.h in Headers */, + 0F919D11157F332C004A4E7D /* JSSegmentedVariableObject.h in Headers */, + 0F919D2615853CE3004A4E7D /* Watchpoint.h in Headers */, + 0FF42731158EBD54004CB9FF /* Disassembler.h in Headers */, + 0FF42741158EBE8D004CB9FF /* udis86_decode.h in Headers */, + 0FF42742158EBE91004CB9FF /* udis86_extern.h in Headers */, + 0FF42744158EBE91004CB9FF /* udis86_input.h in Headers */, + 0FF42748158EBE91004CB9FF /* udis86_syn.h in Headers */, + 0FF42749158EBE91004CB9FF /* udis86_types.h in Headers */, + 0FF4274B158EBE91004CB9FF /* udis86.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2936,7 +3038,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "mkdir -p \"${BUILT_PRODUCTS_DIR}/DerivedSources/JavaScriptCore/docs\"\ncd \"${BUILT_PRODUCTS_DIR}/DerivedSources/JavaScriptCore\"\n\n/bin/ln -sfh \"${SRCROOT}\" JavaScriptCore\nexport JavaScriptCore=\"JavaScriptCore\"\nexport BUILT_PRODUCTS_DIR=\"../..\"\n\nmake --no-builtin-rules -f \"JavaScriptCore/DerivedSources.make\" -j `/usr/sbin/sysctl -n hw.ncpu`\n\n/usr/bin/env ruby JavaScriptCore/offlineasm/asm.rb JavaScriptCore/llint/LowLevelInterpreter.asm ${BUILT_PRODUCTS_DIR}/JSCLLIntOffsetsExtractor LLIntAssembly.h\n"; + shellScript = "mkdir -p \"${BUILT_PRODUCTS_DIR}/DerivedSources/JavaScriptCore/docs\"\ncd \"${BUILT_PRODUCTS_DIR}/DerivedSources/JavaScriptCore\"\n\n/bin/ln -sfh \"${SRCROOT}\" JavaScriptCore\nexport JavaScriptCore=\"JavaScriptCore\"\nexport BUILT_PRODUCTS_DIR=\"../..\"\n\nmake --no-builtin-rules -f \"JavaScriptCore/DerivedSources.make\" -j `/usr/sbin/sysctl -n hw.ncpu` || exit 1\n\n/usr/bin/env ruby JavaScriptCore/offlineasm/asm.rb JavaScriptCore/llint/LowLevelInterpreter.asm ${BUILT_PRODUCTS_DIR}/JSCLLIntOffsetsExtractor LLIntAssembly.h || exit 1\n"; }; 9319586B09D9F91A00A56FD4 /* Check For Global Initializers */ = { isa = PBXShellScriptBuildPhase; @@ -3067,7 +3169,6 @@ 86DB64640F95C6FC00D7D921 /* ExecutableAllocatorFixedVMPool.cpp in Sources */, 147F39CB107EC37600427A48 /* FunctionConstructor.cpp in Sources */, 147F39CC107EC37600427A48 /* FunctionPrototype.cpp in Sources */, - DDF7ABD511F60ED200108E36 /* GCActivityCallbackCF.cpp in Sources */, 14280855107EC0E70013E7B2 /* GetterSetter.cpp in Sources */, 142E3135134FF0A600AFADB5 /* HandleSet.cpp in Sources */, 142E3137134FF0A600AFADB5 /* HandleStack.cpp in Sources */, @@ -3147,7 +3248,7 @@ 0FE228EE1436AB2C00196C48 /* Options.cpp in Sources */, 148F21BC107EC54D0042EC2C /* Parser.cpp in Sources */, 93052C340FB792190048FDC3 /* ParserArena.cpp in Sources */, - 0FD82E86141F3FF100179C94 /* PredictedType.cpp in Sources */, + 0FD82E86141F3FF100179C94 /* SpeculatedType.cpp in Sources */, 95742F650DD11F5A000917FB /* Profile.cpp in Sources */, 95CD45760E1C4FDD0085358E /* ProfileGenerator.cpp in Sources */, 95AB83560DA43C3000BC83F3 /* ProfileNode.cpp in Sources */, @@ -3229,6 +3330,21 @@ 0FD81AD2154FB4EE00983E72 /* DFGDominators.cpp in Sources */, 0F16015D156198C900C2587C /* DFGArgumentsSimplificationPhase.cpp in Sources */, C25F8BCD157544A900245B71 /* IncrementalSweeper.cpp in Sources */, + 0F919D0C157EE09F004A4E7D /* JSSymbolTableObject.cpp in Sources */, + 0F919D10157F3329004A4E7D /* JSSegmentedVariableObject.cpp in Sources */, + 0F919D2515853CE0004A4E7D /* Watchpoint.cpp in Sources */, + 0F919D2815856773004A4E7D /* SymbolTable.cpp in Sources */, + 0FF42732158EBD58004CB9FF /* UDis86Disassembler.cpp in Sources */, + 0FF42740158EBE8B004CB9FF /* udis86_decode.c in Sources */, + 0FF42743158EBE91004CB9FF /* udis86_input.c in Sources */, + 0FF42745158EBE91004CB9FF /* udis86_syn-att.c in Sources */, + 0FF42746158EBE91004CB9FF /* udis86_syn-intel.c in Sources */, + 0FF42747158EBE91004CB9FF /* udis86_syn.c in Sources */, + 0FF4274A158EBE91004CB9FF /* udis86.c in Sources */, + 0FF4274D158EBFE6004CB9FF /* udis86_itab_holder.c in Sources */, + C2E526BD1590EF000054E48D /* HeapTimer.cpp in Sources */, + 0FF4275715914A20004CB9FF /* LinkBuffer.cpp in Sources */, + C2D58C3415912FEE0021A844 /* GCActivityCallback.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Source/JavaScriptCore/PlatformBlackBerry.cmake b/Source/JavaScriptCore/PlatformBlackBerry.cmake index abfae85be..cc3cfead3 100644 --- a/Source/JavaScriptCore/PlatformBlackBerry.cmake +++ b/Source/JavaScriptCore/PlatformBlackBerry.cmake @@ -2,4 +2,12 @@ LIST(INSERT JavaScriptCore_INCLUDE_DIRECTORIES 0 "${BLACKBERRY_THIRD_PARTY_DIR}/icu" ) +LIST(REMOVE_ITEM JavaScriptCore_SOURCES + runtime/GCActivityCallback.cpp +) + +LIST(APPEND JavaScriptCore_SOURCES + runtime/GCActivityCallbackBlackBerry.cpp +) + INSTALL(FILES "wtf/Forward.h" DESTINATION usr/include/browser/webkit/wtf) diff --git a/Source/JavaScriptCore/Target.pri b/Source/JavaScriptCore/Target.pri index ed682d94a..e3488c74e 100644 --- a/Source/JavaScriptCore/Target.pri +++ b/Source/JavaScriptCore/Target.pri @@ -47,6 +47,7 @@ SOURCES += \ API/OpaqueJSString.cpp \ assembler/ARMAssembler.cpp \ assembler/ARMv7Assembler.cpp \ + assembler/LinkBuffer.cpp \ assembler/MacroAssemblerARM.cpp \ assembler/MacroAssemblerSH4.cpp \ bytecode/CallLinkInfo.cpp \ @@ -62,10 +63,11 @@ SOURCES += \ bytecode/MethodOfGettingAValueProfile.cpp \ bytecode/Opcode.cpp \ bytecode/PolymorphicPutByIdList.cpp \ - bytecode/PredictedType.cpp \ bytecode/PutByIdStatus.cpp \ bytecode/SamplingTool.cpp \ + bytecode/SpeculatedType.cpp \ bytecode/StructureStubInfo.cpp \ + bytecode/Watchpoint.cpp \ bytecompiler/BytecodeGenerator.cpp \ bytecompiler/NodesCodegen.cpp \ heap/CopiedSpace.cpp \ @@ -78,6 +80,7 @@ SOURCES += \ heap/HandleStack.cpp \ heap/BlockAllocator.cpp \ heap/Heap.cpp \ + heap/HeapTimer.cpp \ heap/IncrementalSweeper.cpp \ heap/MachineStackMarker.cpp \ heap/MarkStack.cpp \ @@ -194,9 +197,11 @@ SOURCES += \ runtime/JSObject.cpp \ runtime/JSONObject.cpp \ runtime/JSPropertyNameIterator.cpp \ + runtime/JSSegmentedVariableObject.cpp \ runtime/JSStaticScopeObject.cpp \ runtime/JSString.cpp \ runtime/JSStringJoiner.cpp \ + runtime/JSSymbolTableObject.cpp \ runtime/JSValue.cpp \ runtime/JSVariableObject.cpp \ runtime/JSWrapperObject.cpp \ @@ -234,6 +239,7 @@ SOURCES += \ runtime/StringRecursionChecker.cpp \ runtime/StructureChain.cpp \ runtime/Structure.cpp \ + runtime/SymbolTable.cpp \ runtime/TimeoutChecker.cpp \ runtime/UString.cpp \ tools/CodeProfile.cpp \ diff --git a/Source/JavaScriptCore/assembler/ARMv7Assembler.h b/Source/JavaScriptCore/assembler/ARMv7Assembler.h index 0cbe799b4..95c812c94 100644 --- a/Source/JavaScriptCore/assembler/ARMv7Assembler.h +++ b/Source/JavaScriptCore/assembler/ARMv7Assembler.h @@ -483,6 +483,12 @@ public: JumpLinkType m_linkType : 8; Condition m_condition : 16; }; + + ARMv7Assembler() + : m_indexOfLastWatchpoint(INT_MIN) + , m_indexOfTailOfLastWatchpoint(INT_MIN) + { + } private: @@ -1820,10 +1826,25 @@ public: { m_formatter.oneWordOp8Imm8(OP_NOP_T1, 0); } + + AssemblerLabel labelForWatchpoint() + { + AssemblerLabel result = m_formatter.label(); + if (static_cast<int>(result.m_offset) != m_indexOfLastWatchpoint) + result = label(); + m_indexOfLastWatchpoint = result.m_offset; + m_indexOfTailOfLastWatchpoint = result.m_offset + maxJumpReplacementSize(); + return result; + } AssemblerLabel label() { - return m_formatter.label(); + AssemblerLabel result = m_formatter.label(); + while (UNLIKELY(static_cast<int>(result.m_offset) < m_indexOfTailOfLastWatchpoint)) { + nop(); + result = m_formatter.label(); + } + return result; } AssemblerLabel align(int alignment) @@ -2067,6 +2088,30 @@ public: { return reinterpret_cast<void*>(readInt32(where)); } + + static void replaceWithJump(void* instructionStart, void* to) + { + ASSERT(!(bitwise_cast<uintptr_t>(instructionStart) & 1)); + ASSERT(!(bitwise_cast<uintptr_t>(to) & 1)); + uint16_t* ptr = reinterpret_cast<uint16_t*>(instructionStart) + 2; + + // Ensure that we're not in one of those errata-triggering thingies. If we are, then + // prepend a nop. + bool spansTwo4K = ((reinterpret_cast<intptr_t>(ptr) & 0xfff) == 0x002); + + if (spansTwo4K) { + ptr[-2] = OP_NOP_T1; + ptr++; + } + + linkJumpT4(ptr, to); + cacheFlush(ptr - 2, sizeof(uint16_t) * 2); + } + + static ptrdiff_t maxJumpReplacementSize() + { + return 6; + } unsigned debugOffset() { return m_formatter.debugOffset(); } @@ -2604,6 +2649,8 @@ private: Vector<LinkRecord> m_jumpsToLink; Vector<int32_t> m_offsets; + int m_indexOfLastWatchpoint; + int m_indexOfTailOfLastWatchpoint; }; } // namespace JSC diff --git a/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h b/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h index a0039cb52..27b8a58d1 100644 --- a/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h +++ b/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 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 @@ -48,6 +48,7 @@ namespace JSC { class LinkBuffer; class RepatchBuffer; +class Watchpoint; namespace DFG { class CorrectableJumpPoint; } @@ -70,7 +71,6 @@ public: // The following types are used as operands to MacroAssembler operations, // describing immediate and memory operands to the instructions to be planted. - enum Scale { TimesOne, TimesTwo, @@ -279,6 +279,7 @@ public: friend class Jump; friend class MacroAssemblerCodeRef; friend class LinkBuffer; + friend class Watchpoint; public: Label() @@ -559,6 +560,13 @@ public: return Label(this); } + Label watchpointLabel() + { + Label result; + result.m_label = m_assembler.labelForWatchpoint(); + return result; + } + Label align() { m_assembler.align(16); @@ -655,18 +663,6 @@ protected: { return AssemblerType::readPointer(dataLabelPtr.dataLocation()); } - - static void unreachableForPlatform() - { -#if COMPILER(CLANG) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wmissing-noreturn" - ASSERT_NOT_REACHED(); -#pragma clang diagnostic pop -#else - ASSERT_NOT_REACHED(); -#endif - } }; } // namespace JSC diff --git a/Source/JavaScriptCore/assembler/AssemblerBuffer.h b/Source/JavaScriptCore/assembler/AssemblerBuffer.h index d1deef234..6bc1b3924 100644 --- a/Source/JavaScriptCore/assembler/AssemblerBuffer.h +++ b/Source/JavaScriptCore/assembler/AssemblerBuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 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 @@ -28,11 +28,11 @@ #if ENABLE(ASSEMBLER) +#include "ExecutableAllocator.h" #include "JITCompilationEffort.h" #include "JSGlobalData.h" #include "stdint.h" #include <string.h> -#include <jit/ExecutableAllocator.h> #include <wtf/Assertions.h> #include <wtf/FastMalloc.h> #include <wtf/StdLibExtras.h> diff --git a/Source/JavaScriptCore/assembler/LinkBuffer.cpp b/Source/JavaScriptCore/assembler/LinkBuffer.cpp new file mode 100644 index 000000000..58030ba7d --- /dev/null +++ b/Source/JavaScriptCore/assembler/LinkBuffer.cpp @@ -0,0 +1,231 @@ +/* + * 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 "LinkBuffer.h" + +#if ENABLE(ASSEMBLER) + +#include "Options.h" + +namespace JSC { + +LinkBuffer::CodeRef LinkBuffer::finalizeCodeWithoutDisassembly() +{ + performFinalization(); + + return CodeRef(m_executableMemory); +} + +LinkBuffer::CodeRef LinkBuffer::finalizeCodeWithDisassembly(const char* format, ...) +{ + ASSERT(Options::showDisassembly); + + CodeRef result = finalizeCodeWithoutDisassembly(); + + dataLog("Generated JIT code for "); + va_list argList; + va_start(argList, format); + WTF::dataLogV(format, argList); + va_end(argList); + dataLog(":\n"); + + dataLog(" Code at [%p, %p):\n", result.code().executableAddress(), static_cast<char*>(result.code().executableAddress()) + result.size()); + if (!tryToDisassemble(result.code(), m_size, " ", WTF::dataFile())) + dataLog(" <no disassembly available>"); + + return result; +} + +void LinkBuffer::linkCode(void* ownerUID, JITCompilationEffort effort) +{ + ASSERT(!m_code); +#if !ENABLE(BRANCH_COMPACTION) + m_executableMemory = m_assembler->m_assembler.executableCopy(*m_globalData, ownerUID, effort); + if (!m_executableMemory) + return; + m_code = m_executableMemory->start(); + m_size = m_assembler->m_assembler.codeSize(); + ASSERT(m_code); +#else + m_initialSize = m_assembler->m_assembler.codeSize(); + m_executableMemory = m_globalData->executableAllocator.allocate(*m_globalData, m_initialSize, ownerUID, effort); + if (!m_executableMemory) + return; + m_code = (uint8_t*)m_executableMemory->start(); + ASSERT(m_code); + ExecutableAllocator::makeWritable(m_code, m_initialSize); + uint8_t* inData = (uint8_t*)m_assembler->unlinkedCode(); + uint8_t* outData = reinterpret_cast<uint8_t*>(m_code); + int readPtr = 0; + int writePtr = 0; + Vector<LinkRecord>& jumpsToLink = m_assembler->jumpsToLink(); + unsigned jumpCount = jumpsToLink.size(); + for (unsigned i = 0; i < jumpCount; ++i) { + int offset = readPtr - writePtr; + ASSERT(!(offset & 1)); + + // Copy the instructions from the last jump to the current one. + size_t regionSize = jumpsToLink[i].from() - readPtr; + uint16_t* copySource = reinterpret_cast_ptr<uint16_t*>(inData + readPtr); + uint16_t* copyEnd = reinterpret_cast_ptr<uint16_t*>(inData + readPtr + regionSize); + uint16_t* copyDst = reinterpret_cast_ptr<uint16_t*>(outData + writePtr); + ASSERT(!(regionSize % 2)); + ASSERT(!(readPtr % 2)); + ASSERT(!(writePtr % 2)); + while (copySource != copyEnd) + *copyDst++ = *copySource++; + m_assembler->recordLinkOffsets(readPtr, jumpsToLink[i].from(), offset); + readPtr += regionSize; + writePtr += regionSize; + + // Calculate absolute address of the jump target, in the case of backwards + // branches we need to be precise, forward branches we are pessimistic + const uint8_t* target; + if (jumpsToLink[i].to() >= jumpsToLink[i].from()) + target = outData + jumpsToLink[i].to() - offset; // Compensate for what we have collapsed so far + else + target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to()); + + JumpLinkType jumpLinkType = m_assembler->computeJumpType(jumpsToLink[i], outData + writePtr, target); + // Compact branch if we can... + if (m_assembler->canCompact(jumpsToLink[i].type())) { + // Step back in the write stream + int32_t delta = m_assembler->jumpSizeDelta(jumpsToLink[i].type(), jumpLinkType); + if (delta) { + writePtr -= delta; + m_assembler->recordLinkOffsets(jumpsToLink[i].from() - delta, readPtr, readPtr - writePtr); + } + } + jumpsToLink[i].setFrom(writePtr); + } + // Copy everything after the last jump + memcpy(outData + writePtr, inData + readPtr, m_initialSize - readPtr); + m_assembler->recordLinkOffsets(readPtr, m_initialSize, readPtr - writePtr); + + for (unsigned i = 0; i < jumpCount; ++i) { + uint8_t* location = outData + jumpsToLink[i].from(); + uint8_t* target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to()); + m_assembler->link(jumpsToLink[i], location, target); + } + + jumpsToLink.clear(); + m_size = writePtr + m_initialSize - readPtr; + m_executableMemory->shrink(m_size); + +#if DUMP_LINK_STATISTICS + dumpLinkStatistics(m_code, m_initialSize, m_size); +#endif +#if DUMP_CODE + dumpCode(m_code, m_size); +#endif +#endif +} + +void LinkBuffer::performFinalization() +{ +#ifndef NDEBUG + ASSERT(!m_completed); + ASSERT(isValid()); + m_completed = true; +#endif + +#if ENABLE(BRANCH_COMPACTION) + ExecutableAllocator::makeExecutable(code(), m_initialSize); +#else + ExecutableAllocator::makeExecutable(code(), m_size); +#endif + MacroAssembler::cacheFlush(code(), m_size); +} + +#if DUMP_LINK_STATISTICS +void LinkBuffer::dumpLinkStatistics(void* code, size_t initializeSize, size_t finalSize) +{ + static unsigned linkCount = 0; + static unsigned totalInitialSize = 0; + static unsigned totalFinalSize = 0; + linkCount++; + totalInitialSize += initialSize; + totalFinalSize += finalSize; + dataLog("link %p: orig %u, compact %u (delta %u, %.2f%%)\n", + code, static_cast<unsigned>(initialSize), static_cast<unsigned>(finalSize), + static_cast<unsigned>(initialSize - finalSize), + 100.0 * (initialSize - finalSize) / initialSize); + dataLog("\ttotal %u: orig %u, compact %u (delta %u, %.2f%%)\n", + linkCount, totalInitialSize, totalFinalSize, totalInitialSize - totalFinalSize, + 100.0 * (totalInitialSize - totalFinalSize) / totalInitialSize); +} +#endif + +#if DUMP_CODE +void LinkBuffer::dumpCode(void* code, size_t size) +{ +#if CPU(ARM_THUMB2) + // Dump the generated code in an asm file format that can be assembled and then disassembled + // for debugging purposes. For example, save this output as jit.s: + // gcc -arch armv7 -c jit.s + // otool -tv jit.o + static unsigned codeCount = 0; + unsigned short* tcode = static_cast<unsigned short*>(code); + size_t tsize = size / sizeof(short); + char nameBuf[128]; + snprintf(nameBuf, sizeof(nameBuf), "_jsc_jit%u", codeCount++); + dataLog("\t.syntax unified\n" + "\t.section\t__TEXT,__text,regular,pure_instructions\n" + "\t.globl\t%s\n" + "\t.align 2\n" + "\t.code 16\n" + "\t.thumb_func\t%s\n" + "# %p\n" + "%s:\n", nameBuf, nameBuf, code, nameBuf); + + for (unsigned i = 0; i < tsize; i++) + dataLog("\t.short\t0x%x\n", tcode[i]); +#elif CPU(ARM_TRADITIONAL) + // gcc -c jit.s + // objdump -D jit.o + static unsigned codeCount = 0; + unsigned int* tcode = static_cast<unsigned int*>(code); + size_t tsize = size / sizeof(unsigned int); + char nameBuf[128]; + snprintf(nameBuf, sizeof(nameBuf), "_jsc_jit%u", codeCount++); + dataLog("\t.globl\t%s\n" + "\t.align 4\n" + "\t.code 32\n" + "\t.text\n" + "# %p\n" + "%s:\n", nameBuf, code, nameBuf); + + for (unsigned i = 0; i < tsize; i++) + dataLog("\t.long\t0x%x\n", tcode[i]); +#endif +} +#endif + +} // namespace JSC + +#endif // ENABLE(ASSEMBLER) + + diff --git a/Source/JavaScriptCore/assembler/LinkBuffer.h b/Source/JavaScriptCore/assembler/LinkBuffer.h index eff320d57..c6e003142 100644 --- a/Source/JavaScriptCore/assembler/LinkBuffer.h +++ b/Source/JavaScriptCore/assembler/LinkBuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2010, 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 @@ -193,13 +193,13 @@ public: return applyOffset(label.m_label).m_offset; } - // Upon completion of all patching 'finalizeCode()' should be called once to complete generation of the code. - CodeRef finalizeCode() - { - performFinalization(); - - return CodeRef(m_executableMemory); - } + // Upon completion of all patching 'FINALIZE_CODE()' should be called once to + // complete generation of the code. Alternatively, call + // finalizeCodeWithoutDisassembly() directly if you have your own way of + // displaying disassembly. + + CodeRef finalizeCodeWithoutDisassembly(); + CodeRef finalizeCodeWithDisassembly(const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3); CodePtr trampolineAt(Label label) { @@ -231,169 +231,16 @@ private: return m_code; } - void linkCode(void* ownerUID, JITCompilationEffort effort) - { - ASSERT(!m_code); -#if !ENABLE(BRANCH_COMPACTION) - m_executableMemory = m_assembler->m_assembler.executableCopy(*m_globalData, ownerUID, effort); - if (!m_executableMemory) - return; - m_code = m_executableMemory->start(); - m_size = m_assembler->m_assembler.codeSize(); - ASSERT(m_code); -#else - m_initialSize = m_assembler->m_assembler.codeSize(); - m_executableMemory = m_globalData->executableAllocator.allocate(*m_globalData, m_initialSize, ownerUID, effort); - if (!m_executableMemory) - return; - m_code = (uint8_t*)m_executableMemory->start(); - ASSERT(m_code); - ExecutableAllocator::makeWritable(m_code, m_initialSize); - uint8_t* inData = (uint8_t*)m_assembler->unlinkedCode(); - uint8_t* outData = reinterpret_cast<uint8_t*>(m_code); - int readPtr = 0; - int writePtr = 0; - Vector<LinkRecord>& jumpsToLink = m_assembler->jumpsToLink(); - unsigned jumpCount = jumpsToLink.size(); - for (unsigned i = 0; i < jumpCount; ++i) { - int offset = readPtr - writePtr; - ASSERT(!(offset & 1)); - - // Copy the instructions from the last jump to the current one. - size_t regionSize = jumpsToLink[i].from() - readPtr; - uint16_t* copySource = reinterpret_cast_ptr<uint16_t*>(inData + readPtr); - uint16_t* copyEnd = reinterpret_cast_ptr<uint16_t*>(inData + readPtr + regionSize); - uint16_t* copyDst = reinterpret_cast_ptr<uint16_t*>(outData + writePtr); - ASSERT(!(regionSize % 2)); - ASSERT(!(readPtr % 2)); - ASSERT(!(writePtr % 2)); - while (copySource != copyEnd) - *copyDst++ = *copySource++; - m_assembler->recordLinkOffsets(readPtr, jumpsToLink[i].from(), offset); - readPtr += regionSize; - writePtr += regionSize; - - // Calculate absolute address of the jump target, in the case of backwards - // branches we need to be precise, forward branches we are pessimistic - const uint8_t* target; - if (jumpsToLink[i].to() >= jumpsToLink[i].from()) - target = outData + jumpsToLink[i].to() - offset; // Compensate for what we have collapsed so far - else - target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to()); - - JumpLinkType jumpLinkType = m_assembler->computeJumpType(jumpsToLink[i], outData + writePtr, target); - // Compact branch if we can... - if (m_assembler->canCompact(jumpsToLink[i].type())) { - // Step back in the write stream - int32_t delta = m_assembler->jumpSizeDelta(jumpsToLink[i].type(), jumpLinkType); - if (delta) { - writePtr -= delta; - m_assembler->recordLinkOffsets(jumpsToLink[i].from() - delta, readPtr, readPtr - writePtr); - } - } - jumpsToLink[i].setFrom(writePtr); - } - // Copy everything after the last jump - memcpy(outData + writePtr, inData + readPtr, m_initialSize - readPtr); - m_assembler->recordLinkOffsets(readPtr, m_initialSize, readPtr - writePtr); - - for (unsigned i = 0; i < jumpCount; ++i) { - uint8_t* location = outData + jumpsToLink[i].from(); - uint8_t* target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to()); - m_assembler->link(jumpsToLink[i], location, target); - } - - jumpsToLink.clear(); - m_size = writePtr + m_initialSize - readPtr; - m_executableMemory->shrink(m_size); - -#if DUMP_LINK_STATISTICS - dumpLinkStatistics(m_code, m_initialSize, m_size); -#endif -#if DUMP_CODE - dumpCode(m_code, m_size); -#endif -#endif - } + void linkCode(void* ownerUID, JITCompilationEffort); - void performFinalization() - { -#ifndef NDEBUG - ASSERT(!m_completed); - ASSERT(isValid()); - m_completed = true; -#endif - -#if ENABLE(BRANCH_COMPACTION) - ExecutableAllocator::makeExecutable(code(), m_initialSize); -#else - ExecutableAllocator::makeExecutable(code(), m_size); -#endif - MacroAssembler::cacheFlush(code(), m_size); - } + void performFinalization(); #if DUMP_LINK_STATISTICS - static void dumpLinkStatistics(void* code, size_t initialSize, size_t finalSize) - { - static unsigned linkCount = 0; - static unsigned totalInitialSize = 0; - static unsigned totalFinalSize = 0; - linkCount++; - totalInitialSize += initialSize; - totalFinalSize += finalSize; - dataLog("link %p: orig %u, compact %u (delta %u, %.2f%%)\n", - code, static_cast<unsigned>(initialSize), static_cast<unsigned>(finalSize), - static_cast<unsigned>(initialSize - finalSize), - 100.0 * (initialSize - finalSize) / initialSize); - dataLog("\ttotal %u: orig %u, compact %u (delta %u, %.2f%%)\n", - linkCount, totalInitialSize, totalFinalSize, totalInitialSize - totalFinalSize, - 100.0 * (totalInitialSize - totalFinalSize) / totalInitialSize); - } + static void dumpLinkStatistics(void* code, size_t initialSize, size_t finalSize); #endif #if DUMP_CODE - static void dumpCode(void* code, size_t size) - { -#if CPU(ARM_THUMB2) - // Dump the generated code in an asm file format that can be assembled and then disassembled - // for debugging purposes. For example, save this output as jit.s: - // gcc -arch armv7 -c jit.s - // otool -tv jit.o - static unsigned codeCount = 0; - unsigned short* tcode = static_cast<unsigned short*>(code); - size_t tsize = size / sizeof(short); - char nameBuf[128]; - snprintf(nameBuf, sizeof(nameBuf), "_jsc_jit%u", codeCount++); - dataLog("\t.syntax unified\n" - "\t.section\t__TEXT,__text,regular,pure_instructions\n" - "\t.globl\t%s\n" - "\t.align 2\n" - "\t.code 16\n" - "\t.thumb_func\t%s\n" - "# %p\n" - "%s:\n", nameBuf, nameBuf, code, nameBuf); - - for (unsigned i = 0; i < tsize; i++) - dataLog("\t.short\t0x%x\n", tcode[i]); -#elif CPU(ARM_TRADITIONAL) - // gcc -c jit.s - // objdump -D jit.o - static unsigned codeCount = 0; - unsigned int* tcode = static_cast<unsigned int*>(code); - size_t tsize = size / sizeof(unsigned int); - char nameBuf[128]; - snprintf(nameBuf, sizeof(nameBuf), "_jsc_jit%u", codeCount++); - dataLog("\t.globl\t%s\n" - "\t.align 4\n" - "\t.code 32\n" - "\t.text\n" - "# %p\n" - "%s:\n", nameBuf, code, nameBuf); - - for (unsigned i = 0; i < tsize; i++) - dataLog("\t.long\t0x%x\n", tcode[i]); -#endif - } + static void dumpCode(void* code, size_t); #endif RefPtr<ExecutableMemoryHandle> m_executableMemory; @@ -410,6 +257,27 @@ private: #endif }; +// Use this to finalize code, like so: +// +// CodeRef code = FINALIZE_CODE(linkBuffer, ("my super thingy number %d", number)); +// +// Which, in disassembly mode, will print: +// +// Generated JIT code for my super thingy number 42: +// Code at [0x123456, 0x234567]: +// 0x123456: mov $0, 0 +// 0x12345a: ret +// +// ... and so on. +// +// Note that the dataLogArgumentsForHeading are only evaluated when showDisassembly +// is true, so you can hide expensive disassembly-only computations inside there. + +#define FINALIZE_CODE(linkBufferReference, dataLogArgumentsForHeading) \ + (UNLIKELY(Options::showDisassembly) \ + ? ((linkBufferReference).finalizeCodeWithDisassembly dataLogArgumentsForHeading) \ + : (linkBufferReference).finalizeCodeWithoutDisassembly()) + } // namespace JSC #endif // ENABLE(ASSEMBLER) diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerARM.h b/Source/JavaScriptCore/assembler/MacroAssemblerARM.h index 1775cb4cf..8ea29e3a0 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerARM.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerARM.h @@ -514,6 +514,13 @@ public: return branchTest32(cond, ARMRegisters::S1, mask); } + Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1)) + { + move(TrustedImmPtr(address.m_ptr), ARMRegisters::S1); + load8(Address(ARMRegisters::S1), ARMRegisters::S1); + return branchTest32(cond, ARMRegisters::S1, mask); + } + Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask) { ASSERT((cond == Zero) || (cond == NonZero)); @@ -1010,6 +1017,17 @@ public: return FunctionPtr(reinterpret_cast<void(*)()>(ARMAssembler::readCallTarget(call.dataLocation()))); } + static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination) + { + ASSERT_NOT_REACHED(); + } + + static ptrdiff_t maxJumpReplacementSize() + { + ASSERT_NOT_REACHED(); + return 0; + } + protected: ARMAssembler::Condition ARMCondition(RelationalCondition cond) { diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h b/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h index 3b62cb5be..6c0feffcf 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h @@ -608,7 +608,7 @@ public: void load8Signed(ImplicitAddress, RegisterID) { - unreachableForPlatform(); + UNREACHABLE_FOR_PLATFORM(); } void load8(BaseIndex address, RegisterID dest) @@ -674,7 +674,7 @@ public: void load16Signed(ImplicitAddress, RegisterID) { - unreachableForPlatform(); + UNREACHABLE_FOR_PLATFORM(); } DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) @@ -1186,6 +1186,16 @@ public: { m_assembler.nop(); } + + static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination) + { + ARMv7Assembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation()); + } + + static ptrdiff_t maxJumpReplacementSize() + { + return ARMv7Assembler::maxJumpReplacementSize(); + } // Forwards / external control flow operations: // @@ -1356,6 +1366,14 @@ public: return branchTest32(cond, addressTempRegister, mask); } + Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1)) + { + // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/ + move(TrustedImmPtr(address.m_ptr), addressTempRegister); + load8(Address(addressTempRegister), addressTempRegister); + return branchTest32(cond, addressTempRegister, mask); + } + void jump(RegisterID target) { m_assembler.bx(target); @@ -1679,12 +1697,14 @@ public: protected: ALWAYS_INLINE Jump jump() { + m_assembler.label(); // Force nop-padding if we're in the middle of a watchpoint. moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister); return Jump(m_assembler.bx(dataTempRegister), m_makeJumpPatchable ? ARMv7Assembler::JumpNoConditionFixedSize : ARMv7Assembler::JumpNoCondition); } ALWAYS_INLINE Jump makeBranch(ARMv7Assembler::Condition cond) { + m_assembler.label(); // Force nop-padding if we're in the middle of a watchpoint. m_assembler.it(cond, true, true); moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister); return Jump(m_assembler.bx(dataTempRegister), m_makeJumpPatchable ? ARMv7Assembler::JumpConditionFixedSize : ARMv7Assembler::JumpCondition, cond); diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerCodeRef.h b/Source/JavaScriptCore/assembler/MacroAssemblerCodeRef.h index ac62c4221..a1b3a8338 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerCodeRef.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerCodeRef.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009, 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 @@ -26,7 +26,9 @@ #ifndef MacroAssemblerCodeRef_h #define MacroAssemblerCodeRef_h +#include "Disassembler.h" #include "ExecutableAllocator.h" +#include <wtf/DataLog.h> #include <wtf/PassRefPtr.h> #include <wtf/RefPtr.h> #include <wtf/UnusedParam.h> @@ -367,6 +369,11 @@ public: return m_executableMemory->sizeInBytes(); } + bool tryToDisassemble(const char* prefix) const + { + return JSC::tryToDisassemble(m_codePtr, size(), prefix, WTF::dataFile()); + } + bool operator!() const { return !m_codePtr; } private: diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h b/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h index f9c3457b5..5adcf9b4e 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h @@ -1149,6 +1149,13 @@ public: return branchTest32(cond, dataTempRegister, mask); } + Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1)) + { + move(TrustedImmPtr(address.m_ptr), dataTempRegister); + load8(Address(dataTempRegister), dataTempRegister); + return branchTest32(cond, dataTempRegister, mask); + } + Jump jump() { return branchEqual(MIPSRegisters::zero, MIPSRegisters::zero); @@ -1868,6 +1875,17 @@ public: return FunctionPtr(reinterpret_cast<void(*)()>(MIPSAssembler::readCallTarget(call.dataLocation()))); } + static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination) + { + ASSERT_NOT_REACHED(); + } + + static ptrdiff_t maxJumpReplacementSize() + { + ASSERT_NOT_REACHED(); + return 0; + } + private: // If m_fixedWidth is true, we will generate a fixed number of instructions. // Otherwise, we can emit any number of instructions. diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerSH4.h b/Source/JavaScriptCore/assembler/MacroAssemblerSH4.h index c132ad642..badf35f81 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerSH4.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerSH4.h @@ -1293,6 +1293,16 @@ void or32(TrustedImm32 imm, RegisterID src, RegisterID dest) return jmp; } + Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1)) + { + RegisterID addressTempRegister = claimScratch(); + move(TrustedImmPtr(address.m_ptr), addressTempRegister); + load8(Address(addressTempRegister), addressTempRegister); + Jump jmp = branchTest32(cond, addressTempRegister, mask); + releaseScratch(addressTempRegister); + return jmp; + } + void signExtend32ToPtr(RegisterID src, RegisterID dest) { if (src != dest) @@ -1971,6 +1981,17 @@ void or32(TrustedImm32 imm, RegisterID src, RegisterID dest) return FunctionPtr(reinterpret_cast<void(*)()>(SH4Assembler::readCallTarget(call.dataLocation()))); } + static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination) + { + ASSERT_NOT_REACHED(); + } + + static ptrdiff_t maxJumpReplacementSize() + { + ASSERT_NOT_REACHED(); + return 0; + } + protected: SH4Assembler::Condition SH4Condition(RelationalCondition cond) { diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerX86.h b/Source/JavaScriptCore/assembler/MacroAssemblerX86.h index 088fe196b..3ea40c967 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerX86.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerX86.h @@ -51,6 +51,7 @@ public: using MacroAssemblerX86Common::loadDouble; using MacroAssemblerX86Common::storeDouble; using MacroAssemblerX86Common::convertInt32ToDouble; + using MacroAssemblerX86Common::branchTest8; void add32(TrustedImm32 imm, RegisterID src, RegisterID dest) { @@ -165,6 +166,16 @@ public: m_assembler.movl_i32r(initialValue.asIntptr(), dest); return DataLabelPtr(this); } + + Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1)) + { + ASSERT(mask.m_value >= -128 && mask.m_value <= 255); + if (mask.m_value == -1) + m_assembler.cmpb_im(0, address.m_ptr); + else + m_assembler.testb_im(mask.m_value, address.m_ptr); + return Jump(m_assembler.jCC(x86Condition(cond))); + } Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0)) { diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h b/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h index e398dcdad..432489dbc 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h @@ -1408,6 +1408,16 @@ public: m_assembler.nop(); } + static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination) + { + X86Assembler::replaceWithJump(instructionStart.executableAddress(), destination.executableAddress()); + } + + static ptrdiff_t maxJumpReplacementSize() + { + return X86Assembler::maxJumpReplacementSize(); + } + protected: X86Assembler::Condition x86Condition(RelationalCondition cond) { diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h b/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h index 41479f996..fa95b335b 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 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 @@ -513,6 +513,12 @@ public: MacroAssemblerX86Common::move(addr, scratchRegister); return MacroAssemblerX86Common::branchTest8(cond, BaseIndex(scratchRegister, address.base, TimesOne), mask); } + + Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1)) + { + MacroAssemblerX86Common::move(TrustedImmPtr(address.m_ptr), scratchRegister); + return MacroAssemblerX86Common::branchTest8(cond, Address(scratchRegister), mask); + } static bool supportsFloatingPoint() { return true; } // See comment on MacroAssemblerARMv7::supportsFloatingPointTruncate() diff --git a/Source/JavaScriptCore/assembler/X86Assembler.h b/Source/JavaScriptCore/assembler/X86Assembler.h index ff8d25bcd..8c5606972 100644 --- a/Source/JavaScriptCore/assembler/X86Assembler.h +++ b/Source/JavaScriptCore/assembler/X86Assembler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 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 @@ -247,6 +247,8 @@ private: public: X86Assembler() + : m_indexOfLastWatchpoint(INT_MIN) + , m_indexOfTailOfLastWatchpoint(INT_MIN) { } @@ -798,6 +800,14 @@ public: m_formatter.oneByteOp(OP_GROUP1_EbIb, GROUP1_OP_CMP, base, index, scale, offset); m_formatter.immediate8(imm); } + +#if CPU(X86) + void cmpb_im(int imm, const void* addr) + { + m_formatter.oneByteOp(OP_GROUP1_EbIb, GROUP1_OP_CMP, addr); + m_formatter.immediate8(imm); + } +#endif void cmpl_im(int imm, int offset, RegisterID base, RegisterID index, int scale) { @@ -948,6 +958,14 @@ public: m_formatter.immediate8(imm); } +#if CPU(X86) + void testb_im(int imm, const void* addr) + { + m_formatter.oneByteOp(OP_GROUP3_EbIb, GROUP3_OP_TEST, addr); + m_formatter.immediate8(imm); + } +#endif + void testl_i32m(int imm, int offset, RegisterID base, RegisterID index, int scale) { m_formatter.oneByteOp(OP_GROUP3_EvIz, GROUP3_OP_TEST, base, index, scale, offset); @@ -1702,10 +1720,25 @@ public: { return m_formatter.codeSize(); } + + AssemblerLabel labelForWatchpoint() + { + AssemblerLabel result = m_formatter.label(); + if (static_cast<int>(result.m_offset) != m_indexOfLastWatchpoint) + result = label(); + m_indexOfLastWatchpoint = result.m_offset; + m_indexOfTailOfLastWatchpoint = result.m_offset + maxJumpReplacementSize(); + return result; + } AssemblerLabel label() { - return m_formatter.label(); + AssemblerLabel result = m_formatter.label(); + while (UNLIKELY(static_cast<int>(result.m_offset) < m_indexOfTailOfLastWatchpoint)) { + nop(); + result = m_formatter.label(); + } + return result; } AssemblerLabel align(int alignment) @@ -1787,6 +1820,20 @@ public: return reinterpret_cast<void**>(where)[-1]; } + static void replaceWithJump(void* instructionStart, void* to) + { + uint8_t* ptr = reinterpret_cast<uint8_t*>(instructionStart); + uint8_t* dstPtr = reinterpret_cast<uint8_t*>(to); + intptr_t distance = (intptr_t)(dstPtr - (ptr + 5)); + ptr[0] = static_cast<uint8_t>(OP_JMP_rel32); + *reinterpret_cast<int32_t*>(ptr + 1) = static_cast<int32_t>(distance); + } + + static ptrdiff_t maxJumpReplacementSize() + { + return 5; + } + static unsigned getCallReturnOffset(AssemblerLabel call) { ASSERT(call.isSet()); @@ -2339,6 +2386,8 @@ private: AssemblerBuffer m_buffer; } m_formatter; + int m_indexOfLastWatchpoint; + int m_indexOfTailOfLastWatchpoint; }; } // namespace JSC diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp index 8ef716028..60596d1c2 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp @@ -228,6 +228,7 @@ void CodeBlock::printGetByIdOp(ExecState* exec, int location, Vector<Instruction it += 5; } +#if ENABLE(JIT) || ENABLE(LLINT) // unused in some configurations static void dumpStructure(const char* name, ExecState* exec, Structure* structure, Identifier& ident) { if (!structure) @@ -239,7 +240,9 @@ static void dumpStructure(const char* name, ExecState* exec, Structure* structur if (offset != notFound) dataLog(" (offset = %lu)", static_cast<unsigned long>(offset)); } +#endif +#if ENABLE(JIT) // unused when not ENABLE(JIT), leading to silly warnings static void dumpChain(ExecState* exec, StructureChain* chain, Identifier& ident) { dataLog("chain = %p: [", chain); @@ -255,6 +258,7 @@ static void dumpChain(ExecState* exec, StructureChain* chain, Identifier& ident) } dataLog("]"); } +#endif void CodeBlock::printGetByIdCacheStatus(ExecState* exec, int location) { @@ -265,6 +269,8 @@ void CodeBlock::printGetByIdCacheStatus(ExecState* exec, int location) Identifier& ident = identifier(instruction[3].u.operand); + UNUSED_PARAM(ident); // tell the compiler to shut up in certain platform configurations. + #if ENABLE(LLINT) Structure* structure = instruction[4].u.structure.get(); dataLog(" llint("); @@ -923,15 +929,31 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& } case op_get_global_var: { int r0 = (++it)->u.operand; - int index = (++it)->u.operand; - dataLog("[%4d] get_global_var\t %s, %d\n", location, registerName(exec, r0).data(), index); + WriteBarrier<Unknown>* registerPointer = (++it)->u.registerPointer; + dataLog("[%4d] get_global_var\t %s, g%d(%p)\n", location, registerName(exec, r0).data(), m_globalObject->findRegisterIndex(registerPointer), registerPointer); + it++; + break; + } + case op_get_global_var_watchable: { + int r0 = (++it)->u.operand; + WriteBarrier<Unknown>* registerPointer = (++it)->u.registerPointer; + dataLog("[%4d] get_global_var_watchable\t %s, g%d(%p)\n", location, registerName(exec, r0).data(), m_globalObject->findRegisterIndex(registerPointer), registerPointer); + it++; it++; break; } case op_put_global_var: { - int index = (++it)->u.operand; + WriteBarrier<Unknown>* registerPointer = (++it)->u.registerPointer; int r0 = (++it)->u.operand; - dataLog("[%4d] put_global_var\t %d, %s\n", location, index, registerName(exec, r0).data()); + dataLog("[%4d] put_global_var\t g%d(%p), %s\n", location, m_globalObject->findRegisterIndex(registerPointer), registerPointer, registerName(exec, r0).data()); + break; + } + case op_put_global_var_check: { + WriteBarrier<Unknown>* registerPointer = (++it)->u.registerPointer; + int r0 = (++it)->u.operand; + dataLog("[%4d] put_global_var_check\t g%d(%p), %s\n", location, m_globalObject->findRegisterIndex(registerPointer), registerPointer, registerName(exec, r0).data()); + it++; + it++; break; } case op_resolve_base: { @@ -1145,9 +1167,9 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& } case op_jneq_ptr: { int r0 = (++it)->u.operand; - int r1 = (++it)->u.operand; + void* pointer = (++it)->u.pointer; int offset = (++it)->u.operand; - dataLog("[%4d] jneq_ptr\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + dataLog("[%4d] jneq_ptr\t\t %s, %p, %d(->%d)\n", location, registerName(exec, r0).data(), pointer, offset, location + offset); break; } case op_jless: { @@ -1306,7 +1328,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& } case op_call_put_result: { int r0 = (++it)->u.operand; - dataLog("[%4d] op_call_put_result\t\t %s\n", location, registerName(exec, r0).data()); + dataLog("[%4d] call_put_result\t\t %s\n", location, registerName(exec, r0).data()); it++; break; } @@ -1578,6 +1600,7 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other, SymbolTable* symTab) , m_forcedOSRExitCounter(0) , m_optimizationDelayCounter(0) , m_reoptimizationRetryCounter(0) + , m_lineInfo(other.m_lineInfo) #if ENABLE(JIT) , m_canCompileWithDFGState(DFG::CapabilityLevelNotSet) #endif @@ -1585,7 +1608,7 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other, SymbolTable* symTab) setNumParameters(other.numParameters()); optimizeAfterWarmUp(); jitAfterWarmUp(); - + if (other.m_rareData) { createRareDataIfNecessary(); @@ -1596,7 +1619,6 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other, SymbolTable* symTab) m_rareData->m_characterSwitchJumpTables = other.m_rareData->m_characterSwitchJumpTables; m_rareData->m_stringSwitchJumpTables = other.m_rareData->m_stringSwitchJumpTables; m_rareData->m_expressionInfo = other.m_rareData->m_expressionInfo; - m_rareData->m_lineInfo = other.m_rareData->m_lineInfo; } } @@ -2141,10 +2163,7 @@ int CodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset) { ASSERT(bytecodeOffset < instructions().size()); - if (!m_rareData) - return m_ownerExecutable->source().firstLine(); - - Vector<LineInfo>& lineInfo = m_rareData->m_lineInfo; + Vector<LineInfo>& lineInfo = m_lineInfo; int low = 0; int high = lineInfo.size(); @@ -2269,6 +2288,7 @@ void CodeBlock::shrinkToFit(ShrinkMode shrinkMode) m_constantRegisters.shrinkToFit(); } // else don't shrink these, because we would have already pointed pointers into these tables. + m_lineInfo.shrinkToFit(); if (m_rareData) { m_rareData->m_exceptionHandlers.shrinkToFit(); m_rareData->m_regexps.shrinkToFit(); @@ -2276,7 +2296,6 @@ void CodeBlock::shrinkToFit(ShrinkMode shrinkMode) m_rareData->m_characterSwitchJumpTables.shrinkToFit(); m_rareData->m_stringSwitchJumpTables.shrinkToFit(); m_rareData->m_expressionInfo.shrinkToFit(); - m_rareData->m_lineInfo.shrinkToFit(); #if ENABLE(JIT) m_rareData->m_callReturnIndexVector.shrinkToFit(); #endif @@ -2560,7 +2579,7 @@ bool CodeBlock::shouldOptimizeNow() profile->computeUpdatedPrediction(); continue; } - if (profile->numberOfSamples() || profile->m_prediction != PredictNone) + if (profile->numberOfSamples() || profile->m_prediction != SpecNone) numberOfLiveNonArgumentValueProfiles++; profile->computeUpdatedPrediction(); } @@ -2614,7 +2633,7 @@ void CodeBlock::dumpValueProfiles() dataLog(" arg = %u: ", i); } else dataLog(" bc = %d: ", profile->m_bytecodeOffset); - if (!profile->numberOfSamples() && profile->m_prediction == PredictNone) { + if (!profile->numberOfSamples() && profile->m_prediction == SpecNone) { dataLog("<empty>\n"); continue; } diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h index cdc6a19e8..573d422d3 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.h +++ b/Source/JavaScriptCore/bytecode/CodeBlock.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> * * Redistribution and use in source and binary forms, with or without @@ -62,6 +62,7 @@ #include "UString.h" #include "UnconditionalFinalizer.h" #include "ValueProfile.h" +#include "Watchpoint.h" #include <wtf/RefCountedArray.h> #include <wtf/FastAllocBase.h> #include <wtf/PassOwnPtr.h> @@ -273,10 +274,12 @@ namespace JSC { return result; } - void appendOSRExit(const DFG::OSRExit& osrExit) + unsigned appendOSRExit(const DFG::OSRExit& osrExit) { createDFGDataIfNecessary(); + unsigned result = m_dfgData->osrExit.size(); m_dfgData->osrExit.append(osrExit); + return result; } DFG::OSRExit& lastOSRExit() @@ -284,10 +287,20 @@ namespace JSC { return m_dfgData->osrExit.last(); } - void appendSpeculationRecovery(const DFG::SpeculationRecovery& recovery) + unsigned appendSpeculationRecovery(const DFG::SpeculationRecovery& recovery) { createDFGDataIfNecessary(); + unsigned result = m_dfgData->speculationRecovery.size(); m_dfgData->speculationRecovery.append(recovery); + return result; + } + + unsigned appendWatchpoint(const Watchpoint& watchpoint) + { + createDFGDataIfNecessary(); + unsigned result = m_dfgData->watchpoints.size(); + m_dfgData->watchpoints.append(watchpoint); + return result; } unsigned numberOfOSRExits() @@ -304,6 +317,13 @@ namespace JSC { return m_dfgData->speculationRecovery.size(); } + unsigned numberOfWatchpoints() + { + if (!m_dfgData) + return 0; + return m_dfgData->watchpoints.size(); + } + DFG::OSRExit& osrExit(unsigned index) { return m_dfgData->osrExit[index]; @@ -314,6 +334,11 @@ namespace JSC { return m_dfgData->speculationRecovery[index]; } + Watchpoint& watchpoint(unsigned index) + { + return m_dfgData->watchpoints[index]; + } + void appendWeakReference(JSCell* target) { createDFGDataIfNecessary(); @@ -576,7 +601,7 @@ namespace JSC { bytecodeOffset].u.opcode)) - 1].u.profile == result); return result; } - PredictedType valueProfilePredictionForBytecodeOffset(int bytecodeOffset) + SpeculatedType valueProfilePredictionForBytecodeOffset(int bytecodeOffset) { return valueProfileForBytecodeOffset(bytecodeOffset)->computeUpdatedPrediction(); } @@ -686,8 +711,7 @@ namespace JSC { void addLineInfo(unsigned bytecodeOffset, int lineNo) { - createRareDataIfNecessary(); - Vector<LineInfo>& lineInfo = m_rareData->m_lineInfo; + Vector<LineInfo>& lineInfo = m_lineInfo; if (!lineInfo.size() || lineInfo.last().lineNumber != lineNo) { LineInfo info = { bytecodeOffset, lineNo }; lineInfo.append(info); @@ -695,14 +719,6 @@ namespace JSC { } bool hasExpressionInfo() { return m_rareData && m_rareData->m_expressionInfo.size(); } - bool hasLineInfo() { return m_rareData && m_rareData->m_lineInfo.size(); } - // We only generate exception handling info if the user is debugging - // (and may want line number info), or if the function contains exception handler. - bool needsCallReturnIndices() - { - return m_rareData && - (m_rareData->m_expressionInfo.size() || m_rareData->m_lineInfo.size() || m_rareData->m_exceptionHandlers.size()); - } #if ENABLE(JIT) Vector<CallReturnOffsetToBytecodeOffset>& callReturnIndexVector() @@ -1238,6 +1254,7 @@ namespace JSC { Vector<DFG::OSREntryData> osrEntry; SegmentedVector<DFG::OSRExit, 8> osrExit; Vector<DFG::SpeculationRecovery> speculationRecovery; + SegmentedVector<Watchpoint, 1, 0> watchpoints; Vector<WeakReferenceTransition> transitions; Vector<WriteBarrier<JSCell> > weakReferences; bool mayBeExecuting; @@ -1285,7 +1302,9 @@ namespace JSC { uint32_t m_forcedOSRExitCounter; uint16_t m_optimizationDelayCounter; uint16_t m_reoptimizationRetryCounter; - + + Vector<LineInfo> m_lineInfo; + struct RareData { WTF_MAKE_FAST_ALLOCATED; public: @@ -1307,7 +1326,6 @@ namespace JSC { // Expression info - present if debugging. Vector<ExpressionRangeInfo> m_expressionInfo; // Line info - present if profiling or debugging. - Vector<LineInfo> m_lineInfo; #if ENABLE(JIT) Vector<CallReturnOffsetToBytecodeOffset> m_callReturnIndexVector; #endif @@ -1499,6 +1517,11 @@ namespace JSC { } #endif + inline JSValue Structure::prototypeForLookup(CodeBlock* codeBlock) const + { + return prototypeForLookup(codeBlock->globalObject()); + } + } // namespace JSC #endif // CodeBlock_h diff --git a/Source/JavaScriptCore/bytecode/DFGExitProfile.h b/Source/JavaScriptCore/bytecode/DFGExitProfile.h index 09f9ee075..d751ce654 100644 --- a/Source/JavaScriptCore/bytecode/DFGExitProfile.h +++ b/Source/JavaScriptCore/bytecode/DFGExitProfile.h @@ -41,6 +41,7 @@ enum ExitKind { InadequateCoverage, // We exited because we ended up in code that didn't have profiling coverage. ArgumentsEscaped, // We exited because arguments escaped but we didn't expect them to. Uncountable, // We exited for none of the above reasons, and we should not count it. Most uses of this should be viewed as a FIXME. + UncountableWatchpoint // We exited because of a watchpoint, which isn't counted because watchpoints do tracking themselves. }; inline const char* exitKindToString(ExitKind kind) @@ -58,6 +59,12 @@ inline const char* exitKindToString(ExitKind kind) return "NegativeZero"; case InadequateCoverage: return "InadequateCoverage"; + case ArgumentsEscaped: + return "ArgumentsEscaped"; + case Uncountable: + return "Uncountable"; + case UncountableWatchpoint: + return "UncountableWatchpoint"; default: return "Unknown"; } @@ -70,6 +77,7 @@ inline bool exitKindIsCountable(ExitKind kind) ASSERT_NOT_REACHED(); case BadType: case Uncountable: + case UncountableWatchpoint: return false; default: return true; diff --git a/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp b/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp index 11aead3df..a62a43f7f 100644 --- a/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp +++ b/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp @@ -44,15 +44,61 @@ GetByIdStatus GetByIdStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned Structure* structure = instruction[4].u.structure.get(); if (!structure) - return GetByIdStatus(NoInformation, StructureSet(), notFound, false); + return GetByIdStatus(NoInformation, false); - size_t offset = structure->get(*profiledBlock->globalData(), ident); + unsigned attributesIgnored; + JSCell* specificValue; + size_t offset = structure->get( + *profiledBlock->globalData(), ident, attributesIgnored, specificValue); if (offset == notFound) - return GetByIdStatus(NoInformation, StructureSet(), notFound, false); + return GetByIdStatus(NoInformation, false); - return GetByIdStatus(SimpleDirect, StructureSet(structure), offset, false); + return GetByIdStatus(Simple, false, StructureSet(structure), offset, specificValue); #else - return GetByIdStatus(NoInformation, StructureSet(), notFound, false); + return GetByIdStatus(NoInformation, false); +#endif +} + +void GetByIdStatus::computeForChain(GetByIdStatus& result, CodeBlock* profiledBlock, Identifier& ident, Structure* structure) +{ +#if ENABLE(JIT) && ENABLE(VALUE_PROFILER) + // Validate the chain. If the chain is invalid, then currently the best thing + // we can do is to assume that TakesSlow is true. In the future, it might be + // worth exploring reifying the structure chain from the structure we've got + // instead of using the one from the cache, since that will do the right things + // if the structure chain has changed. But that may be harder, because we may + // then end up having a different type of access altogether. And it currently + // does not appear to be worth it to do so -- effectively, the heuristic we + // have now is that if the structure chain has changed between when it was + // cached on in the baseline JIT and when the DFG tried to inline the access, + // then we fall back on a polymorphic access. + Structure* currentStructure = structure; + JSObject* currentObject = 0; + for (unsigned i = 0; i < result.m_chain.size(); ++i) { + currentObject = asObject(currentStructure->prototypeForLookup(profiledBlock)); + currentStructure = result.m_chain[i]; + if (currentObject->structure() != currentStructure) + return; + } + + ASSERT(currentObject); + + unsigned attributesIgnored; + JSCell* specificValue; + + result.m_offset = currentStructure->get( + *profiledBlock->globalData(), ident, attributesIgnored, specificValue); + if (result.m_offset == notFound) + return; + + result.m_structureSet.add(structure); + result.m_specificValue = JSValue(specificValue); +#else + UNUSED_PARAM(result); + UNUSED_PARAM(profiledBlock); + UNUSED_PARAM(ident); + UNUSED_PARAM(structure); + UNREACHABLE_FOR_PLATFORM(); #endif } @@ -89,12 +135,12 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec } for (int i = 0; i < listSize; ++i) { if (!list->list[i].isDirect) - return GetByIdStatus(MakesCalls, StructureSet(), notFound, true); + return GetByIdStatus(MakesCalls, true); } // Next check if it takes slow case, in which case we want to be kind of careful. if (profiledBlock->likelyToTakeSlowCase(bytecodeIndex)) - return GetByIdStatus(TakesSlowPath, StructureSet(), notFound, true); + return GetByIdStatus(TakesSlowPath, true); // Finally figure out if we can derive an access strategy. GetByIdStatus result; @@ -105,10 +151,15 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec case access_get_by_id_self: { Structure* structure = stubInfo.u.getByIdSelf.baseObjectStructure.get(); - result.m_offset = structure->get(*profiledBlock->globalData(), ident); + unsigned attributesIgnored; + JSCell* specificValue; + result.m_offset = structure->get( + *profiledBlock->globalData(), ident, attributesIgnored, specificValue); - if (result.m_offset != notFound) + if (result.m_offset != notFound) { result.m_structureSet.add(structure); + result.m_specificValue = JSValue(specificValue); + } if (result.m_offset != notFound) ASSERT(result.m_structureSet.size()); @@ -116,29 +167,32 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec } case access_get_by_id_self_list: { - PolymorphicAccessStructureList* list = stubInfo.u.getByIdProtoList.structureList; - unsigned size = stubInfo.u.getByIdProtoList.listSize; - for (unsigned i = 0; i < size; ++i) { + for (int i = 0; i < listSize; ++i) { ASSERT(list->list[i].isDirect); Structure* structure = list->list[i].base.get(); if (result.m_structureSet.contains(structure)) continue; - size_t myOffset = structure->get(*profiledBlock->globalData(), ident); + unsigned attributesIgnored; + JSCell* specificValue; + size_t myOffset = structure->get( + *profiledBlock->globalData(), ident, attributesIgnored, specificValue); if (myOffset == notFound) { result.m_offset = notFound; break; } - if (!i) + if (!i) { result.m_offset = myOffset; - else if (result.m_offset != myOffset) { + result.m_specificValue = JSValue(specificValue); + } else if (result.m_offset != myOffset) { result.m_offset = notFound; break; - } - + } else if (result.m_specificValue != JSValue(specificValue)) + result.m_specificValue = JSValue(); + result.m_structureSet.add(structure); } @@ -147,6 +201,27 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec break; } + case access_get_by_id_proto: { + if (!stubInfo.u.getByIdProto.isDirect) + return GetByIdStatus(MakesCalls, true); + result.m_chain.append(stubInfo.u.getByIdProto.prototypeStructure.get()); + computeForChain( + result, profiledBlock, ident, + stubInfo.u.getByIdProto.baseObjectStructure.get()); + break; + } + + case access_get_by_id_chain: { + if (!stubInfo.u.getByIdChain.isDirect) + return GetByIdStatus(MakesCalls, true); + for (unsigned i = 0; i < stubInfo.u.getByIdChain.count; ++i) + result.m_chain.append(stubInfo.u.getByIdChain.chain->head()[i].get()); + computeForChain( + result, profiledBlock, ident, + stubInfo.u.getByIdChain.baseObjectStructure.get()); + break; + } + default: ASSERT(result.m_offset == notFound); break; @@ -155,12 +230,14 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec if (result.m_offset == notFound) { result.m_state = TakesSlowPath; result.m_structureSet.clear(); + result.m_chain.clear(); + result.m_specificValue = JSValue(); } else - result.m_state = SimpleDirect; + result.m_state = Simple; return result; #else // ENABLE(JIT) - return GetByIdStatus(NoInformation, StructureSet(), notFound, false); + return GetByIdStatus(NoInformation, false); #endif // ENABLE(JIT) } diff --git a/Source/JavaScriptCore/bytecode/GetByIdStatus.h b/Source/JavaScriptCore/bytecode/GetByIdStatus.h index 39476c009..42eadfd68 100644 --- a/Source/JavaScriptCore/bytecode/GetByIdStatus.h +++ b/Source/JavaScriptCore/bytecode/GetByIdStatus.h @@ -38,7 +38,8 @@ class GetByIdStatus { public: enum State { NoInformation, // It's uncached so we have no information. - SimpleDirect, // It's cached for a direct access to a known object property. + Simple, // It's cached for a simple access to a known object property with + // a possible structure chain and a possible specific value. TakesSlowPath, // It's known to often take slow path. MakesCalls // It's known to take paths that make calls. }; @@ -49,13 +50,17 @@ public: { } - GetByIdStatus(State state, const StructureSet& structureSet, size_t offset, bool wasSeenInJIT) + GetByIdStatus( + State state, bool wasSeenInJIT, const StructureSet& structureSet = StructureSet(), + size_t offset = notFound, JSValue specificValue = JSValue(), Vector<Structure*> chain = Vector<Structure*>()) : m_state(state) , m_structureSet(structureSet) + , m_chain(chain) + , m_specificValue(specificValue) , m_offset(offset) , m_wasSeenInJIT(wasSeenInJIT) { - ASSERT((state == SimpleDirect) == (offset != notFound)); + ASSERT((state == Simple) == (offset != notFound)); } static GetByIdStatus computeFor(CodeBlock*, unsigned bytecodeIndex, Identifier&); @@ -64,20 +69,25 @@ public: bool isSet() const { return m_state != NoInformation; } bool operator!() const { return !isSet(); } - bool isSimpleDirect() const { return m_state == SimpleDirect; } + bool isSimple() const { return m_state == Simple; } bool takesSlowPath() const { return m_state == TakesSlowPath || m_state == MakesCalls; } bool makesCalls() const { return m_state == MakesCalls; } const StructureSet& structureSet() const { return m_structureSet; } + const Vector<Structure*>& chain() const { return m_chain; } // Returns empty vector if this is a direct access. + JSValue specificValue() const { return m_specificValue; } // Returns JSValue() if there is no specific value. size_t offset() const { return m_offset; } bool wasSeenInJIT() const { return m_wasSeenInJIT; } private: + static void computeForChain(GetByIdStatus& result, CodeBlock*, Identifier&, Structure*); static GetByIdStatus computeFromLLInt(CodeBlock*, unsigned bytecodeIndex, Identifier&); State m_state; StructureSet m_structureSet; + Vector<Structure*> m_chain; + JSValue m_specificValue; size_t m_offset; bool m_wasSeenInJIT; }; diff --git a/Source/JavaScriptCore/bytecode/Instruction.h b/Source/JavaScriptCore/bytecode/Instruction.h index c4989d2db..6e76512ff 100644 --- a/Source/JavaScriptCore/bytecode/Instruction.h +++ b/Source/JavaScriptCore/bytecode/Instruction.h @@ -191,6 +191,10 @@ namespace JSC { Instruction(LLIntCallLinkInfo* callLinkInfo) { u.callLinkInfo = callLinkInfo; } Instruction(ValueProfile* profile) { u.profile = profile; } + + Instruction(WriteBarrier<Unknown>* registerPointer) { u.registerPointer = registerPointer; } + + Instruction(bool* predicatePointer) { u.predicatePointer = predicatePointer; } union { Opcode opcode; @@ -198,10 +202,12 @@ namespace JSC { WriteBarrierBase<Structure> structure; WriteBarrierBase<StructureChain> structureChain; WriteBarrierBase<JSCell> jsCell; + WriteBarrier<Unknown>* registerPointer; PropertySlot::GetValueFunc getterFunc; LLIntCallLinkInfo* callLinkInfo; ValueProfile* profile; void* pointer; + bool* predicatePointer; } u; private: diff --git a/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.cpp b/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.cpp index 695e21219..59f0d0234 100644 --- a/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.cpp +++ b/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.cpp @@ -84,12 +84,12 @@ LazyOperandValueProfile* LazyOperandValueProfileParser::getIfPresent( return iter->second; } -PredictedType LazyOperandValueProfileParser::prediction( +SpeculatedType LazyOperandValueProfileParser::prediction( const LazyOperandValueProfileKey& key) const { LazyOperandValueProfile* profile = getIfPresent(key); if (!profile) - return PredictNone; + return SpecNone; return profile->computeUpdatedPrediction(); } diff --git a/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.h b/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.h index 91e5314aa..a117db64f 100644 --- a/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.h +++ b/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.h @@ -174,7 +174,7 @@ public: LazyOperandValueProfile* getIfPresent( const LazyOperandValueProfileKey& key) const; - PredictedType prediction(const LazyOperandValueProfileKey& key) const; + SpeculatedType prediction(const LazyOperandValueProfileKey& key) const; private: CompressedLazyOperandValueProfileHolder& m_holder; HashMap<LazyOperandValueProfileKey, LazyOperandValueProfile*> m_map; diff --git a/Source/JavaScriptCore/bytecode/Opcode.h b/Source/JavaScriptCore/bytecode/Opcode.h index aa83d9b97..e0cff165a 100644 --- a/Source/JavaScriptCore/bytecode/Opcode.h +++ b/Source/JavaScriptCore/bytecode/Opcode.h @@ -100,7 +100,9 @@ namespace JSC { macro(op_get_scoped_var, 5) /* has value profiling */ \ macro(op_put_scoped_var, 4) \ macro(op_get_global_var, 4) /* has value profiling */ \ + macro(op_get_global_var_watchable, 5) /* has value profiling */ \ macro(op_put_global_var, 3) \ + macro(op_put_global_var_check, 5) \ macro(op_resolve_base, 5) /* has value profiling */ \ macro(op_ensure_property_exists, 3) \ macro(op_resolve_with_base, 5) /* has value profiling */ \ diff --git a/Source/JavaScriptCore/bytecode/PredictedType.h b/Source/JavaScriptCore/bytecode/PredictedType.h deleted file mode 100644 index 9f0964a14..000000000 --- a/Source/JavaScriptCore/bytecode/PredictedType.h +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright (C) 2011, 2012 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef PredictedType_h -#define PredictedType_h - -#include "JSValue.h" - -namespace JSC { - -class Structure; - -typedef uint32_t PredictedType; -static const PredictedType PredictNone = 0x00000000; // We don't know anything yet. -static const PredictedType PredictFinalObject = 0x00000001; // It's definitely a JSFinalObject. -static const PredictedType PredictArray = 0x00000002; // It's definitely a JSArray. -static const PredictedType PredictFunction = 0x00000008; // It's definitely a JSFunction or one of its subclasses. -static const PredictedType PredictInt8Array = 0x00000010; // It's definitely an Int8Array or one of its subclasses. -static const PredictedType PredictInt16Array = 0x00000020; // It's definitely an Int16Array or one of its subclasses. -static const PredictedType PredictInt32Array = 0x00000040; // It's definitely an Int32Array or one of its subclasses. -static const PredictedType PredictUint8Array = 0x00000080; // It's definitely an Uint8Array or one of its subclasses. -static const PredictedType PredictUint8ClampedArray = 0x00000100; // It's definitely an Uint8ClampedArray or one of its subclasses. -static const PredictedType PredictUint16Array = 0x00000200; // It's definitely an Uint16Array or one of its subclasses. -static const PredictedType PredictUint32Array = 0x00000400; // It's definitely an Uint32Array or one of its subclasses. -static const PredictedType PredictFloat32Array = 0x00000800; // It's definitely an Uint16Array or one of its subclasses. -static const PredictedType PredictFloat64Array = 0x00001000; // It's definitely an Uint16Array or one of its subclasses. -static const PredictedType PredictMyArguments = 0x00002000; // It's definitely an Arguments object, and it's definitely the one for my current frame. -static const PredictedType PredictForeignArguments = 0x00004000; // It's definitely an Arguments object, and it's definitely not mine. -static const PredictedType PredictArguments = 0x00006000; // It's definitely an Arguments object. -static const PredictedType PredictObjectOther = 0x00008000; // It's definitely an object but not JSFinalObject, JSArray, or JSFunction. -static const PredictedType PredictObjectMask = 0x0000ffff; // Bitmask used for testing for any kind of object prediction. -static const PredictedType PredictString = 0x00010000; // It's definitely a JSString. -static const PredictedType PredictCellOther = 0x00020000; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString. -static const PredictedType PredictCell = 0x0003ffff; // It's definitely a JSCell. -static const PredictedType PredictInt32 = 0x00800000; // It's definitely an Int32. -static const PredictedType PredictDoubleReal = 0x01000000; // It's definitely a non-NaN double. -static const PredictedType PredictDoubleNaN = 0x02000000; // It's definitely a NaN. -static const PredictedType PredictDouble = 0x03000000; // It's either a non-NaN or a NaN double. -static const PredictedType PredictNumber = 0x03800000; // It's either an Int32 or a Double. -static const PredictedType PredictBoolean = 0x04000000; // It's definitely a Boolean. -static const PredictedType PredictOther = 0x08000000; // It's definitely none of the above. -static const PredictedType PredictTop = 0x0fffffff; // It can be any of the above. -static const PredictedType PredictEmpty = 0x10000000; // It's definitely an empty value marker. -static const PredictedType PredictEmptyOrTop = 0x1fffffff; // It can be any of the above. -static const PredictedType FixedIndexedStorageMask = PredictInt8Array | PredictInt16Array | PredictInt32Array | PredictUint8Array | PredictUint8ClampedArray | PredictUint16Array | PredictUint32Array | PredictFloat32Array | PredictFloat64Array; - -typedef bool (*PredictionChecker)(PredictedType); - -// Dummy prediction checker, only useful if someone insists on requiring a prediction checker. -inline bool isAnyPrediction(PredictedType) -{ - return true; -} - -inline bool isCellPrediction(PredictedType value) -{ - return !!(value & PredictCell) && !(value & ~PredictCell); -} - -inline bool isObjectPrediction(PredictedType value) -{ - return !!(value & PredictObjectMask) && !(value & ~PredictObjectMask); -} - -inline bool isFinalObjectPrediction(PredictedType value) -{ - return value == PredictFinalObject; -} - -inline bool isFinalObjectOrOtherPrediction(PredictedType value) -{ - return !!(value & (PredictFinalObject | PredictOther)) && !(value & ~(PredictFinalObject | PredictOther)); -} - -inline bool isFixedIndexedStorageObjectPrediction(PredictedType value) -{ - return !!value && (value & FixedIndexedStorageMask) == value; -} - -inline bool isStringPrediction(PredictedType value) -{ - return value == PredictString; -} - -inline bool isArrayPrediction(PredictedType value) -{ - return value == PredictArray; -} - -inline bool isFunctionPrediction(PredictedType value) -{ - return value == PredictFunction; -} - -inline bool isInt8ArrayPrediction(PredictedType value) -{ - return value == PredictInt8Array; -} - -inline bool isInt16ArrayPrediction(PredictedType value) -{ - return value == PredictInt16Array; -} - -inline bool isInt32ArrayPrediction(PredictedType value) -{ - return value == PredictInt32Array; -} - -inline bool isUint8ArrayPrediction(PredictedType value) -{ - return value == PredictUint8Array; -} - -inline bool isUint8ClampedArrayPrediction(PredictedType value) -{ - return value == PredictUint8ClampedArray; -} - -inline bool isUint16ArrayPrediction(PredictedType value) -{ - return value == PredictUint16Array; -} - -inline bool isUint32ArrayPrediction(PredictedType value) -{ - return value == PredictUint32Array; -} - -inline bool isFloat32ArrayPrediction(PredictedType value) -{ - return value == PredictFloat32Array; -} - -inline bool isFloat64ArrayPrediction(PredictedType value) -{ - return value == PredictFloat64Array; -} - -inline bool isArgumentsPrediction(PredictedType value) -{ - return !!value && (value & PredictArguments) == value; -} - -inline bool isActionableIntMutableArrayPrediction(PredictedType value) -{ - return isInt8ArrayPrediction(value) - || isInt16ArrayPrediction(value) - || isInt32ArrayPrediction(value) - || isUint8ArrayPrediction(value) - || isUint8ClampedArrayPrediction(value) - || isUint16ArrayPrediction(value) - || isUint32ArrayPrediction(value); -} - -inline bool isActionableFloatMutableArrayPrediction(PredictedType value) -{ - return isFloat32ArrayPrediction(value) - || isFloat64ArrayPrediction(value); -} - -inline bool isActionableTypedMutableArrayPrediction(PredictedType value) -{ - return isActionableIntMutableArrayPrediction(value) - || isActionableFloatMutableArrayPrediction(value); -} - -inline bool isActionableMutableArrayPrediction(PredictedType value) -{ - return isArrayPrediction(value) - || isArgumentsPrediction(value) - || isActionableTypedMutableArrayPrediction(value); -} - -inline bool isActionableArrayPrediction(PredictedType value) -{ - return isStringPrediction(value) - || isActionableMutableArrayPrediction(value); -} - -inline bool isArrayOrOtherPrediction(PredictedType value) -{ - return !!(value & (PredictArray | PredictOther)) && !(value & ~(PredictArray | PredictOther)); -} - -inline bool isMyArgumentsPrediction(PredictedType value) -{ - return value == PredictMyArguments; -} - -inline bool isInt32Prediction(PredictedType value) -{ - return value == PredictInt32; -} - -inline bool isDoubleRealPrediction(PredictedType value) -{ - return value == PredictDoubleReal; -} - -inline bool isDoublePrediction(PredictedType value) -{ - return !!value && (value & PredictDouble) == value; -} - -inline bool isNumberPrediction(PredictedType value) -{ - return !!(value & PredictNumber) && !(value & ~PredictNumber); -} - -inline bool isBooleanPrediction(PredictedType value) -{ - return value == PredictBoolean; -} - -inline bool isOtherPrediction(PredictedType value) -{ - return value == PredictOther; -} - -inline bool isEmptyPrediction(PredictedType value) -{ - return value == PredictEmpty; -} - -const char* predictionToString(PredictedType value); -const char* predictionToAbbreviatedString(PredictedType value); - -// Merge two predictions. Note that currently this just does left | right. It may -// seem tempting to do so directly, but you would be doing so at your own peril, -// since the merging protocol PredictedType may change at any time (and has already -// changed several times in its history). -inline PredictedType mergePredictions(PredictedType left, PredictedType right) -{ - return left | right; -} - -template<typename T> -inline bool mergePrediction(T& left, PredictedType right) -{ - PredictedType newPrediction = static_cast<T>(mergePredictions(static_cast<PredictedType>(left), right)); - bool result = newPrediction != static_cast<PredictedType>(left); - left = newPrediction; - return result; -} - -PredictedType predictionFromClassInfo(const ClassInfo*); -PredictedType predictionFromStructure(Structure*); -PredictedType predictionFromCell(JSCell*); -PredictedType predictionFromValue(JSValue); - -} // namespace JSC - -#endif // PredictedType_h diff --git a/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp b/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp index 209d4cd5e..3715606fe 100644 --- a/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp +++ b/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp @@ -53,6 +53,8 @@ PutByIdStatus PutByIdStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned return PutByIdStatus(SimpleReplace, structure, 0, 0, offset); } + ASSERT(structure->transitionWatchpointSetHasBeenInvalidated()); + ASSERT(instruction[0].u.opcode == llint_op_put_by_id_transition_direct || instruction[0].u.opcode == llint_op_put_by_id_transition_normal); @@ -106,6 +108,7 @@ PutByIdStatus PutByIdStatus::computeFor(CodeBlock* profiledBlock, unsigned bytec case access_put_by_id_transition_normal: case access_put_by_id_transition_direct: { + ASSERT(stubInfo.u.putByIdTransition.previousStructure->transitionWatchpointSetHasBeenInvalidated()); size_t offset = stubInfo.u.putByIdTransition.structure->get( *profiledBlock->globalData(), ident); if (offset != notFound) { diff --git a/Source/JavaScriptCore/bytecode/PredictedType.cpp b/Source/JavaScriptCore/bytecode/SpeculatedType.cpp index 5258f4079..02d0f7e77 100644 --- a/Source/JavaScriptCore/bytecode/PredictedType.cpp +++ b/Source/JavaScriptCore/bytecode/SpeculatedType.cpp @@ -27,7 +27,7 @@ */ #include "config.h" -#include "PredictedType.h" +#include "SpeculatedType.h" #include "Arguments.h" #include "JSArray.h" @@ -37,9 +37,9 @@ namespace JSC { -const char* predictionToString(PredictedType value) +const char* speculationToString(SpeculatedType value) { - if (value == PredictNone) + if (value == SpecNone) return "None"; static const int size = 256; @@ -48,112 +48,112 @@ const char* predictionToString(PredictedType value) bool isTop = true; - if (value & PredictCellOther) + if (value & SpecCellOther) ptr.strcat("Othercell"); else isTop = false; - if (value & PredictObjectOther) + if (value & SpecObjectOther) ptr.strcat("Otherobj"); else isTop = false; - if (value & PredictFinalObject) + if (value & SpecFinalObject) ptr.strcat("Final"); else isTop = false; - if (value & PredictArray) + if (value & SpecArray) ptr.strcat("Array"); else isTop = false; - if (value & PredictInt8Array) + if (value & SpecInt8Array) ptr.strcat("Int8array"); else isTop = false; - if (value & PredictInt16Array) + if (value & SpecInt16Array) ptr.strcat("Int16array"); else isTop = false; - if (value & PredictInt32Array) + if (value & SpecInt32Array) ptr.strcat("Int32array"); else isTop = false; - if (value & PredictUint8Array) + if (value & SpecUint8Array) ptr.strcat("Uint8array"); else isTop = false; - if (value & PredictUint8ClampedArray) + if (value & SpecUint8ClampedArray) ptr.strcat("Uint8clampedarray"); else isTop = false; - if (value & PredictUint16Array) + if (value & SpecUint16Array) ptr.strcat("Uint16array"); else isTop = false; - if (value & PredictUint32Array) + if (value & SpecUint32Array) ptr.strcat("Uint32array"); else isTop = false; - if (value & PredictFloat32Array) + if (value & SpecFloat32Array) ptr.strcat("Float32array"); else isTop = false; - if (value & PredictFloat64Array) + if (value & SpecFloat64Array) ptr.strcat("Float64array"); else isTop = false; - if (value & PredictFunction) + if (value & SpecFunction) ptr.strcat("Function"); else isTop = false; - if (value & PredictMyArguments) + if (value & SpecMyArguments) ptr.strcat("Myarguments"); else isTop = false; - if (value & PredictForeignArguments) + if (value & SpecForeignArguments) ptr.strcat("Foreignarguments"); else isTop = false; - if (value & PredictString) + if (value & SpecString) ptr.strcat("String"); else isTop = false; - if (value & PredictInt32) + if (value & SpecInt32) ptr.strcat("Int"); else isTop = false; - if (value & PredictDoubleReal) + if (value & SpecDoubleReal) ptr.strcat("Doublereal"); else isTop = false; - if (value & PredictDoubleNaN) + if (value & SpecDoubleNaN) ptr.strcat("Doublenan"); else isTop = false; - if (value & PredictBoolean) + if (value & SpecBoolean) ptr.strcat("Bool"); else isTop = false; - if (value & PredictOther) + if (value & SpecOther) ptr.strcat("Other"); else isTop = false; @@ -163,7 +163,7 @@ const char* predictionToString(PredictedType value) ptr.strcat("Top"); } - if (value & PredictEmpty) + if (value & SpecEmpty) ptr.strcat("Empty"); *ptr++ = 0; @@ -171,130 +171,130 @@ const char* predictionToString(PredictedType value) return description; } -const char* predictionToAbbreviatedString(PredictedType prediction) +const char* speculationToAbbreviatedString(SpeculatedType prediction) { - if (isFinalObjectPrediction(prediction)) + if (isFinalObjectSpeculation(prediction)) return "<Final>"; - if (isArrayPrediction(prediction)) + if (isArraySpeculation(prediction)) return "<Array>"; - if (isStringPrediction(prediction)) + if (isStringSpeculation(prediction)) return "<String>"; - if (isFunctionPrediction(prediction)) + if (isFunctionSpeculation(prediction)) return "<Function>"; - if (isInt8ArrayPrediction(prediction)) + if (isInt8ArraySpeculation(prediction)) return "<Int8array>"; - if (isInt16ArrayPrediction(prediction)) + if (isInt16ArraySpeculation(prediction)) return "<Int16array>"; - if (isInt32ArrayPrediction(prediction)) + if (isInt32ArraySpeculation(prediction)) return "<Int32array>"; - if (isUint8ArrayPrediction(prediction)) + if (isUint8ArraySpeculation(prediction)) return "<Uint8array>"; - if (isUint16ArrayPrediction(prediction)) + if (isUint16ArraySpeculation(prediction)) return "<Uint16array>"; - if (isUint32ArrayPrediction(prediction)) + if (isUint32ArraySpeculation(prediction)) return "<Uint32array>"; - if (isFloat32ArrayPrediction(prediction)) + if (isFloat32ArraySpeculation(prediction)) return "<Float32array>"; - if (isFloat64ArrayPrediction(prediction)) + if (isFloat64ArraySpeculation(prediction)) return "<Float64array>"; - if (isMyArgumentsPrediction(prediction)) + if (isMyArgumentsSpeculation(prediction)) return "<Myarguments>"; - if (isArgumentsPrediction(prediction)) + if (isArgumentsSpeculation(prediction)) return "<Arguments>"; - if (isObjectPrediction(prediction)) + if (isObjectSpeculation(prediction)) return "<Object>"; - if (isCellPrediction(prediction)) + if (isCellSpeculation(prediction)) return "<Cell>"; - if (isInt32Prediction(prediction)) + if (isInt32Speculation(prediction)) return "<Int32>"; - if (isDoublePrediction(prediction)) + if (isDoubleSpeculation(prediction)) return "<Double>"; - if (isNumberPrediction(prediction)) + if (isNumberSpeculation(prediction)) return "<Number>"; - if (isBooleanPrediction(prediction)) + if (isBooleanSpeculation(prediction)) return "<Boolean>"; - if (isOtherPrediction(prediction)) + if (isOtherSpeculation(prediction)) return "<Other>"; return ""; } -PredictedType predictionFromClassInfo(const ClassInfo* classInfo) +SpeculatedType speculationFromClassInfo(const ClassInfo* classInfo) { if (classInfo == &JSFinalObject::s_info) - return PredictFinalObject; + return SpecFinalObject; if (classInfo == &JSArray::s_info) - return PredictArray; + return SpecArray; if (classInfo == &JSString::s_info) - return PredictString; + return SpecString; if (classInfo == &Arguments::s_info) - return PredictArguments; // Cannot distinguish between MyArguments and ForeignArguments at this stage. That happens in the flow analysis. + return SpecArguments; // Cannot distinguish between MyArguments and ForeignArguments at this stage. That happens in the flow analysis. if (classInfo->isSubClassOf(&JSFunction::s_info)) - return PredictFunction; + return SpecFunction; if (classInfo->typedArrayStorageType != TypedArrayNone) { switch (classInfo->typedArrayStorageType) { case TypedArrayInt8: - return PredictInt8Array; + return SpecInt8Array; case TypedArrayInt16: - return PredictInt16Array; + return SpecInt16Array; case TypedArrayInt32: - return PredictInt32Array; + return SpecInt32Array; case TypedArrayUint8: - return PredictUint8Array; + return SpecUint8Array; case TypedArrayUint8Clamped: - return PredictUint8ClampedArray; + return SpecUint8ClampedArray; case TypedArrayUint16: - return PredictUint16Array; + return SpecUint16Array; case TypedArrayUint32: - return PredictUint32Array; + return SpecUint32Array; case TypedArrayFloat32: - return PredictFloat32Array; + return SpecFloat32Array; case TypedArrayFloat64: - return PredictFloat64Array; + return SpecFloat64Array; default: break; } } if (classInfo->isSubClassOf(&JSObject::s_info)) - return PredictObjectOther; + return SpecObjectOther; - return PredictCellOther; + return SpecCellOther; } -PredictedType predictionFromStructure(Structure* structure) +SpeculatedType speculationFromStructure(Structure* structure) { - return predictionFromClassInfo(structure->classInfo()); + return speculationFromClassInfo(structure->classInfo()); } -PredictedType predictionFromCell(JSCell* cell) +SpeculatedType speculationFromCell(JSCell* cell) { - return predictionFromStructure(cell->structure()); + return speculationFromStructure(cell->structure()); } -PredictedType predictionFromValue(JSValue value) +SpeculatedType speculationFromValue(JSValue value) { if (value.isEmpty()) - return PredictEmpty; + return SpecEmpty; if (value.isInt32()) - return PredictInt32; + return SpecInt32; if (value.isDouble()) { double number = value.asNumber(); if (number == number) - return PredictDoubleReal; - return PredictDoubleNaN; + return SpecDoubleReal; + return SpecDoubleNaN; } if (value.isCell()) - return predictionFromCell(value.asCell()); + return speculationFromCell(value.asCell()); if (value.isBoolean()) - return PredictBoolean; + return SpecBoolean; ASSERT(value.isUndefinedOrNull()); - return PredictOther; + return SpecOther; } } // namespace JSC diff --git a/Source/JavaScriptCore/bytecode/SpeculatedType.h b/Source/JavaScriptCore/bytecode/SpeculatedType.h new file mode 100644 index 000000000..91fb4fe4d --- /dev/null +++ b/Source/JavaScriptCore/bytecode/SpeculatedType.h @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2011, 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SpeculatedType_h +#define SpeculatedType_h + +#include "JSValue.h" + +namespace JSC { + +class Structure; + +typedef uint32_t SpeculatedType; +static const SpeculatedType SpecNone = 0x00000000; // We don't know anything yet. +static const SpeculatedType SpecFinalObject = 0x00000001; // It's definitely a JSFinalObject. +static const SpeculatedType SpecArray = 0x00000002; // It's definitely a JSArray. +static const SpeculatedType SpecFunction = 0x00000008; // It's definitely a JSFunction or one of its subclasses. +static const SpeculatedType SpecInt8Array = 0x00000010; // It's definitely an Int8Array or one of its subclasses. +static const SpeculatedType SpecInt16Array = 0x00000020; // It's definitely an Int16Array or one of its subclasses. +static const SpeculatedType SpecInt32Array = 0x00000040; // It's definitely an Int32Array or one of its subclasses. +static const SpeculatedType SpecUint8Array = 0x00000080; // It's definitely an Uint8Array or one of its subclasses. +static const SpeculatedType SpecUint8ClampedArray = 0x00000100; // It's definitely an Uint8ClampedArray or one of its subclasses. +static const SpeculatedType SpecUint16Array = 0x00000200; // It's definitely an Uint16Array or one of its subclasses. +static const SpeculatedType SpecUint32Array = 0x00000400; // It's definitely an Uint32Array or one of its subclasses. +static const SpeculatedType SpecFloat32Array = 0x00000800; // It's definitely an Uint16Array or one of its subclasses. +static const SpeculatedType SpecFloat64Array = 0x00001000; // It's definitely an Uint16Array or one of its subclasses. +static const SpeculatedType SpecMyArguments = 0x00002000; // It's definitely an Arguments object, and it's definitely the one for my current frame. +static const SpeculatedType SpecForeignArguments = 0x00004000; // It's definitely an Arguments object, and it's definitely not mine. +static const SpeculatedType SpecArguments = 0x00006000; // It's definitely an Arguments object. +static const SpeculatedType SpecObjectOther = 0x00008000; // It's definitely an object but not JSFinalObject, JSArray, or JSFunction. +static const SpeculatedType SpecObjectMask = 0x0000ffff; // Bitmask used for testing for any kind of object prediction. +static const SpeculatedType SpecString = 0x00010000; // It's definitely a JSString. +static const SpeculatedType SpecCellOther = 0x00020000; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString. +static const SpeculatedType SpecCell = 0x0003ffff; // It's definitely a JSCell. +static const SpeculatedType SpecInt32 = 0x00800000; // It's definitely an Int32. +static const SpeculatedType SpecDoubleReal = 0x01000000; // It's definitely a non-NaN double. +static const SpeculatedType SpecDoubleNaN = 0x02000000; // It's definitely a NaN. +static const SpeculatedType SpecDouble = 0x03000000; // It's either a non-NaN or a NaN double. +static const SpeculatedType SpecNumber = 0x03800000; // It's either an Int32 or a Double. +static const SpeculatedType SpecBoolean = 0x04000000; // It's definitely a Boolean. +static const SpeculatedType SpecOther = 0x08000000; // It's definitely none of the above. +static const SpeculatedType SpecTop = 0x0fffffff; // It can be any of the above. +static const SpeculatedType SpecEmpty = 0x10000000; // It's definitely an empty value marker. +static const SpeculatedType SpecEmptyOrTop = 0x1fffffff; // It can be any of the above. +static const SpeculatedType FixedIndexedStorageMask = SpecInt8Array | SpecInt16Array | SpecInt32Array | SpecUint8Array | SpecUint8ClampedArray | SpecUint16Array | SpecUint32Array | SpecFloat32Array | SpecFloat64Array; + +typedef bool (*SpeculatedTypeChecker)(SpeculatedType); + +// Dummy prediction checker, only useful if someone insists on requiring a prediction checker. +inline bool isAnySpeculation(SpeculatedType) +{ + return true; +} + +inline bool isCellSpeculation(SpeculatedType value) +{ + return !!(value & SpecCell) && !(value & ~SpecCell); +} + +inline bool isObjectSpeculation(SpeculatedType value) +{ + return !!(value & SpecObjectMask) && !(value & ~SpecObjectMask); +} + +inline bool isFinalObjectSpeculation(SpeculatedType value) +{ + return value == SpecFinalObject; +} + +inline bool isFinalObjectOrOtherSpeculation(SpeculatedType value) +{ + return !!(value & (SpecFinalObject | SpecOther)) && !(value & ~(SpecFinalObject | SpecOther)); +} + +inline bool isFixedIndexedStorageObjectSpeculation(SpeculatedType value) +{ + return !!value && (value & FixedIndexedStorageMask) == value; +} + +inline bool isStringSpeculation(SpeculatedType value) +{ + return value == SpecString; +} + +inline bool isArraySpeculation(SpeculatedType value) +{ + return value == SpecArray; +} + +inline bool isFunctionSpeculation(SpeculatedType value) +{ + return value == SpecFunction; +} + +inline bool isInt8ArraySpeculation(SpeculatedType value) +{ + return value == SpecInt8Array; +} + +inline bool isInt16ArraySpeculation(SpeculatedType value) +{ + return value == SpecInt16Array; +} + +inline bool isInt32ArraySpeculation(SpeculatedType value) +{ + return value == SpecInt32Array; +} + +inline bool isUint8ArraySpeculation(SpeculatedType value) +{ + return value == SpecUint8Array; +} + +inline bool isUint8ClampedArraySpeculation(SpeculatedType value) +{ + return value == SpecUint8ClampedArray; +} + +inline bool isUint16ArraySpeculation(SpeculatedType value) +{ + return value == SpecUint16Array; +} + +inline bool isUint32ArraySpeculation(SpeculatedType value) +{ + return value == SpecUint32Array; +} + +inline bool isFloat32ArraySpeculation(SpeculatedType value) +{ + return value == SpecFloat32Array; +} + +inline bool isFloat64ArraySpeculation(SpeculatedType value) +{ + return value == SpecFloat64Array; +} + +inline bool isArgumentsSpeculation(SpeculatedType value) +{ + return !!value && (value & SpecArguments) == value; +} + +inline bool isActionableIntMutableArraySpeculation(SpeculatedType value) +{ + return isInt8ArraySpeculation(value) + || isInt16ArraySpeculation(value) + || isInt32ArraySpeculation(value) + || isUint8ArraySpeculation(value) + || isUint8ClampedArraySpeculation(value) + || isUint16ArraySpeculation(value) + || isUint32ArraySpeculation(value); +} + +inline bool isActionableFloatMutableArraySpeculation(SpeculatedType value) +{ + return isFloat32ArraySpeculation(value) + || isFloat64ArraySpeculation(value); +} + +inline bool isActionableTypedMutableArraySpeculation(SpeculatedType value) +{ + return isActionableIntMutableArraySpeculation(value) + || isActionableFloatMutableArraySpeculation(value); +} + +inline bool isActionableMutableArraySpeculation(SpeculatedType value) +{ + return isArraySpeculation(value) + || isArgumentsSpeculation(value) + || isActionableTypedMutableArraySpeculation(value); +} + +inline bool isActionableArraySpeculation(SpeculatedType value) +{ + return isStringSpeculation(value) + || isActionableMutableArraySpeculation(value); +} + +inline bool isArrayOrOtherSpeculation(SpeculatedType value) +{ + return !!(value & (SpecArray | SpecOther)) && !(value & ~(SpecArray | SpecOther)); +} + +inline bool isMyArgumentsSpeculation(SpeculatedType value) +{ + return value == SpecMyArguments; +} + +inline bool isInt32Speculation(SpeculatedType value) +{ + return value == SpecInt32; +} + +inline bool isDoubleRealSpeculation(SpeculatedType value) +{ + return value == SpecDoubleReal; +} + +inline bool isDoubleSpeculation(SpeculatedType value) +{ + return !!value && (value & SpecDouble) == value; +} + +inline bool isNumberSpeculation(SpeculatedType value) +{ + return !!(value & SpecNumber) && !(value & ~SpecNumber); +} + +inline bool isBooleanSpeculation(SpeculatedType value) +{ + return value == SpecBoolean; +} + +inline bool isOtherSpeculation(SpeculatedType value) +{ + return value == SpecOther; +} + +inline bool isEmptySpeculation(SpeculatedType value) +{ + return value == SpecEmpty; +} + +const char* speculationToString(SpeculatedType value); +const char* speculationToAbbreviatedString(SpeculatedType value); + +// Merge two predictions. Note that currently this just does left | right. It may +// seem tempting to do so directly, but you would be doing so at your own peril, +// since the merging protocol SpeculatedType may change at any time (and has already +// changed several times in its history). +inline SpeculatedType mergeSpeculations(SpeculatedType left, SpeculatedType right) +{ + return left | right; +} + +template<typename T> +inline bool mergeSpeculation(T& left, SpeculatedType right) +{ + SpeculatedType newSpeculation = static_cast<T>(mergeSpeculations(static_cast<SpeculatedType>(left), right)); + bool result = newSpeculation != static_cast<SpeculatedType>(left); + left = newSpeculation; + return result; +} + +SpeculatedType speculationFromClassInfo(const ClassInfo*); +SpeculatedType speculationFromStructure(Structure*); +SpeculatedType speculationFromCell(JSCell*); +SpeculatedType speculationFromValue(JSValue); + +} // namespace JSC + +#endif // SpeculatedType_h diff --git a/Source/JavaScriptCore/bytecode/StructureSet.h b/Source/JavaScriptCore/bytecode/StructureSet.h index bfc30fc3c..2bbc50cad 100644 --- a/Source/JavaScriptCore/bytecode/StructureSet.h +++ b/Source/JavaScriptCore/bytecode/StructureSet.h @@ -26,7 +26,7 @@ #ifndef StructureSet_h #define StructureSet_h -#include "PredictedType.h" +#include "SpeculatedType.h" #include "Structure.h" #include <stdio.h> #include <wtf/Vector.h> @@ -90,6 +90,13 @@ public: return false; } + bool containsOnly(Structure* structure) const + { + if (size() != 1) + return false; + return singletonStructure() == structure; + } + bool isSubsetOf(const StructureSet& other) const { for (size_t i = 0; i < m_structures.size(); ++i) { @@ -115,18 +122,26 @@ public: return true; } + // Call this if you know that the structure set must consist of exactly + // one structure. + Structure* singletonStructure() const + { + ASSERT(m_structures.size() == 1); + return m_structures[0]; + } + Structure* at(size_t i) const { return m_structures.at(i); } Structure* operator[](size_t i) const { return at(i); } Structure* last() const { return m_structures.last(); } - PredictedType predictionFromStructures() const + SpeculatedType speculationFromStructures() const { - PredictedType result = PredictNone; + SpeculatedType result = SpecNone; for (size_t i = 0; i < m_structures.size(); ++i) - mergePrediction(result, predictionFromStructure(m_structures[i])); + mergeSpeculation(result, speculationFromStructure(m_structures[i])); return result; } diff --git a/Source/JavaScriptCore/bytecode/StructureStubInfo.h b/Source/JavaScriptCore/bytecode/StructureStubInfo.h index 9aa40532a..573f6e975 100644 --- a/Source/JavaScriptCore/bytecode/StructureStubInfo.h +++ b/Source/JavaScriptCore/bytecode/StructureStubInfo.h @@ -102,20 +102,23 @@ namespace JSC { u.getByIdSelf.baseObjectStructure.set(globalData, owner, baseObjectStructure); } - void initGetByIdProto(JSGlobalData& globalData, JSCell* owner, Structure* baseObjectStructure, Structure* prototypeStructure) + void initGetByIdProto(JSGlobalData& globalData, JSCell* owner, Structure* baseObjectStructure, Structure* prototypeStructure, bool isDirect) { accessType = access_get_by_id_proto; u.getByIdProto.baseObjectStructure.set(globalData, owner, baseObjectStructure); u.getByIdProto.prototypeStructure.set(globalData, owner, prototypeStructure); + u.getByIdProto.isDirect = isDirect; } - void initGetByIdChain(JSGlobalData& globalData, JSCell* owner, Structure* baseObjectStructure, StructureChain* chain) + void initGetByIdChain(JSGlobalData& globalData, JSCell* owner, Structure* baseObjectStructure, StructureChain* chain, unsigned count, bool isDirect) { accessType = access_get_by_id_chain; u.getByIdChain.baseObjectStructure.set(globalData, owner, baseObjectStructure); u.getByIdChain.chain.set(globalData, owner, chain); + u.getByIdChain.count = count; + u.getByIdChain.isDirect = isDirect; } void initGetByIdSelfList(PolymorphicAccessStructureList* structureList, int listSize) @@ -251,10 +254,13 @@ namespace JSC { struct { WriteBarrierBase<Structure> baseObjectStructure; WriteBarrierBase<Structure> prototypeStructure; + bool isDirect; } getByIdProto; struct { WriteBarrierBase<Structure> baseObjectStructure; WriteBarrierBase<StructureChain> chain; + unsigned count : 31; + bool isDirect : 1; } getByIdChain; struct { PolymorphicAccessStructureList* structureList; diff --git a/Source/JavaScriptCore/bytecode/ValueProfile.h b/Source/JavaScriptCore/bytecode/ValueProfile.h index 47fa8b72c..31e76842f 100644 --- a/Source/JavaScriptCore/bytecode/ValueProfile.h +++ b/Source/JavaScriptCore/bytecode/ValueProfile.h @@ -35,7 +35,7 @@ #include "Heap.h" #include "JSArray.h" -#include "PredictedType.h" +#include "SpeculatedType.h" #include "Structure.h" #include "WriteBarrier.h" @@ -50,7 +50,7 @@ struct ValueProfileBase { ValueProfileBase() : m_bytecodeOffset(-1) - , m_prediction(PredictNone) + , m_prediction(SpecNone) , m_numberOfSamplesInPrediction(0) , m_singletonValueIsTop(false) { @@ -60,7 +60,7 @@ struct ValueProfileBase { ValueProfileBase(int bytecodeOffset) : m_bytecodeOffset(bytecodeOffset) - , m_prediction(PredictNone) + , m_prediction(SpecNone) , m_numberOfSamplesInPrediction(0) , m_singletonValueIsTop(false) { @@ -114,7 +114,7 @@ struct ValueProfileBase { fprintf(out, "samples = %u, prediction = %s", totalNumberOfSamples(), - predictionToString(m_prediction)); + speculationToString(m_prediction)); fprintf(out, ", value = "); if (m_singletonValueIsTop) fprintf(out, "TOP"); @@ -135,7 +135,7 @@ struct ValueProfileBase { } // Updates the prediction and returns the new one. - PredictedType computeUpdatedPrediction(OperationInProgress operation = NoOperation) + SpeculatedType computeUpdatedPrediction(OperationInProgress operation = NoOperation) { for (unsigned i = 0; i < totalNumberOfBuckets; ++i) { JSValue value = JSValue::decode(m_buckets[i]); @@ -143,7 +143,7 @@ struct ValueProfileBase { continue; m_numberOfSamplesInPrediction++; - mergePrediction(m_prediction, predictionFromValue(value)); + mergeSpeculation(m_prediction, speculationFromValue(value)); if (!m_singletonValueIsTop && !!value) { if (!m_singletonValue) @@ -167,7 +167,7 @@ struct ValueProfileBase { int m_bytecodeOffset; // -1 for prologue - PredictedType m_prediction; + SpeculatedType m_prediction; unsigned m_numberOfSamplesInPrediction; bool m_singletonValueIsTop; diff --git a/Source/JavaScriptCore/bytecode/Watchpoint.cpp b/Source/JavaScriptCore/bytecode/Watchpoint.cpp new file mode 100644 index 000000000..1dd633f52 --- /dev/null +++ b/Source/JavaScriptCore/bytecode/Watchpoint.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Watchpoint.h" + +#include "LinkBuffer.h" + +namespace JSC { + +Watchpoint::~Watchpoint() +{ + if (isOnList()) + remove(); +} + +#if ENABLE(JIT) +void Watchpoint::correctLabels(LinkBuffer& linkBuffer) +{ + MacroAssembler::Label label; + label.m_label.m_offset = m_source; + m_source = bitwise_cast<uintptr_t>(linkBuffer.locationOf(label).dataLocation()); + label.m_label.m_offset = m_destination; + m_destination = bitwise_cast<uintptr_t>(linkBuffer.locationOf(label).dataLocation()); +} +#endif + +void Watchpoint::fire() +{ +#if ENABLE(JIT) + MacroAssembler::replaceWithJump( + CodeLocationLabel(bitwise_cast<void*>(m_source)), + CodeLocationLabel(bitwise_cast<void*>(m_destination))); + if (isOnList()) + remove(); +#else + UNREACHABLE_FOR_PLATFORM(); +#endif +} + +WatchpointSet::WatchpointSet(InitialWatchpointSetMode mode) + : m_isWatched(mode == InitializedWatching) + , m_isInvalidated(false) +{ +} + +WatchpointSet::~WatchpointSet() +{ + // Fire all watchpoints. This is necessary because it is possible, say with + // structure watchpoints, for the watchpoint set owner to die while the + // watchpoint owners are still live. + fireAllWatchpoints(); +} + +void WatchpointSet::add(Watchpoint* watchpoint) +{ + if (!watchpoint) + return; + m_set.push(watchpoint); + m_isWatched = true; +} + +void WatchpointSet::notifyWriteSlow() +{ + ASSERT(m_isWatched); + + fireAllWatchpoints(); + m_isWatched = false; + m_isInvalidated = true; +} + +void WatchpointSet::fireAllWatchpoints() +{ + while (!m_set.isEmpty()) + m_set.begin()->fire(); +} + +void InlineWatchpointSet::add(Watchpoint* watchpoint) +{ + inflate()->add(watchpoint); +} + +WatchpointSet* InlineWatchpointSet::inflateSlow() +{ + ASSERT(isThin()); + WatchpointSet* fat = adoptRef(new WatchpointSet(InitializedBlind)).leakRef(); + if (m_data & IsInvalidatedFlag) + fat->m_isInvalidated = true; + if (m_data & IsWatchedFlag) + fat->m_isWatched = true; + m_data = bitwise_cast<uintptr_t>(fat); + return fat; +} + +void InlineWatchpointSet::freeFat() +{ + ASSERT(isFat()); + fat()->deref(); +} + +} // namespace JSC + diff --git a/Source/JavaScriptCore/bytecode/Watchpoint.h b/Source/JavaScriptCore/bytecode/Watchpoint.h new file mode 100644 index 000000000..0055bf607 --- /dev/null +++ b/Source/JavaScriptCore/bytecode/Watchpoint.h @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef Watchpoint_h +#define Watchpoint_h + +#include "CodeLocation.h" +#include "MacroAssembler.h" +#include <wtf/RefCounted.h> +#include <wtf/SentinelLinkedList.h> + +namespace JSC { + +class Watchpoint : public BasicRawSentinelNode<Watchpoint> { +public: + Watchpoint() + : m_source(std::numeric_limits<uintptr_t>::max()) + , m_destination(std::numeric_limits<uintptr_t>::max()) + { + } + +#if ENABLE(JIT) + Watchpoint(MacroAssembler::Label source) + : m_source(source.m_label.m_offset) + , m_destination(std::numeric_limits<uintptr_t>::max()) + { + } + + void setDestination(MacroAssembler::Label destination) + { + m_destination = destination.m_label.m_offset; + } + + void correctLabels(LinkBuffer&); +#endif + + ~Watchpoint(); + + void fire(); + +private: + uintptr_t m_source; + uintptr_t m_destination; +}; + +enum InitialWatchpointSetMode { InitializedWatching, InitializedBlind }; + +class InlineWatchpointSet; + +class WatchpointSet : public RefCounted<WatchpointSet> { +public: + WatchpointSet(InitialWatchpointSetMode); + ~WatchpointSet(); + + bool isStillValid() const { return !m_isInvalidated; } + bool hasBeenInvalidated() const { return m_isInvalidated; } + + // As a convenience, this will ignore 0. That's because code paths in the DFG + // that create speculation watchpoints may choose to bail out if speculation + // had already been terminated. + void add(Watchpoint*); + + // Force the watchpoint set to behave as if it was being watched even if no + // watchpoints have been installed. This will result in invalidation if the + // watchpoint would have fired. That's a pretty good indication that you + // probably don't want to set watchpoints, since we typically don't want to + // set watchpoints that we believe will actually be fired. + void startWatching() { m_isWatched = true; } + + void notifyWrite() + { + if (!m_isWatched) + return; + notifyWriteSlow(); + } + + bool* addressOfIsWatched() { return &m_isWatched; } + + void notifyWriteSlow(); // Call only if you've checked isWatched. + +private: + void fireAllWatchpoints(); + + friend class InlineWatchpointSet; + + SentinelLinkedList<Watchpoint, BasicRawSentinelNode<Watchpoint> > m_set; + bool m_isWatched; + bool m_isInvalidated; +}; + +// InlineWatchpointSet is a low-overhead, non-copyable watchpoint set in which +// it is not possible to quickly query whether it is being watched in a single +// branch. There is a fairly simple tradeoff between WatchpointSet and +// InlineWatchpointSet: +// +// Do you have to emit JIT code that rapidly tests whether the watchpoint set +// is being watched? If so, use WatchpointSet. +// +// Do you need multiple parties to have pointers to the same WatchpointSet? +// If so, use WatchpointSet. +// +// Do you have to allocate a lot of watchpoint sets? If so, use +// InlineWatchpointSet unless you answered "yes" to the previous questions. +// +// InlineWatchpointSet will use just one pointer-width word of memory unless +// you actually add watchpoints to it, in which case it internally inflates +// to a pointer to a WatchpointSet, and transfers its state to the +// WatchpointSet. + +class InlineWatchpointSet { + WTF_MAKE_NONCOPYABLE(InlineWatchpointSet); +public: + InlineWatchpointSet(InitialWatchpointSetMode mode) + : m_data((mode == InitializedWatching ? IsWatchedFlag : 0) | IsThinFlag) + { + } + + ~InlineWatchpointSet() + { + if (isThin()) + return; + freeFat(); + } + + bool hasBeenInvalidated() const + { + if (isFat()) + return fat()->hasBeenInvalidated(); + return m_data & IsInvalidatedFlag; + } + + bool isStillValid() const + { + return !hasBeenInvalidated(); + } + + void add(Watchpoint*); + + void startWatching() + { + if (isFat()) { + fat()->startWatching(); + return; + } + m_data |= IsWatchedFlag; + } + + void notifyWrite() + { + if (isFat()) { + fat()->notifyWrite(); + return; + } + if (!(m_data & IsWatchedFlag)) + return; + m_data |= IsInvalidatedFlag; + } + +private: + static const uintptr_t IsThinFlag = 1; + static const uintptr_t IsInvalidatedFlag = 2; + static const uintptr_t IsWatchedFlag = 4; + + bool isThin() const { return m_data & IsThinFlag; } + bool isFat() const { return !isThin(); }; + + WatchpointSet* fat() + { + ASSERT(isFat()); + return bitwise_cast<WatchpointSet*>(m_data); + } + + const WatchpointSet* fat() const + { + ASSERT(isFat()); + return bitwise_cast<WatchpointSet*>(m_data); + } + + WatchpointSet* inflate() + { + if (LIKELY(isFat())) + return fat(); + return inflateSlow(); + } + + JS_EXPORT_PRIVATE WatchpointSet* inflateSlow(); + JS_EXPORT_PRIVATE void freeFat(); + + uintptr_t m_data; +}; + +} // namespace JSC + +#endif // Watchpoint_h + diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp index fb05e48ff..8969a7f25 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp @@ -148,6 +148,7 @@ void ResolveResult::checkValidity() return; case IndexedGlobal: case ReadOnlyIndexedGlobal: + case WatchedIndexedGlobal: case DynamicIndexedGlobal: case DynamicReadOnlyIndexedGlobal: ASSERT(m_index != missingSymbolMarker()); @@ -161,6 +162,11 @@ void ResolveResult::checkValidity() } #endif +WriteBarrier<Unknown>* ResolveResult::registerPointer() const +{ + return &jsCast<JSGlobalObject*>(globalObject())->registerAt(index()); +} + static bool s_dumpsGeneratedCode = false; void BytecodeGenerator::setDumpsGeneratedCode(bool dumpsGeneratedCode) @@ -211,13 +217,19 @@ bool BytecodeGenerator::addVar(const Identifier& ident, bool isConstant, Registe return true; } -int BytecodeGenerator::addGlobalVar(const Identifier& ident, bool isConstant) +int BytecodeGenerator::addGlobalVar( + const Identifier& ident, ConstantMode constantMode, FunctionMode functionMode) { + UNUSED_PARAM(functionMode); int index = symbolTable().size(); - SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0); + SymbolTableEntry newEntry(index, (constantMode == IsConstant) ? ReadOnly : 0); + if (functionMode == IsFunctionToSpecialize) + newEntry.attemptToWatch(); SymbolTable::AddResult result = symbolTable().add(ident.impl(), newEntry); - if (!result.isNewEntry) + if (!result.isNewEntry) { + result.iterator->second.notifyWrite(); index = result.iterator->second.getIndex(); + } return index; } @@ -280,21 +292,27 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, ScopeChainNode* s size_t newGlobals = varStack.size() + functionStack.size(); if (!newGlobals) return; - globalObject->resizeRegisters(symbolTable->size() + newGlobals); + globalObject->addRegisters(newGlobals); for (size_t i = 0; i < functionStack.size(); ++i) { FunctionBodyNode* function = functionStack[i]; - globalObject->removeDirect(*m_globalData, function->ident()); // Newly declared functions overwrite existing properties. - + bool propertyDidExist = + globalObject->removeDirect(*m_globalData, function->ident()); // Newly declared functions overwrite existing properties. + JSValue value = JSFunction::create(exec, makeFunction(exec, function), scopeChain); - int index = addGlobalVar(function->ident(), false); + int index = addGlobalVar( + function->ident(), IsVariable, + !propertyDidExist ? IsFunctionToSpecialize : NotFunctionOrNotSpecializable); globalObject->registerAt(index).set(*m_globalData, globalObject, value); } for (size_t i = 0; i < varStack.size(); ++i) { if (globalObject->hasProperty(exec, *varStack[i].first)) continue; - addGlobalVar(*varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant); + addGlobalVar( + *varStack[i].first, + (varStack[i].second & DeclarationStacks::IsConstant) ? IsConstant : IsVariable, + NotFunctionOrNotSpecializable); } } @@ -679,6 +697,14 @@ void BytecodeGenerator::retrieveLastUnaryOp(int& dstIndex, int& srcIndex) srcIndex = instructions().at(size - 1).u.operand; } +void BytecodeGenerator::retrieveLastUnaryOp(WriteBarrier<Unknown>*& dstPointer, int& srcIndex) +{ + ASSERT(instructions().size() >= 3); + size_t size = instructions().size(); + dstPointer = instructions().at(size - 2).u.registerPointer; + srcIndex = instructions().at(size - 1).u.operand; +} + void ALWAYS_INLINE BytecodeGenerator::rewindBinaryOp() { ASSERT(instructions().size() >= 4); @@ -1170,6 +1196,7 @@ ResolveResult BytecodeGenerator::resolve(const Identifier& property) ScopeChainIterator iter = m_scopeChain->begin(); ScopeChainIterator end = m_scopeChain->end(); size_t depth = 0; + size_t depthOfFirstScopeWithDynamicChecks = 0; unsigned flags = 0; for (; iter != end; ++iter, ++depth) { JSObject* currentScope = iter->get(); @@ -1177,7 +1204,7 @@ ResolveResult BytecodeGenerator::resolve(const Identifier& property) flags |= ResolveResult::DynamicFlag; break; } - JSVariableObject* currentVariableObject = jsCast<JSVariableObject*>(currentScope); + JSSymbolTableObject* currentVariableObject = jsCast<JSSymbolTableObject*>(currentScope); SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.impl()); // Found the property @@ -1188,7 +1215,9 @@ ResolveResult BytecodeGenerator::resolve(const Identifier& property) if (++iter == end) { if (flags & ResolveResult::DynamicFlag) return ResolveResult::dynamicIndexedGlobalResolve(entry.getIndex(), depth, currentScope, flags); - return ResolveResult::indexedGlobalResolve(entry.getIndex(), currentScope, flags); + return ResolveResult::indexedGlobalResolve( + entry.getIndex(), currentScope, + flags | (entry.couldBeWatched() ? ResolveResult::WatchedFlag : 0)); } #if !ASSERT_DISABLED if (JSActivation* activation = jsDynamicCast<JSActivation*>(currentVariableObject)) @@ -1199,19 +1228,27 @@ ResolveResult BytecodeGenerator::resolve(const Identifier& property) bool scopeRequiresDynamicChecks = false; if (currentVariableObject->isDynamicScope(scopeRequiresDynamicChecks)) break; - if (scopeRequiresDynamicChecks) - flags |= ResolveResult::DynamicFlag; + if (!(flags & ResolveResult::DynamicFlag)) { + if (scopeRequiresDynamicChecks) + flags |= ResolveResult::DynamicFlag; + else + ++depthOfFirstScopeWithDynamicChecks; + } } // Can't locate the property but we're able to avoid a few lookups. JSObject* scope = iter->get(); + // Step over the function's activation, if it needs one. At this point we + // know there is no dynamic scope in the function itself, so this is safe to + // do. depth += m_codeBlock->needsFullScopeChain(); + depthOfFirstScopeWithDynamicChecks += m_codeBlock->needsFullScopeChain(); if (++iter == end) { if ((flags & ResolveResult::DynamicFlag) && depth) return ResolveResult::dynamicGlobalResolve(depth, scope); return ResolveResult::globalResolve(scope); } - return ResolveResult::dynamicResolve(depth); + return ResolveResult::dynamicResolve(depthOfFirstScopeWithDynamicChecks); } ResolveResult BytecodeGenerator::resolveConstDecl(const Identifier& property) @@ -1234,7 +1271,7 @@ ResolveResult BytecodeGenerator::resolveConstDecl(const Identifier& property) JSObject* currentScope = iter->get(); if (!currentScope->isVariableObject()) continue; - JSVariableObject* currentVariableObject = jsCast<JSVariableObject*>(currentScope); + JSSymbolTableObject* currentVariableObject = jsCast<JSSymbolTableObject*>(currentScope); SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.impl()); if (entry.isNull()) continue; @@ -1274,7 +1311,7 @@ bool BytecodeGenerator::shouldAvoidResolveGlobal() RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& property) { if (resolveResult.isStatic()) - return emitGetStaticVar(dst, resolveResult); + return emitGetStaticVar(dst, resolveResult, property); if (resolveResult.isGlobal() && !shouldAvoidResolveGlobal()) { #if ENABLE(JIT) @@ -1357,7 +1394,7 @@ RegisterID* BytecodeGenerator::emitResolveWithBase(RegisterID* baseDst, Register if (resolveResult.isStatic()) { // Directly index the property lookup across multiple scopes. - emitGetStaticVar(propDst, resolveResult); + emitGetStaticVar(propDst, resolveResult, property); return baseDst; } @@ -1396,7 +1433,7 @@ RegisterID* BytecodeGenerator::emitResolveWithThis(RegisterID* baseDst, Register { if (resolveResult.isStatic()) { emitLoad(baseDst, jsUndefined()); - emitGetStaticVar(propDst, resolveResult); + emitGetStaticVar(propDst, resolveResult, property); return baseDst; } @@ -1414,7 +1451,7 @@ RegisterID* BytecodeGenerator::emitResolveWithThis(RegisterID* baseDst, Register return emitResolve(propDst, resolveResult, property); } -RegisterID* BytecodeGenerator::emitGetStaticVar(RegisterID* dst, const ResolveResult& resolveResult) +RegisterID* BytecodeGenerator::emitGetStaticVar(RegisterID* dst, const ResolveResult& resolveResult, const Identifier& identifier) { ValueProfile* profile = 0; @@ -1437,16 +1474,27 @@ RegisterID* BytecodeGenerator::emitGetStaticVar(RegisterID* dst, const ResolveRe case ResolveResult::IndexedGlobal: case ResolveResult::ReadOnlyIndexedGlobal: if (m_lastOpcodeID == op_put_global_var) { - int dstIndex; + WriteBarrier<Unknown>* dstPointer; int srcIndex; - retrieveLastUnaryOp(dstIndex, srcIndex); - if (dstIndex == resolveResult.index() && srcIndex == dst->index()) + retrieveLastUnaryOp(dstPointer, srcIndex); + if (dstPointer == resolveResult.registerPointer() && srcIndex == dst->index()) return dst; } profile = emitProfiledOpcode(op_get_global_var); instructions().append(dst->index()); - instructions().append(resolveResult.index()); + instructions().append(resolveResult.registerPointer()); + instructions().append(profile); + return dst; + + case ResolveResult::WatchedIndexedGlobal: + // Skip the peephole for now. It's not clear that it's profitable given + // the DFG's capabilities, and the fact that if it's watchable then we + // don't expect to see any put_global_var's anyway. + profile = emitProfiledOpcode(op_get_global_var_watchable); + instructions().append(dst->index()); + instructions().append(resolveResult.registerPointer()); + instructions().append(addConstant(identifier)); // For the benefit of the DFG. instructions().append(profile); return dst; @@ -1456,7 +1504,7 @@ RegisterID* BytecodeGenerator::emitGetStaticVar(RegisterID* dst, const ResolveRe } } -RegisterID* BytecodeGenerator::emitPutStaticVar(const ResolveResult& resolveResult, RegisterID* value) +RegisterID* BytecodeGenerator::emitPutStaticVar(const ResolveResult& resolveResult, const Identifier& identifier, RegisterID* value) { switch (resolveResult.type()) { case ResolveResult::Register: @@ -1474,8 +1522,16 @@ RegisterID* BytecodeGenerator::emitPutStaticVar(const ResolveResult& resolveResu case ResolveResult::IndexedGlobal: case ResolveResult::ReadOnlyIndexedGlobal: emitOpcode(op_put_global_var); - instructions().append(resolveResult.index()); + instructions().append(resolveResult.registerPointer()); + instructions().append(value->index()); + return value; + + case ResolveResult::WatchedIndexedGlobal: + emitOpcode(op_put_global_var_check); + instructions().append(resolveResult.registerPointer()); instructions().append(value->index()); + instructions().append(jsCast<JSGlobalObject*>(resolveResult.globalObject())->symbolTable().get(identifier.impl()).addressOfIsWatched()); + instructions().append(addConstant(identifier)); return value; default: diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h index a71bbb785..8b1d1d744 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h @@ -111,7 +111,9 @@ namespace JSC { // The resolved binding is immutable. ReadOnlyFlag = 0x20, // The base object is the global object. - GlobalFlag = 0x40 + GlobalFlag = 0x40, + // The property is being watched, so writes should be special. + WatchedFlag = 0x80 }; enum Type { // The property is local, and stored in a register. @@ -131,6 +133,8 @@ namespace JSC { // binding created with "var" at the top level. At runtime we'll // just index into the global object. IndexedGlobal = IndexedFlag | GlobalFlag | StaticFlag, + // Like IndexedGlobal, but the property is being watched. + WatchedIndexedGlobal = IndexedFlag | GlobalFlag | StaticFlag | WatchedFlag, // Like IndexedGlobal, but the property is also read-only, like NaN, // Infinity, or undefined. ReadOnlyIndexedGlobal = IndexedFlag | ReadOnlyFlag | GlobalFlag | StaticFlag, @@ -197,6 +201,7 @@ namespace JSC { int index() const { ASSERT (isIndexed() || isRegister()); return m_index; } size_t depth() const { ASSERT(isScoped()); return m_depth; } JSObject* globalObject() const { ASSERT(isGlobal()); ASSERT(m_globalObject); return m_globalObject; } + WriteBarrier<Unknown>* registerPointer() const; bool isRegister() const { return m_type & RegisterFlag; } bool isDynamic() const { return m_type & DynamicFlag; } @@ -440,8 +445,8 @@ namespace JSC { RegisterID* emitTypeOf(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_typeof, dst, src); } RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base) { return emitBinaryOp(op_in, dst, property, base, OperandTypes()); } - RegisterID* emitGetStaticVar(RegisterID* dst, const ResolveResult&); - RegisterID* emitPutStaticVar(const ResolveResult&, RegisterID* value); + RegisterID* emitGetStaticVar(RegisterID* dst, const ResolveResult&, const Identifier&); + RegisterID* emitPutStaticVar(const ResolveResult&, const Identifier&, RegisterID* value); RegisterID* emitResolve(RegisterID* dst, const ResolveResult&, const Identifier& property); RegisterID* emitResolveBase(RegisterID* dst, const ResolveResult&, const Identifier& property); @@ -541,6 +546,7 @@ namespace JSC { ValueProfile* emitProfiledOpcode(OpcodeID); void retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index); void retrieveLastUnaryOp(int& dstIndex, int& srcIndex); + void retrieveLastUnaryOp(WriteBarrier<Unknown>*& dstPointer, int& srcIndex); ALWAYS_INLINE void rewindBinaryOp(); ALWAYS_INLINE void rewindUnaryOp(); @@ -572,7 +578,9 @@ namespace JSC { } // Returns the index of the added var. - int addGlobalVar(const Identifier&, bool isConstant); + enum ConstantMode { IsConstant, IsVariable }; + enum FunctionMode { IsFunctionToSpecialize, NotFunctionOrNotSpecializable }; + int addGlobalVar(const Identifier&, ConstantMode, FunctionMode); void addParameter(const Identifier&, int parameterIndex); @@ -608,10 +616,7 @@ namespace JSC { void addLineInfo(unsigned lineNo) { -#if !ENABLE(OPCODE_SAMPLING) - if (m_shouldEmitRichSourceInfo) -#endif - m_codeBlock->addLineInfo(instructions().size(), lineNo); + m_codeBlock->addLineInfo(instructions().size(), lineNo); } RegisterID* emitInitLazyRegister(RegisterID*); diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp index 4f113f776..d243e8ce0 100644 --- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp +++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp @@ -430,7 +430,7 @@ RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, if (resolveResult.isStatic()) { RefPtr<RegisterID> func = generator.newTemporary(); CallArguments callArguments(generator, m_args); - generator.emitGetStaticVar(func.get(), resolveResult); + generator.emitGetStaticVar(func.get(), resolveResult, m_ident); generator.emitLoad(callArguments.thisRegister(), jsUndefined()); return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); } @@ -618,7 +618,7 @@ RegisterID* PostfixResolveNode::emitBytecode(BytecodeGenerator& generator, Regis } if (resolveResult.isStatic() && !resolveResult.isReadOnly()) { - RefPtr<RegisterID> value = generator.emitGetStaticVar(generator.newTemporary(), resolveResult); + RefPtr<RegisterID> value = generator.emitGetStaticVar(generator.newTemporary(), resolveResult, m_ident); RegisterID* oldValue; if (dst == generator.ignoredResult()) { oldValue = 0; @@ -626,7 +626,7 @@ RegisterID* PostfixResolveNode::emitBytecode(BytecodeGenerator& generator, Regis } else { oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator); } - generator.emitPutStaticVar(resolveResult, value.get()); + generator.emitPutStaticVar(resolveResult, m_ident, value.get()); return oldValue; } @@ -803,9 +803,9 @@ RegisterID* PrefixResolveNode::emitBytecode(BytecodeGenerator& generator, Regist } if (resolveResult.isStatic() && !resolveResult.isReadOnly()) { - RefPtr<RegisterID> propDst = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult); + RefPtr<RegisterID> propDst = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, m_ident); emitPreIncOrDec(generator, propDst.get(), m_operator); - generator.emitPutStaticVar(resolveResult, propDst.get()); + generator.emitPutStaticVar(resolveResult, m_ident, propDst.get()); return generator.moveToDestinationIfNeeded(dst, propDst.get()); } @@ -1226,9 +1226,9 @@ RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, Re } if (resolveResult.isStatic() && !resolveResult.isReadOnly()) { - RefPtr<RegisterID> src1 = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult); + RefPtr<RegisterID> src1 = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, m_ident); RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); - generator.emitPutStaticVar(resolveResult, result); + generator.emitPutStaticVar(resolveResult, m_ident, result); return result; } @@ -1256,7 +1256,7 @@ RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, Regist if (dst == generator.ignoredResult()) dst = 0; RegisterID* value = generator.emitNode(dst, m_right); - generator.emitPutStaticVar(resolveResult, value); + generator.emitPutStaticVar(resolveResult, m_ident, value); return value; } @@ -1361,7 +1361,7 @@ RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator) RefPtr<RegisterID> value = m_init ? generator.emitNode(m_init) : generator.emitLoad(0, jsUndefined()); if (resolveResult.isStatic()) - return generator.emitPutStaticVar(resolveResult, value.get()); + return generator.emitPutStaticVar(resolveResult, m_ident, value.get()); if (generator.codeType() != EvalCode) return value.get(); diff --git a/Source/JavaScriptCore/debugger/Debugger.cpp b/Source/JavaScriptCore/debugger/Debugger.cpp index ede8a9ba2..0a66d6f34 100644 --- a/Source/JavaScriptCore/debugger/Debugger.cpp +++ b/Source/JavaScriptCore/debugger/Debugger.cpp @@ -79,7 +79,7 @@ inline void Recompiler::operator()(JSCell* cell) return; ExecState* exec = function->scope()->globalObject->JSGlobalObject::globalExec(); - executable->discardCode(); + executable->clearCodeIfNotCompiling(); if (m_debugger == function->scope()->globalObject->debugger()) m_sourceProviders.add(executable->source().provider(), exec); } diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp index a0849acea..94e96853d 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp +++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp @@ -99,31 +99,31 @@ void AbstractState::initialize(Graph& graph) continue; } - PredictedType prediction = node.variableAccessData()->prediction(); - if (isInt32Prediction(prediction)) - root->valuesAtHead.argument(i).set(PredictInt32); - else if (isArrayPrediction(prediction)) - root->valuesAtHead.argument(i).set(PredictArray); - else if (isBooleanPrediction(prediction)) - root->valuesAtHead.argument(i).set(PredictBoolean); - else if (isInt8ArrayPrediction(prediction)) - root->valuesAtHead.argument(i).set(PredictInt8Array); - else if (isInt16ArrayPrediction(prediction)) - root->valuesAtHead.argument(i).set(PredictInt16Array); - else if (isInt32ArrayPrediction(prediction)) - root->valuesAtHead.argument(i).set(PredictInt32Array); - else if (isUint8ArrayPrediction(prediction)) - root->valuesAtHead.argument(i).set(PredictUint8Array); - else if (isUint8ClampedArrayPrediction(prediction)) - root->valuesAtHead.argument(i).set(PredictUint8ClampedArray); - else if (isUint16ArrayPrediction(prediction)) - root->valuesAtHead.argument(i).set(PredictUint16Array); - else if (isUint32ArrayPrediction(prediction)) - root->valuesAtHead.argument(i).set(PredictUint32Array); - else if (isFloat32ArrayPrediction(prediction)) - root->valuesAtHead.argument(i).set(PredictFloat32Array); - else if (isFloat64ArrayPrediction(prediction)) - root->valuesAtHead.argument(i).set(PredictFloat64Array); + 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)) + root->valuesAtHead.argument(i).set(SpecInt8Array); + else if (isInt16ArraySpeculation(prediction)) + root->valuesAtHead.argument(i).set(SpecInt16Array); + else if (isInt32ArraySpeculation(prediction)) + root->valuesAtHead.argument(i).set(SpecInt32Array); + else if (isUint8ArraySpeculation(prediction)) + root->valuesAtHead.argument(i).set(SpecUint8Array); + else if (isUint8ClampedArraySpeculation(prediction)) + root->valuesAtHead.argument(i).set(SpecUint8ClampedArray); + else if (isUint16ArraySpeculation(prediction)) + root->valuesAtHead.argument(i).set(SpecUint16Array); + else if (isUint32ArraySpeculation(prediction)) + root->valuesAtHead.argument(i).set(SpecUint32Array); + else if (isFloat32ArraySpeculation(prediction)) + root->valuesAtHead.argument(i).set(SpecFloat32Array); + else if (isFloat64ArraySpeculation(prediction)) + root->valuesAtHead.argument(i).set(SpecFloat64Array); else root->valuesAtHead.argument(i).makeTop(); @@ -219,7 +219,9 @@ bool AbstractState::execute(unsigned indexInBlock) { ASSERT(m_block); ASSERT(m_isValid); - + + m_didClobber = false; + NodeIndex nodeIndex = m_block->at(indexInBlock); Node& node = m_graph[nodeIndex]; @@ -237,24 +239,29 @@ bool AbstractState::execute(unsigned indexInBlock) case GetLocal: { VariableAccessData* variableAccessData = node.variableAccessData(); + if (variableAccessData->prediction() == SpecNone) { + m_isValid = false; + node.setCanExit(true); + break; + } bool canExit = false; - canExit |= variableAccessData->prediction() == PredictNone; - if (variableAccessData->isCaptured()) - forNode(nodeIndex) = m_variables.operand(variableAccessData->local()); - else { - AbstractValue value = m_variables.operand(variableAccessData->local()); + AbstractValue value = m_variables.operand(variableAccessData->local()); + if (!variableAccessData->isCaptured()) { if (value.isClear()) canExit |= true; - if (value.value()) - m_foundConstants = true; - forNode(nodeIndex) = value; } + if (value.value()) + m_foundConstants = true; + forNode(nodeIndex) = value; node.setCanExit(canExit); break; } case GetLocalUnlinked: { - forNode(nodeIndex) = m_variables.operand(node.unlinkedLocal()); + AbstractValue value = m_variables.operand(node.unlinkedLocal()); + if (value.value()) + m_foundConstants = true; + forNode(nodeIndex) = value; node.setCanExit(false); break; } @@ -268,17 +275,17 @@ bool AbstractState::execute(unsigned indexInBlock) if (node.variableAccessData()->shouldUseDoubleFormat()) { speculateNumberUnary(node); - m_variables.operand(node.local()).set(PredictDouble); + m_variables.operand(node.local()).set(SpecDouble); break; } - PredictedType predictedType = node.variableAccessData()->argumentAwarePrediction(); - if (isInt32Prediction(predictedType)) + SpeculatedType predictedType = node.variableAccessData()->argumentAwarePrediction(); + if (isInt32Speculation(predictedType)) speculateInt32Unary(node); - else if (isArrayPrediction(predictedType)) { - node.setCanExit(!isArrayPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictArray); - } else if (isBooleanPrediction(predictedType)) + else if (isArraySpeculation(predictedType)) { + node.setCanExit(!isArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecArray); + } else if (isBooleanSpeculation(predictedType)) speculateBooleanUnary(node); else node.setCanExit(false); @@ -331,7 +338,7 @@ bool AbstractState::execute(unsigned indexInBlock) break; } speculateInt32Binary(node); - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); break; } @@ -345,10 +352,10 @@ bool AbstractState::execute(unsigned indexInBlock) break; } if (!node.canSpeculateInteger()) { - forNode(nodeIndex).set(PredictDouble); + forNode(nodeIndex).set(SpecDouble); node.setCanExit(false); } else { - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); node.setCanExit(true); } break; @@ -367,8 +374,8 @@ bool AbstractState::execute(unsigned indexInBlock) } } node.setCanExit(true); - forNode(node.child1()).filter(PredictNumber); - forNode(nodeIndex).set(PredictInt32); + forNode(node.child1()).filter(SpecNumber); + forNode(nodeIndex).set(SpecInt32); break; } @@ -392,7 +399,7 @@ bool AbstractState::execute(unsigned indexInBlock) else node.setCanExit(false); - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); break; } @@ -405,12 +412,12 @@ bool AbstractState::execute(unsigned indexInBlock) break; } speculateNumberUnary(node); - forNode(nodeIndex).set(PredictDouble); + forNode(nodeIndex).set(SpecDouble); break; } case CheckNumber: - forNode(node.child1()).filter(PredictNumber); + forNode(node.child1()).filter(SpecNumber); break; case ValueAdd: @@ -426,17 +433,17 @@ bool AbstractState::execute(unsigned indexInBlock) if (m_graph.addShouldSpeculateInteger(node)) { speculateInt32Binary( node, !nodeCanTruncateInteger(node.arithNodeFlags())); - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); break; } if (Node::shouldSpeculateNumber(m_graph[node.child1()], m_graph[node.child2()])) { speculateNumberBinary(node); - forNode(nodeIndex).set(PredictDouble); + forNode(nodeIndex).set(SpecDouble); break; } if (node.op() == ValueAdd) { clobberWorld(node.codeOrigin, indexInBlock); - forNode(nodeIndex).set(PredictString | PredictInt32 | PredictNumber); + forNode(nodeIndex).set(SpecString | SpecInt32 | SpecNumber); node.setCanExit(false); break; } @@ -458,11 +465,11 @@ bool AbstractState::execute(unsigned indexInBlock) if (m_graph.addShouldSpeculateInteger(node)) { speculateInt32Binary( node, !nodeCanTruncateInteger(node.arithNodeFlags())); - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); break; } speculateNumberBinary(node); - forNode(nodeIndex).set(PredictDouble); + forNode(nodeIndex).set(SpecDouble); break; } @@ -477,11 +484,11 @@ bool AbstractState::execute(unsigned indexInBlock) if (m_graph.negateShouldSpeculateInteger(node)) { speculateInt32Unary( node, !nodeCanTruncateInteger(node.arithNodeFlags())); - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); break; } speculateNumberUnary(node); - forNode(nodeIndex).set(PredictDouble); + forNode(nodeIndex).set(SpecDouble); break; } @@ -499,11 +506,11 @@ bool AbstractState::execute(unsigned indexInBlock) node, !nodeCanTruncateInteger(node.arithNodeFlags()) || !nodeCanIgnoreNegativeZero(node.arithNodeFlags())); - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); break; } speculateNumberBinary(node); - forNode(nodeIndex).set(PredictDouble); + forNode(nodeIndex).set(SpecDouble); break; } @@ -541,11 +548,11 @@ bool AbstractState::execute(unsigned indexInBlock) m_graph[node.child1()], m_graph[node.child2()]) && node.canSpeculateInteger()) { speculateInt32Binary(node, true); // forcing can-exit, which is a bit on the conservative side. - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); break; } speculateNumberBinary(node); - forNode(nodeIndex).set(PredictDouble); + forNode(nodeIndex).set(SpecDouble); break; } @@ -560,11 +567,11 @@ bool AbstractState::execute(unsigned indexInBlock) if (m_graph[node.child1()].shouldSpeculateInteger() && node.canSpeculateInteger()) { speculateInt32Unary(node, true); - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); break; } speculateNumberUnary(node); - forNode(nodeIndex).set(PredictDouble); + forNode(nodeIndex).set(SpecDouble); break; } @@ -577,7 +584,7 @@ bool AbstractState::execute(unsigned indexInBlock) break; } speculateNumberUnary(node); - forNode(nodeIndex).set(PredictDouble); + forNode(nodeIndex).set(SpecDouble); break; } @@ -585,27 +592,28 @@ bool AbstractState::execute(unsigned indexInBlock) JSValue childConst = forNode(node.child1()).value(); if (childConst) { forNode(nodeIndex).set(jsBoolean(!childConst.toBoolean())); + m_foundConstants = true; node.setCanExit(false); break; } Node& child = m_graph[node.child1()]; - if (isBooleanPrediction(child.prediction())) + if (isBooleanSpeculation(child.prediction())) speculateBooleanUnary(node); else if (child.shouldSpeculateFinalObjectOrOther()) { node.setCanExit( - !isFinalObjectOrOtherPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictFinalObject | PredictOther); + !isFinalObjectOrOtherSpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecFinalObject | SpecOther); } else if (child.shouldSpeculateArrayOrOther()) { node.setCanExit( - !isArrayOrOtherPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictArray | PredictOther); + !isArrayOrOtherSpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecArray | SpecOther); } else if (child.shouldSpeculateInteger()) speculateInt32Unary(node); else if (child.shouldSpeculateNumber()) speculateNumberUnary(node); else node.setCanExit(false); - forNode(nodeIndex).set(PredictBoolean); + forNode(nodeIndex).set(SpecBoolean); break; } @@ -643,7 +651,7 @@ bool AbstractState::execute(unsigned indexInBlock) break; } } - forNode(nodeIndex).set(PredictBoolean); + forNode(nodeIndex).set(SpecBoolean); break; } @@ -682,18 +690,18 @@ bool AbstractState::execute(unsigned indexInBlock) break; } - forNode(nodeIndex).set(PredictBoolean); + forNode(nodeIndex).set(SpecBoolean); Node& left = m_graph[node.child1()]; Node& right = m_graph[node.child2()]; - PredictedType filter; - PredictionChecker checker; + SpeculatedType filter; + SpeculatedTypeChecker checker; if (Node::shouldSpeculateInteger(left, right)) { - filter = PredictInt32; - checker = isInt32Prediction; + filter = SpecInt32; + checker = isInt32Speculation; } else if (Node::shouldSpeculateNumber(left, right)) { - filter = PredictNumber; - checker = isNumberPrediction; + filter = SpecNumber; + checker = isNumberSpeculation; } else if (node.op() == CompareEq) { if ((m_graph.isConstant(node.child1().index()) && m_graph.valueOfJSConstant(node.child1().index()).isNull()) @@ -705,47 +713,47 @@ bool AbstractState::execute(unsigned indexInBlock) } if (Node::shouldSpeculateFinalObject(left, right)) { - filter = PredictFinalObject; - checker = isFinalObjectPrediction; + filter = SpecFinalObject; + checker = isFinalObjectSpeculation; } else if (Node::shouldSpeculateArray(left, right)) { - filter = PredictArray; - checker = isArrayPrediction; + filter = SpecArray; + checker = isArraySpeculation; } else if (left.shouldSpeculateFinalObject() && right.shouldSpeculateFinalObjectOrOther()) { node.setCanExit( - !isFinalObjectPrediction(forNode(node.child1()).m_type) - || !isFinalObjectOrOtherPrediction(forNode(node.child2()).m_type)); - forNode(node.child1()).filter(PredictFinalObject); - forNode(node.child2()).filter(PredictFinalObject | PredictOther); + !isFinalObjectSpeculation(forNode(node.child1()).m_type) + || !isFinalObjectOrOtherSpeculation(forNode(node.child2()).m_type)); + forNode(node.child1()).filter(SpecFinalObject); + forNode(node.child2()).filter(SpecFinalObject | SpecOther); break; } else if (right.shouldSpeculateFinalObject() && left.shouldSpeculateFinalObjectOrOther()) { node.setCanExit( - !isFinalObjectOrOtherPrediction(forNode(node.child1()).m_type) - || !isFinalObjectPrediction(forNode(node.child2()).m_type)); - forNode(node.child1()).filter(PredictFinalObject | PredictOther); - forNode(node.child2()).filter(PredictFinalObject); + !isFinalObjectOrOtherSpeculation(forNode(node.child1()).m_type) + || !isFinalObjectSpeculation(forNode(node.child2()).m_type)); + forNode(node.child1()).filter(SpecFinalObject | SpecOther); + forNode(node.child2()).filter(SpecFinalObject); break; } else if (left.shouldSpeculateArray() && right.shouldSpeculateArrayOrOther()) { node.setCanExit( - !isArrayPrediction(forNode(node.child1()).m_type) - || !isArrayOrOtherPrediction(forNode(node.child2()).m_type)); - forNode(node.child1()).filter(PredictArray); - forNode(node.child2()).filter(PredictArray | PredictOther); + !isArraySpeculation(forNode(node.child1()).m_type) + || !isArrayOrOtherSpeculation(forNode(node.child2()).m_type)); + forNode(node.child1()).filter(SpecArray); + forNode(node.child2()).filter(SpecArray | SpecOther); break; } else if (right.shouldSpeculateArray() && left.shouldSpeculateArrayOrOther()) { node.setCanExit( - !isArrayOrOtherPrediction(forNode(node.child1()).m_type) - || !isArrayPrediction(forNode(node.child2()).m_type)); - forNode(node.child1()).filter(PredictArray | PredictOther); - forNode(node.child2()).filter(PredictArray); + !isArrayOrOtherSpeculation(forNode(node.child1()).m_type) + || !isArraySpeculation(forNode(node.child2()).m_type)); + forNode(node.child1()).filter(SpecArray | SpecOther); + forNode(node.child2()).filter(SpecArray); break; } else { - filter = PredictTop; - checker = isAnyPrediction; + filter = SpecTop; + checker = isAnySpeculation; clobberWorld(node.codeOrigin, indexInBlock); } } else { - filter = PredictTop; - checker = isAnyPrediction; + filter = SpecTop; + checker = isAnySpeculation; clobberWorld(node.codeOrigin, indexInBlock); } node.setCanExit( @@ -765,7 +773,7 @@ bool AbstractState::execute(unsigned indexInBlock) node.setCanExit(false); break; } - forNode(nodeIndex).set(PredictBoolean); + forNode(nodeIndex).set(SpecBoolean); if (m_graph.isJSConstant(node.child1().index())) { JSValue value = m_graph.valueOfJSConstant(node.child1().index()); if (!value.isNumber() && !value.isString()) { @@ -793,19 +801,19 @@ bool AbstractState::execute(unsigned indexInBlock) if (Node::shouldSpeculateFinalObject( m_graph[node.child1()], m_graph[node.child2()])) { node.setCanExit( - !isFinalObjectPrediction(forNode(node.child1()).m_type) - || !isFinalObjectPrediction(forNode(node.child2()).m_type)); - forNode(node.child1()).filter(PredictFinalObject); - forNode(node.child2()).filter(PredictFinalObject); + !isFinalObjectSpeculation(forNode(node.child1()).m_type) + || !isFinalObjectSpeculation(forNode(node.child2()).m_type)); + forNode(node.child1()).filter(SpecFinalObject); + forNode(node.child2()).filter(SpecFinalObject); break; } if (Node::shouldSpeculateArray( m_graph[node.child1()], m_graph[node.child2()])) { node.setCanExit( - !isArrayPrediction(forNode(node.child1()).m_type) - || !isArrayPrediction(forNode(node.child2()).m_type)); - forNode(node.child1()).filter(PredictArray); - forNode(node.child2()).filter(PredictArray); + !isArraySpeculation(forNode(node.child1()).m_type) + || !isArraySpeculation(forNode(node.child2()).m_type)); + forNode(node.child1()).filter(SpecArray); + forNode(node.child2()).filter(SpecArray); break; } node.setCanExit(false); @@ -814,16 +822,16 @@ bool AbstractState::execute(unsigned indexInBlock) case StringCharCodeAt: node.setCanExit(true); - forNode(node.child1()).filter(PredictString); - forNode(node.child2()).filter(PredictInt32); - forNode(nodeIndex).set(PredictInt32); + forNode(node.child1()).filter(SpecString); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecInt32); break; case StringCharAt: node.setCanExit(true); - forNode(node.child1()).filter(PredictString); - forNode(node.child2()).filter(PredictInt32); - forNode(nodeIndex).set(PredictString); + forNode(node.child1()).filter(SpecString); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecString); break; case GetByVal: { @@ -832,84 +840,84 @@ bool AbstractState::execute(unsigned indexInBlock) m_isValid = false; break; } - if (!isActionableArrayPrediction(m_graph[node.child1()].prediction()) || !m_graph[node.child2()].shouldSpeculateInteger()) { + if (!isActionableArraySpeculation(m_graph[node.child1()].prediction()) || !m_graph[node.child2()].shouldSpeculateInteger()) { clobberWorld(node.codeOrigin, indexInBlock); forNode(nodeIndex).makeTop(); break; } if (m_graph[node.child1()].shouldSpeculateArguments()) { - forNode(node.child1()).filter(PredictArguments); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecArguments); + forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).makeTop(); break; } - if (m_graph[node.child1()].prediction() == PredictString) { - forNode(node.child1()).filter(PredictString); - forNode(node.child2()).filter(PredictInt32); - forNode(nodeIndex).set(PredictString); + if (m_graph[node.child1()].prediction() == SpecString) { + forNode(node.child1()).filter(SpecString); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecString); break; } if (m_graph[node.child1()].shouldSpeculateInt8Array()) { - forNode(node.child1()).filter(PredictInt8Array); - forNode(node.child2()).filter(PredictInt32); - forNode(nodeIndex).set(PredictInt32); + forNode(node.child1()).filter(SpecInt8Array); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecInt32); break; } if (m_graph[node.child1()].shouldSpeculateInt16Array()) { - forNode(node.child1()).filter(PredictInt16Array); - forNode(node.child2()).filter(PredictInt32); - forNode(nodeIndex).set(PredictInt32); + forNode(node.child1()).filter(SpecInt16Array); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecInt32); break; } if (m_graph[node.child1()].shouldSpeculateInt32Array()) { - forNode(node.child1()).filter(PredictInt32Array); - forNode(node.child2()).filter(PredictInt32); - forNode(nodeIndex).set(PredictInt32); + forNode(node.child1()).filter(SpecInt32Array); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecInt32); break; } if (m_graph[node.child1()].shouldSpeculateUint8Array()) { - forNode(node.child1()).filter(PredictUint8Array); - forNode(node.child2()).filter(PredictInt32); - forNode(nodeIndex).set(PredictInt32); + forNode(node.child1()).filter(SpecUint8Array); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecInt32); break; } if (m_graph[node.child1()].shouldSpeculateUint8ClampedArray()) { - forNode(node.child1()).filter(PredictUint8ClampedArray); - forNode(node.child2()).filter(PredictInt32); - forNode(nodeIndex).set(PredictInt32); + forNode(node.child1()).filter(SpecUint8ClampedArray); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecInt32); break; } if (m_graph[node.child1()].shouldSpeculateUint16Array()) { - forNode(node.child1()).filter(PredictUint16Array); - forNode(node.child2()).filter(PredictInt32); - forNode(nodeIndex).set(PredictInt32); + forNode(node.child1()).filter(SpecUint16Array); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecInt32); break; } if (m_graph[node.child1()].shouldSpeculateUint32Array()) { - forNode(node.child1()).filter(PredictUint32Array); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecUint32Array); + forNode(node.child2()).filter(SpecInt32); if (node.shouldSpeculateInteger()) - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); else - forNode(nodeIndex).set(PredictDouble); + forNode(nodeIndex).set(SpecDouble); break; } if (m_graph[node.child1()].shouldSpeculateFloat32Array()) { - forNode(node.child1()).filter(PredictFloat32Array); - forNode(node.child2()).filter(PredictInt32); - forNode(nodeIndex).set(PredictDouble); + forNode(node.child1()).filter(SpecFloat32Array); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecDouble); break; } if (m_graph[node.child1()].shouldSpeculateFloat64Array()) { - forNode(node.child1()).filter(PredictFloat64Array); - forNode(node.child2()).filter(PredictInt32); - forNode(nodeIndex).set(PredictDouble); + forNode(node.child1()).filter(SpecFloat64Array); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecDouble); break; } ASSERT(m_graph[node.child1()].shouldSpeculateArray()); - forNode(node.child1()).filter(PredictArray); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecArray); + forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).makeTop(); break; } @@ -921,7 +929,7 @@ bool AbstractState::execute(unsigned indexInBlock) m_isValid = false; break; } - if (!m_graph[node.child2()].shouldSpeculateInteger() || !isActionableMutableArrayPrediction(m_graph[node.child1()].prediction()) + if (!m_graph[node.child2()].shouldSpeculateInteger() || !isActionableMutableArraySpeculation(m_graph[node.child1()].prediction()) #if USE(JSVALUE32_64) || m_graph[node.child1()].shouldSpeculateArguments() #endif @@ -933,110 +941,112 @@ bool AbstractState::execute(unsigned indexInBlock) } if (m_graph[node.child1()].shouldSpeculateArguments()) { - forNode(node.child1()).filter(PredictArguments); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecArguments); + forNode(node.child2()).filter(SpecInt32); break; } if (m_graph[node.child1()].shouldSpeculateInt8Array()) { - forNode(node.child1()).filter(PredictInt8Array); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecInt8Array); + forNode(node.child2()).filter(SpecInt32); if (m_graph[node.child3()].shouldSpeculateInteger()) - forNode(node.child3()).filter(PredictInt32); + forNode(node.child3()).filter(SpecInt32); else - forNode(node.child3()).filter(PredictNumber); + forNode(node.child3()).filter(SpecNumber); break; } if (m_graph[node.child1()].shouldSpeculateInt16Array()) { - forNode(node.child1()).filter(PredictInt16Array); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecInt16Array); + forNode(node.child2()).filter(SpecInt32); if (m_graph[node.child3()].shouldSpeculateInteger()) - forNode(node.child3()).filter(PredictInt32); + forNode(node.child3()).filter(SpecInt32); else - forNode(node.child3()).filter(PredictNumber); + forNode(node.child3()).filter(SpecNumber); break; } if (m_graph[node.child1()].shouldSpeculateInt32Array()) { - forNode(node.child1()).filter(PredictInt32Array); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecInt32Array); + forNode(node.child2()).filter(SpecInt32); if (m_graph[node.child3()].shouldSpeculateInteger()) - forNode(node.child3()).filter(PredictInt32); + forNode(node.child3()).filter(SpecInt32); else - forNode(node.child3()).filter(PredictNumber); + forNode(node.child3()).filter(SpecNumber); break; } if (m_graph[node.child1()].shouldSpeculateUint8Array()) { - forNode(node.child1()).filter(PredictUint8Array); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecUint8Array); + forNode(node.child2()).filter(SpecInt32); if (m_graph[node.child3()].shouldSpeculateInteger()) - forNode(node.child3()).filter(PredictInt32); + forNode(node.child3()).filter(SpecInt32); else - forNode(node.child3()).filter(PredictNumber); + forNode(node.child3()).filter(SpecNumber); break; } if (m_graph[node.child1()].shouldSpeculateUint8ClampedArray()) { - forNode(node.child1()).filter(PredictUint8ClampedArray); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecUint8ClampedArray); + forNode(node.child2()).filter(SpecInt32); if (m_graph[node.child3()].shouldSpeculateInteger()) - forNode(node.child3()).filter(PredictInt32); + forNode(node.child3()).filter(SpecInt32); else - forNode(node.child3()).filter(PredictNumber); + forNode(node.child3()).filter(SpecNumber); break; } if (m_graph[node.child1()].shouldSpeculateUint16Array()) { - forNode(node.child1()).filter(PredictUint16Array); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecUint16Array); + forNode(node.child2()).filter(SpecInt32); if (m_graph[node.child3()].shouldSpeculateInteger()) - forNode(node.child3()).filter(PredictInt32); + forNode(node.child3()).filter(SpecInt32); else - forNode(node.child3()).filter(PredictNumber); + forNode(node.child3()).filter(SpecNumber); break; } if (m_graph[node.child1()].shouldSpeculateUint32Array()) { - forNode(node.child1()).filter(PredictUint32Array); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecUint32Array); + forNode(node.child2()).filter(SpecInt32); if (m_graph[node.child3()].shouldSpeculateInteger()) - forNode(node.child3()).filter(PredictInt32); + forNode(node.child3()).filter(SpecInt32); else - forNode(node.child3()).filter(PredictNumber); + forNode(node.child3()).filter(SpecNumber); break; } if (m_graph[node.child1()].shouldSpeculateFloat32Array()) { - forNode(node.child1()).filter(PredictFloat32Array); - forNode(node.child2()).filter(PredictInt32); - forNode(node.child3()).filter(PredictNumber); + forNode(node.child1()).filter(SpecFloat32Array); + forNode(node.child2()).filter(SpecInt32); + forNode(node.child3()).filter(SpecNumber); break; } if (m_graph[node.child1()].shouldSpeculateFloat64Array()) { - forNode(node.child1()).filter(PredictFloat64Array); - forNode(node.child2()).filter(PredictInt32); - forNode(node.child3()).filter(PredictNumber); + forNode(node.child1()).filter(SpecFloat64Array); + forNode(node.child2()).filter(SpecInt32); + forNode(node.child3()).filter(SpecNumber); break; } ASSERT(m_graph[node.child1()].shouldSpeculateArray()); - forNode(node.child1()).filter(PredictArray); - forNode(node.child2()).filter(PredictInt32); + forNode(node.child1()).filter(SpecArray); + forNode(node.child2()).filter(SpecInt32); + if (node.op() == PutByVal) + clobberWorld(node.codeOrigin, indexInBlock); break; } case ArrayPush: node.setCanExit(true); - forNode(node.child1()).filter(PredictArray); - forNode(nodeIndex).set(PredictNumber); + forNode(node.child1()).filter(SpecArray); + forNode(nodeIndex).set(SpecNumber); break; case ArrayPop: node.setCanExit(true); - forNode(node.child1()).filter(PredictArray); + forNode(node.child1()).filter(SpecArray); forNode(nodeIndex).makeTop(); break; case RegExpExec: case RegExpTest: node.setCanExit( - !isCellPrediction(forNode(node.child1()).m_type) - || !isCellPrediction(forNode(node.child2()).m_type)); - forNode(node.child1()).filter(PredictCell); - forNode(node.child2()).filter(PredictCell); + !isCellSpeculation(forNode(node.child1()).m_type) + || !isCellSpeculation(forNode(node.child2()).m_type)); + forNode(node.child1()).filter(SpecCell); + forNode(node.child2()).filter(SpecCell); forNode(nodeIndex).makeTop(); break; @@ -1067,12 +1077,12 @@ bool AbstractState::execute(unsigned indexInBlock) speculateBooleanUnary(node); else if (child.shouldSpeculateFinalObjectOrOther()) { node.setCanExit( - !isFinalObjectOrOtherPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictFinalObject | PredictOther); + !isFinalObjectOrOtherSpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecFinalObject | SpecOther); } else if (child.shouldSpeculateArrayOrOther()) { node.setCanExit( - !isArrayOrOtherPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictArray | PredictOther); + !isArrayOrOtherSpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecArray | SpecOther); } else if (child.shouldSpeculateInteger()) speculateInt32Unary(node); else if (child.shouldSpeculateNumber()) @@ -1106,17 +1116,17 @@ bool AbstractState::execute(unsigned indexInBlock) Node& child = m_graph[node.child1()]; if (child.shouldSpeculateInteger()) { speculateInt32Unary(node); - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); break; } AbstractValue& source = forNode(node.child1()); AbstractValue& destination = forNode(nodeIndex); - PredictedType type = source.m_type; - if (type & ~(PredictNumber | PredictString | PredictBoolean)) { - type &= (PredictNumber | PredictString | PredictBoolean); - type |= PredictString; + SpeculatedType type = source.m_type; + if (type & ~(SpecNumber | SpecString | SpecBoolean)) { + type &= (SpecNumber | SpecString | SpecBoolean); + type |= SpecString; } destination.set(type); node.setCanExit(false); @@ -1125,7 +1135,7 @@ bool AbstractState::execute(unsigned indexInBlock) case StrCat: node.setCanExit(false); - forNode(nodeIndex).set(PredictString); + forNode(nodeIndex).set(SpecString); break; case NewArray: @@ -1146,7 +1156,7 @@ bool AbstractState::execute(unsigned indexInBlock) AbstractValue& source = forNode(node.child1()); AbstractValue& destination = forNode(nodeIndex); - if (isObjectPrediction(source.m_type)) { + if (isObjectSpeculation(source.m_type)) { // This is the simple case. We already know that the source is an // object, so there's nothing to do. I don't think this case will // be hit, but then again, you never know. @@ -1157,20 +1167,20 @@ bool AbstractState::execute(unsigned indexInBlock) node.setCanExit(true); - if (isOtherPrediction(child.prediction())) { - source.filter(PredictOther); - destination.set(PredictObjectOther); + if (isOtherSpeculation(child.prediction())) { + source.filter(SpecOther); + destination.set(SpecObjectOther); break; } - if (isObjectPrediction(child.prediction())) { - source.filter(PredictObjectMask); + if (isObjectSpeculation(child.prediction())) { + source.filter(SpecObjectMask); destination = source; break; } destination = source; - destination.merge(PredictObjectOther); + destination.merge(SpecObjectOther); break; } @@ -1178,10 +1188,10 @@ bool AbstractState::execute(unsigned indexInBlock) AbstractValue& source = forNode(node.child1()); AbstractValue& destination = forNode(nodeIndex); - node.setCanExit(!isCellPrediction(source.m_type)); + node.setCanExit(!isCellSpeculation(source.m_type)); - source.filter(PredictFunction); - destination.set(PredictFinalObject); + source.filter(SpecFunction); + destination.set(SpecFinalObject); break; } @@ -1210,10 +1220,13 @@ bool AbstractState::execute(unsigned indexInBlock) break; case CheckArgumentsNotCreated: - node.setCanExit( - !isEmptyPrediction( + if (isEmptySpeculation( m_variables.operand( - m_graph.argumentsRegisterFor(node.codeOrigin)).m_type)); + m_graph.argumentsRegisterFor(node.codeOrigin)).m_type)) { + node.setCanExit(false); + m_foundConstants = true; + } else + node.setCanExit(true); break; case GetMyArgumentsLength: @@ -1224,9 +1237,9 @@ bool AbstractState::execute(unsigned indexInBlock) if (node.codeOrigin.inlineCallFrame) forNode(nodeIndex).set(jsNumber(node.codeOrigin.inlineCallFrame->arguments.size() - 1)); else - forNode(nodeIndex).set(PredictInt32); + forNode(nodeIndex).set(SpecInt32); node.setCanExit( - !isEmptyPrediction( + !isEmptySpeculation( m_variables.operand( m_graph.argumentsRegisterFor(node.codeOrigin)).m_type)); break; @@ -1246,7 +1259,7 @@ bool AbstractState::execute(unsigned indexInBlock) // We know that this executable does not escape its arguments, so we can optimize // the arguments a bit. Note that this ends up being further optimized by the // ArgumentsSimplificationPhase. - forNode(node.child1()).filter(PredictInt32); + forNode(node.child1()).filter(SpecInt32); forNode(nodeIndex).makeTop(); break; @@ -1256,7 +1269,7 @@ bool AbstractState::execute(unsigned indexInBlock) // a getter. We don't speculate against this. clobberWorld(node.codeOrigin, indexInBlock); // But we do speculate that the index is an integer. - forNode(node.child1()).filter(PredictInt32); + forNode(node.child1()).filter(SpecInt32); // And the result is unknown. forNode(nodeIndex).makeTop(); break; @@ -1270,12 +1283,12 @@ bool AbstractState::execute(unsigned indexInBlock) case GetCallee: node.setCanExit(false); - forNode(nodeIndex).set(PredictFunction); + forNode(nodeIndex).set(SpecFunction); break; case GetScopeChain: node.setCanExit(false); - forNode(nodeIndex).set(PredictCellOther); + forNode(nodeIndex).set(SpecCellOther); break; case GetScopedVar: @@ -1295,74 +1308,74 @@ bool AbstractState::execute(unsigned indexInBlock) m_isValid = false; break; } - if (isCellPrediction(m_graph[node.child1()].prediction())) - forNode(node.child1()).filter(PredictCell); + if (isCellSpeculation(m_graph[node.child1()].prediction())) + forNode(node.child1()).filter(SpecCell); clobberWorld(node.codeOrigin, indexInBlock); forNode(nodeIndex).makeTop(); break; case GetArrayLength: node.setCanExit(true); - forNode(node.child1()).filter(PredictArray); - forNode(nodeIndex).set(PredictInt32); + forNode(node.child1()).filter(SpecArray); + forNode(nodeIndex).set(SpecInt32); break; case GetArgumentsLength: node.setCanExit(true); - forNode(node.child1()).filter(PredictArguments); - forNode(nodeIndex).set(PredictInt32); + forNode(node.child1()).filter(SpecArguments); + forNode(nodeIndex).set(SpecInt32); break; case GetStringLength: - node.setCanExit(!isStringPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictString); - forNode(nodeIndex).set(PredictInt32); + node.setCanExit(!isStringSpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecString); + forNode(nodeIndex).set(SpecInt32); break; case GetInt8ArrayLength: - node.setCanExit(!isInt8ArrayPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictInt8Array); - forNode(nodeIndex).set(PredictInt32); + node.setCanExit(!isInt8ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecInt8Array); + forNode(nodeIndex).set(SpecInt32); break; case GetInt16ArrayLength: - node.setCanExit(!isInt16ArrayPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictInt16Array); - forNode(nodeIndex).set(PredictInt32); + node.setCanExit(!isInt16ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecInt16Array); + forNode(nodeIndex).set(SpecInt32); break; case GetInt32ArrayLength: - node.setCanExit(!isInt32ArrayPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictInt32Array); - forNode(nodeIndex).set(PredictInt32); + node.setCanExit(!isInt32ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecInt32Array); + forNode(nodeIndex).set(SpecInt32); break; case GetUint8ArrayLength: - node.setCanExit(!isUint8ArrayPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictUint8Array); - forNode(nodeIndex).set(PredictInt32); + node.setCanExit(!isUint8ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecUint8Array); + forNode(nodeIndex).set(SpecInt32); break; case GetUint8ClampedArrayLength: - node.setCanExit(!isUint8ClampedArrayPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictUint8ClampedArray); - forNode(nodeIndex).set(PredictInt32); + node.setCanExit(!isUint8ClampedArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecUint8ClampedArray); + forNode(nodeIndex).set(SpecInt32); break; case GetUint16ArrayLength: - node.setCanExit(!isUint16ArrayPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictUint16Array); - forNode(nodeIndex).set(PredictInt32); + node.setCanExit(!isUint16ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecUint16Array); + forNode(nodeIndex).set(SpecInt32); break; case GetUint32ArrayLength: - node.setCanExit(!isUint32ArrayPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictUint32Array); - forNode(nodeIndex).set(PredictInt32); + node.setCanExit(!isUint32ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecUint32Array); + forNode(nodeIndex).set(SpecInt32); break; case GetFloat32ArrayLength: - node.setCanExit(!isFloat32ArrayPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictFloat32Array); - forNode(nodeIndex).set(PredictInt32); + node.setCanExit(!isFloat32ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecFloat32Array); + forNode(nodeIndex).set(SpecInt32); break; case GetFloat64ArrayLength: - node.setCanExit(!isFloat64ArrayPrediction(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(PredictFloat64Array); - forNode(nodeIndex).set(PredictInt32); + node.setCanExit(!isFloat64ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecFloat64Array); + forNode(nodeIndex).set(SpecInt32); break; case CheckStructure: { @@ -1370,11 +1383,20 @@ bool AbstractState::execute(unsigned indexInBlock) AbstractValue& value = forNode(node.child1()); node.setCanExit( !value.m_structure.isSubsetOf(node.structureSet()) - || !isCellPrediction(value.m_type)); + || !isCellSpeculation(value.m_type)); value.filter(node.structureSet()); m_haveStructures = true; break; } + + case StructureTransitionWatchpoint: { + // FIXME: Turn CheckStructure into StructureTransitionWatchpoint when possible! + AbstractValue& value = forNode(node.child1()); + ASSERT(isCellSpeculation(value.m_type)); + value.filter(node.structure()); + node.setCanExit(true); + break; + } case PutStructure: case PhantomPutStructure: @@ -1385,13 +1407,13 @@ bool AbstractState::execute(unsigned indexInBlock) break; case GetPropertyStorage: node.setCanExit(false); - forNode(node.child1()).filter(PredictCell); + forNode(node.child1()).filter(SpecCell); forNode(nodeIndex).clear(); // The result is not a JS value. break; case GetIndexedPropertyStorage: { node.setCanExit(true); // Lies, but this is (almost) always followed by GetByVal, which does exit. So no point in trying to be more precise. - PredictedType basePrediction = m_graph[node.child2()].prediction(); - if (!(basePrediction & PredictInt32) && basePrediction) { + SpeculatedType basePrediction = m_graph[node.child2()].prediction(); + if (!(basePrediction & SpecInt32) && basePrediction) { forNode(nodeIndex).clear(); break; } @@ -1399,82 +1421,82 @@ bool AbstractState::execute(unsigned indexInBlock) ASSERT_NOT_REACHED(); break; } - if (m_graph[node.child1()].prediction() == PredictString) { - forNode(node.child1()).filter(PredictString); + if (m_graph[node.child1()].prediction() == SpecString) { + forNode(node.child1()).filter(SpecString); forNode(nodeIndex).clear(); break; } if (m_graph[node.child1()].shouldSpeculateInt8Array()) { - forNode(node.child1()).filter(PredictInt8Array); + forNode(node.child1()).filter(SpecInt8Array); forNode(nodeIndex).clear(); break; } if (m_graph[node.child1()].shouldSpeculateInt16Array()) { - forNode(node.child1()).filter(PredictInt16Array); + forNode(node.child1()).filter(SpecInt16Array); forNode(nodeIndex).clear(); break; } if (m_graph[node.child1()].shouldSpeculateInt32Array()) { - forNode(node.child1()).filter(PredictInt32Array); + forNode(node.child1()).filter(SpecInt32Array); forNode(nodeIndex).clear(); break; } if (m_graph[node.child1()].shouldSpeculateUint8Array()) { - forNode(node.child1()).filter(PredictUint8Array); + forNode(node.child1()).filter(SpecUint8Array); forNode(nodeIndex).clear(); break; } if (m_graph[node.child1()].shouldSpeculateUint8ClampedArray()) { - forNode(node.child1()).filter(PredictUint8ClampedArray); + forNode(node.child1()).filter(SpecUint8ClampedArray); forNode(nodeIndex).clear(); break; } if (m_graph[node.child1()].shouldSpeculateUint16Array()) { - forNode(node.child1()).filter(PredictUint16Array); - forNode(nodeIndex).set(PredictOther); + forNode(node.child1()).filter(SpecUint16Array); + forNode(nodeIndex).set(SpecOther); break; } if (m_graph[node.child1()].shouldSpeculateUint32Array()) { - forNode(node.child1()).filter(PredictUint32Array); + forNode(node.child1()).filter(SpecUint32Array); forNode(nodeIndex).clear(); break; } if (m_graph[node.child1()].shouldSpeculateFloat32Array()) { - forNode(node.child1()).filter(PredictFloat32Array); + forNode(node.child1()).filter(SpecFloat32Array); forNode(nodeIndex).clear(); break; } if (m_graph[node.child1()].shouldSpeculateFloat64Array()) { - forNode(node.child1()).filter(PredictFloat64Array); + forNode(node.child1()).filter(SpecFloat64Array); forNode(nodeIndex).clear(); break; } - forNode(node.child1()).filter(PredictArray); + forNode(node.child1()).filter(SpecArray); forNode(nodeIndex).clear(); break; } case GetByOffset: node.setCanExit(false); - forNode(node.child1()).filter(PredictCell); + forNode(node.child1()).filter(SpecCell); forNode(nodeIndex).makeTop(); break; case PutByOffset: node.setCanExit(false); - forNode(node.child1()).filter(PredictCell); + forNode(node.child1()).filter(SpecCell); break; case CheckFunction: node.setCanExit(true); // Lies! We can do better. - forNode(node.child1()).filter(PredictFunction); + forNode(node.child1()).filter(SpecFunction); // FIXME: Should be able to propagate the fact that we know what the function is. break; - + case PutById: case PutByIdDirect: node.setCanExit(true); - forNode(node.child1()).filter(PredictCell); + forNode(node.child1()).filter(SpecCell); clobberWorld(node.codeOrigin, indexInBlock); break; @@ -1482,24 +1504,29 @@ bool AbstractState::execute(unsigned indexInBlock) node.setCanExit(false); forNode(nodeIndex).makeTop(); break; + + case GlobalVarWatchpoint: + node.setCanExit(true); + break; case PutGlobalVar: + case PutGlobalVarCheck: node.setCanExit(false); break; case CheckHasInstance: node.setCanExit(true); - forNode(node.child1()).filter(PredictCell); + forNode(node.child1()).filter(SpecCell); // Sadly, we don't propagate the fact that we've done CheckHasInstance break; case InstanceOf: node.setCanExit(true); // Again, sadly, we don't propagate the fact that we've done InstanceOf - if (!(m_graph[node.child1()].prediction() & ~PredictCell) && !(forNode(node.child1()).m_type & ~PredictCell)) - forNode(node.child1()).filter(PredictCell); - forNode(node.child3()).filter(PredictCell); - forNode(nodeIndex).set(PredictBoolean); + if (!(m_graph[node.child1()].prediction() & ~SpecCell) && !(forNode(node.child1()).m_type & ~SpecCell)) + forNode(node.child1()).filter(SpecCell); + forNode(node.child3()).filter(SpecCell); + forNode(nodeIndex).set(SpecBoolean); break; case Phi: @@ -1572,6 +1599,7 @@ inline void AbstractState::clobberStructures(unsigned indexInBlock) for (size_t i = m_variables.numberOfLocals(); i--;) m_variables.local(i).clobberStructures(); m_haveStructures = false; + m_didClobber = true; } inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, NodeIndex nodeIndex) @@ -1625,7 +1653,7 @@ inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, Abstract // before and after setting it. if (node.variableAccessData()->shouldUseDoubleFormat()) { // FIXME: This unnecessarily loses precision. - source.set(PredictDouble); + source.set(SpecDouble); } else source = forNode(node.child1()); #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.h b/Source/JavaScriptCore/dfg/DFGAbstractState.h index 4b0a248f3..9bb74cd86 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractState.h +++ b/Source/JavaScriptCore/dfg/DFGAbstractState.h @@ -193,6 +193,9 @@ public: // of Throw. bool execute(unsigned); + // Did the last executed node clobber the world? + bool didClobber() const { return m_didClobber; } + // Is the execution state still valid? This will be false if execute() has // returned false previously. bool isValid() const { return m_isValid; } @@ -223,22 +226,22 @@ private: void speculateInt32Unary(Node& node, bool forceCanExit = false) { AbstractValue& childValue = forNode(node.child1()); - node.setCanExit(forceCanExit || !isInt32Prediction(childValue.m_type)); - childValue.filter(PredictInt32); + node.setCanExit(forceCanExit || !isInt32Speculation(childValue.m_type)); + childValue.filter(SpecInt32); } void speculateNumberUnary(Node& node) { AbstractValue& childValue = forNode(node.child1()); - node.setCanExit(!isNumberPrediction(childValue.m_type)); - childValue.filter(PredictNumber); + node.setCanExit(!isNumberSpeculation(childValue.m_type)); + childValue.filter(SpecNumber); } void speculateBooleanUnary(Node& node) { AbstractValue& childValue = forNode(node.child1()); - node.setCanExit(!isBooleanPrediction(childValue.m_type)); - childValue.filter(PredictBoolean); + node.setCanExit(!isBooleanSpeculation(childValue.m_type)); + childValue.filter(SpecBoolean); } void speculateInt32Binary(Node& node, bool forceCanExit = false) @@ -247,10 +250,10 @@ private: AbstractValue& childValue2 = forNode(node.child2()); node.setCanExit( forceCanExit - || !isInt32Prediction(childValue1.m_type) - || !isInt32Prediction(childValue2.m_type)); - childValue1.filter(PredictInt32); - childValue2.filter(PredictInt32); + || !isInt32Speculation(childValue1.m_type) + || !isInt32Speculation(childValue2.m_type)); + childValue1.filter(SpecInt32); + childValue2.filter(SpecInt32); } void speculateNumberBinary(Node& node) @@ -258,10 +261,10 @@ private: AbstractValue& childValue1 = forNode(node.child1()); AbstractValue& childValue2 = forNode(node.child2()); node.setCanExit( - !isNumberPrediction(childValue1.m_type) - || !isNumberPrediction(childValue2.m_type)); - childValue1.filter(PredictNumber); - childValue2.filter(PredictNumber); + !isNumberSpeculation(childValue1.m_type) + || !isNumberSpeculation(childValue2.m_type)); + childValue1.filter(SpecNumber); + childValue2.filter(SpecNumber); } CodeBlock* m_codeBlock; @@ -274,6 +277,7 @@ private: bool m_foundConstants; bool m_isValid; + bool m_didClobber; BranchDirection m_branchDirection; // This is only set for blocks that end in Branch and that execute to completion (i.e. m_isValid == true). }; diff --git a/Source/JavaScriptCore/dfg/DFGAbstractValue.h b/Source/JavaScriptCore/dfg/DFGAbstractValue.h index c61a383eb..f81af4ecf 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractValue.h +++ b/Source/JavaScriptCore/dfg/DFGAbstractValue.h @@ -31,7 +31,7 @@ #if ENABLE(DFG_JIT) #include "JSCell.h" -#include "PredictedType.h" +#include "SpeculatedType.h" #include "StructureSet.h" namespace JSC { namespace DFG { @@ -225,9 +225,9 @@ public: m_structure = 0; } - void filter(PredictedType other) + void filter(SpeculatedType other) { - if (!(other & PredictCell)) { + if (!(other & SpecCell)) { clear(); return; } @@ -235,7 +235,7 @@ public: if (isClearOrTop()) return; - if (!(predictionFromStructure(m_structure) & other)) + if (!(speculationFromStructure(m_structure) & other)) m_structure = 0; } @@ -273,13 +273,13 @@ public: return at(0); } - PredictedType predictionFromStructures() const + SpeculatedType speculationFromStructures() const { if (isTop()) - return PredictCell; + return SpecCell; if (isClear()) - return PredictNone; - return predictionFromStructure(m_structure); + return SpecNone; + return speculationFromStructure(m_structure); } bool operator==(const StructureAbstractValue& other) const @@ -309,13 +309,13 @@ private: struct AbstractValue { AbstractValue() - : m_type(PredictNone) + : m_type(SpecNone) { } void clear() { - m_type = PredictNone; + m_type = SpecNone; m_structure.clear(); m_value = JSValue(); checkConsistency(); @@ -323,7 +323,7 @@ struct AbstractValue { bool isClear() const { - bool result = m_type == PredictNone && m_structure.isClear(); + bool result = m_type == SpecNone && m_structure.isClear(); if (result) ASSERT(!m_value); return result; @@ -331,7 +331,7 @@ struct AbstractValue { void makeTop() { - m_type = PredictTop; + m_type = SpecTop; m_structure.makeTop(); m_value = JSValue(); checkConsistency(); @@ -339,7 +339,7 @@ struct AbstractValue { void clobberStructures() { - if (m_type & PredictCell) + if (m_type & SpecCell) m_structure.makeTop(); else ASSERT(m_structure.isClear()); @@ -353,7 +353,7 @@ struct AbstractValue { bool isTop() const { - return m_type == PredictTop && m_structure.isTop(); + return m_type == SpecTop && m_structure.isTop(); } bool valueIsTop() const @@ -386,7 +386,7 @@ struct AbstractValue { } else m_structure.clear(); - m_type = predictionFromValue(value); + m_type = speculationFromValue(value); m_value = value; checkConsistency(); @@ -397,15 +397,15 @@ struct AbstractValue { m_structure.clear(); m_structure.add(structure); - m_type = predictionFromStructure(structure); + m_type = speculationFromStructure(structure); m_value = JSValue(); checkConsistency(); } - void set(PredictedType type) + void set(SpeculatedType type) { - if (type & PredictCell) + if (type & SpecCell) m_structure.makeTop(); else m_structure.clear(); @@ -435,7 +435,7 @@ struct AbstractValue { *this = other; result = !other.isClear(); } else { - result |= mergePrediction(m_type, other.m_type); + result |= mergeSpeculation(m_type, other.m_type); result |= m_structure.addAll(other.m_structure); if (m_value != other.m_value) { result |= !!m_value; @@ -447,11 +447,11 @@ struct AbstractValue { return result; } - void merge(PredictedType type) + void merge(SpeculatedType type) { - mergePrediction(m_type, type); + mergeSpeculation(m_type, type); - if (type & PredictCell) + if (type & SpecCell) m_structure.makeTop(); m_value = JSValue(); @@ -460,13 +460,13 @@ struct AbstractValue { void filter(const StructureSet& other) { - m_type &= other.predictionFromStructures(); + m_type &= other.speculationFromStructures(); m_structure.filter(other); // It's possible that prior to the above two statements we had (Foo, TOP), where - // Foo is a PredictedType that is disjoint with the passed StructureSet. In that + // 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 PredictedType needs to be fed back + // 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); @@ -476,9 +476,9 @@ struct AbstractValue { checkConsistency(); } - void filter(PredictedType type) + void filter(SpeculatedType type) { - if (type == PredictTop) + if (type == SpecTop) return; m_type &= type; @@ -499,11 +499,11 @@ struct AbstractValue { if (isTop()) return true; - if (mergePredictions(m_type, predictionFromValue(value)) != m_type) + if (mergeSpeculations(m_type, speculationFromValue(value)) != m_type) return false; if (value.isEmpty()) { - ASSERT(m_type & PredictEmpty); + ASSERT(m_type & SpecEmpty); return true; } @@ -511,7 +511,7 @@ struct AbstractValue { return true; if (!!value && value.isCell()) { - ASSERT(m_type & PredictCell); + ASSERT(m_type & SpecCell); return m_structure.contains(value.asCell()->structure()); } @@ -526,11 +526,11 @@ struct AbstractValue { if (!!m_value) return m_value == value; - if (mergePredictions(m_type, predictionFromValue(value)) != m_type) + if (mergeSpeculations(m_type, speculationFromValue(value)) != m_type) return false; if (value.isEmpty()) { - ASSERT(m_type & PredictEmpty); + ASSERT(m_type & SpecEmpty); return true; } @@ -538,7 +538,7 @@ struct AbstractValue { return true; if (!!value && value.isCell()) { - ASSERT(m_type & PredictCell); + ASSERT(m_type & SpecCell); return m_structure.contains(value.asCell()->structure()); } @@ -547,14 +547,14 @@ struct AbstractValue { void checkConsistency() const { - if (!(m_type & PredictCell)) + if (!(m_type & SpecCell)) ASSERT(m_structure.isClear()); if (isClear()) ASSERT(!m_value); if (!!m_value) - ASSERT(mergePredictions(m_type, predictionFromValue(m_value)) == m_type); + ASSERT(mergeSpeculations(m_type, speculationFromValue(m_value)) == m_type); // Note that it's possible for a prediction like (Final, []). This really means that // the value is bottom and that any code that uses the value is unreachable. But @@ -564,7 +564,7 @@ struct AbstractValue { void dump(FILE* out) const { - fprintf(out, "(%s, ", predictionToString(m_type)); + fprintf(out, "(%s, ", speculationToString(m_type)); m_structure.dump(out); if (!!m_value) fprintf(out, ", %s", m_value.description()); @@ -572,7 +572,7 @@ struct AbstractValue { } StructureAbstractValue m_structure; - PredictedType m_type; + SpeculatedType m_type; JSValue m_value; }; diff --git a/Source/JavaScriptCore/dfg/DFGArgumentPosition.h b/Source/JavaScriptCore/dfg/DFGArgumentPosition.h index ed447ff91..05d1cb048 100644 --- a/Source/JavaScriptCore/dfg/DFGArgumentPosition.h +++ b/Source/JavaScriptCore/dfg/DFGArgumentPosition.h @@ -28,14 +28,14 @@ #include "DFGDoubleFormatState.h" #include "DFGVariableAccessData.h" -#include "PredictedType.h" +#include "SpeculatedType.h" namespace JSC { namespace DFG { class ArgumentPosition { public: ArgumentPosition() - : m_prediction(PredictNone) + : m_prediction(SpecNone) , m_doubleFormatState(EmptyDoubleFormatState) { } @@ -49,7 +49,7 @@ public: { bool changed = false; for (unsigned i = 0; i < m_variables.size(); ++i) { - changed |= mergePrediction(m_prediction, m_variables[i]->argumentAwarePrediction()); + changed |= mergeSpeculation(m_prediction, m_variables[i]->argumentAwarePrediction()); changed |= mergeDoubleFormatState(m_doubleFormatState, m_variables[i]->doubleFormatState()); } if (!changed) @@ -62,8 +62,15 @@ public: return changed; } + SpeculatedType prediction() const { return m_prediction; } + DoubleFormatState doubleFormatState() const { return m_doubleFormatState; } + bool shouldUseDoubleFormat() const + { + return doubleFormatState() == UsingDoubleFormat; + } + private: - PredictedType m_prediction; + SpeculatedType m_prediction; DoubleFormatState m_doubleFormatState; Vector<VariableAccessData*, 2> m_variables; diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp index 48163a91b..28e686aef 100644 --- a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp @@ -170,9 +170,17 @@ public: break; } + case TearOffArguments: { + // Ignore arguments tear off, because it's only relevant if we actually + // need to create the arguments. + break; + } + case SetLocal: { Node& source = m_graph[node.child1()]; VariableAccessData* variableAccessData = node.variableAccessData(); + int argumentsRegister = + m_graph.uncheckedArgumentsRegisterFor(node.codeOrigin); if (source.op() != CreateArguments) { // Make sure that the source of the SetLocal knows that if it's // a variable that we think is aliased to the arguments, then it @@ -180,8 +188,28 @@ public: // aliasing. But not yet. observeBadArgumentsUse(node.child1()); - if (variableAccessData->isCaptured()) + if (variableAccessData->isCaptured()) { + // If this is an assignment to the arguments register, then + // pretend as if the arguments were created. We don't want to + // optimize code that explicitly assigns to the arguments, + // because that seems too ugly. + + // But, before getting rid of CreateArguments, we will have + // an assignment to the arguments registers with JSValue(). + // That's because CSE will refuse to get rid of the + // init_lazy_reg since it treats CreateArguments as reading + // local variables. That could be fixed, but it's easier to + // work around this here. + if (source.op() == JSConstant + && !source.valueOfJSConstant(codeBlock())) + break; + + if (argumentsRegister != InvalidVirtualRegister + && (variableAccessData->local() == argumentsRegister + || variableAccessData->local() == unmodifiedArgumentsRegister(argumentsRegister))) + m_createsArguments.add(node.codeOrigin.inlineCallFrame); break; + } // Make sure that if it's a variable that we think is aliased to // the arguments, that we know that it might actually not be. @@ -191,11 +219,9 @@ public: data.mergeCallContext(node.codeOrigin.inlineCallFrame); break; } - int argumentsRegister = - m_graph.uncheckedArgumentsRegisterFor(node.codeOrigin); - if (variableAccessData->local() == argumentsRegister - || variableAccessData->local() == - unmodifiedArgumentsRegister(argumentsRegister)) { + if (argumentsRegister != InvalidVirtualRegister + && (variableAccessData->local() == argumentsRegister + || variableAccessData->local() == unmodifiedArgumentsRegister(argumentsRegister))) { if (node.codeOrigin.inlineCallFrame == source.codeOrigin.inlineCallFrame) break; m_createsArguments.add(source.codeOrigin.inlineCallFrame); @@ -258,7 +284,7 @@ public: break; } - if (!isActionableArrayPrediction(m_graph[node.child1()].prediction()) + if (!isActionableArraySpeculation(m_graph[node.child1()].prediction()) || !m_graph[node.child2()].shouldSpeculateInteger()) { observeBadArgumentsUses(node); break; @@ -398,10 +424,25 @@ public: if (source.op() != CreateArguments) break; + if (m_createsArguments.contains(source.codeOrigin.inlineCallFrame)) + break; + VariableAccessData* variableAccessData = node.variableAccessData(); - if (variableAccessData->isCaptured()) + if (variableAccessData->isCaptured()) { + ASSERT(m_graph.argumentsRegisterFor(node.codeOrigin) == variableAccessData->local() + || unmodifiedArgumentsRegister(m_graph.argumentsRegisterFor(node.codeOrigin)) == variableAccessData->local()); + // The child of this store should really be the empty value. + Node emptyJSValue(JSConstant, node.codeOrigin, OpInfo(codeBlock()->addOrFindConstant(JSValue()))); + emptyJSValue.ref(); + NodeIndex emptyJSValueIndex = m_graph.size(); + m_graph.deref(node.child1()); + node.children.child1() = Edge(emptyJSValueIndex); + m_graph.append(emptyJSValue); + insertionSet.append(indexInBlock, emptyJSValueIndex); + changed = true; break; + } // If this is a store into a VariableAccessData* that is marked as // arguments aliasing for an InlineCallFrame* that does not create @@ -410,11 +451,8 @@ public: // things. Note also that the SetLocal should become dead as soon as // we replace all uses of this variable with GetMyArgumentsLength and // GetMyArgumentByVal. - if (m_argumentsAliasing.find(variableAccessData)->second.isValid() - && !m_createsArguments.contains(source.codeOrigin.inlineCallFrame)) { - changed |= variableAccessData->mergeIsArgumentsAlias(true); - break; - } + ASSERT(m_argumentsAliasing.find(variableAccessData)->second.isValid()); + changed |= variableAccessData->mergeIsArgumentsAlias(true); break; } @@ -439,7 +477,7 @@ public: || !m_graph[node.child2()].prediction()) break; - if (!isActionableArrayPrediction(m_graph[node.child1()].prediction()) + if (!isActionableArraySpeculation(m_graph[node.child1()].prediction()) || !m_graph[node.child2()].shouldSpeculateInteger()) break; @@ -487,19 +525,21 @@ public: node.setOp(GetMyArgumentsLength); changed = true; } - if (!node.codeOrigin.inlineCallFrame) + + CodeOrigin codeOrigin = node.codeOrigin; + if (!codeOrigin.inlineCallFrame) break; // We know exactly what this will return. But only after we have checked // that nobody has escaped our arguments. - Node check(CheckArgumentsNotCreated, node.codeOrigin); + Node check(CheckArgumentsNotCreated, codeOrigin); check.ref(); NodeIndex checkIndex = m_graph.size(); m_graph.append(check); insertionSet.append(indexInBlock, checkIndex); m_graph.convertToConstant( - nodeIndex, jsNumber(node.codeOrigin.inlineCallFrame->arguments.size() - 1)); + nodeIndex, jsNumber(codeOrigin.inlineCallFrame->arguments.size() - 1)); changed = true; break; } @@ -559,6 +599,16 @@ public: break; } + case TearOffArguments: { + if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame)) + continue; + + node.setOpAndDefaultFlags(Nop); + m_graph.clearAndDerefChild1(node); + node.setRefCount(0); + break; + } + default: break; } @@ -573,8 +623,6 @@ public: for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { NodeIndex nodeIndex = block->at(indexInBlock); Node& node = m_graph[nodeIndex]; - if (!node.shouldGenerate()) - continue; if (node.op() != CreateArguments) continue; // If this is a CreateArguments for an InlineCallFrame* that does @@ -583,14 +631,16 @@ public: // empty value) in DFG and arguments creation for OSR exit. if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame)) continue; - Node phantom(Phantom, node.codeOrigin); - phantom.children = node.children; - phantom.ref(); + if (node.shouldGenerate()) { + Node phantom(Phantom, node.codeOrigin); + phantom.children = node.children; + phantom.ref(); + NodeIndex phantomNodeIndex = m_graph.size(); + m_graph.append(phantom); + insertionSet.append(indexInBlock, phantomNodeIndex); + } node.setOpAndDefaultFlags(PhantomArguments); node.children.reset(); - NodeIndex phantomNodeIndex = m_graph.size(); - m_graph.append(phantom); - insertionSet.append(indexInBlock, phantomNodeIndex); } insertionSet.execute(*block); } @@ -622,7 +672,10 @@ private: } case GetLocal: { - if (child.local() == m_graph.uncheckedArgumentsRegisterFor(child.codeOrigin)) { + int argumentsRegister = m_graph.uncheckedArgumentsRegisterFor(child.codeOrigin); + if (argumentsRegister != InvalidVirtualRegister + && (child.local() == argumentsRegister + || child.local() == unmodifiedArgumentsRegister(argumentsRegister))) { m_createsArguments.add(child.codeOrigin.inlineCallFrame); break; } @@ -684,25 +737,31 @@ private: bool isOKToOptimize(Node& source) { + if (m_createsArguments.contains(source.codeOrigin.inlineCallFrame)) + return false; + switch (source.op()) { case GetLocal: { VariableAccessData* variableAccessData = source.variableAccessData(); - if (variableAccessData->isCaptured()) + if (variableAccessData->isCaptured()) { + int argumentsRegister = m_graph.uncheckedArgumentsRegisterFor(source.codeOrigin); + if (argumentsRegister == InvalidVirtualRegister) + break; + if (argumentsRegister == variableAccessData->local()) + return true; + if (unmodifiedArgumentsRegister(argumentsRegister) == variableAccessData->local()) + return true; break; + } ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->second; if (!data.isValid()) break; - if (m_createsArguments.contains(source.codeOrigin.inlineCallFrame)) - break; return true; } case CreateArguments: { - if (m_createsArguments.contains(source.codeOrigin.inlineCallFrame)) - break; - return true; } diff --git a/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h b/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h index 9087eec57..f86c15e65 100644 --- a/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h +++ b/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h @@ -115,21 +115,6 @@ public: #endif } - static Address addressForGlobalVar(GPRReg global, int32_t varNumber) - { - return Address(global, varNumber * sizeof(Register)); - } - - static Address tagForGlobalVar(GPRReg global, int32_t varNumber) - { - return Address(global, varNumber * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)); - } - - static Address payloadForGlobalVar(GPRReg global, int32_t varNumber) - { - return Address(global, varNumber * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)); - } - static Address addressFor(VirtualRegister virtualRegister) { return Address(GPRInfo::callFrameRegister, virtualRegister * sizeof(Register)); diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp index 358171029..317a08504 100644 --- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp +++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp @@ -93,7 +93,10 @@ private: // Handle setting the result of an intrinsic. void setIntrinsicResult(bool usesResult, int resultOperand, NodeIndex); // Handle intrinsic functions. Return true if it succeeded, false if we need to plant a call. - bool handleIntrinsic(bool usesResult, int resultOperand, Intrinsic, int registerOffset, int argumentCountIncludingThis, PredictedType prediction); + bool handleIntrinsic(bool usesResult, int resultOperand, Intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction); + void handleGetById( + int destinationOperand, SpeculatedType, NodeIndex base, unsigned identifierNumber, + const GetByIdStatus&); // Prepare to parse a block. void prepareToParseBlock(); // Parse a single basic block of bytecode instructions. @@ -109,7 +112,7 @@ private: template<PhiStackType stackType> void processPhiStack(); - void fixVariableAccessPredictions(); + void fixVariableAccessSpeculations(); // Add spill locations to nodes. void allocateVirtualRegisters(); @@ -159,17 +162,17 @@ private: setDirect(m_inlineStackTop->remapOperand(operand), value, setMode); } - NodeIndex injectLazyOperandPrediction(NodeIndex nodeIndex) + NodeIndex injectLazyOperandSpeculation(NodeIndex nodeIndex) { Node& node = m_graph[nodeIndex]; ASSERT(node.op() == GetLocal); ASSERT(node.codeOrigin.bytecodeIndex == m_currentIndex); - PredictedType prediction = + SpeculatedType prediction = m_inlineStackTop->m_lazyOperands.prediction( LazyOperandValueProfileKey(m_currentIndex, node.local())); #if DFG_ENABLE(DEBUG_VERBOSE) dataLog("Lazy operand [@%u, bc#%u, r%d] prediction: %s\n", - nodeIndex, m_currentIndex, node.local(), predictionToString(prediction)); + nodeIndex, m_currentIndex, node.local(), speculationToString(prediction)); #endif node.variableAccessData()->predict(prediction); return nodeIndex; @@ -192,7 +195,7 @@ private: if (flushChild.op() == Phi) { VariableAccessData* variableAccessData = flushChild.variableAccessData(); variableAccessData->mergeIsCaptured(isCaptured); - nodeIndex = injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(variableAccessData), nodeIndex)); + nodeIndex = injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(variableAccessData), nodeIndex)); m_currentBlock->variablesAtTail.local(operand) = nodeIndex; return nodeIndex; } @@ -213,7 +216,7 @@ private: if (nodePtr->op() == GetLocal) nodeIndex = nodePtr->child1().index(); - return injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(nodePtr->variableAccessData()), nodeIndex)); + return injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(nodePtr->variableAccessData()), nodeIndex)); } if (nodePtr->op() == GetLocal) @@ -230,7 +233,7 @@ private: NodeIndex phi = addToGraph(Phi, OpInfo(variableAccessData)); m_localPhiStack.append(PhiStackEntry(m_currentBlock, phi, operand)); - nodeIndex = injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(variableAccessData), phi)); + nodeIndex = injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(variableAccessData), phi)); m_currentBlock->variablesAtTail.local(operand) = nodeIndex; m_currentBlock->variablesAtHead.setLocalFirstTime(operand, nodeIndex); @@ -274,7 +277,7 @@ private: if (flushChild.op() == Phi) { VariableAccessData* variableAccessData = flushChild.variableAccessData(); variableAccessData->mergeIsCaptured(isCaptured); - nodeIndex = injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(variableAccessData), nodeIndex)); + nodeIndex = injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(variableAccessData), nodeIndex)); m_currentBlock->variablesAtTail.argument(argument) = nodeIndex; return nodeIndex; } @@ -290,7 +293,7 @@ private: // We're getting an argument in the first basic block; link // the GetLocal to the SetArgument. ASSERT(nodePtr->local() == static_cast<VirtualRegister>(operand)); - nodeIndex = injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(nodePtr->variableAccessData()), nodeIndex)); + nodeIndex = injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(nodePtr->variableAccessData()), nodeIndex)); m_currentBlock->variablesAtTail.argument(argument) = nodeIndex; return nodeIndex; } @@ -298,7 +301,7 @@ private: if (isCaptured) { if (nodePtr->op() == GetLocal) nodeIndex = nodePtr->child1().index(); - return injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(nodePtr->variableAccessData()), nodeIndex)); + return injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(nodePtr->variableAccessData()), nodeIndex)); } if (nodePtr->op() == GetLocal) @@ -312,7 +315,7 @@ private: NodeIndex phi = addToGraph(Phi, OpInfo(variableAccessData)); m_argumentPhiStack.append(PhiStackEntry(m_currentBlock, phi, argument)); - nodeIndex = injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(variableAccessData), phi)); + nodeIndex = injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(variableAccessData), phi)); m_currentBlock->variablesAtTail.argument(argument) = nodeIndex; m_currentBlock->variablesAtHead.setArgumentFirstTime(argument, nodeIndex); @@ -725,7 +728,7 @@ private: { Instruction* putInstruction = currentInstruction + OPCODE_LENGTH(op_call); - PredictedType prediction = PredictNone; + SpeculatedType prediction = SpecNone; if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) { m_currentProfilingIndex = m_currentIndex + OPCODE_LENGTH(op_call); prediction = getPrediction(); @@ -747,23 +750,44 @@ private: return call; } - PredictedType getPredictionWithoutOSRExit(NodeIndex nodeIndex, unsigned bytecodeIndex) + NodeIndex addStructureTransitionCheck(JSCell* object, Structure* structure) + { + // Add a weak JS constant for the object regardless, since the code should + // be jettisoned if the object ever dies. + NodeIndex objectIndex = cellConstant(object); + + if (object->structure() == structure && structure->transitionWatchpointSetIsStillValid()) { + addToGraph(StructureTransitionWatchpoint, OpInfo(structure), objectIndex); + return objectIndex; + } + + addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(structure)), objectIndex); + + return objectIndex; + } + + NodeIndex addStructureTransitionCheck(JSCell* object) + { + return addStructureTransitionCheck(object, object->structure()); + } + + SpeculatedType getPredictionWithoutOSRExit(NodeIndex nodeIndex, unsigned bytecodeIndex) { UNUSED_PARAM(nodeIndex); - PredictedType prediction = m_inlineStackTop->m_profiledBlock->valueProfilePredictionForBytecodeOffset(bytecodeIndex); + SpeculatedType prediction = m_inlineStackTop->m_profiledBlock->valueProfilePredictionForBytecodeOffset(bytecodeIndex); #if DFG_ENABLE(DEBUG_VERBOSE) - dataLog("Dynamic [@%u, bc#%u] prediction: %s\n", nodeIndex, bytecodeIndex, predictionToString(prediction)); + dataLog("Dynamic [@%u, bc#%u] prediction: %s\n", nodeIndex, bytecodeIndex, speculationToString(prediction)); #endif return prediction; } - PredictedType getPrediction(NodeIndex nodeIndex, unsigned bytecodeIndex) + SpeculatedType getPrediction(NodeIndex nodeIndex, unsigned bytecodeIndex) { - PredictedType prediction = getPredictionWithoutOSRExit(nodeIndex, bytecodeIndex); + SpeculatedType prediction = getPredictionWithoutOSRExit(nodeIndex, bytecodeIndex); - if (prediction == PredictNone) { + if (prediction == SpecNone) { // We have no information about what values this node generates. Give up // on executing this code, since we're likely to do more damage than good. addToGraph(ForceOSRExit); @@ -772,12 +796,12 @@ private: return prediction; } - PredictedType getPredictionWithoutOSRExit() + SpeculatedType getPredictionWithoutOSRExit() { return getPredictionWithoutOSRExit(m_graph.size(), m_currentProfilingIndex); } - PredictedType getPrediction() + SpeculatedType getPrediction() { return getPrediction(m_graph.size(), m_currentProfilingIndex); } @@ -1020,7 +1044,7 @@ private: VirtualRegister m_returnValue; - // Predictions about variable types collected from the profiled code block, + // Speculations about variable types collected from the profiled code block, // which are based on OSR exit profiles that past DFG compilatins of this // code block had gathered. LazyOperandValueProfileParser m_lazyOperands; @@ -1147,7 +1171,7 @@ void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentIn int resultOperand = 0; // make compiler happy unsigned nextOffset = m_currentIndex + OPCODE_LENGTH(op_call); Instruction* putInstruction = currentInstruction + OPCODE_LENGTH(op_call); - PredictedType prediction = PredictNone; + SpeculatedType prediction = SpecNone; if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) { resultOperand = putInstruction[1].u.operand; usesResult = true; @@ -1231,6 +1255,9 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c // Does the code block's size match the heuristics/requirements for being // an inline candidate? CodeBlock* profiledBlock = executable->profiledCodeBlockFor(kind); + if (!profiledBlock) + return false; + if (!mightInlineFunctionFor(profiledBlock, kind)) return false; @@ -1270,6 +1297,8 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c for (size_t i = 0; i < m_graph.m_blocks.size(); ++i) m_graph.m_blocks[i]->ensureLocals(newNumLocals); } + + size_t argumentPositionStart = m_graph.m_argumentPositions.size(); InlineStackEntry inlineStackEntry( this, codeBlock, profiledBlock, m_graph.m_blocks.size() - 1, @@ -1284,7 +1313,7 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c m_currentIndex = 0; m_currentProfilingIndex = 0; - addToGraph(InlineStart); + addToGraph(InlineStart, OpInfo(argumentPositionStart)); parseCodeBlock(); @@ -1418,7 +1447,7 @@ bool ByteCodeParser::handleMinMax(bool usesResult, int resultOperand, NodeType o // FIXME: We dead-code-eliminate unused Math intrinsics, but that's invalid because // they need to perform the ToNumber conversion, which can have side-effects. -bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrinsic intrinsic, int registerOffset, int argumentCountIncludingThis, PredictedType prediction) +bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrinsic intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction) { switch (intrinsic) { case AbsIntrinsic: { @@ -1482,7 +1511,7 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins return false; int thisOperand = registerOffset + argumentToOperand(0); - if (!(m_graph[get(thisOperand)].prediction() & PredictString)) + if (!(m_graph[get(thisOperand)].prediction() & SpecString)) return false; int indexOperand = registerOffset + argumentToOperand(1); @@ -1499,7 +1528,7 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins return false; int thisOperand = registerOffset + argumentToOperand(0); - if (!(m_graph[get(thisOperand)].prediction() & PredictString)) + if (!(m_graph[get(thisOperand)].prediction() & SpecString)) return false; int indexOperand = registerOffset + argumentToOperand(1); @@ -1538,6 +1567,80 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins } } +void ByteCodeParser::handleGetById( + int destinationOperand, SpeculatedType prediction, NodeIndex base, unsigned identifierNumber, + const GetByIdStatus& getByIdStatus) +{ + if (!getByIdStatus.isSimple() + || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) { + set(destinationOperand, + addToGraph( + getByIdStatus.makesCalls() ? GetByIdFlush : GetById, + OpInfo(identifierNumber), OpInfo(prediction), base)); + return; + } + + ASSERT(getByIdStatus.structureSet().size()); + + // The implementation of GetByOffset does not know to terminate speculative + // execution if it doesn't have a prediction, so we do it manually. + if (prediction == SpecNone) + addToGraph(ForceOSRExit); + + NodeIndex originalBaseForBaselineJIT = base; + + addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(getByIdStatus.structureSet())), base); + + bool useInlineStorage; + if (!getByIdStatus.chain().isEmpty()) { + Structure* currentStructure = getByIdStatus.structureSet().singletonStructure(); + JSObject* currentObject = 0; + for (unsigned i = 0; i < getByIdStatus.chain().size(); ++i) { + currentObject = asObject(currentStructure->prototypeForLookup(m_inlineStackTop->m_codeBlock)); + currentStructure = getByIdStatus.chain()[i]; + base = addStructureTransitionCheck(currentObject, currentStructure); + } + useInlineStorage = currentStructure->isUsingInlineStorage(); + } else + useInlineStorage = getByIdStatus.structureSet().allAreUsingInlinePropertyStorage(); + + // Unless we want bugs like https://bugs.webkit.org/show_bug.cgi?id=88783, we need to + // ensure that the base of the original get_by_id is kept alive until we're done with + // all of the speculations. We only insert the Phantom if there had been a CheckStructure + // on something other than the base following the CheckStructure on base, or if the + // access was compiled to a WeakJSConstant specific value, in which case we might not + // have any explicit use of the base at all. + if (getByIdStatus.specificValue() || originalBaseForBaselineJIT != base) + addToGraph(Phantom, originalBaseForBaselineJIT); + + if (getByIdStatus.specificValue()) { + ASSERT(getByIdStatus.specificValue().isCell()); + + set(destinationOperand, cellConstant(getByIdStatus.specificValue().asCell())); + return; + } + + NodeIndex propertyStorage; + size_t offsetOffset; + if (useInlineStorage) { + propertyStorage = base; + ASSERT(!(sizeof(JSObject) % sizeof(EncodedJSValue))); + offsetOffset = sizeof(JSObject) / sizeof(EncodedJSValue); + } else { + propertyStorage = addToGraph(GetPropertyStorage, base); + offsetOffset = 0; + } + set(destinationOperand, + addToGraph( + GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), + propertyStorage)); + + StorageAccessData storageAccessData; + storageAccessData.offset = getByIdStatus.offset() + offsetOffset; + storageAccessData.identifierNumber = identifierNumber; + m_graph.m_storageAccessData.append(storageAccessData); +} + void ByteCodeParser::prepareToParseBlock() { for (unsigned i = 0; i < m_constants.size(); ++i) @@ -1972,7 +2075,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) // === Property access operations === case op_get_by_val: { - PredictedType prediction = getPrediction(); + SpeculatedType prediction = getPrediction(); NodeIndex base = get(currentInstruction[2].u.operand); NodeIndex property = get(currentInstruction[3].u.operand); @@ -1997,7 +2100,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) m_currentProfilingIndex += OPCODE_LENGTH(op_method_check); Instruction* getInstruction = currentInstruction + OPCODE_LENGTH(op_method_check); - PredictedType prediction = getPrediction(); + SpeculatedType prediction = getPrediction(); ASSERT(interpreter->getOpcodeID(getInstruction->u.opcode) == op_get_by_id); @@ -2020,18 +2123,22 @@ bool ByteCodeParser::parseBlock(unsigned limit) // but the slow path (i.e. the normal get_by_id) never fired. addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(methodCallStatus.structure())), base); - if (methodCallStatus.needsPrototypeCheck()) - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(methodCallStatus.prototypeStructure())), cellConstant(methodCallStatus.prototype())); - + if (methodCallStatus.needsPrototypeCheck()) { + addStructureTransitionCheck( + methodCallStatus.prototype(), methodCallStatus.prototypeStructure()); + addToGraph(Phantom, base); + } set(getInstruction[1].u.operand, cellConstant(methodCallStatus.function())); - } else - set(getInstruction[1].u.operand, addToGraph(getByIdStatus.makesCalls() ? GetByIdFlush : GetById, OpInfo(identifier), OpInfo(prediction), base)); + } else { + handleGetById( + getInstruction[1].u.operand, prediction, base, identifier, getByIdStatus); + } m_currentIndex += OPCODE_LENGTH(op_method_check) + OPCODE_LENGTH(op_get_by_id); continue; } case op_get_scoped_var: { - PredictedType prediction = getPrediction(); + SpeculatedType prediction = getPrediction(); int dst = currentInstruction[1].u.operand; int slot = currentInstruction[2].u.operand; int depth = currentInstruction[3].u.operand; @@ -2049,7 +2156,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) NEXT_OPCODE(op_put_scoped_var); } case op_get_by_id: { - PredictedType prediction = getPredictionWithoutOSRExit(); + SpeculatedType prediction = getPredictionWithoutOSRExit(); NodeIndex base = get(currentInstruction[2].u.operand); unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand]; @@ -2058,34 +2165,8 @@ bool ByteCodeParser::parseBlock(unsigned limit) GetByIdStatus getByIdStatus = GetByIdStatus::computeFor( m_inlineStackTop->m_profiledBlock, m_currentIndex, identifier); - if (getByIdStatus.isSimpleDirect() - && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) { - ASSERT(getByIdStatus.structureSet().size()); - - // The implementation of GetByOffset does not know to terminate speculative - // execution if it doesn't have a prediction, so we do it manually. - if (prediction == PredictNone) - addToGraph(ForceOSRExit); - - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(getByIdStatus.structureSet())), base); - NodeIndex propertyStorage; - size_t offsetOffset; - if (getByIdStatus.structureSet().allAreUsingInlinePropertyStorage()) { - propertyStorage = base; - ASSERT(!(sizeof(JSObject) % sizeof(EncodedJSValue))); - offsetOffset = sizeof(JSObject) / sizeof(EncodedJSValue); - } else { - propertyStorage = addToGraph(GetPropertyStorage, base); - offsetOffset = 0; - } - set(currentInstruction[1].u.operand, addToGraph(GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), propertyStorage)); - - StorageAccessData storageAccessData; - storageAccessData.offset = getByIdStatus.offset() + offsetOffset; - storageAccessData.identifierNumber = identifierNumber; - m_graph.m_storageAccessData.append(storageAccessData); - } else - set(currentInstruction[1].u.operand, addToGraph(getByIdStatus.makesCalls() ? GetByIdFlush : GetById, OpInfo(identifierNumber), OpInfo(prediction), base)); + handleGetById( + currentInstruction[1].u.operand, prediction, base, identifierNumber, getByIdStatus); NEXT_OPCODE(op_get_by_id); } @@ -2134,23 +2215,20 @@ bool ByteCodeParser::parseBlock(unsigned limit) addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(putByIdStatus.oldStructure())), base); if (!direct) { - if (!putByIdStatus.oldStructure()->storedPrototype().isNull()) - addToGraph( - CheckStructure, - OpInfo(m_graph.addStructureSet(putByIdStatus.oldStructure()->storedPrototype().asCell()->structure())), - cellConstant(putByIdStatus.oldStructure()->storedPrototype().asCell())); + if (!putByIdStatus.oldStructure()->storedPrototype().isNull()) { + addStructureTransitionCheck( + putByIdStatus.oldStructure()->storedPrototype().asCell()); + } for (WriteBarrier<Structure>* it = putByIdStatus.structureChain()->head(); *it; ++it) { JSValue prototype = (*it)->storedPrototype(); if (prototype.isNull()) continue; ASSERT(prototype.isCell()); - addToGraph( - CheckStructure, - OpInfo(m_graph.addStructureSet(prototype.asCell()->structure())), - cellConstant(prototype.asCell())); + addStructureTransitionCheck(prototype.asCell()); } } + ASSERT(putByIdStatus.oldStructure()->transitionWatchpointSetHasBeenInvalidated()); addToGraph( PutStructure, OpInfo( @@ -2192,19 +2270,94 @@ bool ByteCodeParser::parseBlock(unsigned limit) } case op_get_global_var: { - PredictedType prediction = getPrediction(); + SpeculatedType prediction = getPrediction(); - NodeIndex getGlobalVar = addToGraph(GetGlobalVar, OpInfo(currentInstruction[2].u.operand), OpInfo(prediction)); + JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject(); + + NodeIndex getGlobalVar = addToGraph( + GetGlobalVar, + OpInfo(globalObject->assertRegisterIsInThisObject(currentInstruction[2].u.registerPointer)), + OpInfo(prediction)); set(currentInstruction[1].u.operand, getGlobalVar); NEXT_OPCODE(op_get_global_var); } + + case op_get_global_var_watchable: { + SpeculatedType prediction = getPrediction(); + + JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject(); + + unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand]; + Identifier identifier = m_codeBlock->identifier(identifierNumber); + SymbolTableEntry entry = globalObject->symbolTable().get(identifier.impl()); + if (!entry.couldBeWatched()) { + NodeIndex getGlobalVar = addToGraph( + GetGlobalVar, + OpInfo(globalObject->assertRegisterIsInThisObject(currentInstruction[2].u.registerPointer)), + OpInfo(prediction)); + set(currentInstruction[1].u.operand, getGlobalVar); + NEXT_OPCODE(op_get_global_var_watchable); + } + + // The watchpoint is still intact! This means that we will get notified if the + // current value in the global variable changes. So, we can inline that value. + // Moreover, currently we can assume that this value is a JSFunction*, which + // implies that it's a cell. This simplifies things, since in general we'd have + // to use a JSConstant for non-cells and a WeakJSConstant for cells. So instead + // of having both cases we just assert that the value is a cell. + + // NB. If it wasn't for CSE, GlobalVarWatchpoint would have no need for the + // register pointer. But CSE tracks effects on global variables by comparing + // register pointers. Because CSE executes multiple times while the backend + // executes once, we use the following performance trade-off: + // - The node refers directly to the register pointer to make CSE super cheap. + // - To perform backend code generation, the node only contains the identifier + // number, from which it is possible to get (via a few average-time O(1) + // lookups) to the WatchpointSet. + + addToGraph( + GlobalVarWatchpoint, + OpInfo(globalObject->assertRegisterIsInThisObject(currentInstruction[2].u.registerPointer)), + OpInfo(identifierNumber)); + + JSValue specificValue = globalObject->registerAt(entry.getIndex()).get(); + ASSERT(specificValue.isCell()); + set(currentInstruction[1].u.operand, cellConstant(specificValue.asCell())); + + NEXT_OPCODE(op_get_global_var_watchable); + } case op_put_global_var: { NodeIndex value = get(currentInstruction[2].u.operand); - addToGraph(PutGlobalVar, OpInfo(currentInstruction[1].u.operand), value); + addToGraph( + PutGlobalVar, + OpInfo(m_inlineStackTop->m_codeBlock->globalObject()->assertRegisterIsInThisObject(currentInstruction[1].u.registerPointer)), + value); NEXT_OPCODE(op_put_global_var); } + case op_put_global_var_check: { + NodeIndex value = get(currentInstruction[2].u.operand); + CodeBlock* codeBlock = m_inlineStackTop->m_codeBlock; + JSGlobalObject* globalObject = codeBlock->globalObject(); + unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[4].u.operand]; + Identifier identifier = m_codeBlock->identifier(identifierNumber); + SymbolTableEntry entry = globalObject->symbolTable().get(identifier.impl()); + if (!entry.couldBeWatched()) { + addToGraph( + PutGlobalVar, + OpInfo(globalObject->assertRegisterIsInThisObject(currentInstruction[1].u.registerPointer)), + value); + NEXT_OPCODE(op_put_global_var_check); + } + addToGraph( + PutGlobalVarCheck, + OpInfo(codeBlock->globalObject()->assertRegisterIsInThisObject(currentInstruction[1].u.registerPointer)), + OpInfo(identifierNumber), + value); + NEXT_OPCODE(op_put_global_var_check); + } + // === Block terminators. === case op_jmp: { @@ -2433,7 +2586,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) Instruction* putInstruction = currentInstruction + OPCODE_LENGTH(op_call_varargs); - PredictedType prediction = PredictNone; + SpeculatedType prediction = SpecNone; if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) { m_currentProfilingIndex = m_currentIndex + OPCODE_LENGTH(op_call_varargs); prediction = getPrediction(); @@ -2471,7 +2624,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) LAST_OPCODE(op_jneq_ptr); case op_resolve: { - PredictedType prediction = getPrediction(); + SpeculatedType prediction = getPrediction(); unsigned identifier = m_inlineStackTop->m_identifierRemap[currentInstruction[2].u.operand]; @@ -2482,7 +2635,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) } case op_resolve_base: { - PredictedType prediction = getPrediction(); + SpeculatedType prediction = getPrediction(); unsigned identifier = m_inlineStackTop->m_identifierRemap[currentInstruction[2].u.operand]; @@ -2493,7 +2646,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) } case op_resolve_global: { - PredictedType prediction = getPrediction(); + SpeculatedType prediction = getPrediction(); NodeIndex resolve = addToGraph(ResolveGlobal, OpInfo(m_graph.m_resolveGlobalData.size()), OpInfo(prediction)); m_graph.m_resolveGlobalData.append(ResolveGlobalData()); @@ -2747,7 +2900,7 @@ void ByteCodeParser::processPhiStack() } } -void ByteCodeParser::fixVariableAccessPredictions() +void ByteCodeParser::fixVariableAccessSpeculations() { for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) { VariableAccessData* data = &m_graph.m_variableAccessData[i]; @@ -2843,7 +2996,7 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry( , m_caller(byteCodeParser->m_inlineStackTop) { m_argumentPositions.resize(argumentCountIncludingThis); - for (unsigned i = argumentCountIncludingThis; i--;) { + for (int i = 0; i < argumentCountIncludingThis; ++i) { byteCodeParser->m_graph.m_argumentPositions.append(ArgumentPosition()); ArgumentPosition* argumentPosition = &byteCodeParser->m_graph.m_argumentPositions.last(); m_argumentPositions[i] = argumentPosition; @@ -3073,7 +3226,7 @@ bool ByteCodeParser::parse() m_graph.m_blocks[blockIndex].clear(); } - fixVariableAccessPredictions(); + fixVariableAccessSpeculations(); m_graph.m_preservedVars = m_preservedVars; m_graph.m_localVars = m_numLocals; diff --git a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h index dc3af636e..4cacd45c1 100644 --- a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h +++ b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h @@ -94,6 +94,12 @@ public: addCallArgument(arg1); addCallArgument(arg2); } + + ALWAYS_INLINE void setupArguments(TrustedImmPtr arg1) + { + resetCallArguments(); + addCallArgument(arg1); + } ALWAYS_INLINE void setupArgumentsExecState() { @@ -216,6 +222,15 @@ public: addCallArgument(arg4); } + ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImmPtr arg2, GPRReg arg3) + { + resetCallArguments(); + addCallArgument(GPRInfo::callFrameRegister); + addCallArgument(arg1); + addCallArgument(arg2); + addCallArgument(arg3); + } + ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, TrustedImmPtr arg4) { resetCallArguments(); @@ -424,6 +439,11 @@ public: { setupTwoStubArgs<GPRInfo::argumentGPR0, GPRInfo::argumentGPR1>(arg1, arg2); } + + ALWAYS_INLINE void setupArguments(TrustedImmPtr arg1) + { + move(arg1, GPRInfo::argumentGPR0); + } ALWAYS_INLINE void setupArgumentsExecState() { @@ -554,6 +574,14 @@ public: move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); } + ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImmPtr arg2, GPRReg arg3) + { + move(arg3, GPRInfo::argumentGPR3); + move(arg1, GPRInfo::argumentGPR1); + move(arg2, GPRInfo::argumentGPR2); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + } + ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, GPRReg arg2, TrustedImm32 arg3) { move(arg2, GPRInfo::argumentGPR2); diff --git a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp index 0f0a22562..161f51e30 100644 --- a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp @@ -288,7 +288,7 @@ private: if (child.op() != GetLocal) return; #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) - dataLog(" Considering GetLocal at @%u.\n", edge.index()); + dataLog(" Considering GetLocal at @%u, local r%d.\n", edge.index(), child.local()); #endif if (child.variableAccessData()->isCaptured()) { #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) @@ -302,6 +302,10 @@ private: #endif ASSERT(originalNodeIndex != NoNode); Node* originalNode = &m_graph[originalNodeIndex]; +#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) + dataLog(" Original has local r%d.\n", originalNode->local()); +#endif + ASSERT(child.local() == originalNode->local()); if (changeRef) ASSERT(originalNode->shouldGenerate()); // Possibilities: @@ -389,7 +393,7 @@ private: if (myNode.op() == GetLocal) myNodeIndex = myNode.child1().index(); for (unsigned j = 0; j < AdjacencyList::Size; ++j) - removePotentiallyDeadPhiReference(myNodeIndex, phiNode, j); + removePotentiallyDeadPhiReference(myNodeIndex, phiNode, j, sourceBlock->isReachable); #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLog("\n"); #endif @@ -414,14 +418,14 @@ private: fixPhis(blockIndex, jettisonedBlockIndex); } - void removePotentiallyDeadPhiReference(NodeIndex myNodeIndex, Node& phiNode, unsigned edgeIndex) + void removePotentiallyDeadPhiReference(NodeIndex myNodeIndex, Node& phiNode, unsigned edgeIndex, bool changeRef) { if (phiNode.children.child(edgeIndex).indexUnchecked() != myNodeIndex) return; #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLog(" Removing reference at child %u.", edgeIndex); #endif - if (phiNode.shouldGenerate()) + if (changeRef && phiNode.shouldGenerate()) m_graph.deref(myNodeIndex); phiNode.children.removeEdgeFromBag(edgeIndex); } @@ -600,6 +604,8 @@ private: NodeIndex nodeIndex = secondBlock->at(i); Node& node = m_graph[nodeIndex]; + bool childrenAlreadyFixed = false; + switch (node.op()) { case Phantom: { if (!node.child1()) @@ -611,8 +617,12 @@ private: NodeIndex setLocalIndex = firstBlock->variablesAtTail.operand(possibleLocalOp.local()); Node& setLocal = m_graph[setLocalIndex]; - if (setLocal.op() == SetLocal) + if (setLocal.op() == SetLocal) { m_graph.changeEdge(node.children.child1(), setLocal.child1()); + ASSERT(!node.child2()); + ASSERT(!node.child3()); + childrenAlreadyFixed = true; + } } break; } @@ -632,6 +642,19 @@ private: NodeIndex atFirstIndex = firstBlock->variablesAtTail.operand(node.local()); m_graph.changeEdge(node.children.child1(), Edge(skipGetLocal(atFirstIndex)), node.shouldGenerate()); + childrenAlreadyFixed = true; + + if (node.op() != GetLocal) + break; + + NodeIndex atFirstHeadIndex = firstBlock->variablesAtHead.operand(node.local()); + if (atFirstHeadIndex == NoNode) + break; + + if (m_graph[atFirstHeadIndex].op() != Phi) + break; + + firstBlock->variablesAtHead.operand(node.local()) = nodeIndex; break; } @@ -639,20 +662,22 @@ private: break; } - bool changeRef = node.shouldGenerate(); + if (!childrenAlreadyFixed) { + bool changeRef = node.shouldGenerate(); - // If the child is a GetLocal, then we might like to fix it. - if (node.flags() & NodeHasVarArgs) { - for (unsigned childIdx = node.firstChild(); - childIdx < node.firstChild() + node.numChildren(); - ++childIdx) - fixPossibleGetLocal(firstBlock, m_graph.m_varArgChildren[childIdx], changeRef); - } else if (!!node.child1()) { - fixPossibleGetLocal(firstBlock, node.children.child1(), changeRef); - if (!!node.child2()) { - fixPossibleGetLocal(firstBlock, node.children.child2(), changeRef); - if (!!node.child3()) - fixPossibleGetLocal(firstBlock, node.children.child3(), changeRef); + // If the child is a GetLocal, then we might like to fix it. + if (node.flags() & NodeHasVarArgs) { + for (unsigned childIdx = node.firstChild(); + childIdx < node.firstChild() + node.numChildren(); + ++childIdx) + fixPossibleGetLocal(firstBlock, m_graph.m_varArgChildren[childIdx], changeRef); + } else if (!!node.child1()) { + fixPossibleGetLocal(firstBlock, node.children.child1(), changeRef); + if (!!node.child2()) { + fixPossibleGetLocal(firstBlock, node.children.child2(), changeRef); + if (!!node.child3()) + fixPossibleGetLocal(firstBlock, node.children.child3(), changeRef); + } } } diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp index 31488cb1c..a362e6e97 100644 --- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp @@ -48,9 +48,10 @@ public: bool run() { + m_changed = false; for (unsigned block = 0; block < m_graph.m_blocks.size(); ++block) performBlockCSE(m_graph.m_blocks[block].get()); - return true; // Maybe we'll need to make this reason about whether it changed the graph in an actionable way? + return m_changed; } private: @@ -193,18 +194,18 @@ private: return NoNode; } - NodeIndex globalVarLoadElimination(unsigned varNumber, JSGlobalObject* globalObject) + NodeIndex globalVarLoadElimination(WriteBarrier<Unknown>* registerPointer) { for (unsigned i = m_indexInBlock; i--;) { NodeIndex index = m_currentBlock->at(i); Node& node = m_graph[index]; switch (node.op()) { case GetGlobalVar: - if (node.varNumber() == varNumber && codeBlock()->globalObjectFor(node.codeOrigin) == globalObject) + if (node.registerPointer() == registerPointer) return index; break; case PutGlobalVar: - if (node.varNumber() == varNumber && codeBlock()->globalObjectFor(node.codeOrigin) == globalObject) + if (node.registerPointer() == registerPointer) return node.child1().index(); break; default: @@ -216,7 +217,30 @@ private: return NoNode; } - NodeIndex globalVarStoreElimination(unsigned varNumber, JSGlobalObject* globalObject) + bool globalVarWatchpointElimination(WriteBarrier<Unknown>* registerPointer) + { + for (unsigned i = m_indexInBlock; i--;) { + NodeIndex index = m_currentBlock->at(i); + Node& node = m_graph[index]; + switch (node.op()) { + case GlobalVarWatchpoint: + if (node.registerPointer() == registerPointer) + return true; + break; + case PutGlobalVar: + if (node.registerPointer() == registerPointer) + return false; + break; + default: + break; + } + if (m_graph.clobbersWorld(index)) + break; + } + return false; + } + + NodeIndex globalVarStoreElimination(WriteBarrier<Unknown>* registerPointer) { for (unsigned i = m_indexInBlock; i--;) { NodeIndex index = m_currentBlock->at(i); @@ -225,12 +249,13 @@ private: continue; switch (node.op()) { case PutGlobalVar: - if (node.varNumber() == varNumber && codeBlock()->globalObjectFor(node.codeOrigin) == globalObject) + case PutGlobalVarCheck: + if (node.registerPointer() == registerPointer) return index; break; case GetGlobalVar: - if (node.varNumber() == varNumber && codeBlock()->globalObjectFor(node.codeOrigin) == globalObject) + if (node.registerPointer() == registerPointer) return NoNode; break; @@ -316,6 +341,12 @@ private: return true; break; + case StructureTransitionWatchpoint: + if (node.child1() == child1 + && structureSet.contains(node.structure())) + return true; + break; + case PutStructure: if (node.child1() == child1 && structureSet.contains(node.structureTransitionData().newStructure)) @@ -347,6 +378,53 @@ private: return false; } + bool structureTransitionWatchpointElimination(Structure* structure, NodeIndex child1) + { + for (unsigned i = m_indexInBlock; i--;) { + NodeIndex index = m_currentBlock->at(i); + if (index == child1) + break; + + Node& node = m_graph[index]; + switch (node.op()) { + case CheckStructure: + if (node.child1() == child1 + && node.structureSet().containsOnly(structure)) + return true; + break; + + case PutStructure: + ASSERT(node.structureTransitionData().previousStructure != structure); + break; + + case PutByOffset: + // Setting a property cannot change the structure. + break; + + case PutByVal: + case PutByValAlias: + if (m_graph.byValIsPure(node)) { + // If PutByVal speculates that it's accessing an array with an + // integer index, then it's impossible for it to cause a structure + // change. + break; + } + return false; + + case StructureTransitionWatchpoint: + if (node.structure() == structure && node.child1() == child1) + return true; + break; + + default: + if (m_graph.clobbersWorld(index)) + return false; + break; + } + } + return false; + } + NodeIndex putStructureStoreElimination(NodeIndex child1) { for (unsigned i = m_indexInBlock; i--;) { @@ -538,8 +616,8 @@ private: Node& node = m_graph[index]; switch (node.op()) { case GetIndexedPropertyStorage: { - PredictedType basePrediction = m_graph[node.child2()].prediction(); - bool nodeHasIntegerIndexPrediction = !(!(basePrediction & PredictInt32) && basePrediction); + SpeculatedType basePrediction = m_graph[node.child2()].prediction(); + bool nodeHasIntegerIndexPrediction = !(!(basePrediction & SpecInt32) && basePrediction); if (node.child1() == child1 && hasIntegerIndexPrediction == nodeHasIntegerIndexPrediction) return index; break; @@ -556,7 +634,7 @@ private: break; case PutByVal: - if (isFixedIndexedStorageObjectPrediction(m_graph[node.child1()].prediction()) && m_graph.byValIsPure(node)) + if (isFixedIndexedStorageObjectSpeculation(m_graph[node.child1()].prediction()) && m_graph.byValIsPure(node)) break; return NoNode; @@ -619,9 +697,22 @@ private: return NoNode; } - // This returns the Flush node that is keeping a SetLocal alive. - NodeIndex setLocalStoreElimination(VirtualRegister local, NodeIndex expectedNodeIndex) + struct SetLocalStoreEliminationResult { + SetLocalStoreEliminationResult() + : mayBeAccessed(false) + , mayExit(false) + , mayClobberWorld(false) + { + } + + bool mayBeAccessed; + bool mayExit; + bool mayClobberWorld; + }; + SetLocalStoreEliminationResult setLocalStoreElimination( + VirtualRegister local, NodeIndex expectedNodeIndex) { + SetLocalStoreEliminationResult result; for (unsigned i = m_indexInBlock; i--;) { NodeIndex index = m_currentBlock->at(i); Node& node = m_graph[index]; @@ -631,46 +722,67 @@ private: case GetLocal: case Flush: if (node.local() == local) - return NoNode; + result.mayBeAccessed = true; break; case GetLocalUnlinked: if (node.unlinkedLocal() == local) - return NoNode; + result.mayBeAccessed = true; break; case SetLocal: { if (node.local() != local) break; if (index != expectedNodeIndex) - return NoNode; + result.mayBeAccessed = true; if (m_graph[index].refCount() > 1) - return NoNode; - return index; + result.mayBeAccessed = true; + return result; } case GetScopeChain: if (m_graph.uncheckedActivationRegisterFor(node.codeOrigin) == local) - return NoNode; + result.mayBeAccessed = true; + break; + + case CheckArgumentsNotCreated: + case GetMyArgumentsLength: + case GetMyArgumentsLengthSafe: + if (m_graph.uncheckedArgumentsRegisterFor(node.codeOrigin) == local) + result.mayBeAccessed = true; + break; + + case GetMyArgumentByVal: + case GetMyArgumentByValSafe: + result.mayBeAccessed = true; + break; + + case GetByVal: + // If this is accessing arguments then it's potentially accessing locals. + if (m_graph[node.child1()].shouldSpeculateArguments()) + result.mayBeAccessed = true; break; + case CreateArguments: case TearOffActivation: case TearOffArguments: // If an activation is being torn off then it means that captured variables // are live. We could be clever here and check if the local qualifies as an // argument register. But that seems like it would buy us very little since // any kind of tear offs are rare to begin with. - return NoNode; + result.mayBeAccessed = true; + break; default: - if (m_graph.clobbersWorld(index)) - return NoNode; break; } - if (node.canExit()) - return NoNode; + result.mayExit |= node.canExit(); + result.mayClobberWorld |= m_graph.clobbersWorld(index); } - return NoNode; + ASSERT_NOT_REACHED(); + // Be safe in release mode. + result.mayBeAccessed = true; + return result; } void performSubstitution(Edge& child, bool addRef = true) @@ -848,35 +960,64 @@ private: m_graph.ref(phiIndex); } } + m_changed = true; break; } case GetLocalUnlinked: { NodeIndex relevantLocalOpIgnored; - setReplacement(getLocalLoadElimination(node.unlinkedLocal(), relevantLocalOpIgnored)); + m_changed |= setReplacement(getLocalLoadElimination(node.unlinkedLocal(), relevantLocalOpIgnored)); break; } case Flush: { - if (m_fixpointState == FixpointNotConverged) - break; VariableAccessData* variableAccessData = node.variableAccessData(); - if (!variableAccessData->isCaptured()) - break; VirtualRegister local = variableAccessData->local(); - NodeIndex replacementIndex = setLocalStoreElimination(local, node.child1().index()); - if (replacementIndex == NoNode) - break; + NodeIndex replacementIndex = node.child1().index(); Node& replacement = m_graph[replacementIndex]; + if (replacement.op() != SetLocal) + break; + ASSERT(replacement.variableAccessData() == variableAccessData); + // FIXME: We should be able to remove SetLocals that can exit; we just need + // to replace them with appropriate type checks. + if (m_fixpointState == FixpointNotConverged) { + // Need to be conservative at this time; if the SetLocal has any chance of performing + // any speculations then we cannot do anything. + if (variableAccessData->isCaptured()) { + // Captured SetLocals never speculate and hence never exit. + } else { + if (variableAccessData->shouldUseDoubleFormat()) + break; + SpeculatedType prediction = variableAccessData->argumentAwarePrediction(); + if (isInt32Speculation(prediction)) + break; + if (isArraySpeculation(prediction)) + break; + if (isBooleanSpeculation(prediction)) + break; + } + } else { + if (replacement.canExit()) + break; + } + SetLocalStoreEliminationResult result = + setLocalStoreElimination(local, replacementIndex); + if (result.mayBeAccessed || result.mayClobberWorld) + break; ASSERT(replacement.op() == SetLocal); ASSERT(replacement.refCount() == 1); ASSERT(replacement.shouldGenerate()); + // FIXME: Investigate using mayExit as a further optimization. node.setOpAndDefaultFlags(Phantom); NodeIndex dataNodeIndex = replacement.child1().index(); ASSERT(m_graph[dataNodeIndex].hasResult()); m_graph.clearAndDerefChild1(node); node.children.child1() = Edge(dataNodeIndex); m_graph.ref(dataNodeIndex); + NodeIndex oldTailIndex = m_currentBlock->variablesAtTail.operand(local); + if (oldTailIndex == m_compileIndex) + m_currentBlock->variablesAtTail.operand(local) = replacementIndex; + m_changed = true; break; } @@ -918,13 +1059,19 @@ private: // Finally handle heap accesses. These are not quite pure, but we can still // optimize them provided that some subtle conditions are met. case GetGlobalVar: - setReplacement(globalVarLoadElimination(node.varNumber(), codeBlock()->globalObjectFor(node.codeOrigin))); + setReplacement(globalVarLoadElimination(node.registerPointer())); + break; + + case GlobalVarWatchpoint: + if (globalVarWatchpointElimination(node.registerPointer())) + eliminate(); break; case PutGlobalVar: + case PutGlobalVarCheck: if (m_fixpointState == FixpointNotConverged) break; - eliminate(globalVarStoreElimination(node.varNumber(), codeBlock()->globalObjectFor(node.codeOrigin))); + eliminate(globalVarStoreElimination(node.registerPointer())); break; case GetByVal: @@ -944,6 +1091,11 @@ private: eliminate(); break; + case StructureTransitionWatchpoint: + if (structureTransitionWatchpointElimination(node.structure(), node.child1().index())) + eliminate(); + break; + case PutStructure: if (m_fixpointState == FixpointNotConverged) break; @@ -956,8 +1108,8 @@ private: break; case GetIndexedPropertyStorage: { - PredictedType basePrediction = m_graph[node.child2()].prediction(); - bool nodeHasIntegerIndexPrediction = !(!(basePrediction & PredictInt32) && basePrediction); + SpeculatedType basePrediction = m_graph[node.child2()].prediction(); + bool nodeHasIntegerIndexPrediction = !(!(basePrediction & SpecInt32) && basePrediction); setReplacement(getIndexedPropertyStorageLoadElimination(node.child1().index(), nodeHasIntegerIndexPrediction)); break; } @@ -1010,6 +1162,7 @@ private: Vector<NodeIndex, 16> m_replacements; FixedArray<unsigned, LastNodeType> m_lastSeen; OptimizationFixpointState m_fixpointState; + bool m_changed; // Only tracks changes that have a substantive effect on other optimizations. }; bool performCSE(Graph& graph, OptimizationFixpointState fixpointState) diff --git a/Source/JavaScriptCore/dfg/DFGCapabilities.h b/Source/JavaScriptCore/dfg/DFGCapabilities.h index 694e886ee..027b0f78b 100644 --- a/Source/JavaScriptCore/dfg/DFGCapabilities.h +++ b/Source/JavaScriptCore/dfg/DFGCapabilities.h @@ -123,7 +123,9 @@ inline CapabilityLevel canCompileOpcode(OpcodeID opcodeID, CodeBlock*, Instructi case op_put_by_id_transition_direct: case op_put_by_id_transition_normal: case op_get_global_var: + case op_get_global_var_watchable: case op_put_global_var: + case op_put_global_var_check: case op_jmp: case op_loop: case op_jtrue: diff --git a/Source/JavaScriptCore/dfg/DFGCommon.h b/Source/JavaScriptCore/dfg/DFGCommon.h index b2e3bb4ee..fce76c68c 100644 --- a/Source/JavaScriptCore/dfg/DFGCommon.h +++ b/Source/JavaScriptCore/dfg/DFGCommon.h @@ -55,6 +55,8 @@ #else #define DFG_ENABLE_VALIDATION 0 #endif +// Enable validation on completion of each phase. +#define DFG_ENABLE_PER_PHASE_VALIDATION 0 // Consistency check contents compiler data structures. #define DFG_ENABLE_CONSISTENCY_CHECK 0 // Emit a breakpoint into the head of every generated function, to aid debugging in GDB. diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp index 1e75ddea1..9e6720c80 100644 --- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp @@ -56,15 +56,44 @@ public: continue; if (!block->cfaFoundConstants) continue; +#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) + dataLog("Constant folding considering Block #%u.\n", blockIndex); +#endif state.beginBasicBlock(block); for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { if (!state.isValid()) break; - state.execute(indexInBlock); NodeIndex nodeIndex = block->at(indexInBlock); Node& node = m_graph[nodeIndex]; + + bool eliminated = false; + + switch (node.op()) { + case CheckArgumentsNotCreated: { + if (!isEmptySpeculation( + state.variables().operand( + m_graph.argumentsRegisterFor(node.codeOrigin)).m_type)) + break; + ASSERT(node.refCount() == 1); + node.setOpAndDefaultFlags(Phantom); + eliminated = true; + break; + } + + // FIXME: This would be a great place to remove CheckStructure's. + + default: + break; + } + + if (eliminated) { + changed = true; + continue; + } + + state.execute(indexInBlock); if (!node.shouldGenerate() - || m_graph.clobbersWorld(node) + || state.didClobber() || node.hasConstant()) continue; JSValue value = state.forNode(nodeIndex).value(); @@ -74,11 +103,9 @@ public: Node phantom(Phantom, node.codeOrigin); if (node.op() == GetLocal) { - ASSERT(m_graph[node.child1()].op() == Phi); - ASSERT(!m_graph[node.child1()].hasResult()); - NodeIndex previousLocalAccess = NoNode; - if (block->variablesAtHead.operand(node.local()) == nodeIndex) { + if (block->variablesAtHead.operand(node.local()) == nodeIndex + && m_graph[node.child1()].op() == Phi) { // We expect this to be the common case. ASSERT(block->isInPhis(node.child1().index())); previousLocalAccess = node.child1().index(); @@ -86,7 +113,7 @@ public: } else { ASSERT(indexInBlock > 0); // Must search for the previous access to this local. - for (BlockIndex subIndexInBlock = indexInBlock - 1; subIndexInBlock--;) { + for (BlockIndex subIndexInBlock = indexInBlock; subIndexInBlock--;) { NodeIndex subNodeIndex = block->at(subIndexInBlock); Node& subNode = m_graph[subNodeIndex]; if (!subNode.shouldGenerate()) @@ -97,13 +124,6 @@ public: continue; // The two must have been unified. ASSERT(subNode.variableAccessData() == node.variableAccessData()); - // Currently, the previous node must be a flush. - // NOTE: This assertion should be removed if we ever do - // constant folding on captured variables. In particular, - // this code does not require the previous node to be a flush, - // but we are asserting this anyway because it is a constraint - // of the IR and this is as good a place as any to assert it. - ASSERT(subNode.op() == Flush); previousLocalAccess = subNodeIndex; break; } diff --git a/Source/JavaScriptCore/dfg/DFGCorrectableJumpPoint.h b/Source/JavaScriptCore/dfg/DFGCorrectableJumpPoint.h index bfa149604..93cb49c01 100644 --- a/Source/JavaScriptCore/dfg/DFGCorrectableJumpPoint.h +++ b/Source/JavaScriptCore/dfg/DFGCorrectableJumpPoint.h @@ -66,6 +66,11 @@ public: #endif } + bool isSet() + { + return m_codeOffset != std::numeric_limits<uint32_t>::max(); + } + void switchToLateJump(MacroAssembler::PatchableJump check) { #ifndef NDEBUG diff --git a/Source/JavaScriptCore/dfg/DFGDriver.cpp b/Source/JavaScriptCore/dfg/DFGDriver.cpp index 6ebe338f5..e932792df 100644 --- a/Source/JavaScriptCore/dfg/DFGDriver.cpp +++ b/Source/JavaScriptCore/dfg/DFGDriver.cpp @@ -82,10 +82,11 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo changed |= performConstantFolding(dfg); changed |= performArgumentsSimplification(dfg); changed |= performCFGSimplification(dfg); + changed |= performCSE(dfg, FixpointNotConverged); if (!changed) break; - performCSE(dfg, FixpointNotConverged); dfg.resetExitStates(); + performFixup(dfg); } performCSE(dfg, FixpointConverged); #if DFG_ENABLE(DEBUG_VERBOSE) @@ -94,10 +95,13 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo dfg.m_dominators.compute(dfg); performVirtualRegisterAllocation(dfg); + GraphDumpMode modeForFinalValidate = DumpGraph; #if DFG_ENABLE(DEBUG_VERBOSE) dataLog("Graph after optimization:\n"); dfg.dump(); + modeForFinalValidate = DontDumpGraph; #endif + validate(dfg, modeForFinalValidate); JITCompiler dataFlowJIT(dfg); bool result; diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp index e54d2cfaf..f6e3c0a96 100644 --- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp @@ -74,13 +74,13 @@ private: switch (op) { case GetById: { - if (!isInt32Prediction(m_graph[m_compileIndex].prediction())) + if (!isInt32Speculation(m_graph[m_compileIndex].prediction())) break; if (codeBlock()->identifier(node.identifierNumber()) != globalData().propertyNames->length) break; - bool isArray = isArrayPrediction(m_graph[node.child1()].prediction()); - bool isArguments = isArgumentsPrediction(m_graph[node.child1()].prediction()); - bool isString = isStringPrediction(m_graph[node.child1()].prediction()); + bool isArray = isArraySpeculation(m_graph[node.child1()].prediction()); + bool isArguments = isArgumentsSpeculation(m_graph[node.child1()].prediction()); + bool isString = isStringSpeculation(m_graph[node.child1()].prediction()); bool isInt8Array = m_graph[node.child1()].shouldSpeculateInt8Array(); bool isInt16Array = m_graph[node.child1()].shouldSpeculateInt16Array(); bool isInt32Array = m_graph[node.child1()].shouldSpeculateInt32Array(); @@ -129,10 +129,10 @@ private: break; } case GetIndexedPropertyStorage: { - PredictedType basePrediction = m_graph[node.child2()].prediction(); - if ((!(basePrediction & PredictInt32) && basePrediction) + SpeculatedType basePrediction = m_graph[node.child2()].prediction(); + if ((!(basePrediction & SpecInt32) && basePrediction) || m_graph[node.child1()].shouldSpeculateArguments() - || !isActionableArrayPrediction(m_graph[node.child1()].prediction())) { + || !isActionableArraySpeculation(m_graph[node.child1()].prediction())) { node.setOpAndDefaultFlags(Nop); m_graph.clearAndDerefChild1(node); m_graph.clearAndDerefChild2(node); @@ -150,7 +150,8 @@ private: } case ValueToInt32: { - if (m_graph[node.child1()].shouldSpeculateNumber()) { + if (m_graph[node.child1()].shouldSpeculateNumber() + && node.mustGenerate()) { node.clearFlags(NodeMustGenerate); m_graph.deref(m_compileIndex); } @@ -284,7 +285,7 @@ private: Node newDivision = oldDivision; newDivision.setRefCount(2); - newDivision.predict(PredictDouble); + newDivision.predict(SpecDouble); NodeIndex newDivisionIndex = m_graph.size(); oldDivision.setOp(DoubleAsInt32); @@ -318,7 +319,7 @@ private: break; if (!m_graph[node.child2()].shouldSpeculateInteger()) break; - if (isActionableIntMutableArrayPrediction(m_graph[node.child1()].prediction())) { + if (isActionableIntMutableArraySpeculation(m_graph[node.child1()].prediction())) { if (m_graph[node.child3()].isConstant()) break; if (m_graph[node.child3()].shouldSpeculateInteger()) @@ -326,7 +327,7 @@ private: fixDoubleEdge(2); break; } - if (isActionableFloatMutableArrayPrediction(m_graph[node.child1()].prediction())) { + if (isActionableFloatMutableArraySpeculation(m_graph[node.child1()].prediction())) { fixDoubleEdge(2); break; } @@ -390,7 +391,7 @@ private: m_insertionSet.append(m_indexInBlock, resultIndex); Node& int32ToDouble = m_graph[resultIndex]; - int32ToDouble.predict(PredictDouble); + int32ToDouble.predict(SpecDouble); int32ToDouble.ref(); } diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp index 4562e30ee..93de024d7 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.cpp +++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp @@ -76,7 +76,7 @@ const char* Graph::nameOfVariableAccessData(VariableAccessData* variableAccessDa if (variableAccessData->isCaptured()) *ptr++ = '*'; - ptr.strcat(predictionToAbbreviatedString(variableAccessData->prediction())); + ptr.strcat(speculationToAbbreviatedString(variableAccessData->prediction())); *ptr++ = 0; @@ -169,7 +169,7 @@ void Graph::dump(NodeIndex nodeIndex) dataLog("%s@%u%s", useKindToString(m_varArgChildren[childIdx].useKind()), m_varArgChildren[childIdx].index(), - predictionToAbbreviatedString( + speculationToAbbreviatedString( at(m_varArgChildren[childIdx]).prediction())); } } else { @@ -177,19 +177,19 @@ void Graph::dump(NodeIndex nodeIndex) dataLog("%s@%u%s", useKindToString(node.child1().useKind()), node.child1().index(), - predictionToAbbreviatedString(at(node.child1()).prediction())); + speculationToAbbreviatedString(at(node.child1()).prediction())); } if (!!node.child2()) { dataLog(", %s@%u%s", useKindToString(node.child2().useKind()), node.child2().index(), - predictionToAbbreviatedString(at(node.child2()).prediction())); + speculationToAbbreviatedString(at(node.child2()).prediction())); } if (!!node.child3()) { dataLog(", %s@%u%s", useKindToString(node.child3().useKind()), node.child3().index(), - predictionToAbbreviatedString(at(node.child3()).prediction())); + speculationToAbbreviatedString(at(node.child3()).prediction())); } hasPrinted = !!node.child1(); } @@ -202,6 +202,13 @@ void Graph::dump(NodeIndex nodeIndex) dataLog("%svar%u", hasPrinted ? ", " : "", node.varNumber()); hasPrinted = true; } + if (node.hasRegisterPointer()) { + dataLog( + "%sglobal%u(%p)", hasPrinted ? ", " : "", + globalObjectFor(node.codeOrigin)->findRegisterIndex(node.registerPointer()), + node.registerPointer()); + hasPrinted = true; + } if (node.hasIdentifier()) { dataLog("%sid%u{%s}", hasPrinted ? ", " : "", node.identifierNumber(), m_codeBlock->identifier(node.identifierNumber()).ustring().utf8().data()); hasPrinted = true; @@ -212,6 +219,10 @@ void Graph::dump(NodeIndex nodeIndex) hasPrinted = true; } } + if (node.hasStructure()) { + dataLog("%sstruct(%p)", hasPrinted ? ", " : "", node.structure()); + hasPrinted = true; + } if (node.hasStructureTransitionData()) { dataLog("%sstruct(%p -> %p)", hasPrinted ? ", " : "", node.structureTransitionData().previousStructure, node.structureTransitionData().newStructure); hasPrinted = true; @@ -269,9 +280,9 @@ void Graph::dump(NodeIndex nodeIndex) if (!skipped) { if (node.hasVariableAccessData()) - dataLog(" predicting %s, double ratio %lf%s", predictionToString(node.variableAccessData()->prediction()), node.variableAccessData()->doubleVoteRatio(), node.variableAccessData()->shouldUseDoubleFormat() ? ", forcing double" : ""); + dataLog(" predicting %s, double ratio %lf%s", speculationToString(node.variableAccessData()->prediction()), node.variableAccessData()->doubleVoteRatio(), node.variableAccessData()->shouldUseDoubleFormat() ? ", forcing double" : ""); else if (node.hasHeapPrediction()) - dataLog(" predicting %s", predictionToString(node.getHeapPrediction())); + dataLog(" predicting %s", speculationToString(node.getHeapPrediction())); } dataLog("\n"); @@ -386,7 +397,7 @@ void Graph::predictArgumentTypes() at(m_arguments[arg]).variableAccessData()->predict(profile->computeUpdatedPrediction()); #if DFG_ENABLE(DEBUG_VERBOSE) - dataLog("Argument [%zu] prediction: %s\n", arg, predictionToString(at(m_arguments[arg]).variableAccessData()->prediction())); + dataLog("Argument [%zu] prediction: %s\n", arg, speculationToString(at(m_arguments[arg]).variableAccessData()->prediction())); #endif } } diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h index 8ca3e2047..acc9ff472 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.h +++ b/Source/JavaScriptCore/dfg/DFGGraph.h @@ -187,9 +187,9 @@ public: BlockIndex blockIndexForBytecodeOffset(Vector<BlockIndex>& blocks, unsigned bytecodeBegin); - PredictedType getJSConstantPrediction(Node& node) + SpeculatedType getJSConstantSpeculation(Node& node) { - return predictionFromValue(node.valueOfJSConstant(m_codeBlock)); + return speculationFromValue(node.valueOfJSConstant(m_codeBlock)); } bool addShouldSpeculateInteger(Node& add) @@ -258,6 +258,13 @@ public: { return at(nodeIndex).isBooleanConstant(m_codeBlock); } + bool isCellConstant(NodeIndex nodeIndex) + { + if (!isJSConstant(nodeIndex)) + return false; + JSValue value = valueOfJSConstant(nodeIndex); + return value.isCell() && !!value; + } bool isFunctionConstant(NodeIndex nodeIndex) { if (!isJSConstant(nodeIndex)) @@ -310,6 +317,11 @@ public: return &m_structureTransitionData.last(); } + JSGlobalObject* globalObjectFor(CodeOrigin codeOrigin) + { + return m_codeBlock->globalObjectFor(codeOrigin); + } + ExecutableBase* executableFor(InlineCallFrame* inlineCallFrame) { if (!inlineCallFrame) @@ -424,17 +436,17 @@ public: bool isPredictedNumerical(Node& node) { - PredictedType left = at(node.child1()).prediction(); - PredictedType right = at(node.child2()).prediction(); - return isNumberPrediction(left) && isNumberPrediction(right); + SpeculatedType left = at(node.child1()).prediction(); + SpeculatedType right = at(node.child2()).prediction(); + return isNumberSpeculation(left) && isNumberSpeculation(right); } bool byValIsPure(Node& node) { return at(node.child2()).shouldSpeculateInteger() && ((node.op() == PutByVal || node.op() == PutByValAlias) - ? isActionableMutableArrayPrediction(at(node.child1()).prediction()) - : isActionableArrayPrediction(at(node.child1()).prediction())); + ? isActionableMutableArraySpeculation(at(node.child1()).prediction()) + : isActionableArraySpeculation(at(node.child1()).prediction())); } bool clobbersWorld(Node& node) diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp index 54b5aaee6..561f51615 100644 --- a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp +++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp @@ -44,7 +44,11 @@ void JITCompiler::linkOSRExits() { for (unsigned i = 0; i < codeBlock()->numberOfOSRExits(); ++i) { OSRExit& exit = codeBlock()->osrExit(i); - exit.m_check.initialJump().link(this); + ASSERT(!exit.m_check.isSet() == (exit.m_watchpointIndex != std::numeric_limits<unsigned>::max())); + if (exit.m_watchpointIndex == std::numeric_limits<unsigned>::max()) + exit.m_check.initialJump().link(this); + else + codeBlock()->watchpoint(exit.m_watchpointIndex).setDestination(label()); jitAssertHasValidCallFrame(); store32(TrustedImm32(i), &globalData()->osrExitIndex); exit.m_check.switchToLateJump(patchableJump()); @@ -124,16 +128,14 @@ void JITCompiler::link(LinkBuffer& linkBuffer) for (unsigned i = 0; i < m_calls.size(); ++i) linkBuffer.link(m_calls[i].m_call, m_calls[i].m_function); - if (m_codeBlock->needsCallReturnIndices()) { - m_codeBlock->callReturnIndexVector().reserveCapacity(m_exceptionChecks.size()); - for (unsigned i = 0; i < m_exceptionChecks.size(); ++i) { - unsigned returnAddressOffset = linkBuffer.returnAddressOffset(m_exceptionChecks[i].m_call); - CodeOrigin codeOrigin = m_exceptionChecks[i].m_codeOrigin; - while (codeOrigin.inlineCallFrame) - codeOrigin = codeOrigin.inlineCallFrame->caller; - unsigned exceptionInfo = codeOrigin.bytecodeIndex; - m_codeBlock->callReturnIndexVector().append(CallReturnOffsetToBytecodeOffset(returnAddressOffset, exceptionInfo)); - } + m_codeBlock->callReturnIndexVector().reserveCapacity(m_exceptionChecks.size()); + for (unsigned i = 0; i < m_exceptionChecks.size(); ++i) { + unsigned returnAddressOffset = linkBuffer.returnAddressOffset(m_exceptionChecks[i].m_call); + CodeOrigin codeOrigin = m_exceptionChecks[i].m_codeOrigin; + while (codeOrigin.inlineCallFrame) + codeOrigin = codeOrigin.inlineCallFrame->caller; + unsigned exceptionInfo = codeOrigin.bytecodeIndex; + m_codeBlock->callReturnIndexVector().append(CallReturnOffsetToBytecodeOffset(returnAddressOffset, exceptionInfo)); } Vector<CodeOriginAtCallReturnOffset>& codeOrigins = m_codeBlock->codeOrigins(); @@ -190,6 +192,8 @@ void JITCompiler::link(LinkBuffer& linkBuffer) OSRExit& exit = codeBlock()->osrExit(i); linkBuffer.link(exit.m_check.lateJump(), target); exit.m_check.correctLateJump(linkBuffer); + if (exit.m_watchpointIndex != std::numeric_limits<unsigned>::max()) + codeBlock()->watchpoint(exit.m_watchpointIndex).correctLabels(linkBuffer); } codeBlock()->shrinkToFit(CodeBlock::LateShrink); @@ -216,7 +220,9 @@ bool JITCompiler::compile(JITCode& entry) link(linkBuffer); speculative.linkOSREntries(linkBuffer); - entry = JITCode(linkBuffer.finalizeCode(), JITCode::DFGJIT); + entry = JITCode( + FINALIZE_CODE(linkBuffer, ("DFG program/eval CodeBlock %p", m_codeBlock)), + JITCode::DFGJIT); return true; } @@ -298,7 +304,9 @@ bool JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWi linkBuffer.link(callArityCheck, m_codeBlock->m_isConstructor ? cti_op_construct_arityCheck : cti_op_call_arityCheck); entryWithArityCheck = linkBuffer.locationOf(arityCheck); - entry = JITCode(linkBuffer.finalizeCode(), JITCode::DFGJIT); + entry = JITCode( + FINALIZE_CODE(linkBuffer, ("DFG function CodeBlock %p", m_codeBlock)), + JITCode::DFGJIT); return true; } diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.h b/Source/JavaScriptCore/dfg/DFGJITCompiler.h index d3ff3be07..9d69ec9f3 100644 --- a/Source/JavaScriptCore/dfg/DFGJITCompiler.h +++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.h @@ -260,9 +260,9 @@ public: } // Helper methods to get predictions - PredictedType getPrediction(Node& node) { return node.prediction(); } - PredictedType getPrediction(NodeIndex nodeIndex) { return getPrediction(graph()[nodeIndex]); } - PredictedType getPrediction(Edge nodeUse) { return getPrediction(nodeUse.index()); } + SpeculatedType getSpeculation(Node& node) { return node.prediction(); } + SpeculatedType getSpeculation(NodeIndex nodeIndex) { return getSpeculation(graph()[nodeIndex]); } + SpeculatedType getSpeculation(Edge nodeUse) { return getSpeculation(nodeUse.index()); } #if USE(JSVALUE32_64) void* addressOfDoubleConstant(NodeIndex nodeIndex) @@ -288,6 +288,12 @@ public: m_codeBlock->appendWeakReference(target); } + void addWeakReferences(const StructureSet& structureSet) + { + for (unsigned i = structureSet.size(); i--;) + addWeakReference(structureSet[i]); + } + void addWeakReferenceTransition(JSCell* codeOrigin, JSCell* from, JSCell* to) { m_codeBlock->appendWeakReferenceTransition(codeOrigin, from, to); diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h index 12ebba823..64e6fe097 100644 --- a/Source/JavaScriptCore/dfg/DFGNode.h +++ b/Source/JavaScriptCore/dfg/DFGNode.h @@ -39,7 +39,7 @@ #include "DFGVariableAccessData.h" #include "JSValue.h" #include "Operands.h" -#include "PredictedType.h" +#include "SpeculatedType.h" #include "ValueProfile.h" namespace JSC { namespace DFG { @@ -82,7 +82,7 @@ struct Node { , children(AdjacencyList::Fixed, child1, child2, child3) , m_virtualRegister(InvalidVirtualRegister) , m_refCount(0) - , m_prediction(PredictNone) + , m_prediction(SpecNone) { setOpAndDefaultFlags(op); ASSERT(!(m_flags & NodeHasVarArgs)); @@ -95,7 +95,7 @@ struct Node { , m_virtualRegister(InvalidVirtualRegister) , m_refCount(0) , m_opInfo(imm.m_value) - , m_prediction(PredictNone) + , m_prediction(SpecNone) { setOpAndDefaultFlags(op); ASSERT(!(m_flags & NodeHasVarArgs)); @@ -109,7 +109,7 @@ struct Node { , m_refCount(0) , m_opInfo(imm1.m_value) , m_opInfo2(safeCast<unsigned>(imm2.m_value)) - , m_prediction(PredictNone) + , m_prediction(SpecNone) { setOpAndDefaultFlags(op); ASSERT(!(m_flags & NodeHasVarArgs)); @@ -123,7 +123,7 @@ struct Node { , m_refCount(0) , m_opInfo(imm1.m_value) , m_opInfo2(safeCast<unsigned>(imm2.m_value)) - , m_prediction(PredictNone) + , m_prediction(SpecNone) { setOpAndDefaultFlags(op); ASSERT(m_flags & NodeHasVarArgs); @@ -421,7 +421,7 @@ struct Node { bool hasVarNumber() { - return op() == GetGlobalVar || op() == PutGlobalVar || op() == GetScopedVar || op() == PutScopedVar; + return op() == GetScopedVar || op() == PutScopedVar; } unsigned varNumber() @@ -429,6 +429,27 @@ struct Node { ASSERT(hasVarNumber()); return m_opInfo; } + + bool hasIdentifierNumberForCheck() + { + return op() == GlobalVarWatchpoint || op() == PutGlobalVarCheck; + } + + unsigned identifierNumberForCheck() + { + ASSERT(hasIdentifierNumberForCheck()); + return m_opInfo2; + } + + bool hasRegisterPointer() + { + return op() == GetGlobalVar || op() == PutGlobalVar || op() == GlobalVarWatchpoint || op() == PutGlobalVarCheck; + } + + WriteBarrier<Unknown>* registerPointer() + { + return bitwise_cast<WriteBarrier<Unknown>*>(m_opInfo); + } bool hasScopeChainDepth() { @@ -584,17 +605,17 @@ struct Node { } } - PredictedType getHeapPrediction() + SpeculatedType getHeapPrediction() { ASSERT(hasHeapPrediction()); - return static_cast<PredictedType>(m_opInfo2); + return static_cast<SpeculatedType>(m_opInfo2); } - bool predictHeap(PredictedType prediction) + bool predictHeap(SpeculatedType prediction) { ASSERT(hasHeapPrediction()); - return mergePrediction(m_opInfo2, prediction); + return mergeSpeculation(m_opInfo2, prediction); } bool hasFunctionCheckData() @@ -630,6 +651,17 @@ struct Node { return *reinterpret_cast<StructureSet*>(m_opInfo); } + bool hasStructure() + { + return op() == StructureTransitionWatchpoint; + } + + Structure* structure() + { + ASSERT(hasStructure()); + return reinterpret_cast<Structure*>(m_opInfo); + } + bool hasStorageAccessData() { return op() == GetByOffset || op() == PutByOffset; @@ -682,6 +714,17 @@ struct Node { ASSERT(m_virtualRegister == InvalidVirtualRegister); m_virtualRegister = virtualRegister; } + + bool hasArgumentPositionStart() + { + return op() == InlineStart; + } + + unsigned argumentPositionStart() + { + ASSERT(hasArgumentPositionStart()); + return m_opInfo; + } bool shouldGenerate() { @@ -756,114 +799,114 @@ struct Node { return children.numChildren(); } - PredictedType prediction() + SpeculatedType prediction() { return m_prediction; } - bool predict(PredictedType prediction) + bool predict(SpeculatedType prediction) { - return mergePrediction(m_prediction, prediction); + return mergeSpeculation(m_prediction, prediction); } bool shouldSpeculateInteger() { - return isInt32Prediction(prediction()); + return isInt32Speculation(prediction()); } bool shouldSpeculateDouble() { - return isDoublePrediction(prediction()); + return isDoubleSpeculation(prediction()); } bool shouldSpeculateNumber() { - return isNumberPrediction(prediction()); + return isNumberSpeculation(prediction()); } bool shouldSpeculateBoolean() { - return isBooleanPrediction(prediction()); + return isBooleanSpeculation(prediction()); } bool shouldSpeculateFinalObject() { - return isFinalObjectPrediction(prediction()); + return isFinalObjectSpeculation(prediction()); } bool shouldSpeculateFinalObjectOrOther() { - return isFinalObjectOrOtherPrediction(prediction()); + return isFinalObjectOrOtherSpeculation(prediction()); } bool shouldSpeculateArray() { - return isArrayPrediction(prediction()); + return isArraySpeculation(prediction()); } bool shouldSpeculateArguments() { - return isArgumentsPrediction(prediction()); + return isArgumentsSpeculation(prediction()); } bool shouldSpeculateInt8Array() { - return isInt8ArrayPrediction(prediction()); + return isInt8ArraySpeculation(prediction()); } bool shouldSpeculateInt16Array() { - return isInt16ArrayPrediction(prediction()); + return isInt16ArraySpeculation(prediction()); } bool shouldSpeculateInt32Array() { - return isInt32ArrayPrediction(prediction()); + return isInt32ArraySpeculation(prediction()); } bool shouldSpeculateUint8Array() { - return isUint8ArrayPrediction(prediction()); + return isUint8ArraySpeculation(prediction()); } bool shouldSpeculateUint8ClampedArray() { - return isUint8ClampedArrayPrediction(prediction()); + return isUint8ClampedArraySpeculation(prediction()); } bool shouldSpeculateUint16Array() { - return isUint16ArrayPrediction(prediction()); + return isUint16ArraySpeculation(prediction()); } bool shouldSpeculateUint32Array() { - return isUint32ArrayPrediction(prediction()); + return isUint32ArraySpeculation(prediction()); } bool shouldSpeculateFloat32Array() { - return isFloat32ArrayPrediction(prediction()); + return isFloat32ArraySpeculation(prediction()); } bool shouldSpeculateFloat64Array() { - return isFloat64ArrayPrediction(prediction()); + return isFloat64ArraySpeculation(prediction()); } bool shouldSpeculateArrayOrOther() { - return isArrayOrOtherPrediction(prediction()); + return isArrayOrOtherSpeculation(prediction()); } bool shouldSpeculateObject() { - return isObjectPrediction(prediction()); + return isObjectSpeculation(prediction()); } bool shouldSpeculateCell() { - return isCellPrediction(prediction()); + return isCellSpeculation(prediction()); } static bool shouldSpeculateInteger(Node& op1, Node& op2) @@ -921,7 +964,7 @@ private: uintptr_t m_opInfo; unsigned m_opInfo2; // The prediction ascribed to this node after propagation. - PredictedType m_prediction; + SpeculatedType m_prediction; }; } } // namespace JSC::DFG diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h index 743f87955..4671f6b6c 100644 --- a/Source/JavaScriptCore/dfg/DFGNodeType.h +++ b/Source/JavaScriptCore/dfg/DFGNodeType.h @@ -118,6 +118,18 @@ namespace JSC { namespace DFG { macro(PutById, NodeMustGenerate | NodeClobbersWorld) \ macro(PutByIdDirect, NodeMustGenerate | NodeClobbersWorld) \ macro(CheckStructure, NodeMustGenerate) \ + /* Transition watchpoints are a contract between the party setting the watchpoint */\ + /* and the runtime system, where the party promises that the child object once had */\ + /* the structure being watched, and the runtime system in turn promises that the */\ + /* watchpoint will be turned into an OSR exit if any object with that structure */\ + /* ever transitions to a different structure. Hence, the child object must have */\ + /* previously had a CheckStructure executed on it or we're dealing with an object */\ + /* constant (WeakJSConstant) and the object was known to have that structure at */\ + /* compile-time. In the latter case this means that no structure checks have to be */\ + /* performed for this object by JITted code. In the former case this means that*/\ + /* the object's structure does not need to be rechecked due to side-effecting */\ + /* (clobbering) operations. */\ + macro(StructureTransitionWatchpoint, NodeMustGenerate) \ macro(PutStructure, NodeMustGenerate) \ macro(PhantomPutStructure, NodeMustGenerate | NodeDoesNotExit) \ macro(GetPropertyStorage, NodeResultStorage) \ @@ -141,6 +153,8 @@ namespace JSC { namespace DFG { macro(PutScopedVar, NodeMustGenerate | NodeClobbersWorld) \ macro(GetGlobalVar, NodeResultJS | NodeMustGenerate) \ macro(PutGlobalVar, NodeMustGenerate) \ + macro(GlobalVarWatchpoint, NodeMustGenerate) \ + macro(PutGlobalVarCheck, NodeMustGenerate) \ macro(CheckFunction, NodeMustGenerate) \ \ /* Optimizations for array mutation. */\ diff --git a/Source/JavaScriptCore/dfg/DFGOSRExit.cpp b/Source/JavaScriptCore/dfg/DFGOSRExit.cpp index bcb98a1ed..d0e0de9da 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExit.cpp +++ b/Source/JavaScriptCore/dfg/DFGOSRExit.cpp @@ -51,6 +51,7 @@ OSRExit::OSRExit(ExitKind kind, JSValueSource jsValueSource, MethodOfGettingAVal , m_codeOrigin(jit->m_codeOriginForOSR) , m_codeOriginForExitProfile(m_codeOrigin) , m_recoveryIndex(recoveryIndex) + , m_watchpointIndex(std::numeric_limits<unsigned>::max()) , m_kind(kind) , m_count(0) , m_arguments(jit->m_arguments.size()) diff --git a/Source/JavaScriptCore/dfg/DFGOSRExit.h b/Source/JavaScriptCore/dfg/DFGOSRExit.h index 841fdddb3..683f260f1 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExit.h +++ b/Source/JavaScriptCore/dfg/DFGOSRExit.h @@ -96,6 +96,7 @@ struct OSRExit { CodeOrigin m_codeOriginForExitProfile; unsigned m_recoveryIndex; + unsigned m_watchpointIndex; ExitKind m_kind; uint32_t m_count; diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp index 888a4a2c5..d46d59650 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp +++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp @@ -79,11 +79,11 @@ void compileOSRExit(ExecState* exec) exitCompiler.compileExit(exit, recovery); LinkBuffer patchBuffer(*globalData, &jit, codeBlock); - exit.m_code = patchBuffer.finalizeCode(); - -#if DFG_ENABLE(DEBUG_VERBOSE) - dataLog("OSR exit code at [%p, %p).\n", patchBuffer.debugAddress(), static_cast<char*>(patchBuffer.debugAddress()) + patchBuffer.debugSize()); -#endif + exit.m_code = FINALIZE_CODE( + patchBuffer, + ("DFG OSR exit #%u (bc#%u, @%u, %s) from CodeBlock %p", + exitIndex, exit.m_codeOrigin.bytecodeIndex, exit.m_nodeIndex, + exitKindToString(exit.m_kind), codeBlock)); } { diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.h b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.h index 86345b0eb..ae29a92d5 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.h +++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.h @@ -78,7 +78,7 @@ private: }; extern "C" { -void DFG_OPERATION compileOSRExit(ExecState*); +void DFG_OPERATION compileOSRExit(ExecState*) WTF_INTERNAL; } } } // namespace JSC::DFG diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp index d773cb4ac..09912b3e5 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp +++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler32_64.cpp @@ -533,70 +533,6 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco } } - // 11) Create arguments if necessary and place them into the appropriate aliased - // registers. - - if (haveArguments) { - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); - if (recovery.technique() != ArgumentsThatWereNotCreated) - continue; - int operand = exit.operandForIndex(index); - // Find the right inline call frame. - InlineCallFrame* inlineCallFrame = 0; - for (InlineCallFrame* current = exit.m_codeOrigin.inlineCallFrame; - current; - current = current->caller.inlineCallFrame) { - if (current->stackOffset <= operand) { - inlineCallFrame = current; - break; - } - } - int argumentsRegister = m_jit.argumentsRegisterFor(inlineCallFrame); - - m_jit.load32(AssemblyHelpers::payloadFor(argumentsRegister), GPRInfo::regT0); - AssemblyHelpers::Jump haveArguments = m_jit.branch32( - AssemblyHelpers::NotEqual, - AssemblyHelpers::tagFor(argumentsRegister), - AssemblyHelpers::TrustedImm32(JSValue::EmptyValueTag)); - - if (inlineCallFrame) { - m_jit.setupArgumentsWithExecState( - AssemblyHelpers::TrustedImmPtr(inlineCallFrame)); - m_jit.move( - AssemblyHelpers::TrustedImmPtr( - bitwise_cast<void*>(operationCreateInlinedArguments)), - GPRInfo::nonArgGPR0); - } else { - m_jit.setupArgumentsExecState(); - m_jit.move( - AssemblyHelpers::TrustedImmPtr( - bitwise_cast<void*>(operationCreateArguments)), - GPRInfo::nonArgGPR0); - } - m_jit.call(GPRInfo::nonArgGPR0); - m_jit.store32( - AssemblyHelpers::TrustedImm32(JSValue::CellTag), - AssemblyHelpers::tagFor(argumentsRegister)); - m_jit.store32( - GPRInfo::returnValueGPR, - AssemblyHelpers::payloadFor(argumentsRegister)); - m_jit.store32( - AssemblyHelpers::TrustedImm32(JSValue::CellTag), - AssemblyHelpers::tagFor(unmodifiedArgumentsRegister(argumentsRegister))); - m_jit.store32( - GPRInfo::returnValueGPR, - AssemblyHelpers::payloadFor(unmodifiedArgumentsRegister(argumentsRegister))); - m_jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0); // no-op move on almost all platforms. - - haveArguments.link(&m_jit); - m_jit.store32( - AssemblyHelpers::TrustedImm32(JSValue::CellTag), - AssemblyHelpers::tagFor(operand)); - m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor(operand)); - } - } - // 12) Adjust the old JIT's execute counter. Since we are exiting OSR, we know // that all new calls into this code will go to the new JIT, so the execute // counter only affects call frames that performed OSR exit and call frames @@ -635,14 +571,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco handleExitCounts(exit); - // 13) Load the result of the last bytecode operation into regT0. - - if (exit.m_lastSetOperand != std::numeric_limits<int>::max()) { - m_jit.load32(AssemblyHelpers::payloadFor((VirtualRegister)exit.m_lastSetOperand), GPRInfo::cachedResultRegister); - m_jit.load32(AssemblyHelpers::tagFor((VirtualRegister)exit.m_lastSetOperand), GPRInfo::cachedResultRegister2); - } - - // 14) Fix call frame (s). + // 13) Reify inlined call frames. ASSERT(m_jit.baselineCodeBlock()->getJITType() == JITCode::BaselineJIT); m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(m_jit.baselineCodeBlock()), AssemblyHelpers::addressFor((VirtualRegister)RegisterFile::CodeBlock)); @@ -678,10 +607,83 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(inlineCallFrame->callee.get()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::Callee))); } + // 14) Create arguments if necessary and place them into the appropriate aliased + // registers. + + if (haveArguments) { + for (int index = 0; index < exit.numberOfRecoveries(); ++index) { + const ValueRecovery& recovery = exit.valueRecovery(index); + if (recovery.technique() != ArgumentsThatWereNotCreated) + continue; + int operand = exit.operandForIndex(index); + // Find the right inline call frame. + InlineCallFrame* inlineCallFrame = 0; + for (InlineCallFrame* current = exit.m_codeOrigin.inlineCallFrame; + current; + current = current->caller.inlineCallFrame) { + if (current->stackOffset <= operand) { + inlineCallFrame = current; + break; + } + } + int argumentsRegister = m_jit.argumentsRegisterFor(inlineCallFrame); + + m_jit.load32(AssemblyHelpers::payloadFor(argumentsRegister), GPRInfo::regT0); + AssemblyHelpers::Jump haveArguments = m_jit.branch32( + AssemblyHelpers::NotEqual, + AssemblyHelpers::tagFor(argumentsRegister), + AssemblyHelpers::TrustedImm32(JSValue::EmptyValueTag)); + + if (inlineCallFrame) { + m_jit.setupArgumentsWithExecState( + AssemblyHelpers::TrustedImmPtr(inlineCallFrame)); + m_jit.move( + AssemblyHelpers::TrustedImmPtr( + bitwise_cast<void*>(operationCreateInlinedArguments)), + GPRInfo::nonArgGPR0); + } else { + m_jit.setupArgumentsExecState(); + m_jit.move( + AssemblyHelpers::TrustedImmPtr( + bitwise_cast<void*>(operationCreateArguments)), + GPRInfo::nonArgGPR0); + } + m_jit.call(GPRInfo::nonArgGPR0); + m_jit.store32( + AssemblyHelpers::TrustedImm32(JSValue::CellTag), + AssemblyHelpers::tagFor(argumentsRegister)); + m_jit.store32( + GPRInfo::returnValueGPR, + AssemblyHelpers::payloadFor(argumentsRegister)); + m_jit.store32( + AssemblyHelpers::TrustedImm32(JSValue::CellTag), + AssemblyHelpers::tagFor(unmodifiedArgumentsRegister(argumentsRegister))); + m_jit.store32( + GPRInfo::returnValueGPR, + AssemblyHelpers::payloadFor(unmodifiedArgumentsRegister(argumentsRegister))); + m_jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0); // no-op move on almost all platforms. + + haveArguments.link(&m_jit); + m_jit.store32( + AssemblyHelpers::TrustedImm32(JSValue::CellTag), + AssemblyHelpers::tagFor(operand)); + m_jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor(operand)); + } + } + + // 15) Load the result of the last bytecode operation into regT0. + + if (exit.m_lastSetOperand != std::numeric_limits<int>::max()) { + m_jit.load32(AssemblyHelpers::payloadFor((VirtualRegister)exit.m_lastSetOperand), GPRInfo::cachedResultRegister); + m_jit.load32(AssemblyHelpers::tagFor((VirtualRegister)exit.m_lastSetOperand), GPRInfo::cachedResultRegister2); + } + + // 16) Adjust the call frame pointer. + if (exit.m_codeOrigin.inlineCallFrame) m_jit.addPtr(AssemblyHelpers::TrustedImm32(exit.m_codeOrigin.inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister); - // 15) Jump into the corresponding baseline JIT code. + // 17) Jump into the corresponding baseline JIT code. CodeBlock* baselineCodeBlock = m_jit.baselineCodeBlockFor(exit.m_codeOrigin); Vector<BytecodeAndMachineOffset>& decodedCodeMap = m_jit.decodedCodeMapFor(baselineCodeBlock); diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp index 22b236115..33ba69a35 100644 --- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp +++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler64.cpp @@ -511,58 +511,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco } } - // 13) Create arguments if necessary and place them into the appropriate aliased - // registers. - - if (haveArguments) { - for (int index = 0; index < exit.numberOfRecoveries(); ++index) { - const ValueRecovery& recovery = exit.valueRecovery(index); - if (recovery.technique() != ArgumentsThatWereNotCreated) - continue; - int operand = exit.operandForIndex(index); - // Find the right inline call frame. - InlineCallFrame* inlineCallFrame = 0; - for (InlineCallFrame* current = exit.m_codeOrigin.inlineCallFrame; - current; - current = current->caller.inlineCallFrame) { - if (current->stackOffset <= operand) { - inlineCallFrame = current; - break; - } - } - int argumentsRegister = m_jit.argumentsRegisterFor(inlineCallFrame); - - m_jit.loadPtr(AssemblyHelpers::addressFor(argumentsRegister), GPRInfo::regT0); - AssemblyHelpers::Jump haveArguments = m_jit.branchTestPtr( - AssemblyHelpers::NonZero, GPRInfo::regT0); - - if (inlineCallFrame) { - m_jit.setupArgumentsWithExecState( - AssemblyHelpers::TrustedImmPtr(inlineCallFrame)); - m_jit.move( - AssemblyHelpers::TrustedImmPtr( - bitwise_cast<void*>(operationCreateInlinedArguments)), - GPRInfo::nonArgGPR0); - } else { - m_jit.setupArgumentsExecState(); - m_jit.move( - AssemblyHelpers::TrustedImmPtr( - bitwise_cast<void*>(operationCreateArguments)), - GPRInfo::nonArgGPR0); - } - m_jit.call(GPRInfo::nonArgGPR0); - m_jit.storePtr(GPRInfo::returnValueGPR, AssemblyHelpers::addressFor(argumentsRegister)); - m_jit.storePtr( - GPRInfo::returnValueGPR, - AssemblyHelpers::addressFor(unmodifiedArgumentsRegister(argumentsRegister))); - m_jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0); // no-op move on almost all platforms. - - haveArguments.link(&m_jit); - m_jit.storePtr(GPRInfo::regT0, AssemblyHelpers::addressFor(operand)); - } - } - - // 14) Adjust the old JIT's execute counter. Since we are exiting OSR, we know + // 13) Adjust the old JIT's execute counter. Since we are exiting OSR, we know // that all new calls into this code will go to the new JIT, so the execute // counter only affects call frames that performed OSR exit and call frames // that were still executing the old JIT at the time of another call frame's @@ -600,12 +549,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco handleExitCounts(exit); - // 15) Load the result of the last bytecode operation into regT0. - - if (exit.m_lastSetOperand != std::numeric_limits<int>::max()) - m_jit.loadPtr(AssemblyHelpers::addressFor((VirtualRegister)exit.m_lastSetOperand), GPRInfo::cachedResultRegister); - - // 16) Fix call frame(s). + // 14) Reify inlined call frames. ASSERT(m_jit.baselineCodeBlock()->getJITType() == JITCode::BaselineJIT); m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(m_jit.baselineCodeBlock()), AssemblyHelpers::addressFor((VirtualRegister)RegisterFile::CodeBlock)); @@ -638,10 +582,63 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, SpeculationRecovery* reco m_jit.storePtr(AssemblyHelpers::TrustedImmPtr(inlineCallFrame->callee.get()), AssemblyHelpers::addressFor((VirtualRegister)(inlineCallFrame->stackOffset + RegisterFile::Callee))); } + // 15) Create arguments if necessary and place them into the appropriate aliased + // registers. + + if (haveArguments) { + for (int index = 0; index < exit.numberOfRecoveries(); ++index) { + const ValueRecovery& recovery = exit.valueRecovery(index); + if (recovery.technique() != ArgumentsThatWereNotCreated) + continue; + int operand = exit.operandForIndex(index); + // Find the right inline call frame. + InlineCallFrame* inlineCallFrame = 0; + for (InlineCallFrame* current = exit.m_codeOrigin.inlineCallFrame; + current; + current = current->caller.inlineCallFrame) { + if (current->stackOffset <= operand) { + inlineCallFrame = current; + break; + } + } + int argumentsRegister = m_jit.argumentsRegisterFor(inlineCallFrame); + + m_jit.loadPtr(AssemblyHelpers::addressFor(argumentsRegister), GPRInfo::regT0); + AssemblyHelpers::Jump haveArguments = m_jit.branchTestPtr( + AssemblyHelpers::NonZero, GPRInfo::regT0); + + if (inlineCallFrame) { + m_jit.addPtr(AssemblyHelpers::TrustedImm32(inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister, GPRInfo::regT0); + m_jit.setupArguments(GPRInfo::regT0); + } else + m_jit.setupArgumentsExecState(); + m_jit.move( + AssemblyHelpers::TrustedImmPtr( + bitwise_cast<void*>(operationCreateArguments)), + GPRInfo::nonArgGPR0); + m_jit.call(GPRInfo::nonArgGPR0); + m_jit.storePtr(GPRInfo::returnValueGPR, AssemblyHelpers::addressFor(argumentsRegister)); + m_jit.storePtr( + GPRInfo::returnValueGPR, + AssemblyHelpers::addressFor(unmodifiedArgumentsRegister(argumentsRegister))); + m_jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0); // no-op move on almost all platforms. + + haveArguments.link(&m_jit); + m_jit.storePtr(GPRInfo::regT0, AssemblyHelpers::addressFor(operand)); + } + } + + // 16) Load the result of the last bytecode operation into regT0. + + if (exit.m_lastSetOperand != std::numeric_limits<int>::max()) + m_jit.loadPtr(AssemblyHelpers::addressFor((VirtualRegister)exit.m_lastSetOperand), GPRInfo::cachedResultRegister); + + // 17) Adjust the call frame pointer. + if (exit.m_codeOrigin.inlineCallFrame) m_jit.addPtr(AssemblyHelpers::TrustedImm32(exit.m_codeOrigin.inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister); - // 17) Jump into the corresponding baseline JIT code. + // 18) Jump into the corresponding baseline JIT code. CodeBlock* baselineCodeBlock = m_jit.baselineCodeBlockFor(exit.m_codeOrigin); Vector<BytecodeAndMachineOffset>& decodedCodeMap = m_jit.decodedCodeMapFor(baselineCodeBlock); diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp index b5ac4601a..06a1cf883 100644 --- a/Source/JavaScriptCore/dfg/DFGOperations.cpp +++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp @@ -51,7 +51,7 @@ HIDE_SYMBOL(function) "\n" \ SYMBOL_STRING(function) ":" "\n" \ "mov (%rsp), %" STRINGIZE(register) "\n" \ - "jmp " SYMBOL_STRING_RELOCATION(function##WithReturnAddress) "\n" \ + "jmp " LOCAL_REFERENCE(function##WithReturnAddress) "\n" \ ); #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, rsi) #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, rcx) @@ -68,7 +68,7 @@ SYMBOL_STRING(function) ":" "\n" \ "mov (%esp), %eax\n" \ "mov %eax, " STRINGIZE(offset) "(%esp)\n" \ - "jmp " SYMBOL_STRING_RELOCATION(function##WithReturnAddress) "\n" \ + "jmp " LOCAL_REFERENCE(function##WithReturnAddress) "\n" \ ); #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, 8) #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, 16) @@ -87,7 +87,7 @@ ".thumb_func " THUMB_FUNC_PARAM(function) "\n" \ SYMBOL_STRING(function) ":" "\n" \ "mov a2, lr" "\n" \ - "b " SYMBOL_STRING_RELOCATION(function) "WithReturnAddress" "\n" \ + "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ ); #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) \ @@ -100,7 +100,7 @@ ".thumb_func " THUMB_FUNC_PARAM(function) "\n" \ SYMBOL_STRING(function) ":" "\n" \ "mov a4, lr" "\n" \ - "b " SYMBOL_STRING_RELOCATION(function) "WithReturnAddress" "\n" \ + "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ ); // EncodedJSValue in JSVALUE32_64 is a 64-bit integer. When being compiled in ARM EABI, it must be aligned even-numbered register (r0, r2 or [sp]). @@ -123,7 +123,7 @@ ".thumb_func " THUMB_FUNC_PARAM(function) "\n" \ SYMBOL_STRING(function) ":" "\n" \ INSTRUCTION_STORE_RETURN_ADDRESS_EJI "\n" \ - "b " SYMBOL_STRING_RELOCATION(function) "WithReturnAddress" "\n" \ + "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ ); #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) \ @@ -136,25 +136,25 @@ ".thumb_func " THUMB_FUNC_PARAM(function) "\n" \ SYMBOL_STRING(function) ":" "\n" \ INSTRUCTION_STORE_RETURN_ADDRESS_EJCI "\n" \ - "b " SYMBOL_STRING_RELOCATION(function) "WithReturnAddress" "\n" \ + "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ ); #endif #define P_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) \ -void* DFG_OPERATION function##WithReturnAddress(ExecState*, ReturnAddressPtr) REFERENCED_FROM_ASM; \ +void* DFG_OPERATION function##WithReturnAddress(ExecState*, ReturnAddressPtr) REFERENCED_FROM_ASM WTF_INTERNAL; \ FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) #define J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) \ -EncodedJSValue DFG_OPERATION function##WithReturnAddress(ExecState*, JSCell*, Identifier*, ReturnAddressPtr) REFERENCED_FROM_ASM; \ +EncodedJSValue DFG_OPERATION function##WithReturnAddress(ExecState*, JSCell*, Identifier*, ReturnAddressPtr) REFERENCED_FROM_ASM WTF_INTERNAL; \ FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) #define J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) \ -EncodedJSValue DFG_OPERATION function##WithReturnAddress(ExecState*, EncodedJSValue, Identifier*, ReturnAddressPtr) REFERENCED_FROM_ASM; \ +EncodedJSValue DFG_OPERATION function##WithReturnAddress(ExecState*, EncodedJSValue, Identifier*, ReturnAddressPtr) REFERENCED_FROM_ASM WTF_INTERNAL; \ FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) #define V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) \ -void DFG_OPERATION function##WithReturnAddress(ExecState*, EncodedJSValue, JSCell*, Identifier*, ReturnAddressPtr) REFERENCED_FROM_ASM; \ +void DFG_OPERATION function##WithReturnAddress(ExecState*, EncodedJSValue, JSCell*, Identifier*, ReturnAddressPtr) REFERENCED_FROM_ASM WTF_INTERNAL; \ FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) namespace JSC { namespace DFG { @@ -924,6 +924,11 @@ void* DFG_OPERATION operationVirtualConstruct(ExecState* execCallee) return virtualFor(execCallee, CodeForConstruct); } +void DFG_OPERATION operationNotifyGlobalVarWrite(WatchpointSet* watchpointSet) +{ + watchpointSet->notifyWrite(); +} + EncodedJSValue DFG_OPERATION operationResolve(ExecState* exec, Identifier* propertyName) { JSGlobalData* globalData = &exec->globalData(); @@ -1096,6 +1101,8 @@ void DFG_OPERATION operationTearOffInlinedArguments( EncodedJSValue DFG_OPERATION operationGetArgumentsLength(ExecState* exec, int32_t argumentsRegister) { + // Here we can assume that the argumernts were created. Because otherwise the JIT code would + // have not made this call. Identifier ident(&exec->globalData(), "length"); JSValue baseValue = exec->uncheckedR(argumentsRegister).jsValue(); PropertySlot slot(baseValue); @@ -1104,8 +1111,29 @@ EncodedJSValue DFG_OPERATION operationGetArgumentsLength(ExecState* exec, int32_ EncodedJSValue DFG_OPERATION operationGetArgumentByVal(ExecState* exec, int32_t argumentsRegister, int32_t index) { - return JSValue::encode( - exec->uncheckedR(argumentsRegister).jsValue().get(exec, index)); + JSValue argumentsValue = exec->uncheckedR(argumentsRegister).jsValue(); + + // If there are no arguments, and we're accessing out of bounds, then we have to create the + // arguments in case someone has installed a getter on a numeric property. + if (!argumentsValue) + exec->uncheckedR(argumentsRegister) = argumentsValue = Arguments::create(exec->globalData(), exec); + + return JSValue::encode(argumentsValue.get(exec, index)); +} + +EncodedJSValue DFG_OPERATION operationGetInlinedArgumentByVal( + ExecState* exec, int32_t argumentsRegister, InlineCallFrame* inlineCallFrame, int32_t index) +{ + JSValue argumentsValue = exec->uncheckedR(argumentsRegister).jsValue(); + + // If there are no arguments, and we're accessing out of bounds, then we have to create the + // arguments in case someone has installed a getter on a numeric property. + if (!argumentsValue) { + exec->uncheckedR(argumentsRegister) = argumentsValue = + Arguments::create(exec->globalData(), exec, inlineCallFrame); + } + + return JSValue::encode(argumentsValue.get(exec, index)); } JSCell* DFG_OPERATION operationNewFunction(ExecState* exec, JSCell* functionExecutable) @@ -1241,7 +1269,7 @@ HIDE_SYMBOL(getHostCallReturnValue) "\n" SYMBOL_STRING(getHostCallReturnValue) ":" "\n" "mov -40(%r13), %r13\n" "mov %r13, %rdi\n" - "jmp " SYMBOL_STRING_RELOCATION(getHostCallReturnValueWithExecState) "\n" + "jmp " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" ); #elif CPU(X86) asm ( @@ -1251,7 +1279,7 @@ HIDE_SYMBOL(getHostCallReturnValue) "\n" SYMBOL_STRING(getHostCallReturnValue) ":" "\n" "mov -40(%edi), %edi\n" "mov %edi, 4(%esp)\n" - "jmp " SYMBOL_STRING_RELOCATION(getHostCallReturnValueWithExecState) "\n" + "jmp " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" ); #elif CPU(ARM_THUMB2) asm ( @@ -1264,7 +1292,7 @@ HIDE_SYMBOL(getHostCallReturnValue) "\n" SYMBOL_STRING(getHostCallReturnValue) ":" "\n" "ldr r5, [r5, #-40]" "\n" "mov r0, r5" "\n" - "b " SYMBOL_STRING_RELOCATION(getHostCallReturnValueWithExecState) "\n" + "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" ); #endif diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h index 03f198e9d..38166a83f 100644 --- a/Source/JavaScriptCore/dfg/DFGOperations.h +++ b/Source/JavaScriptCore/dfg/DFGOperations.h @@ -77,6 +77,7 @@ typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EPP)(ExecState*, void*, vo typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EPS)(ExecState*, void*, size_t); typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ESS)(ExecState*, size_t, size_t); typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EZ)(ExecState*, int32_t); +typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EZIcfZ)(ExecState*, int32_t, InlineCallFrame*, int32_t); typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EZZ)(ExecState*, int32_t, int32_t); typedef JSCell* DFG_OPERATION (*C_DFGOperation_E)(ExecState*); typedef JSCell* DFG_OPERATION (*C_DFGOperation_EC)(ExecState*, JSCell*); @@ -99,78 +100,81 @@ typedef void DFG_OPERATION (*V_DFGOperation_EJCI)(ExecState*, EncodedJSValue, JS typedef void DFG_OPERATION (*V_DFGOperation_EJJJ)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue); typedef void DFG_OPERATION (*V_DFGOperation_EJPP)(ExecState*, EncodedJSValue, EncodedJSValue, void*); typedef void DFG_OPERATION (*V_DFGOperation_EPZJ)(ExecState*, void*, int32_t, EncodedJSValue); +typedef void DFG_OPERATION (*V_DFGOperation_W)(WatchpointSet*); typedef void* DFG_OPERATION (*P_DFGOperation_E)(ExecState*); // These routines are provide callbacks out to C++ implementations of operations too complex to JIT. -JSCell* DFG_OPERATION operationNewObject(ExecState*); -JSCell* DFG_OPERATION operationCreateThis(ExecState*, JSCell* constructor); -EncodedJSValue DFG_OPERATION operationConvertThis(ExecState*, EncodedJSValue encodedOp1); -EncodedJSValue DFG_OPERATION operationValueAdd(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2); -EncodedJSValue DFG_OPERATION operationValueAddNotNumber(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2); -EncodedJSValue DFG_OPERATION operationGetByVal(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty); -EncodedJSValue DFG_OPERATION operationGetByValCell(ExecState*, JSCell*, EncodedJSValue encodedProperty); -EncodedJSValue DFG_OPERATION operationGetById(ExecState*, EncodedJSValue, Identifier*); -EncodedJSValue DFG_OPERATION operationGetByIdBuildList(ExecState*, EncodedJSValue, Identifier*); -EncodedJSValue DFG_OPERATION operationGetByIdProtoBuildList(ExecState*, EncodedJSValue, Identifier*); -EncodedJSValue DFG_OPERATION operationGetByIdOptimize(ExecState*, EncodedJSValue, Identifier*); -EncodedJSValue DFG_OPERATION operationCallCustomGetter(ExecState*, JSCell*, PropertySlot::GetValueFunc, Identifier*); -EncodedJSValue DFG_OPERATION operationCallGetter(ExecState*, JSCell*, JSCell*); -EncodedJSValue DFG_OPERATION operationResolve(ExecState*, Identifier*); -EncodedJSValue DFG_OPERATION operationResolveBase(ExecState*, Identifier*); -EncodedJSValue DFG_OPERATION operationResolveBaseStrictPut(ExecState*, Identifier*); -EncodedJSValue DFG_OPERATION operationResolveGlobal(ExecState*, GlobalResolveInfo*, Identifier*); -EncodedJSValue DFG_OPERATION operationToPrimitive(ExecState*, EncodedJSValue); -EncodedJSValue DFG_OPERATION operationStrCat(ExecState*, void*, size_t); -EncodedJSValue DFG_OPERATION operationNewArray(ExecState*, void*, size_t); -EncodedJSValue DFG_OPERATION operationNewArrayBuffer(ExecState*, size_t, size_t); -EncodedJSValue DFG_OPERATION operationNewRegexp(ExecState*, void*); -void DFG_OPERATION operationPutByValStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue); -void DFG_OPERATION operationPutByValNonStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue); -void DFG_OPERATION operationPutByValCellStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, EncodedJSValue encodedValue); -void DFG_OPERATION operationPutByValCellNonStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, EncodedJSValue encodedValue); -void DFG_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState*, JSArray*, int32_t index, EncodedJSValue encodedValue); -void DFG_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState*, JSArray*, int32_t index, EncodedJSValue encodedValue); -EncodedJSValue DFG_OPERATION operationArrayPush(ExecState*, EncodedJSValue encodedValue, JSArray*); -EncodedJSValue DFG_OPERATION operationArrayPop(ExecState*, JSArray*); -EncodedJSValue DFG_OPERATION operationRegExpExec(ExecState*, JSCell*, JSCell*); -void DFG_OPERATION operationPutByIdStrict(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); -void DFG_OPERATION operationPutByIdNonStrict(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); -void DFG_OPERATION operationPutByIdDirectStrict(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); -void DFG_OPERATION operationPutByIdDirectNonStrict(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); -void DFG_OPERATION operationPutByIdStrictOptimize(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); -void DFG_OPERATION operationPutByIdNonStrictOptimize(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); -void DFG_OPERATION operationPutByIdDirectStrictOptimize(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); -void DFG_OPERATION operationPutByIdDirectNonStrictOptimize(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); -void DFG_OPERATION operationPutByIdStrictBuildList(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); -void DFG_OPERATION operationPutByIdNonStrictBuildList(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); -void DFG_OPERATION operationPutByIdDirectStrictBuildList(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); -void DFG_OPERATION operationPutByIdDirectNonStrictBuildList(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*); +JSCell* DFG_OPERATION operationNewObject(ExecState*) WTF_INTERNAL; +JSCell* DFG_OPERATION operationCreateThis(ExecState*, JSCell* constructor) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationConvertThis(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationValueAdd(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationValueAddNotNumber(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationGetByVal(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationGetByValCell(ExecState*, JSCell*, EncodedJSValue encodedProperty) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationGetById(ExecState*, EncodedJSValue, Identifier*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationGetByIdBuildList(ExecState*, EncodedJSValue, Identifier*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationGetByIdProtoBuildList(ExecState*, EncodedJSValue, Identifier*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationGetByIdOptimize(ExecState*, EncodedJSValue, Identifier*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationCallCustomGetter(ExecState*, JSCell*, PropertySlot::GetValueFunc, Identifier*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationCallGetter(ExecState*, JSCell*, JSCell*) WTF_INTERNAL; +void DFG_OPERATION operationNotifyGlobalVarWrite(WatchpointSet* watchpointSet) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationResolve(ExecState*, Identifier*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationResolveBase(ExecState*, Identifier*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationResolveBaseStrictPut(ExecState*, Identifier*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationResolveGlobal(ExecState*, GlobalResolveInfo*, Identifier*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationToPrimitive(ExecState*, EncodedJSValue) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationStrCat(ExecState*, void*, size_t) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationNewArray(ExecState*, void*, size_t) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationNewArrayBuffer(ExecState*, size_t, size_t) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationNewRegexp(ExecState*, void*) WTF_INTERNAL; +void DFG_OPERATION operationPutByValStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL; +void DFG_OPERATION operationPutByValNonStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL; +void DFG_OPERATION operationPutByValCellStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL; +void DFG_OPERATION operationPutByValCellNonStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL; +void DFG_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState*, JSArray*, int32_t index, EncodedJSValue encodedValue) WTF_INTERNAL; +void DFG_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState*, JSArray*, int32_t index, EncodedJSValue encodedValue) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationArrayPush(ExecState*, EncodedJSValue encodedValue, JSArray*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationArrayPop(ExecState*, JSArray*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationRegExpExec(ExecState*, JSCell*, JSCell*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdStrict(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdNonStrict(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdDirectStrict(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdDirectNonStrict(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdStrictOptimize(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdNonStrictOptimize(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdDirectStrictOptimize(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdDirectNonStrictOptimize(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdStrictBuildList(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdNonStrictBuildList(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdDirectStrictBuildList(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; +void DFG_OPERATION operationPutByIdDirectNonStrictBuildList(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*) WTF_INTERNAL; // These comparisons return a boolean within a size_t such that the value is zero extended to fill the register. -size_t DFG_OPERATION operationRegExpTest(ExecState*, JSCell*, JSCell*); -size_t DFG_OPERATION operationCompareLess(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2); -size_t DFG_OPERATION operationCompareLessEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2); -size_t DFG_OPERATION operationCompareGreater(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2); -size_t DFG_OPERATION operationCompareGreaterEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2); -size_t DFG_OPERATION operationCompareEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2); -size_t DFG_OPERATION operationCompareStrictEqCell(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2); -size_t DFG_OPERATION operationCompareStrictEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2); -void* DFG_OPERATION operationVirtualCall(ExecState*); -void* DFG_OPERATION operationLinkCall(ExecState*); -void* DFG_OPERATION operationVirtualConstruct(ExecState*); -void* DFG_OPERATION operationLinkConstruct(ExecState*); -JSCell* DFG_OPERATION operationCreateActivation(ExecState*); -JSCell* DFG_OPERATION operationCreateArguments(ExecState*); -JSCell* DFG_OPERATION operationCreateInlinedArguments(ExecState*, InlineCallFrame*); -void DFG_OPERATION operationTearOffActivation(ExecState*, JSCell*, int32_t unmodifiedArgumentsRegister); -void DFG_OPERATION operationTearOffArguments(ExecState*, JSCell*); -void DFG_OPERATION operationTearOffInlinedArguments(ExecState*, JSCell*, InlineCallFrame*); -EncodedJSValue DFG_OPERATION operationGetArgumentsLength(ExecState*, int32_t); -EncodedJSValue DFG_OPERATION operationGetArgumentByVal(ExecState*, int32_t, int32_t); -JSCell* DFG_OPERATION operationNewFunction(ExecState*, JSCell*); -JSCell* DFG_OPERATION operationNewFunctionExpression(ExecState*, JSCell*); -double DFG_OPERATION operationFModOnInts(int32_t, int32_t); -size_t DFG_OPERATION operationIsObject(EncodedJSValue); -size_t DFG_OPERATION operationIsFunction(EncodedJSValue); +size_t DFG_OPERATION operationRegExpTest(ExecState*, JSCell*, JSCell*) WTF_INTERNAL; +size_t DFG_OPERATION operationCompareLess(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; +size_t DFG_OPERATION operationCompareLessEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; +size_t DFG_OPERATION operationCompareGreater(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; +size_t DFG_OPERATION operationCompareGreaterEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; +size_t DFG_OPERATION operationCompareEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; +size_t DFG_OPERATION operationCompareStrictEqCell(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; +size_t DFG_OPERATION operationCompareStrictEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; +void* DFG_OPERATION operationVirtualCall(ExecState*) WTF_INTERNAL; +void* DFG_OPERATION operationLinkCall(ExecState*) WTF_INTERNAL; +void* DFG_OPERATION operationVirtualConstruct(ExecState*) WTF_INTERNAL; +void* DFG_OPERATION operationLinkConstruct(ExecState*) WTF_INTERNAL; +JSCell* DFG_OPERATION operationCreateActivation(ExecState*) WTF_INTERNAL; +JSCell* DFG_OPERATION operationCreateArguments(ExecState*) WTF_INTERNAL; +JSCell* DFG_OPERATION operationCreateInlinedArguments(ExecState*, InlineCallFrame*) WTF_INTERNAL; +void DFG_OPERATION operationTearOffActivation(ExecState*, JSCell*, int32_t unmodifiedArgumentsRegister) WTF_INTERNAL; +void DFG_OPERATION operationTearOffArguments(ExecState*, JSCell*) WTF_INTERNAL; +void DFG_OPERATION operationTearOffInlinedArguments(ExecState*, JSCell*, InlineCallFrame*) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationGetArgumentsLength(ExecState*, int32_t) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationGetInlinedArgumentByVal(ExecState*, int32_t, InlineCallFrame*, int32_t) WTF_INTERNAL; +EncodedJSValue DFG_OPERATION operationGetArgumentByVal(ExecState*, int32_t, int32_t) WTF_INTERNAL; +JSCell* DFG_OPERATION operationNewFunction(ExecState*, JSCell*) WTF_INTERNAL; +JSCell* DFG_OPERATION operationNewFunctionExpression(ExecState*, JSCell*) WTF_INTERNAL; +double DFG_OPERATION operationFModOnInts(int32_t, int32_t) WTF_INTERNAL; +size_t DFG_OPERATION operationIsObject(EncodedJSValue) WTF_INTERNAL; +size_t DFG_OPERATION operationIsFunction(EncodedJSValue) WTF_INTERNAL; // This method is used to lookup an exception hander, keyed by faultLocation, which is // the return location from one of the calls out to one of the helper operations above. @@ -210,17 +214,17 @@ inline DFGHandlerEncoded dfgHandlerEncoded(ExecState* exec, void* handler) return createDFGHandler(exec, handler).u.encoded; } #endif -DFGHandlerEncoded DFG_OPERATION lookupExceptionHandler(ExecState*, uint32_t); -DFGHandlerEncoded DFG_OPERATION lookupExceptionHandlerInStub(ExecState*, StructureStubInfo*); +DFGHandlerEncoded DFG_OPERATION lookupExceptionHandler(ExecState*, uint32_t) WTF_INTERNAL; +DFGHandlerEncoded DFG_OPERATION lookupExceptionHandlerInStub(ExecState*, StructureStubInfo*) WTF_INTERNAL; // These operations implement the implicitly called ToInt32, ToNumber, and ToBoolean conversions from ES5. -double DFG_OPERATION dfgConvertJSValueToNumber(ExecState*, EncodedJSValue); +double DFG_OPERATION dfgConvertJSValueToNumber(ExecState*, EncodedJSValue) WTF_INTERNAL; // This conversion returns an int32_t within a size_t such that the value is zero extended to fill the register. -size_t DFG_OPERATION dfgConvertJSValueToInt32(ExecState*, EncodedJSValue); -size_t DFG_OPERATION dfgConvertJSValueToBoolean(ExecState*, EncodedJSValue); +size_t DFG_OPERATION dfgConvertJSValueToInt32(ExecState*, EncodedJSValue) WTF_INTERNAL; +size_t DFG_OPERATION dfgConvertJSValueToBoolean(ExecState*, EncodedJSValue) WTF_INTERNAL; #if DFG_ENABLE(VERBOSE_SPECULATION_FAILURE) -void DFG_OPERATION debugOperationPrintSpeculationFailure(ExecState*, void*); +void DFG_OPERATION debugOperationPrintSpeculationFailure(ExecState*, void*) WTF_INTERNAL; #endif } // extern "C" diff --git a/Source/JavaScriptCore/dfg/DFGPhase.cpp b/Source/JavaScriptCore/dfg/DFGPhase.cpp index ecf669704..f97c49e31 100644 --- a/Source/JavaScriptCore/dfg/DFGPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGPhase.cpp @@ -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 @@ -39,7 +39,9 @@ void Phase::beginPhase() dataLog("Graph before %s:\n", m_name); m_graph.dump(); } +#endif +#if DFG_ENABLE(PER_PHASE_VALIDATION) void Phase::endPhase() { validate(m_graph, DumpGraph); diff --git a/Source/JavaScriptCore/dfg/DFGPhase.h b/Source/JavaScriptCore/dfg/DFGPhase.h index 6d13bcd25..53055a215 100644 --- a/Source/JavaScriptCore/dfg/DFGPhase.h +++ b/Source/JavaScriptCore/dfg/DFGPhase.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 @@ -65,11 +65,14 @@ private: // Call these hooks when starting and finishing. #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) void beginPhase(); - void endPhase(); -#else // DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) +#else void beginPhase() { } +#endif +#if DFG_ENABLE(PER_PHASE_VALIDATION) + void endPhase(); +#else void endPhase() { } -#endif // DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) +#endif }; template<typename PhaseType> diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp index 75f0b7a74..bcb79a96a 100644 --- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp @@ -82,20 +82,20 @@ public: } private: - bool setPrediction(PredictedType prediction) + bool setPrediction(SpeculatedType prediction) { ASSERT(m_graph[m_compileIndex].hasResult()); // setPrediction() is used when we know that there is no way that we can change // our minds about what the prediction is going to be. There is no semantic - // difference between setPrediction() and mergePrediction() other than the + // difference between setPrediction() and mergeSpeculation() other than the // increased checking to validate this property. - ASSERT(m_graph[m_compileIndex].prediction() == PredictNone || m_graph[m_compileIndex].prediction() == prediction); + ASSERT(m_graph[m_compileIndex].prediction() == SpecNone || m_graph[m_compileIndex].prediction() == prediction); return m_graph[m_compileIndex].predict(prediction); } - bool mergePrediction(PredictedType prediction) + bool mergePrediction(SpeculatedType prediction) { ASSERT(m_graph[m_compileIndex].hasResult()); @@ -134,13 +134,13 @@ private: switch (op) { case JSConstant: case WeakJSConstant: { - changed |= setPrediction(predictionFromValue(m_graph.valueOfJSConstant(m_compileIndex))); + changed |= setPrediction(speculationFromValue(m_graph.valueOfJSConstant(m_compileIndex))); break; } case GetLocal: { VariableAccessData* variableAccessData = node.variableAccessData(); - PredictedType prediction = variableAccessData->prediction(); + SpeculatedType prediction = variableAccessData->prediction(); if (prediction) changed |= mergePrediction(prediction); @@ -168,7 +168,7 @@ private: case BitRShift: case BitLShift: case BitURShift: { - changed |= setPrediction(PredictInt32); + changed |= setPrediction(SpecInt32); flags |= NodeUsedAsInt; flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero); changed |= m_graph[node.child1()].mergeFlags(flags); @@ -177,7 +177,7 @@ private: } case ValueToInt32: { - changed |= setPrediction(PredictInt32); + changed |= setPrediction(SpecInt32); flags |= NodeUsedAsInt; flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero); changed |= m_graph[node.child1()].mergeFlags(flags); @@ -205,22 +205,22 @@ private: } case StringCharCodeAt: { - changed |= mergePrediction(PredictInt32); + changed |= mergePrediction(SpecInt32); changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue); changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt); break; } case ArithMod: { - PredictedType left = m_graph[node.child1()].prediction(); - PredictedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = m_graph[node.child1()].prediction(); + SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { - if (isInt32Prediction(mergePredictions(left, right)) + if (isInt32Speculation(mergeSpeculations(left, right)) && nodeCanSpeculateInteger(node.arithNodeFlags())) - changed |= mergePrediction(PredictInt32); + changed |= mergePrediction(SpecInt32); else - changed |= mergePrediction(PredictDouble); + changed |= mergePrediction(SpecDouble); } flags |= NodeUsedAsValue; @@ -231,29 +231,29 @@ private: case UInt32ToNumber: { if (nodeCanSpeculateInteger(node.arithNodeFlags())) - changed |= mergePrediction(PredictInt32); + changed |= mergePrediction(SpecInt32); else - changed |= mergePrediction(PredictNumber); + changed |= mergePrediction(SpecNumber); changed |= m_graph[node.child1()].mergeFlags(flags); break; } case ValueAdd: { - PredictedType left = m_graph[node.child1()].prediction(); - PredictedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = m_graph[node.child1()].prediction(); + SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { - if (isNumberPrediction(left) && isNumberPrediction(right)) { + if (isNumberSpeculation(left) && isNumberSpeculation(right)) { if (m_graph.addShouldSpeculateInteger(node)) - changed |= mergePrediction(PredictInt32); + changed |= mergePrediction(SpecInt32); else - changed |= mergePrediction(PredictDouble); - } else if (!(left & PredictNumber) || !(right & PredictNumber)) { + changed |= mergePrediction(SpecDouble); + } else if (!(left & SpecNumber) || !(right & SpecNumber)) { // left or right is definitely something other than a number. - changed |= mergePrediction(PredictString); + changed |= mergePrediction(SpecString); } else - changed |= mergePrediction(PredictString | PredictInt32 | PredictDouble); + changed |= mergePrediction(SpecString | SpecInt32 | SpecDouble); } if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index())) @@ -265,14 +265,14 @@ private: } case ArithAdd: { - PredictedType left = m_graph[node.child1()].prediction(); - PredictedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = m_graph[node.child1()].prediction(); + SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { if (m_graph.addShouldSpeculateInteger(node)) - changed |= mergePrediction(PredictInt32); + changed |= mergePrediction(SpecInt32); else - changed |= mergePrediction(PredictDouble); + changed |= mergePrediction(SpecDouble); } if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index())) @@ -284,14 +284,14 @@ private: } case ArithSub: { - PredictedType left = m_graph[node.child1()].prediction(); - PredictedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = m_graph[node.child1()].prediction(); + SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { if (m_graph.addShouldSpeculateInteger(node)) - changed |= mergePrediction(PredictInt32); + changed |= mergePrediction(SpecInt32); else - changed |= mergePrediction(PredictDouble); + changed |= mergePrediction(SpecDouble); } if (isNotZero(node.child1().index()) || isNotZero(node.child2().index())) @@ -305,9 +305,9 @@ private: case ArithNegate: if (m_graph[node.child1()].prediction()) { if (m_graph.negateShouldSpeculateInteger(node)) - changed |= mergePrediction(PredictInt32); + changed |= mergePrediction(SpecInt32); else - changed |= mergePrediction(PredictDouble); + changed |= mergePrediction(SpecDouble); } changed |= m_graph[node.child1()].mergeFlags(flags); @@ -315,15 +315,15 @@ private: case ArithMin: case ArithMax: { - PredictedType left = m_graph[node.child1()].prediction(); - PredictedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = m_graph[node.child1()].prediction(); + SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { - if (isInt32Prediction(mergePredictions(left, right)) + if (isInt32Speculation(mergeSpeculations(left, right)) && nodeCanSpeculateInteger(node.arithNodeFlags())) - changed |= mergePrediction(PredictInt32); + changed |= mergePrediction(SpecInt32); else - changed |= mergePrediction(PredictDouble); + changed |= mergePrediction(SpecDouble); } flags |= NodeUsedAsNumber; @@ -333,14 +333,14 @@ private: } case ArithMul: { - PredictedType left = m_graph[node.child1()].prediction(); - PredictedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = m_graph[node.child1()].prediction(); + SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { if (m_graph.mulShouldSpeculateInteger(node)) - changed |= mergePrediction(PredictInt32); + changed |= mergePrediction(SpecInt32); else - changed |= mergePrediction(PredictDouble); + changed |= mergePrediction(SpecDouble); } // As soon as a multiply happens, we can easily end up in the part @@ -355,15 +355,15 @@ private: } case ArithDiv: { - PredictedType left = m_graph[node.child1()].prediction(); - PredictedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = m_graph[node.child1()].prediction(); + SpeculatedType right = m_graph[node.child2()].prediction(); if (left && right) { - if (isInt32Prediction(mergePredictions(left, right)) + if (isInt32Speculation(mergeSpeculations(left, right)) && nodeCanSpeculateInteger(node.arithNodeFlags())) - changed |= mergePrediction(PredictInt32); + changed |= mergePrediction(SpecInt32); else - changed |= mergePrediction(PredictDouble); + changed |= mergePrediction(SpecDouble); } // As soon as a multiply happens, we can easily end up in the part @@ -378,17 +378,17 @@ private: } case ArithSqrt: { - changed |= setPrediction(PredictDouble); + changed |= setPrediction(SpecDouble); changed |= m_graph[node.child1()].mergeFlags(flags | NodeUsedAsValue); break; } case ArithAbs: { - PredictedType child = m_graph[node.child1()].prediction(); + SpeculatedType child = m_graph[node.child1()].prediction(); if (nodeCanSpeculateInteger(node.arithNodeFlags())) changed |= mergePrediction(child); else - changed |= setPrediction(PredictDouble); + changed |= setPrediction(SpecDouble); flags &= ~NodeNeedsNegZero; changed |= m_graph[node.child1()].mergeFlags(flags); @@ -409,7 +409,7 @@ private: case IsString: case IsObject: case IsFunction: { - changed |= setPrediction(PredictBoolean); + changed |= setPrediction(SpecBoolean); changed |= mergeDefaultFlags(node); break; } @@ -428,7 +428,7 @@ private: case GetByVal: { if (m_graph[node.child1()].shouldSpeculateFloat32Array() || m_graph[node.child1()].shouldSpeculateFloat64Array()) - changed |= mergePrediction(PredictDouble); + changed |= mergePrediction(SpecDouble); else changed |= mergePrediction(node.getHeapPrediction()); @@ -444,13 +444,13 @@ private: } case GetMyArgumentsLengthSafe: { - changed |= setPrediction(PredictInt32); + changed |= setPrediction(SpecInt32); break; } case GetPropertyStorage: case GetIndexedPropertyStorage: { - changed |= setPrediction(PredictOther); + changed |= setPrediction(SpecOther); changed |= mergeDefaultFlags(node); break; } @@ -474,11 +474,11 @@ private: } case ConvertThis: { - PredictedType prediction = m_graph[node.child1()].prediction(); + SpeculatedType prediction = m_graph[node.child1()].prediction(); if (prediction) { - if (prediction & ~PredictObjectMask) { - prediction &= PredictObjectMask; - prediction = mergePredictions(prediction, PredictObjectOther); + if (prediction & ~SpecObjectMask) { + prediction &= SpecObjectMask; + prediction = mergeSpeculations(prediction, SpecObjectOther); } changed |= mergePrediction(prediction); } @@ -491,7 +491,8 @@ private: break; } - case PutGlobalVar: { + case PutGlobalVar: + case PutGlobalVarCheck: { changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue); break; } @@ -501,30 +502,30 @@ private: case ResolveBase: case ResolveBaseStrictPut: case ResolveGlobal: { - PredictedType prediction = node.getHeapPrediction(); + SpeculatedType prediction = node.getHeapPrediction(); changed |= mergePrediction(prediction); break; } case GetScopeChain: { - changed |= setPrediction(PredictCellOther); + changed |= setPrediction(SpecCellOther); break; } case GetCallee: { - changed |= setPrediction(PredictFunction); + changed |= setPrediction(SpecFunction); break; } case CreateThis: case NewObject: { - changed |= setPrediction(PredictFinalObject); + changed |= setPrediction(SpecFinalObject); changed |= mergeDefaultFlags(node); break; } case NewArray: { - changed |= setPrediction(PredictArray); + changed |= setPrediction(SpecArray); for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); ++childIdx) { @@ -535,24 +536,24 @@ private: } case NewArrayBuffer: { - changed |= setPrediction(PredictArray); + changed |= setPrediction(SpecArray); break; } case NewRegexp: { - changed |= setPrediction(PredictObjectOther); + changed |= setPrediction(SpecObjectOther); break; } case StringCharAt: { - changed |= setPrediction(PredictString); + changed |= setPrediction(SpecString); changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue); changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt); break; } case StrCat: { - changed |= setPrediction(PredictString); + changed |= setPrediction(SpecString); for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); ++childIdx) @@ -561,20 +562,20 @@ private: } case ToPrimitive: { - PredictedType child = m_graph[node.child1()].prediction(); + SpeculatedType child = m_graph[node.child1()].prediction(); if (child) { - if (isObjectPrediction(child)) { + if (isObjectSpeculation(child)) { // I'd love to fold this case into the case below, but I can't, because - // removing PredictObjectMask from something that only has an object - // prediction and nothing else means we have an ill-formed PredictedType + // removing SpecObjectMask from something that only has an object + // prediction and nothing else means we have an ill-formed SpeculatedType // (strong predict-none). This should be killed once we remove all traces // of static (aka weak) predictions. - changed |= mergePrediction(PredictString); - } else if (child & PredictObjectMask) { + changed |= mergePrediction(SpecString); + } else if (child & SpecObjectMask) { // Objects get turned into strings. So if the input has hints of objectness, // the output will have hinsts of stringiness. changed |= mergePrediction( - mergePredictions(child & ~PredictObjectMask, PredictString)); + mergeSpeculations(child & ~SpecObjectMask, SpecString)); } else changed |= mergePrediction(child); } @@ -583,21 +584,21 @@ private: } case CreateActivation: { - changed |= setPrediction(PredictObjectOther); + changed |= setPrediction(SpecObjectOther); break; } case CreateArguments: { // At this stage we don't try to predict whether the arguments are ours or // someone else's. We could, but we don't, yet. - changed |= setPrediction(PredictArguments); + changed |= setPrediction(SpecArguments); break; } case NewFunction: case NewFunctionNoCheck: case NewFunctionExpression: { - changed |= setPrediction(PredictFunction); + changed |= setPrediction(SpecFunction); break; } @@ -663,12 +664,14 @@ private: case ForceOSRExit: case SetArgument: case CheckStructure: + case StructureTransitionWatchpoint: case CheckFunction: case PutStructure: case TearOffActivation: case TearOffArguments: case CheckNumber: case CheckArgumentsNotCreated: + case GlobalVarWatchpoint: changed |= mergeDefaultFlags(node); break; @@ -689,7 +692,7 @@ private: } #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) - dataLog("%s\n", predictionToString(m_graph[m_compileIndex].prediction())); + dataLog("%s\n", speculationToString(m_graph[m_compileIndex].prediction())); #endif m_changed |= changed; @@ -784,12 +787,12 @@ private: case ValueAdd: case ArithAdd: case ArithSub: { - PredictedType left = m_graph[node.child1()].prediction(); - PredictedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = m_graph[node.child1()].prediction(); + SpeculatedType right = m_graph[node.child2()].prediction(); VariableAccessData::Ballot ballot; - if (isNumberPrediction(left) && isNumberPrediction(right) + if (isNumberSpeculation(left) && isNumberSpeculation(right) && !m_graph.addShouldSpeculateInteger(node)) ballot = VariableAccessData::VoteDouble; else @@ -801,12 +804,12 @@ private: } case ArithMul: { - PredictedType left = m_graph[node.child1()].prediction(); - PredictedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = m_graph[node.child1()].prediction(); + SpeculatedType right = m_graph[node.child2()].prediction(); VariableAccessData::Ballot ballot; - if (isNumberPrediction(left) && isNumberPrediction(right) + if (isNumberSpeculation(left) && isNumberSpeculation(right) && !m_graph.mulShouldSpeculateInteger(node)) ballot = VariableAccessData::VoteDouble; else @@ -821,12 +824,12 @@ private: case ArithMax: case ArithMod: case ArithDiv: { - PredictedType left = m_graph[node.child1()].prediction(); - PredictedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = m_graph[node.child1()].prediction(); + SpeculatedType right = m_graph[node.child2()].prediction(); VariableAccessData::Ballot ballot; - if (isNumberPrediction(left) && isNumberPrediction(right) + if (isNumberSpeculation(left) && isNumberSpeculation(right) && !(Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child1()]) && node.canSpeculateInteger())) ballot = VariableAccessData::VoteDouble; @@ -854,10 +857,10 @@ private: break; case SetLocal: { - PredictedType prediction = m_graph[node.child1()].prediction(); - if (isDoublePrediction(prediction)) + SpeculatedType prediction = m_graph[node.child1()].prediction(); + if (isDoubleSpeculation(prediction)) node.variableAccessData()->vote(VariableAccessData::VoteDouble); - else if (!isNumberPrediction(prediction) || isInt32Prediction(prediction)) + else if (!isNumberSpeculation(prediction) || isInt32Speculation(prediction)) node.variableAccessData()->vote(VariableAccessData::VoteValue); break; } diff --git a/Source/JavaScriptCore/dfg/DFGRepatch.cpp b/Source/JavaScriptCore/dfg/DFGRepatch.cpp index 794538184..9c3391be5 100644 --- a/Source/JavaScriptCore/dfg/DFGRepatch.cpp +++ b/Source/JavaScriptCore/dfg/DFGRepatch.cpp @@ -155,7 +155,10 @@ static void generateProtoChainAccessStub(ExecState* exec, StructureStubInfo& stu linkRestoreScratch(patchBuffer, needToRestoreScratch, success, fail, failureCases, successLabel, slowCaseLabel); - stubRoutine = patchBuffer.finalizeCode(); + stubRoutine = FINALIZE_CODE( + patchBuffer, + ("DFG prototype chain access stub for CodeBlock %p, return point %p", + exec->codeBlock(), successLabel.executableAddress())); } static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo& stubInfo) @@ -206,7 +209,11 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier linkRestoreScratch(patchBuffer, needToRestoreScratch, stubInfo, success, fail, failureCases); - stubInfo.stubRoutine = patchBuffer.finalizeCode(); + stubInfo.stubRoutine = FINALIZE_CODE( + patchBuffer, + ("DFG GetById array length stub for CodeBlock %p, return point %p", + exec->codeBlock(), stubInfo.callReturnLocation.labelAtOffset( + stubInfo.patch.dfg.deltaCallToDone).executableAddress())); RepatchBuffer repatchBuffer(codeBlock); repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck), CodeLocationLabel(stubInfo.stubRoutine.code())); @@ -261,7 +268,7 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck), CodeLocationLabel(stubInfo.stubRoutine.code())); repatchBuffer.relink(stubInfo.callReturnLocation, operationGetByIdProtoBuildList); - stubInfo.initGetByIdChain(*globalData, codeBlock->ownerExecutable(), structure, prototypeChain); + stubInfo.initGetByIdChain(*globalData, codeBlock->ownerExecutable(), structure, prototypeChain, count, true); return true; } @@ -405,7 +412,11 @@ static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identi patchBuffer.link(handlerCall, lookupExceptionHandlerInStub); } - MacroAssemblerCodeRef stubRoutine = patchBuffer.finalizeCode(); + MacroAssemblerCodeRef stubRoutine = FINALIZE_CODE( + patchBuffer, + ("DFG GetById polymorphic list access for CodeBlock %p, return point %p", + exec->codeBlock(), stubInfo.callReturnLocation.labelAtOffset( + stubInfo.patch.dfg.deltaCallToDone).executableAddress())); polymorphicStructureList->list[listIndex].set(*globalData, codeBlock->ownerExecutable(), stubRoutine, structure, isDirect); @@ -611,7 +622,11 @@ static void emitPutReplaceStub( patchBuffer.link(success, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.dfg.deltaCallToDone)); patchBuffer.link(failure, failureLabel); - stubRoutine = patchBuffer.finalizeCode(); + stubRoutine = FINALIZE_CODE( + patchBuffer, + ("DFG PutById replace stub for CodeBlock %p, return point %p", + exec->codeBlock(), stubInfo.callReturnLocation.labelAtOffset( + stubInfo.patch.dfg.deltaCallToDone).executableAddress())); } static void emitPutTransitionStub( @@ -649,6 +664,8 @@ static void emitPutTransitionStub( needToRestoreScratch = true; } + ASSERT(oldStructure->transitionWatchpointSetHasBeenInvalidated()); + failureCases.append(stubJit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(oldStructure))); testPrototype(stubJit, scratchGPR, oldStructure->storedPrototype(), failureCases); @@ -705,7 +722,11 @@ static void emitPutTransitionStub( else patchBuffer.link(failureCases, failureLabel); - stubRoutine = patchBuffer.finalizeCode(); + stubRoutine = FINALIZE_CODE( + patchBuffer, + ("DFG PutById transition stub for CodeBlock %p, return point %p", + exec->codeBlock(), stubInfo.callReturnLocation.labelAtOffset( + stubInfo.patch.dfg.deltaCallToDone).executableAddress())); } static bool tryCachePutByID(ExecState* exec, JSValue baseValue, const Identifier& ident, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind) diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp index 9b82121b3..852f74387 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp @@ -292,7 +292,7 @@ void SpeculativeJIT::writeBarrier(GPRReg ownerGPR, GPRReg valueGPR, Edge valueUs JITCompiler::Jump rhsNotCell; bool hadCellCheck = false; - if (!isKnownCell(valueUse.index()) && !isCellPrediction(m_jit.getPrediction(valueUse.index()))) { + if (!isKnownCell(valueUse.index()) && !isCellSpeculation(m_jit.getSpeculation(valueUse.index()))) { hadCellCheck = true; rhsNotCell = m_jit.branchIfNotCell(valueGPR); } @@ -354,7 +354,7 @@ void SpeculativeJIT::writeBarrier(JSCell* owner, GPRReg valueGPR, Edge valueUse, #if ENABLE(GGC) JITCompiler::Jump rhsNotCell; bool hadCellCheck = false; - if (!isKnownCell(valueUse.index()) && !isCellPrediction(m_jit.getPrediction(valueUse.index()))) { + if (!isKnownCell(valueUse.index()) && !isCellSpeculation(m_jit.getSpeculation(valueUse.index()))) { hadCellCheck = true; rhsNotCell = m_jit.branchIfNotCell(valueGPR); } @@ -826,7 +826,7 @@ void SpeculativeJIT::compilePeepHoleDoubleBranch(Node& node, NodeIndex branchNod jump(notTaken); } -void SpeculativeJIT::compilePeepHoleObjectEquality(Node& node, NodeIndex branchNodeIndex, const ClassInfo* classInfo, PredictionChecker predictionCheck) +void SpeculativeJIT::compilePeepHoleObjectEquality(Node& node, NodeIndex branchNodeIndex, const ClassInfo* classInfo, SpeculatedTypeChecker speculatedTypeChecker) { Node& branchNode = at(branchNodeIndex); BlockIndex taken = branchNode.takenBlockIndex(); @@ -847,9 +847,9 @@ void SpeculativeJIT::compilePeepHoleObjectEquality(Node& node, NodeIndex branchN GPRReg op1GPR = op1.gpr(); GPRReg op2GPR = op2.gpr(); - if (!predictionCheck(m_state.forNode(node.child1()).m_type)) + if (!speculatedTypeChecker(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node.child1().index(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo))); - if (!predictionCheck(m_state.forNode(node.child2()).m_type)) + if (!speculatedTypeChecker(m_state.forNode(node.child2()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node.child2().index(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op2GPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo))); branchPtr(condition, op1GPR, op2GPR, taken); @@ -909,32 +909,32 @@ bool SpeculativeJIT::compilePeepHoleBranch(Node& node, MacroAssembler::Relationa at(node.child1()), at(node.child2()))) { compilePeepHoleObjectEquality( node, branchNodeIndex, &JSFinalObject::s_info, - isFinalObjectPrediction); + isFinalObjectSpeculation); } else if (Node::shouldSpeculateArray( at(node.child1()), at(node.child2()))) { compilePeepHoleObjectEquality( node, branchNodeIndex, &JSArray::s_info, - isArrayPrediction); + isArraySpeculation); } else if (at(node.child1()).shouldSpeculateFinalObject() && at(node.child2()).shouldSpeculateFinalObjectOrOther()) { compilePeepHoleObjectToObjectOrOtherEquality( node.child1(), node.child2(), branchNodeIndex, - &JSFinalObject::s_info, isFinalObjectPrediction); + &JSFinalObject::s_info, isFinalObjectSpeculation); } else if (at(node.child1()).shouldSpeculateFinalObjectOrOther() && at(node.child2()).shouldSpeculateFinalObject()) { compilePeepHoleObjectToObjectOrOtherEquality( node.child2(), node.child1(), branchNodeIndex, - &JSFinalObject::s_info, isFinalObjectPrediction); + &JSFinalObject::s_info, isFinalObjectSpeculation); } else if (at(node.child1()).shouldSpeculateArray() && at(node.child2()).shouldSpeculateArrayOrOther()) { compilePeepHoleObjectToObjectOrOtherEquality( node.child1(), node.child2(), branchNodeIndex, - &JSArray::s_info, isArrayPrediction); + &JSArray::s_info, isArraySpeculation); } else if (at(node.child1()).shouldSpeculateArrayOrOther() && at(node.child2()).shouldSpeculateArray()) { compilePeepHoleObjectToObjectOrOtherEquality( node.child2(), node.child1(), branchNodeIndex, - &JSArray::s_info, isArrayPrediction); + &JSArray::s_info, isArraySpeculation); } else { nonSpeculativePeepholeBranch(node, branchNodeIndex, condition, operation); return true; @@ -991,7 +991,7 @@ void SpeculativeJIT::compile(BasicBlock& block) if (nodeIndex == NoNode || m_jit.codeBlock()->argumentIsCaptured(i)) m_arguments[i] = ValueSource(ValueInRegisterFile); else - m_arguments[i] = ValueSource::forPrediction(at(nodeIndex).variableAccessData()->prediction()); + m_arguments[i] = ValueSource::forSpeculation(at(nodeIndex).variableAccessData()->prediction()); } m_state.reset(); @@ -1011,7 +1011,7 @@ void SpeculativeJIT::compile(BasicBlock& block) else if (at(nodeIndex).variableAccessData()->shouldUseDoubleFormat()) m_variables[i] = ValueSource(DoubleInRegisterFile); else - m_variables[i] = ValueSource::forPrediction(at(nodeIndex).variableAccessData()->argumentAwarePrediction()); + m_variables[i] = ValueSource::forSpeculation(at(nodeIndex).variableAccessData()->argumentAwarePrediction()); } m_lastSetOperand = std::numeric_limits<int>::max(); @@ -1040,8 +1040,29 @@ void SpeculativeJIT::compile(BasicBlock& block) case InlineStart: { InlineCallFrame* inlineCallFrame = node.codeOrigin.inlineCallFrame; int argumentCountIncludingThis = inlineCallFrame->arguments.size(); + unsigned argumentPositionStart = node.argumentPositionStart(); + bool argumentsAreCaptured = + baselineCodeBlockForInlineCallFrame(inlineCallFrame)->argumentsAreCaptured(); for (int i = 0; i < argumentCountIncludingThis; ++i) { - ValueRecovery recovery = computeValueRecoveryFor(m_variables[inlineCallFrame->stackOffset + CallFrame::argumentOffsetIncludingThis(i)]); + ValueRecovery recovery; + if (argumentsAreCaptured) + recovery = ValueRecovery::alreadyInRegisterFile(); + else { + ArgumentPosition& argumentPosition = + m_jit.graph().m_argumentPositions[argumentPositionStart + i]; + ValueSource valueSource; + if (argumentPosition.shouldUseDoubleFormat()) + valueSource = ValueSource(DoubleInRegisterFile); + else if (isInt32Speculation(argumentPosition.prediction())) + valueSource = ValueSource(Int32InRegisterFile); + else if (isArraySpeculation(argumentPosition.prediction())) + valueSource = ValueSource(CellInRegisterFile); + else if (isBooleanSpeculation(argumentPosition.prediction())) + valueSource = ValueSource(BooleanInRegisterFile); + else + valueSource = ValueSource(ValueInRegisterFile); + recovery = computeValueRecoveryFor(valueSource); + } // The recovery should refer either to something that has already been // stored into the register file at the right place, or to a constant, // since the Arguments code isn't smart enough to handle anything else. @@ -1051,12 +1072,15 @@ void SpeculativeJIT::compile(BasicBlock& block) dataLog("\nRecovery for argument %d: ", i); recovery.dump(WTF::dataFile()); #endif - ASSERT(!i || (recovery.isAlreadyInRegisterFile() || recovery.isConstant())); inlineCallFrame->arguments[i] = recovery; } break; } + case WeakJSConstant: + m_jit.addWeakReference(node.weakConstant()); + break; + default: break; } @@ -1154,129 +1178,129 @@ void SpeculativeJIT::checkArgumentTypes() VariableAccessData* variableAccessData = node.variableAccessData(); VirtualRegister virtualRegister = variableAccessData->local(); - PredictedType predictedType = variableAccessData->prediction(); + SpeculatedType predictedType = variableAccessData->prediction(); JSValueSource valueSource = JSValueSource(JITCompiler::addressFor(virtualRegister)); #if USE(JSVALUE64) - if (isInt32Prediction(predictedType)) + if (isInt32Speculation(predictedType)) speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::Below, JITCompiler::addressFor(virtualRegister), GPRInfo::tagTypeNumberRegister)); - else if (isArrayPrediction(predictedType)) { + 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 (isBooleanPrediction(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()); speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), TrustedImm32(static_cast<int32_t>(~1)))); - } else if (isInt8ArrayPrediction(predictedType)) { + } else if (isInt8ArraySpeculation(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(m_jit.globalData()->int8ArrayDescriptor().m_classInfo))); - } else if (isInt16ArrayPrediction(predictedType)) { + } else if (isInt16ArraySpeculation(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(m_jit.globalData()->int16ArrayDescriptor().m_classInfo))); - } else if (isInt32ArrayPrediction(predictedType)) { + } else if (isInt32ArraySpeculation(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(m_jit.globalData()->int32ArrayDescriptor().m_classInfo))); - } else if (isUint8ArrayPrediction(predictedType)) { + } else if (isUint8ArraySpeculation(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(m_jit.globalData()->uint8ArrayDescriptor().m_classInfo))); - } else if (isUint8ClampedArrayPrediction(predictedType)) { + } else if (isUint8ClampedArraySpeculation(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(m_jit.globalData()->uint8ClampedArrayDescriptor().m_classInfo))); - } else if (isUint16ArrayPrediction(predictedType)) { + } else if (isUint16ArraySpeculation(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(m_jit.globalData()->uint16ArrayDescriptor().m_classInfo))); - } else if (isUint32ArrayPrediction(predictedType)) { + } else if (isUint32ArraySpeculation(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(m_jit.globalData()->uint32ArrayDescriptor().m_classInfo))); - } else if (isFloat32ArrayPrediction(predictedType)) { + } else if (isFloat32ArraySpeculation(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(m_jit.globalData()->float32ArrayDescriptor().m_classInfo))); - } else if (isFloat64ArrayPrediction(predictedType)) { + } else if (isFloat64ArraySpeculation(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(m_jit.globalData()->float64ArrayDescriptor().m_classInfo))); } #else - if (isInt32Prediction(predictedType)) + if (isInt32Speculation(predictedType)) speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag))); - else if (isArrayPrediction(predictedType)) { + 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 (isBooleanPrediction(predictedType)) + } else if (isBooleanSpeculation(predictedType)) speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::BooleanTag))); - else if (isInt8ArrayPrediction(predictedType)) { + else if (isInt8ArraySpeculation(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(m_jit.globalData()->int8ArrayDescriptor().m_classInfo))); - } else if (isInt16ArrayPrediction(predictedType)) { + } else if (isInt16ArraySpeculation(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(m_jit.globalData()->int16ArrayDescriptor().m_classInfo))); - } else if (isInt32ArrayPrediction(predictedType)) { + } else if (isInt32ArraySpeculation(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(m_jit.globalData()->int32ArrayDescriptor().m_classInfo))); - } else if (isUint8ArrayPrediction(predictedType)) { + } else if (isUint8ArraySpeculation(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(m_jit.globalData()->uint8ArrayDescriptor().m_classInfo))); - } else if (isUint8ClampedArrayPrediction(predictedType)) { + } else if (isUint8ClampedArraySpeculation(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(m_jit.globalData()->uint8ClampedArrayDescriptor().m_classInfo))); - } else if (isUint16ArrayPrediction(predictedType)) { + } else if (isUint16ArraySpeculation(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(m_jit.globalData()->uint16ArrayDescriptor().m_classInfo))); - } else if (isUint32ArrayPrediction(predictedType)) { + } else if (isUint32ArraySpeculation(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(m_jit.globalData()->uint32ArrayDescriptor().m_classInfo))); - } else if (isFloat32ArrayPrediction(predictedType)) { + } else if (isFloat32ArraySpeculation(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(m_jit.globalData()->float32ArrayDescriptor().m_classInfo))); - } else if (isFloat64ArrayPrediction(predictedType)) { + } else if (isFloat64ArraySpeculation(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))); @@ -1506,8 +1530,8 @@ void SpeculativeJIT::compileGetCharCodeAt(Node& node) GPRReg indexReg = index.gpr(); GPRReg storageReg = storage.gpr(); - if (!isStringPrediction(m_state.forNode(node.child1()).m_type)) { - ASSERT(!(at(node.child1()).prediction() & PredictString)); + if (!isStringSpeculation(m_state.forNode(node.child1()).m_type)) { + ASSERT(!(at(node.child1()).prediction() & SpecString)); terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); noResult(m_compileIndex); return; @@ -1545,8 +1569,8 @@ void SpeculativeJIT::compileGetByValOnString(Node& node) GPRReg propertyReg = property.gpr(); GPRReg storageReg = storage.gpr(); - if (!isStringPrediction(m_state.forNode(node.child1()).m_type)) { - ASSERT(!(at(node.child1()).prediction() & PredictString)); + if (!isStringSpeculation(m_state.forNode(node.child1()).m_type)) { + ASSERT(!(at(node.child1()).prediction() & SpecString)); terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); noResult(m_compileIndex); return; @@ -1680,7 +1704,7 @@ void SpeculativeJIT::compileValueToInt32(Node& node) JITCompiler::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, gpr, GPRInfo::tagTypeNumberRegister); - if (!isNumberPrediction(m_state.forNode(node.child1()).m_type)) + if (!isNumberSpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueRegs(gpr), node.child1().index(), m_jit.branchTestPtr(MacroAssembler::Zero, gpr, GPRInfo::tagTypeNumberRegister)); // First, if we get here we have a double encoded as a JSValue @@ -1717,7 +1741,7 @@ void SpeculativeJIT::compileValueToInt32(Node& node) JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, tagGPR, TrustedImm32(JSValue::Int32Tag)); - if (!isNumberPrediction(m_state.forNode(node.child1()).m_type)) + if (!isNumberSpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), node.child1().index(), m_jit.branch32(MacroAssembler::AboveOrEqual, tagGPR, TrustedImm32(JSValue::LowestTag))); unboxDouble(tagGPR, payloadGPR, fpr, scratch.fpr()); @@ -1829,7 +1853,7 @@ void SpeculativeJIT::compileInt32ToDouble(Node& node) } #endif - if (isInt32Prediction(m_state.forNode(node.child1()).m_type)) { + if (isInt32Speculation(m_state.forNode(node.child1()).m_type)) { SpeculateIntegerOperand op1(this, node.child1()); FPRTemporary result(this); m_jit.convertInt32ToDouble(op1.gpr(), result.fpr()); @@ -1850,9 +1874,11 @@ void SpeculativeJIT::compileInt32ToDouble(Node& node) JITCompiler::Jump isInteger = m_jit.branchPtr( MacroAssembler::AboveOrEqual, op1GPR, GPRInfo::tagTypeNumberRegister); - speculationCheck( - BadType, JSValueRegs(op1GPR), node.child1(), - m_jit.branchTestPtr(MacroAssembler::Zero, op1GPR, GPRInfo::tagTypeNumberRegister)); + if (!isNumberSpeculation(m_state.forNode(node.child1()).m_type)) { + speculationCheck( + BadType, JSValueRegs(op1GPR), node.child1(), + m_jit.branchTestPtr(MacroAssembler::Zero, op1GPR, GPRInfo::tagTypeNumberRegister)); + } m_jit.move(op1GPR, tempGPR); unboxDouble(tempGPR, resultFPR); @@ -1872,9 +1898,11 @@ void SpeculativeJIT::compileInt32ToDouble(Node& node) JITCompiler::Jump isInteger = m_jit.branch32( MacroAssembler::Equal, op1TagGPR, TrustedImm32(JSValue::Int32Tag)); - speculationCheck( - BadType, JSValueRegs(op1TagGPR, op1PayloadGPR), node.child1(), - m_jit.branch32(MacroAssembler::AboveOrEqual, op1TagGPR, TrustedImm32(JSValue::LowestTag))); + if (!isNumberSpeculation(m_state.forNode(node.child1()).m_type)) { + speculationCheck( + BadType, JSValueRegs(op1TagGPR, op1PayloadGPR), node.child1(), + m_jit.branch32(MacroAssembler::AboveOrEqual, op1TagGPR, TrustedImm32(JSValue::LowestTag))); + } unboxDouble(op1TagGPR, op1PayloadGPR, resultFPR, tempFPR); JITCompiler::Jump done = m_jit.jump(); @@ -2245,8 +2273,8 @@ void SpeculativeJIT::compileInstanceOfForObject(Node&, GPRReg valueReg, GPRReg p void SpeculativeJIT::compileInstanceOf(Node& node) { - if ((!!(at(node.child1()).prediction() & ~PredictCell) - && !!(m_state.forNode(node.child1()).m_type & ~PredictCell)) + if ((!!(at(node.child1()).prediction() & ~SpecCell) + && !!(m_state.forNode(node.child1()).m_type & ~SpecCell)) || at(node.child1()).adjustedRefCount() == 1) { // It might not be a cell. Speculate less aggressively. // Or: it might only be used once (i.e. by us), so we get zero benefit @@ -2780,12 +2808,12 @@ bool SpeculativeJIT::compare(Node& node, MacroAssembler::RelationalCondition con if (node.op() == CompareEq) { if (Node::shouldSpeculateFinalObject(at(node.child1()), at(node.child2()))) { - compileObjectEquality(node, &JSFinalObject::s_info, isFinalObjectPrediction); + compileObjectEquality(node, &JSFinalObject::s_info, isFinalObjectSpeculation); return false; } if (Node::shouldSpeculateArray(at(node.child1()), at(node.child2()))) { - compileObjectEquality(node, &JSArray::s_info, isArrayPrediction); + compileObjectEquality(node, &JSArray::s_info, isArraySpeculation); return false; } @@ -2793,7 +2821,7 @@ bool SpeculativeJIT::compare(Node& node, MacroAssembler::RelationalCondition con && at(node.child2()).shouldSpeculateFinalObjectOrOther()) { compileObjectToObjectOrOtherEquality( node.child1(), node.child2(), &JSFinalObject::s_info, - isFinalObjectPrediction); + isFinalObjectSpeculation); return false; } @@ -2801,7 +2829,7 @@ bool SpeculativeJIT::compare(Node& node, MacroAssembler::RelationalCondition con && at(node.child2()).shouldSpeculateFinalObject()) { compileObjectToObjectOrOtherEquality( node.child2(), node.child1(), &JSFinalObject::s_info, - isFinalObjectPrediction); + isFinalObjectSpeculation); return false; } @@ -2809,7 +2837,7 @@ bool SpeculativeJIT::compare(Node& node, MacroAssembler::RelationalCondition con && at(node.child2()).shouldSpeculateArrayOrOther()) { compileObjectToObjectOrOtherEquality( node.child1(), node.child2(), &JSArray::s_info, - isArrayPrediction); + isArraySpeculation); return false; } @@ -2817,7 +2845,7 @@ bool SpeculativeJIT::compare(Node& node, MacroAssembler::RelationalCondition con && at(node.child2()).shouldSpeculateArray()) { compileObjectToObjectOrOtherEquality( node.child2(), node.child1(), &JSArray::s_info, - isArrayPrediction); + isArraySpeculation); return false; } } @@ -2957,14 +2985,14 @@ bool SpeculativeJIT::compileStrictEq(Node& node) unsigned branchIndexInBlock = detectPeepHoleBranch(); if (branchIndexInBlock != UINT_MAX) { NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock); - compilePeepHoleObjectEquality(node, branchNodeIndex, &JSFinalObject::s_info, isFinalObjectPrediction); + compilePeepHoleObjectEquality(node, branchNodeIndex, &JSFinalObject::s_info, isFinalObjectSpeculation); use(node.child1()); use(node.child2()); m_indexInBlock = branchIndexInBlock; m_compileIndex = branchNodeIndex; return true; } - compileObjectEquality(node, &JSFinalObject::s_info, isFinalObjectPrediction); + compileObjectEquality(node, &JSFinalObject::s_info, isFinalObjectSpeculation); return false; } @@ -2972,14 +3000,14 @@ bool SpeculativeJIT::compileStrictEq(Node& node) unsigned branchIndexInBlock = detectPeepHoleBranch(); if (branchIndexInBlock != UINT_MAX) { NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock); - compilePeepHoleObjectEquality(node, branchNodeIndex, &JSArray::s_info, isArrayPrediction); + compilePeepHoleObjectEquality(node, branchNodeIndex, &JSArray::s_info, isArraySpeculation); use(node.child1()); use(node.child2()); m_indexInBlock = branchIndexInBlock; m_compileIndex = branchNodeIndex; return true; } - compileObjectEquality(node, &JSArray::s_info, isArrayPrediction); + compileObjectEquality(node, &JSArray::s_info, isArraySpeculation); return false; } @@ -2998,8 +3026,8 @@ void SpeculativeJIT::compileGetIndexedPropertyStorage(Node& node) SpeculateCellOperand base(this, node.child1()); GPRReg baseReg = base.gpr(); - PredictedType basePrediction = at(node.child2()).prediction(); - if (!(basePrediction & PredictInt32) && basePrediction) { + SpeculatedType basePrediction = at(node.child2()).prediction(); + if (!(basePrediction & SpecInt32) && basePrediction) { ASSERT_NOT_REACHED(); terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); noResult(m_compileIndex); @@ -3010,8 +3038,8 @@ void SpeculativeJIT::compileGetIndexedPropertyStorage(Node& node) GPRReg storageReg = storage.gpr(); if (at(node.child1()).shouldSpeculateArguments()) { ASSERT_NOT_REACHED(); - } else if (at(node.child1()).prediction() == PredictString) { - if (!isStringPrediction(m_state.forNode(node.child1()).m_type)) + } else if (at(node.child1()).prediction() == SpecString) { + if (!isStringSpeculation(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(&JSString::s_info))); m_jit.loadPtr(MacroAssembler::Address(baseReg, JSString::offsetOfValue()), storageReg); @@ -3022,51 +3050,51 @@ void SpeculativeJIT::compileGetIndexedPropertyStorage(Node& node) m_jit.loadPtr(MacroAssembler::Address(storageReg, StringImpl::dataOffset()), storageReg); } else if (at(node.child1()).shouldSpeculateInt8Array()) { const TypedArrayDescriptor& descriptor = m_jit.globalData()->int8ArrayDescriptor(); - if (!isInt8ArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isInt8ArraySpeculation(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(descriptor.m_classInfo))); m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); } else if (at(node.child1()).shouldSpeculateInt16Array()) { const TypedArrayDescriptor& descriptor = m_jit.globalData()->int16ArrayDescriptor(); - if (!isInt16ArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isInt16ArraySpeculation(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(descriptor.m_classInfo))); m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); } else if (at(node.child1()).shouldSpeculateInt32Array()) { const TypedArrayDescriptor& descriptor = m_jit.globalData()->int32ArrayDescriptor(); - if (!isInt32ArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isInt32ArraySpeculation(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(descriptor.m_classInfo))); m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); } else if (at(node.child1()).shouldSpeculateUint8Array()) { const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint8ArrayDescriptor(); - if (!isUint8ArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isUint8ArraySpeculation(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(descriptor.m_classInfo))); m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); } else if (at(node.child1()).shouldSpeculateUint8ClampedArray()) { const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint8ClampedArrayDescriptor(); - if (!isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); } else if (at(node.child1()).shouldSpeculateUint16Array()) { const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint16ArrayDescriptor(); - if (!isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isUint16ArraySpeculation(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(descriptor.m_classInfo))); m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); } else if (at(node.child1()).shouldSpeculateUint32Array()) { const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint32ArrayDescriptor(); - if (!isUint32ArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isUint32ArraySpeculation(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(descriptor.m_classInfo))); m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); } else if (at(node.child1()).shouldSpeculateFloat32Array()) { const TypedArrayDescriptor& descriptor = m_jit.globalData()->float32ArrayDescriptor(); - if (!isFloat32ArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isFloat32ArraySpeculation(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(descriptor.m_classInfo))); m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); } else if (at(node.child1()).shouldSpeculateFloat64Array()) { const TypedArrayDescriptor& descriptor = m_jit.globalData()->float64ArrayDescriptor(); - if (!isFloat64ArrayPrediction(m_state.forNode(node.child1()).m_type)) + if (!isFloat64ArraySpeculation(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(descriptor.m_classInfo))); m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); } else { - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + 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))); m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); } @@ -3094,7 +3122,7 @@ void SpeculativeJIT::compileGetByValOnArguments(Node& node) if (!m_compileOkay) return; - if (!isArgumentsPrediction(m_state.forNode(node.child1()).m_type)) { + if (!isArgumentsSpeculation(m_state.forNode(node.child1()).m_type)) { speculationCheck( BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr( @@ -3162,7 +3190,7 @@ void SpeculativeJIT::compileGetArgumentsLength(Node& node) if (!m_compileOkay) return; - if (!isArgumentsPrediction(m_state.forNode(node.child1()).m_type)) { + if (!isArgumentsSpeculation(m_state.forNode(node.child1()).m_type)) { speculationCheck( BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr( diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h index 56a1a1861..933784685 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h @@ -81,13 +81,13 @@ public: ASSERT(kind() == HaveNode); } - static ValueSource forPrediction(PredictedType prediction) + static ValueSource forSpeculation(SpeculatedType prediction) { - if (isInt32Prediction(prediction)) + if (isInt32Speculation(prediction)) return ValueSource(Int32InRegisterFile); - if (isArrayPrediction(prediction)) + if (isArraySpeculation(prediction)) return ValueSource(CellInRegisterFile); - if (isBooleanPrediction(prediction)) + if (isBooleanSpeculation(prediction)) return ValueSource(BooleanInRegisterFile); return ValueSource(ValueInRegisterFile); } @@ -1294,6 +1294,11 @@ public: m_jit.setupArgumentsWithExecState(TrustedImm32(arg1), arg2); return appendCallWithExceptionCheckSetResult(operation, result); } + JITCompiler::Call callOperation(J_DFGOperation_EZIcfZ operation, GPRReg result, int32_t arg1, InlineCallFrame* inlineCallFrame, GPRReg arg2) + { + m_jit.setupArgumentsWithExecState(TrustedImm32(arg1), TrustedImmPtr(inlineCallFrame), arg2); + return appendCallWithExceptionCheckSetResult(operation, result); + } JITCompiler::Call callOperation(C_DFGOperation_E operation, GPRReg result) { m_jit.setupArgumentsExecState(); @@ -1409,6 +1414,11 @@ public: m_jit.setupArgumentsWithExecState(arg1, TrustedImm32(arg2)); return appendCallWithExceptionCheck(operation); } + JITCompiler::Call callOperation(V_DFGOperation_W operation, WatchpointSet* watchpointSet) + { + m_jit.setupArguments(TrustedImmPtr(watchpointSet)); + return appendCall(operation); + } template<typename FunctionType, typename ArgumentType1> JITCompiler::Call callOperation(FunctionType operation, NoResultTag, ArgumentType1 arg1) { @@ -1547,6 +1557,11 @@ public: m_jit.setupArgumentsWithExecState(TrustedImm32(arg1)); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } + JITCompiler::Call callOperation(J_DFGOperation_EZIcfZ operation, GPRReg resultTag, GPRReg resultPayload, int32_t arg1, InlineCallFrame* inlineCallFrame, GPRReg arg2) + { + m_jit.setupArgumentsWithExecState(TrustedImm32(arg1), TrustedImmPtr(inlineCallFrame), arg2); + return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); + } JITCompiler::Call callOperation(J_DFGOperation_EZZ operation, GPRReg resultTag, GPRReg resultPayload, int32_t arg1, GPRReg arg2) { m_jit.setupArgumentsWithExecState(TrustedImm32(arg1), arg2); @@ -1662,6 +1677,11 @@ public: m_jit.setupArgumentsWithExecState(arg1, arg2, EABI_32BIT_DUMMY_ARG arg3Payload, arg3Tag); return appendCallWithExceptionCheck(operation); } + JITCompiler::Call callOperation(V_DFGOperation_W operation, WatchpointSet* watchpointSet) + { + m_jit.setupArguments(TrustedImmPtr(watchpointSet)); + return appendCall(operation); + } template<typename FunctionType, typename ArgumentType1> JITCompiler::Call callOperation(FunctionType operation, NoResultTag, ArgumentType1 arg1) { @@ -1783,6 +1803,11 @@ public: m_jit.move(GPRInfo::returnValueGPR, result); return call; } + JITCompiler::Call appendCall(const FunctionPtr& function) + { + prepareForExternalCall(); + return m_jit.appendCall(function); + } JITCompiler::Call appendCallWithExceptionCheckSetResult(const FunctionPtr& function, GPRReg result1, GPRReg result2) { JITCompiler::Call call = appendCallWithExceptionCheck(function); @@ -2034,12 +2059,12 @@ public: bool compilePeepHoleBranch(Node&, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, S_DFGOperation_EJJ); void compilePeepHoleIntegerBranch(Node&, NodeIndex branchNodeIndex, JITCompiler::RelationalCondition); void compilePeepHoleDoubleBranch(Node&, NodeIndex branchNodeIndex, JITCompiler::DoubleCondition); - void compilePeepHoleObjectEquality(Node&, NodeIndex branchNodeIndex, const ClassInfo*, PredictionChecker); + void compilePeepHoleObjectEquality(Node&, NodeIndex branchNodeIndex, const ClassInfo*, SpeculatedTypeChecker); void compilePeepHoleObjectToObjectOrOtherEquality( - Edge leftChild, Edge rightChild, NodeIndex branchNodeIndex, const ClassInfo*, PredictionChecker); - void compileObjectEquality(Node&, const ClassInfo*, PredictionChecker); + Edge leftChild, Edge rightChild, NodeIndex branchNodeIndex, const ClassInfo*, SpeculatedTypeChecker); + void compileObjectEquality(Node&, const ClassInfo*, SpeculatedTypeChecker); void compileObjectToObjectOrOtherEquality( - Edge leftChild, Edge rightChild, const ClassInfo*, PredictionChecker); + Edge leftChild, Edge rightChild, const ClassInfo*, SpeculatedTypeChecker); void compileValueAdd(Node&); void compileObjectOrOtherLogicalNot(Edge value, const ClassInfo*, bool needSpeculationCheck); void compileLogicalNot(Node&); @@ -2183,6 +2208,32 @@ public: ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes); speculationCheck(kind, jsValueSource, nodeUse.index(), jumpToFail, recovery); } + // Use this like you would use speculationCheck(), except that you don't pass it a jump + // (because you don't have to execute a branch; that's kind of the whole point), and you + // must register the returned Watchpoint with something relevant. In general, this should + // be used with extreme care. Use speculationCheck() unless you've got an amazing reason + // not to. + Watchpoint* speculationWatchpoint(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex) + { + if (!m_compileOkay) + return 0; + ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes); + OSRExit& exit = m_jit.codeBlock()->osrExit( + m_jit.codeBlock()->appendOSRExit( + OSRExit(kind, jsValueSource, + m_jit.graph().methodOfGettingAValueProfileFor(nodeIndex), + JITCompiler::Jump(), this))); + exit.m_watchpointIndex = m_jit.codeBlock()->appendWatchpoint( + Watchpoint(m_jit.watchpointLabel())); + return &m_jit.codeBlock()->watchpoint(exit.m_watchpointIndex); + } + // The default for speculation watchpoints is that they're uncounted, because the + // act of firing a watchpoint invalidates it. So, future recompilations will not + // attempt to set this watchpoint again. + Watchpoint* speculationWatchpoint() + { + return speculationWatchpoint(UncountableWatchpoint, JSValueSource(), NoNode); + } void forwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, MacroAssembler::Jump jumpToFail, const ValueRecovery& valueRecovery) { ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes); @@ -2197,7 +2248,7 @@ public: setLocal = &at(m_jit.graph().m_blocks[m_block]->at(++setLocalIndexInBlock)); hadInt32ToDouble = true; } - if (setLocal->op() == Flush) + if (setLocal->op() == Flush || setLocal->op() == Phantom) setLocal = &at(m_jit.graph().m_blocks[m_block]->at(++setLocalIndexInBlock)); if (hadInt32ToDouble) diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp index 00a83000a..0c33e0748 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp @@ -30,6 +30,7 @@ #if ENABLE(DFG_JIT) #include "DFGSlowPathGenerator.h" +#include "JSVariableObject.h" namespace JSC { namespace DFG { @@ -1051,7 +1052,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& return allocate(); } - PredictedType type = m_state.forNode(nodeIndex).m_type; + SpeculatedType type = m_state.forNode(nodeIndex).m_type; Node& node = at(nodeIndex); VirtualRegister virtualRegister = node.virtualRegister(); GenerationInfo& info = m_generationInfo[virtualRegister]; @@ -1073,7 +1074,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& ASSERT_UNUSED(spillFormat, (spillFormat & DataFormatJS) || spillFormat == DataFormatInteger); // If we know this was spilled as an integer we can fill without checking. - if (!isInt32Prediction(type)) + if (!isInt32Speculation(type)) speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag))); GPRReg gpr = allocate(); @@ -1091,7 +1092,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& GPRReg payloadGPR = info.payloadGPR(); m_gprs.lock(tagGPR); m_gprs.lock(payloadGPR); - if (!isInt32Prediction(type)) + if (!isInt32Speculation(type)) speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::Int32Tag))); m_gprs.unlock(tagGPR); m_gprs.release(tagGPR); @@ -1147,7 +1148,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) return fprAllocate(); } - PredictedType type = m_state.forNode(nodeIndex).m_type; + SpeculatedType type = m_state.forNode(nodeIndex).m_type; Node& node = at(nodeIndex); VirtualRegister virtualRegister = node.virtualRegister(); GenerationInfo& info = m_generationInfo[virtualRegister]; @@ -1185,7 +1186,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) if (spillFormat != DataFormatJSInteger && spillFormat != DataFormatInteger) { JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag)); - if (!isNumberPrediction(type)) + if (!isNumberSpeculation(type)) speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::AboveOrEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::LowestTag))); m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr); hasUnboxedDouble = m_jit.jump(); @@ -1219,7 +1220,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) if (info.registerFormat() != DataFormatJSInteger) { FPRTemporary scratch(this); JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, tagGPR, TrustedImm32(JSValue::Int32Tag)); - if (!isNumberPrediction(type)) + if (!isNumberSpeculation(type)) speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::AboveOrEqual, tagGPR, TrustedImm32(JSValue::LowestTag))); unboxDouble(tagGPR, payloadGPR, fpr, scratch.fpr()); hasUnboxedDouble = m_jit.jump(); @@ -1280,7 +1281,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) return allocate(); } - PredictedType type = m_state.forNode(nodeIndex).m_type; + SpeculatedType type = m_state.forNode(nodeIndex).m_type; Node& node = at(nodeIndex); VirtualRegister virtualRegister = node.virtualRegister(); GenerationInfo& info = m_generationInfo[virtualRegister]; @@ -1299,7 +1300,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) } ASSERT((info.spillFormat() & DataFormatJS) || info.spillFormat() == DataFormatCell); - if (!isCellPrediction(type)) + if (!isCellSpeculation(type)) speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::CellTag))); GPRReg gpr = allocate(); m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr); @@ -1320,7 +1321,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) GPRReg payloadGPR = info.payloadGPR(); m_gprs.lock(tagGPR); m_gprs.lock(payloadGPR); - if (!isCellPrediction(type)) + if (!isCellSpeculation(type)) speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::CellTag))); m_gprs.unlock(tagGPR); m_gprs.release(tagGPR); @@ -1349,7 +1350,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) #if DFG_ENABLE(DEBUG_VERBOSE) dataLog("SpecBool@%d ", nodeIndex); #endif - PredictedType type = m_state.forNode(nodeIndex).m_type; + SpeculatedType type = m_state.forNode(nodeIndex).m_type; Node& node = m_jit.graph()[nodeIndex]; VirtualRegister virtualRegister = node.virtualRegister(); GenerationInfo& info = m_generationInfo[virtualRegister]; @@ -1374,7 +1375,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) ASSERT((info.spillFormat() & DataFormatJS) || info.spillFormat() == DataFormatBoolean); - if (!isBooleanPrediction(type)) + if (!isBooleanSpeculation(type)) speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::BooleanTag))); GPRReg gpr = allocate(); @@ -1396,7 +1397,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) GPRReg payloadGPR = info.payloadGPR(); m_gprs.lock(tagGPR); m_gprs.lock(payloadGPR); - if (!isBooleanPrediction(type)) + if (!isBooleanSpeculation(type)) speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::BooleanTag))); m_gprs.unlock(tagGPR); @@ -1439,16 +1440,16 @@ JITCompiler::Jump SpeculativeJIT::convertToDouble(JSValueOperand& op, FPRReg res return notNumber; } -void SpeculativeJIT::compileObjectEquality(Node& node, const ClassInfo* classInfo, PredictionChecker predictionCheck) +void SpeculativeJIT::compileObjectEquality(Node& node, const ClassInfo* classInfo, SpeculatedTypeChecker speculatedTypeChecker) { SpeculateCellOperand op1(this, node.child1()); SpeculateCellOperand op2(this, node.child2()); GPRReg op1GPR = op1.gpr(); GPRReg op2GPR = op2.gpr(); - if (!predictionCheck(m_state.forNode(node.child1()).m_type)) + if (!speculatedTypeChecker(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo))); - if (!predictionCheck(m_state.forNode(node.child2()).m_type)) + if (!speculatedTypeChecker(m_state.forNode(node.child2()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node.child2(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op2GPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo))); GPRTemporary resultPayload(this, op2); @@ -1466,7 +1467,7 @@ void SpeculativeJIT::compileObjectEquality(Node& node, const ClassInfo* classInf void SpeculativeJIT::compileObjectToObjectOrOtherEquality( Edge leftChild, Edge rightChild, - const ClassInfo* classInfo, PredictionChecker predictionCheck) + const ClassInfo* classInfo, SpeculatedTypeChecker speculatedTypeChecker) { SpeculateCellOperand op1(this, leftChild); JSValueOperand op2(this, rightChild); @@ -1477,7 +1478,7 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality( GPRReg op2PayloadGPR = op2.payloadGPR(); GPRReg resultGPR = result.gpr(); - if (!predictionCheck(m_state.forNode(leftChild).m_type)) { + if (!speculatedTypeChecker(m_state.forNode(leftChild).m_type)) { speculationCheck( BadType, JSValueSource::unboxedCell(op1GPR), leftChild.index(), m_jit.branchPtr( @@ -1493,9 +1494,9 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality( // We know that within this branch, rightChild must be a cell. If the CFA can tell us that the // proof, when filtered on cell, demonstrates that we have an object of the desired type - // (predictionCheck() will test for FinalObject or Array, currently), then we can skip the + // (speculationCheck() will test for FinalObject or Array, currently), then we can skip the // speculation. - if (!predictionCheck(m_state.forNode(rightChild).m_type & PredictCell)) { + if (!speculatedTypeChecker(m_state.forNode(rightChild).m_type & SpecCell)) { speculationCheck( BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild.index(), m_jit.branchPtr( @@ -1514,7 +1515,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 (!isOtherPrediction(m_state.forNode(rightChild).m_type & ~PredictCell)) { + if (!isOtherSpeculation(m_state.forNode(rightChild).m_type & ~SpecCell)) { m_jit.move(op2TagGPR, resultGPR); m_jit.or32(TrustedImm32(1), resultGPR); @@ -1537,7 +1538,7 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality( void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality( Edge leftChild, Edge rightChild, NodeIndex branchNodeIndex, - const ClassInfo* classInfo, PredictionChecker predictionCheck) + const ClassInfo* classInfo, SpeculatedTypeChecker speculatedTypeChecker) { Node& branchNode = at(branchNodeIndex); BlockIndex taken = branchNode.takenBlockIndex(); @@ -1552,7 +1553,7 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality( GPRReg op2PayloadGPR = op2.payloadGPR(); GPRReg resultGPR = result.gpr(); - if (!predictionCheck(m_state.forNode(leftChild).m_type)) { + if (!speculatedTypeChecker(m_state.forNode(leftChild).m_type)) { speculationCheck( BadType, JSValueSource::unboxedCell(op1GPR), leftChild.index(), m_jit.branchPtr( @@ -1568,9 +1569,9 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality( // We know that within this branch, rightChild must be a cell. If the CFA can tell us that the // proof, when filtered on cell, demonstrates that we have an object of the desired type - // (predictionCheck() will test for FinalObject or Array, currently), then we can skip the + // (speculationCheck() will test for FinalObject or Array, currently), then we can skip the // speculation. - if (!predictionCheck(m_state.forNode(rightChild).m_type & PredictCell)) { + if (!speculatedTypeChecker(m_state.forNode(rightChild).m_type & SpecCell)) { speculationCheck( BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild.index(), m_jit.branchPtr( @@ -1586,7 +1587,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 (isOtherPrediction(m_state.forNode(rightChild).m_type & ~PredictCell)) + if (isOtherSpeculation(m_state.forNode(rightChild).m_type & ~SpecCell)) rightNotCell.link(&m_jit); else { jump(notTaken, ForceJump); @@ -1692,11 +1693,11 @@ void SpeculativeJIT::compileLogicalNot(Node& node) return; } if (at(node.child1()).shouldSpeculateFinalObjectOrOther()) { - compileObjectOrOtherLogicalNot(node.child1(), &JSFinalObject::s_info, !isFinalObjectOrOtherPrediction(m_state.forNode(node.child1()).m_type)); + compileObjectOrOtherLogicalNot(node.child1(), &JSFinalObject::s_info, !isFinalObjectOrOtherSpeculation(m_state.forNode(node.child1()).m_type)); return; } if (at(node.child1()).shouldSpeculateArrayOrOther()) { - compileObjectOrOtherLogicalNot(node.child1(), &JSArray::s_info, !isArrayOrOtherPrediction(m_state.forNode(node.child1()).m_type)); + compileObjectOrOtherLogicalNot(node.child1(), &JSArray::s_info, !isArrayOrOtherSpeculation(m_state.forNode(node.child1()).m_type)); return; } if (at(node.child1()).shouldSpeculateInteger()) { @@ -1787,9 +1788,9 @@ void SpeculativeJIT::emitBranch(Node& node) noResult(m_compileIndex); } else if (at(node.child1()).shouldSpeculateFinalObjectOrOther()) { - emitObjectOrOtherBranch(node.child1(), taken, notTaken, &JSFinalObject::s_info, !isFinalObjectOrOtherPrediction(m_state.forNode(node.child1()).m_type)); + emitObjectOrOtherBranch(node.child1(), taken, notTaken, &JSFinalObject::s_info, !isFinalObjectOrOtherSpeculation(m_state.forNode(node.child1()).m_type)); } else if (at(node.child1()).shouldSpeculateArrayOrOther()) { - emitObjectOrOtherBranch(node.child1(), taken, notTaken, &JSArray::s_info, !isArrayOrOtherPrediction(m_state.forNode(node.child1()).m_type)); + emitObjectOrOtherBranch(node.child1(), taken, notTaken, &JSArray::s_info, !isArrayOrOtherSpeculation(m_state.forNode(node.child1()).m_type)); } else if (at(node.child1()).shouldSpeculateNumber()) { if (at(node.child1()).shouldSpeculateInteger()) { bool invert = false; @@ -1848,7 +1849,13 @@ void SpeculativeJIT::compile(Node& node) switch (op) { case JSConstant: + initConstantInfo(m_compileIndex); + break; + case PhantomArguments: + // This should never be must-generate. + ASSERT_NOT_REACHED(); + // But as a release-mode fall-back make it the empty value. initConstantInfo(m_compileIndex); break; @@ -1858,11 +1865,11 @@ void SpeculativeJIT::compile(Node& node) break; case GetLocal: { - PredictedType prediction = node.variableAccessData()->prediction(); + SpeculatedType prediction = node.variableAccessData()->prediction(); AbstractValue& value = block()->valuesAtHead.operand(node.local()); // If we have no prediction for this local, then don't attempt to compile. - if (prediction == PredictNone) { + if (prediction == SpecNone) { terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode); break; } @@ -1884,7 +1891,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isInt32Prediction(prediction)) { + if (isInt32Speculation(prediction)) { GPRTemporary result(this); m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr()); @@ -1896,7 +1903,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isArrayPrediction(prediction)) { + if (isArraySpeculation(prediction)) { GPRTemporary result(this); m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr()); @@ -1908,7 +1915,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isBooleanPrediction(prediction)) { + if (isBooleanSpeculation(prediction)) { GPRTemporary result(this); m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr()); @@ -1933,7 +1940,7 @@ void SpeculativeJIT::compile(Node& node) m_gprs.retain(tag.gpr(), virtualRegister, SpillOrderJS); DataFormat format; - if (isCellPrediction(value.m_type) + if (isCellSpeculation(value.m_type) && !node.variableAccessData()->isCaptured()) format = DataFormatJSCell; else @@ -1999,7 +2006,7 @@ void SpeculativeJIT::compile(Node& node) valueSourceReferenceForOperand(node.local()) = ValueSource(DoubleInRegisterFile); break; } - PredictedType predictedType = node.variableAccessData()->argumentAwarePrediction(); + SpeculatedType predictedType = node.variableAccessData()->argumentAwarePrediction(); if (m_generationInfo[at(node.child1()).virtualRegister()].registerFormat() == DataFormatDouble) { DoubleOperand value(this, node.child1()); m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node.local())); @@ -2007,24 +2014,24 @@ void SpeculativeJIT::compile(Node& node) valueSourceReferenceForOperand(node.local()) = ValueSource(DoubleInRegisterFile); break; } - if (isInt32Prediction(predictedType)) { + if (isInt32Speculation(predictedType)) { SpeculateIntegerOperand value(this, node.child1()); m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local())); noResult(m_compileIndex); valueSourceReferenceForOperand(node.local()) = ValueSource(Int32InRegisterFile); break; } - if (isArrayPrediction(predictedType)) { + if (isArraySpeculation(predictedType)) { SpeculateCellOperand cell(this, node.child1()); GPRReg cellGPR = cell.gpr(); - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + 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); valueSourceReferenceForOperand(node.local()) = ValueSource(CellInRegisterFile); break; } - if (isBooleanPrediction(predictedType)) { + if (isBooleanSpeculation(predictedType)) { SpeculateBooleanOperand value(this, node.child1()); m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local())); noResult(m_compileIndex); @@ -2122,7 +2129,7 @@ void SpeculativeJIT::compile(Node& node) } case CheckNumber: { - if (!isNumberPrediction(m_state.forNode(node.child1()).m_type)) { + if (!isNumberSpeculation(m_state.forNode(node.child1()).m_type)) { JSValueOperand op1(this, node.child1()); JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, op1.tagGPR(), TrustedImm32(JSValue::Int32Tag)); speculationCheck( @@ -2326,7 +2333,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (!at(node.child2()).shouldSpeculateInteger() || !isActionableArrayPrediction(at(node.child1()).prediction())) { + if (!at(node.child2()).shouldSpeculateInteger() || !isActionableArraySpeculation(at(node.child1()).prediction())) { SpeculateCellOperand base(this, node.child1()); // Save a register, speculate cell. We'll probably be right. JSValueOperand property(this, node.child2()); GPRReg baseGPR = base.gpr(); @@ -2349,7 +2356,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (at(node.child1()).prediction() == PredictString) { + if (at(node.child1()).prediction() == SpecString) { compileGetByValOnString(node); if (!m_compileOkay) return; @@ -2357,63 +2364,63 @@ void SpeculativeJIT::compile(Node& node) } if (at(node.child1()).shouldSpeculateInt8Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), node, sizeof(int8_t), isInt8ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), node, sizeof(int8_t), isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateInt16Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), node, sizeof(int16_t), isInt16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), node, sizeof(int16_t), isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateInt32Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), node, sizeof(int32_t), isInt32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), node, sizeof(int32_t), isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint8Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), node, sizeof(uint8_t), isUint8ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), node, sizeof(uint8_t), isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint8ClampedArray()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, sizeof(uint8_t), isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, sizeof(uint8_t), isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint16Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), node, sizeof(uint16_t), isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), node, sizeof(uint16_t), isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint32Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), node, sizeof(uint32_t), isUint32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), node, sizeof(uint32_t), isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateFloat32Array()) { - compileGetByValOnFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), node, sizeof(float), isFloat32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); + compileGetByValOnFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), node, sizeof(float), isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateFloat64Array()) { - compileGetByValOnFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), node, sizeof(double), isFloat64ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); + compileGetByValOnFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), node, sizeof(double), isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); if (!m_compileOkay) return; break; @@ -2434,7 +2441,7 @@ void SpeculativeJIT::compile(Node& node) { SpeculateCellOperand base(this, node.child1()); GPRReg baseReg = base.gpr(); - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + 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))); speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()))); } @@ -2460,7 +2467,7 @@ void SpeculativeJIT::compile(Node& node) } if (!at(node.child2()).shouldSpeculateInteger() - || !isActionableMutableArrayPrediction(at(node.child1()).prediction()) + || !isActionableMutableArraySpeculation(at(node.child1()).prediction()) || at(node.child1()).shouldSpeculateArguments()) { SpeculateCellOperand base(this, node.child1()); // Save a register, speculate cell. We'll probably be right. JSValueOperand property(this, node.child2()); @@ -2481,63 +2488,63 @@ void SpeculativeJIT::compile(Node& node) SpeculateCellOperand base(this, node.child1()); SpeculateStrictInt32Operand property(this, node.child2()); if (at(node.child1()).shouldSpeculateInt8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), isInt8ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateInt16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), isInt16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateInt32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), isInt32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint8ClampedArray()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray, ClampRounding); + compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray, ClampRounding); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), isUint32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateFloat32Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float), isFloat32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); + compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float), isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateFloat64Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double), isFloat64ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); + compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double), isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); if (!m_compileOkay) return; break; @@ -2562,7 +2569,7 @@ void SpeculativeJIT::compile(Node& node) // 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 (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + 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))); base.use(); @@ -2608,7 +2615,7 @@ void SpeculativeJIT::compile(Node& node) break; } - ASSERT(isActionableMutableArrayPrediction(at(node.child1()).prediction())); + ASSERT(isActionableMutableArraySpeculation(at(node.child1()).prediction())); ASSERT(at(node.child2()).shouldSpeculateInteger()); SpeculateCellOperand base(this, node.child1()); @@ -2763,7 +2770,7 @@ void SpeculativeJIT::compile(Node& node) writeBarrier(baseGPR, valueTagGPR, node.child2(), WriteBarrierForPropertyAccess, storageGPR, storageLengthGPR); - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + 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))); m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR); @@ -2801,7 +2808,7 @@ void SpeculativeJIT::compile(Node& node) GPRReg storageGPR = storage.gpr(); GPRReg storageLengthGPR = storageLength.gpr(); - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + 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))); m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR); @@ -2947,7 +2954,7 @@ void SpeculativeJIT::compile(Node& node) op1.use(); - if (!(m_state.forNode(node.child1()).m_type & ~(PredictNumber | PredictBoolean))) { + if (!(m_state.forNode(node.child1()).m_type & ~(SpecNumber | SpecBoolean))) { m_jit.move(op1TagGPR, resultTagGPR); m_jit.move(op1PayloadGPR, resultPayloadGPR); } else { @@ -3053,7 +3060,7 @@ void SpeculativeJIT::compile(Node& node) } case ConvertThis: { - if (isObjectPrediction(m_state.forNode(node.child1()).m_type)) { + if (isObjectSpeculation(m_state.forNode(node.child1()).m_type)) { SpeculateCellOperand thisValue(this, node.child1()); GPRTemporary result(this, thisValue); m_jit.move(thisValue.gpr(), result.gpr()); @@ -3061,7 +3068,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isOtherPrediction(at(node.child1()).prediction())) { + if (isOtherSpeculation(at(node.child1()).prediction())) { JSValueOperand thisValue(this, node.child1()); GPRTemporary scratch(this); @@ -3080,11 +3087,11 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isObjectPrediction(at(node.child1()).prediction())) { + if (isObjectSpeculation(at(node.child1()).prediction())) { SpeculateCellOperand thisValue(this, node.child1()); GPRReg thisValueGPR = thisValue.gpr(); - if (!isObjectPrediction(m_state.forNode(node.child1()).m_type)) + if (!isObjectSpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueSource::unboxedCell(thisValueGPR), node.child1(), m_jit.branchPtr(JITCompiler::Equal, JITCompiler::Address(thisValueGPR, JSCell::classInfoOffset()), JITCompiler::TrustedImmPtr(&JSString::s_info))); GPRTemporary result(this, thisValue); @@ -3214,7 +3221,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isCellPrediction(at(node.child1()).prediction())) { + if (isCellSpeculation(at(node.child1()).prediction())) { SpeculateCellOperand base(this, node.child1()); GPRTemporary resultTag(this, base); GPRTemporary resultPayload(this); @@ -3268,7 +3275,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isCellPrediction(at(node.child1()).prediction())) { + if (isCellSpeculation(at(node.child1()).prediction())) { SpeculateCellOperand base(this, node.child1()); GPRReg baseGPR = base.gpr(); @@ -3317,7 +3324,7 @@ void SpeculativeJIT::compile(Node& node) SpeculateCellOperand base(this, node.child1()); GPRReg baseGPR = base.gpr(); - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + 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))); GPRTemporary result(this); @@ -3344,7 +3351,7 @@ void SpeculativeJIT::compile(Node& node) GPRReg baseGPR = base.gpr(); GPRReg resultGPR = result.gpr(); - if (!isStringPrediction(m_state.forNode(node.child1()).m_type)) + if (!isStringSpeculation(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(&JSString::s_info))); m_jit.load32(MacroAssembler::Address(baseGPR, JSString::offsetOfLength()), resultGPR); @@ -3354,39 +3361,39 @@ void SpeculativeJIT::compile(Node& node) } case GetInt8ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int8ArrayDescriptor(), node, !isInt8ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->int8ArrayDescriptor(), node, !isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetInt16ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int16ArrayDescriptor(), node, !isInt16ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->int16ArrayDescriptor(), node, !isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetInt32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int32ArrayDescriptor(), node, !isInt32ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->int32ArrayDescriptor(), node, !isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetUint8ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint8ArrayDescriptor(), node, !isUint8ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->uint8ArrayDescriptor(), node, !isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetUint8ClampedArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, !isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, !isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetUint16ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint16ArrayDescriptor(), node, !isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->uint16ArrayDescriptor(), node, !isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetUint32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint32ArrayDescriptor(), node, !isUint32ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->uint32ArrayDescriptor(), node, !isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetFloat32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->float32ArrayDescriptor(), node, !isFloat32ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->float32ArrayDescriptor(), node, !isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetFloat64ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->float64ArrayDescriptor(), node, !isFloat64ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->float64ArrayDescriptor(), node, !isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } @@ -3400,7 +3407,7 @@ void SpeculativeJIT::compile(Node& node) case CheckStructure: { AbstractValue& value = m_state.forNode(node.child1()); if (value.m_structure.isSubsetOf(node.structureSet()) - && isCellPrediction(value.m_type)) { + && isCellSpeculation(value.m_type)) { noResult(m_compileIndex); break; } @@ -3430,7 +3437,23 @@ void SpeculativeJIT::compile(Node& node) break; } + case StructureTransitionWatchpoint: { + m_jit.addWeakReference(node.structure()); + node.structure()->addTransitionWatchpoint(speculationWatchpoint()); + +#if !ASSERT_DISABLED + SpeculateCellOperand op1(this, node.child1()); + JITCompiler::Jump isOK = m_jit.branchPtr(JITCompiler::Equal, JITCompiler::Address(op1.gpr(), JSCell::structureOffset()), TrustedImmPtr(node.structure())); + m_jit.breakpoint(); + isOK.link(&m_jit); +#endif + + noResult(m_compileIndex); + break; + } + case PhantomPutStructure: { + ASSERT(node.structureTransitionData().previousStructure->transitionWatchpointSetHasBeenInvalidated()); m_jit.addWeakReferenceTransition( node.codeOrigin.codeOriginOwner(), node.structureTransitionData().previousStructure, @@ -3440,6 +3463,8 @@ void SpeculativeJIT::compile(Node& node) } case PutStructure: { + ASSERT(node.structureTransitionData().previousStructure->transitionWatchpointSetHasBeenInvalidated()); + SpeculateCellOperand base(this, node.child1()); GPRReg baseGPR = base.gpr(); @@ -3558,34 +3583,89 @@ void SpeculativeJIT::compile(Node& node) } case GetGlobalVar: { - GPRTemporary result(this); - GPRTemporary scratch(this); + GPRTemporary resultPayload(this); + GPRTemporary resultTag(this); - JSVariableObject* globalObject = m_jit.globalObjectFor(node.codeOrigin); - m_jit.loadPtr(const_cast<WriteBarrier<Unknown>**>(globalObject->addressOfRegisters()), result.gpr()); - m_jit.load32(JITCompiler::tagForGlobalVar(result.gpr(), node.varNumber()), scratch.gpr()); - m_jit.load32(JITCompiler::payloadForGlobalVar(result.gpr(), node.varNumber()), result.gpr()); + m_jit.move(TrustedImmPtr(node.registerPointer()), resultPayload.gpr()); + m_jit.load32(JITCompiler::Address(resultPayload.gpr(), OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTag.gpr()); + m_jit.load32(JITCompiler::Address(resultPayload.gpr(), OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayload.gpr()); - jsValueResult(scratch.gpr(), result.gpr(), m_compileIndex); + jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex); break; } case PutGlobalVar: { JSValueOperand value(this, node.child1()); - GPRTemporary globalObject(this); - GPRTemporary scratch(this); - - GPRReg globalObjectReg = globalObject.gpr(); - GPRReg scratchReg = scratch.gpr(); + if (Heap::isWriteBarrierEnabled()) { + GPRTemporary scratch(this); + GPRReg scratchReg = scratch.gpr(); + + writeBarrier(m_jit.globalObjectFor(node.codeOrigin), value.tagGPR(), node.child1(), WriteBarrierForVariableAccess, scratchReg); + } - m_jit.move(MacroAssembler::TrustedImmPtr(m_jit.globalObjectFor(node.codeOrigin)), globalObjectReg); + // FIXME: if we happen to have a spare register - and _ONLY_ if we happen to have + // a spare register - a good optimization would be to put the register pointer into + // a register and then do a zero offset store followed by a four-offset store (or + // vice-versa depending on endianness). + m_jit.store32(value.tagGPR(), node.registerPointer()->tagPointer()); + m_jit.store32(value.payloadGPR(), node.registerPointer()->payloadPointer()); - writeBarrier(m_jit.globalObjectFor(node.codeOrigin), value.tagGPR(), node.child1(), WriteBarrierForVariableAccess, scratchReg); + noResult(m_compileIndex); + break; + } - m_jit.loadPtr(MacroAssembler::Address(globalObjectReg, JSVariableObject::offsetOfRegisters()), scratchReg); - m_jit.store32(value.tagGPR(), JITCompiler::tagForGlobalVar(scratchReg, node.varNumber())); - m_jit.store32(value.payloadGPR(), JITCompiler::payloadForGlobalVar(scratchReg, node.varNumber())); + case PutGlobalVarCheck: { + JSValueOperand value(this, node.child1()); + + WatchpointSet* watchpointSet = + m_jit.globalObjectFor(node.codeOrigin)->symbolTable().get( + identifier(node.identifierNumberForCheck())->impl()).watchpointSet(); + addSlowPathGenerator( + slowPathCall( + m_jit.branchTest8( + JITCompiler::NonZero, + JITCompiler::AbsoluteAddress(watchpointSet->addressOfIsWatched())), + this, operationNotifyGlobalVarWrite, NoResult, watchpointSet)); + + if (Heap::isWriteBarrierEnabled()) { + GPRTemporary scratch(this); + GPRReg scratchReg = scratch.gpr(); + + writeBarrier(m_jit.globalObjectFor(node.codeOrigin), value.tagGPR(), node.child1(), WriteBarrierForVariableAccess, scratchReg); + } + // FIXME: if we happen to have a spare register - and _ONLY_ if we happen to have + // a spare register - a good optimization would be to put the register pointer into + // a register and then do a zero offset store followed by a four-offset store (or + // vice-versa depending on endianness). + m_jit.store32(value.tagGPR(), node.registerPointer()->tagPointer()); + m_jit.store32(value.payloadGPR(), node.registerPointer()->payloadPointer()); + + noResult(m_compileIndex); + break; + } + + case GlobalVarWatchpoint: { + m_jit.globalObjectFor(node.codeOrigin)->symbolTable().get( + identifier(node.identifierNumberForCheck())->impl()).addWatchpoint( + speculationWatchpoint()); + +#if DFG_ENABLE(JIT_ASSERT) + GPRTemporary scratch(this); + GPRReg scratchGPR = scratch.gpr(); + m_jit.load32(node.registerPointer()->tagPointer(), scratchGPR); + JITCompiler::Jump notOK = m_jit.branch32( + JITCompiler::NotEqual, scratchGPR, + TrustedImm32(node.registerPointer()->get().tag())); + m_jit.load32(node.registerPointer()->payloadPointer(), scratchGPR); + JITCompiler::Jump ok = m_jit.branch32( + JITCompiler::Equal, scratchGPR, + TrustedImm32(node.registerPointer()->get().payload())); + notOK.link(&m_jit); + m_jit.breakpoint(); + ok.link(&m_jit); +#endif + noResult(m_compileIndex); break; } @@ -3858,16 +3938,15 @@ void SpeculativeJIT::compile(Node& node) } case CheckArgumentsNotCreated: { - if (!isEmptyPrediction( - m_state.variables().operand( - m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) { - speculationCheck( - Uncountable, JSValueRegs(), NoNode, - m_jit.branch32( - JITCompiler::NotEqual, - JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)), - TrustedImm32(JSValue::EmptyValueTag))); - } + ASSERT(!isEmptySpeculation( + m_state.variables().operand( + m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)); + speculationCheck( + Uncountable, JSValueRegs(), NoNode, + m_jit.branch32( + JITCompiler::NotEqual, + JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)), + TrustedImm32(JSValue::EmptyValueTag))); noResult(m_compileIndex); break; } @@ -3876,7 +3955,7 @@ void SpeculativeJIT::compile(Node& node) GPRTemporary result(this); GPRReg resultGPR = result.gpr(); - if (!isEmptyPrediction( + if (!isEmptySpeculation( m_state.variables().operand( m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) { speculationCheck( @@ -3937,7 +4016,7 @@ void SpeculativeJIT::compile(Node& node) GPRReg resultPayloadGPR = resultPayload.gpr(); GPRReg resultTagGPR = resultTag.gpr(); - if (!isEmptyPrediction( + if (!isEmptySpeculation( m_state.variables().operand( m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) { speculationCheck( @@ -4033,11 +4112,20 @@ void SpeculativeJIT::compile(Node& node) baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR); - addSlowPathGenerator( - slowPathCall( - slowPath, this, operationGetArgumentByVal, - JSValueRegs(resultTagGPR, resultPayloadGPR), - m_jit.argumentsRegisterFor(node.codeOrigin), indexGPR)); + if (node.codeOrigin.inlineCallFrame) { + addSlowPathGenerator( + slowPathCall( + slowPath, this, operationGetInlinedArgumentByVal, + JSValueRegs(resultTagGPR, resultPayloadGPR), + m_jit.argumentsRegisterFor(node.codeOrigin), + node.codeOrigin.inlineCallFrame, indexGPR)); + } else { + addSlowPathGenerator( + slowPathCall( + slowPath, this, operationGetArgumentByVal, + JSValueRegs(resultTagGPR, resultPayloadGPR), + m_jit.argumentsRegisterFor(node.codeOrigin), indexGPR)); + } jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex); break; diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp index ca57743a6..0b7606b2c 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp @@ -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 @@ -1028,7 +1028,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& #if DFG_ENABLE(DEBUG_VERBOSE) dataLog("SpecInt@%d ", nodeIndex); #endif - PredictedType type = m_state.forNode(nodeIndex).m_type; + SpeculatedType type = m_state.forNode(nodeIndex).m_type; Node& node = at(nodeIndex); VirtualRegister virtualRegister = node.virtualRegister(); GenerationInfo& info = m_generationInfo[virtualRegister]; @@ -1086,7 +1086,7 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& // Check the value is an integer. GPRReg gpr = info.gpr(); m_gprs.lock(gpr); - if (!isInt32Prediction(type)) + if (!isInt32Speculation(type)) speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchPtr(MacroAssembler::Below, gpr, GPRInfo::tagTypeNumberRegister)); info.fillJSValue(gpr, DataFormatJSInteger); // If !strict we're done, return. @@ -1175,7 +1175,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) #if DFG_ENABLE(DEBUG_VERBOSE) dataLog("SpecDouble@%d ", nodeIndex); #endif - PredictedType type = m_state.forNode(nodeIndex).m_type; + SpeculatedType type = m_state.forNode(nodeIndex).m_type; Node& node = at(nodeIndex); VirtualRegister virtualRegister = node.virtualRegister(); GenerationInfo& info = m_generationInfo[virtualRegister]; @@ -1260,7 +1260,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) JITCompiler::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, jsValueGpr, GPRInfo::tagTypeNumberRegister); - if (!isNumberPrediction(type)) + if (!isNumberSpeculation(type)) speculationCheck(BadType, JSValueRegs(jsValueGpr), nodeIndex, m_jit.branchTestPtr(MacroAssembler::Zero, jsValueGpr, GPRInfo::tagTypeNumberRegister)); // First, if we get here we have a double encoded as a JSValue @@ -1328,7 +1328,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) #if DFG_ENABLE(DEBUG_VERBOSE) dataLog("SpecCell@%d ", nodeIndex); #endif - PredictedType type = m_state.forNode(nodeIndex).m_type; + SpeculatedType type = m_state.forNode(nodeIndex).m_type; Node& node = at(nodeIndex); VirtualRegister virtualRegister = node.virtualRegister(); GenerationInfo& info = m_generationInfo[virtualRegister]; @@ -1358,7 +1358,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr); info.fillJSValue(gpr, DataFormatJS); - if (!isCellPrediction(type)) + if (!isCellSpeculation(type)) speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister)); info.fillJSValue(gpr, DataFormatJSCell); return gpr; @@ -1374,7 +1374,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) case DataFormatJS: { GPRReg gpr = info.gpr(); m_gprs.lock(gpr); - if (!isCellPrediction(type)) + if (!isCellSpeculation(type)) speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister)); info.fillJSValue(gpr, DataFormatJSCell); return gpr; @@ -1403,7 +1403,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) #if DFG_ENABLE(DEBUG_VERBOSE) dataLog("SpecBool@%d ", nodeIndex); #endif - PredictedType type = m_state.forNode(nodeIndex).m_type; + SpeculatedType type = m_state.forNode(nodeIndex).m_type; Node& node = at(nodeIndex); VirtualRegister virtualRegister = node.virtualRegister(); GenerationInfo& info = m_generationInfo[virtualRegister]; @@ -1433,7 +1433,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr); info.fillJSValue(gpr, DataFormatJS); - if (!isBooleanPrediction(type)) { + if (!isBooleanSpeculation(type)) { m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr); speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg)); m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr); @@ -1452,7 +1452,7 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) case DataFormatJS: { GPRReg gpr = info.gpr(); m_gprs.lock(gpr); - if (!isBooleanPrediction(type)) { + if (!isBooleanSpeculation(type)) { m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr); speculationCheck(BadType, JSValueRegs(gpr), nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg)); m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr); @@ -1499,7 +1499,7 @@ JITCompiler::Jump SpeculativeJIT::convertToDouble(GPRReg value, FPRReg result, G return notNumber; } -void SpeculativeJIT::compileObjectEquality(Node& node, const ClassInfo* classInfo, PredictionChecker predictionCheck) +void SpeculativeJIT::compileObjectEquality(Node& node, const ClassInfo* classInfo, SpeculatedTypeChecker speculatedTypeChecker) { SpeculateCellOperand op1(this, node.child1()); SpeculateCellOperand op2(this, node.child2()); @@ -1509,9 +1509,9 @@ void SpeculativeJIT::compileObjectEquality(Node& node, const ClassInfo* classInf GPRReg op2GPR = op2.gpr(); GPRReg resultGPR = result.gpr(); - if (!predictionCheck(m_state.forNode(node.child1()).m_type)) + if (!speculatedTypeChecker(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueRegs(op1GPR), node.child1().index(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo))); - if (!predictionCheck(m_state.forNode(node.child2()).m_type)) + if (!speculatedTypeChecker(m_state.forNode(node.child2()).m_type)) speculationCheck(BadType, JSValueRegs(op2GPR), node.child2().index(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op2GPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo))); MacroAssembler::Jump falseCase = m_jit.branchPtr(MacroAssembler::NotEqual, op1GPR, op2GPR); @@ -1526,7 +1526,7 @@ void SpeculativeJIT::compileObjectEquality(Node& node, const ClassInfo* classInf void SpeculativeJIT::compileObjectToObjectOrOtherEquality( Edge leftChild, Edge rightChild, - const ClassInfo* classInfo, PredictionChecker predictionCheck) + const ClassInfo* classInfo, SpeculatedTypeChecker speculatedTypeChecker) { SpeculateCellOperand op1(this, leftChild); JSValueOperand op2(this, rightChild); @@ -1536,7 +1536,7 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality( GPRReg op2GPR = op2.gpr(); GPRReg resultGPR = result.gpr(); - if (!predictionCheck(m_state.forNode(leftChild).m_type)) { + if (!speculatedTypeChecker(m_state.forNode(leftChild).m_type)) { speculationCheck( BadType, JSValueRegs(op1GPR), leftChild.index(), m_jit.branchPtr( @@ -1552,9 +1552,9 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality( // We know that within this branch, rightChild must be a cell. If the CFA can tell us that the // proof, when filtered on cell, demonstrates that we have an object of the desired type - // (predictionCheck() will test for FinalObject or Array, currently), then we can skip the + // (speculationCheck() will test for FinalObject or Array, currently), then we can skip the // speculation. - if (!predictionCheck(m_state.forNode(rightChild).m_type & PredictCell)) { + if (!speculatedTypeChecker(m_state.forNode(rightChild).m_type & SpecCell)) { speculationCheck( BadType, JSValueRegs(op2GPR), rightChild.index(), m_jit.branchPtr( @@ -1573,7 +1573,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 (!isOtherPrediction(m_state.forNode(rightChild).m_type & ~PredictCell)) { + if (!isOtherSpeculation(m_state.forNode(rightChild).m_type & ~SpecCell)) { m_jit.move(op2GPR, resultGPR); m_jit.andPtr(MacroAssembler::TrustedImm32(~TagBitUndefined), resultGPR); @@ -1596,7 +1596,7 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality( void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality( Edge leftChild, Edge rightChild, NodeIndex branchNodeIndex, - const ClassInfo* classInfo, PredictionChecker predictionCheck) + const ClassInfo* classInfo, SpeculatedTypeChecker speculatedTypeChecker) { Node& branchNode = at(branchNodeIndex); BlockIndex taken = branchNode.takenBlockIndex(); @@ -1610,7 +1610,7 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality( GPRReg op2GPR = op2.gpr(); GPRReg resultGPR = result.gpr(); - if (!predictionCheck(m_state.forNode(leftChild).m_type)) { + if (!speculatedTypeChecker(m_state.forNode(leftChild).m_type)) { speculationCheck( BadType, JSValueRegs(op1GPR), leftChild.index(), m_jit.branchPtr( @@ -1626,9 +1626,9 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality( // We know that within this branch, rightChild must be a cell. If the CFA can tell us that the // proof, when filtered on cell, demonstrates that we have an object of the desired type - // (predictionCheck() will test for FinalObject or Array, currently), then we can skip the + // (speculationCheck() will test for FinalObject or Array, currently), then we can skip the // speculation. - if (!predictionCheck(m_state.forNode(rightChild).m_type & PredictCell)) { + if (!speculatedTypeChecker(m_state.forNode(rightChild).m_type & SpecCell)) { speculationCheck( BadType, JSValueRegs(op2GPR), rightChild.index(), m_jit.branchPtr( @@ -1644,7 +1644,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 (isOtherPrediction(m_state.forNode(rightChild).m_type & ~PredictCell)) + if (isOtherSpeculation(m_state.forNode(rightChild).m_type & ~SpecCell)) rightNotCell.link(&m_jit); else { jump(notTaken, ForceJump); @@ -1739,11 +1739,11 @@ void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse, const ClassInf void SpeculativeJIT::compileLogicalNot(Node& node) { if (at(node.child1()).shouldSpeculateFinalObjectOrOther()) { - compileObjectOrOtherLogicalNot(node.child1(), &JSFinalObject::s_info, !isFinalObjectOrOtherPrediction(m_state.forNode(node.child1()).m_type)); + compileObjectOrOtherLogicalNot(node.child1(), &JSFinalObject::s_info, !isFinalObjectOrOtherSpeculation(m_state.forNode(node.child1()).m_type)); return; } if (at(node.child1()).shouldSpeculateArrayOrOther()) { - compileObjectOrOtherLogicalNot(node.child1(), &JSArray::s_info, !isArrayOrOtherPrediction(m_state.forNode(node.child1()).m_type)); + compileObjectOrOtherLogicalNot(node.child1(), &JSArray::s_info, !isArrayOrOtherSpeculation(m_state.forNode(node.child1()).m_type)); return; } if (at(node.child1()).shouldSpeculateInteger()) { @@ -1766,9 +1766,9 @@ void SpeculativeJIT::compileLogicalNot(Node& node) return; } - PredictedType prediction = m_jit.getPrediction(node.child1()); - if (isBooleanPrediction(prediction)) { - if (isBooleanPrediction(m_state.forNode(node.child1()).m_type)) { + SpeculatedType prediction = m_jit.getSpeculation(node.child1()); + if (isBooleanSpeculation(prediction)) { + if (isBooleanSpeculation(m_state.forNode(node.child1()).m_type)) { SpeculateBooleanOperand value(this, node.child1()); GPRTemporary result(this, value); @@ -1841,9 +1841,9 @@ void SpeculativeJIT::emitBranch(Node& node) BlockIndex notTaken = node.notTakenBlockIndex(); if (at(node.child1()).shouldSpeculateFinalObjectOrOther()) { - emitObjectOrOtherBranch(node.child1(), taken, notTaken, &JSFinalObject::s_info, !isFinalObjectOrOtherPrediction(m_state.forNode(node.child1()).m_type)); + emitObjectOrOtherBranch(node.child1(), taken, notTaken, &JSFinalObject::s_info, !isFinalObjectOrOtherSpeculation(m_state.forNode(node.child1()).m_type)); } else if (at(node.child1()).shouldSpeculateArrayOrOther()) { - emitObjectOrOtherBranch(node.child1(), taken, notTaken, &JSArray::s_info, !isArrayOrOtherPrediction(m_state.forNode(node.child1()).m_type)); + emitObjectOrOtherBranch(node.child1(), taken, notTaken, &JSArray::s_info, !isArrayOrOtherSpeculation(m_state.forNode(node.child1()).m_type)); } else if (at(node.child1()).shouldSpeculateNumber()) { if (at(node.child1()).shouldSpeculateInteger()) { bool invert = false; @@ -1870,10 +1870,10 @@ void SpeculativeJIT::emitBranch(Node& node) JSValueOperand value(this, node.child1()); GPRReg valueGPR = value.gpr(); - bool predictBoolean = isBooleanPrediction(m_jit.getPrediction(node.child1())); + bool predictBoolean = isBooleanSpeculation(m_jit.getSpeculation(node.child1())); if (predictBoolean) { - if (isBooleanPrediction(m_state.forNode(node.child1()).m_type)) { + if (isBooleanSpeculation(m_state.forNode(node.child1()).m_type)) { MacroAssembler::ResultCondition condition = MacroAssembler::NonZero; if (taken == nextBlock()) { @@ -1924,7 +1924,13 @@ void SpeculativeJIT::compile(Node& node) switch (op) { case JSConstant: + initConstantInfo(m_compileIndex); + break; + case PhantomArguments: + // This should never be must-generate. + ASSERT_NOT_REACHED(); + // But as a release-mode fall-back make it the empty value. initConstantInfo(m_compileIndex); break; @@ -1934,11 +1940,11 @@ void SpeculativeJIT::compile(Node& node) break; case GetLocal: { - PredictedType prediction = node.variableAccessData()->prediction(); + SpeculatedType prediction = node.variableAccessData()->prediction(); AbstractValue& value = block()->valuesAtHead.operand(node.local()); // If we have no prediction for this local, then don't attempt to compile. - if (prediction == PredictNone) { + if (prediction == SpecNone) { terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode); break; } @@ -1960,7 +1966,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isInt32Prediction(value.m_type)) { + if (isInt32Speculation(value.m_type)) { GPRTemporary result(this); m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr()); @@ -1984,9 +1990,9 @@ void SpeculativeJIT::compile(Node& node) DataFormat format; if (node.variableAccessData()->isCaptured()) format = DataFormatJS; - else if (isCellPrediction(value.m_type)) + else if (isCellSpeculation(value.m_type)) format = DataFormatJSCell; - else if (isBooleanPrediction(value.m_type)) + else if (isBooleanSpeculation(value.m_type)) format = DataFormatJSBoolean; else format = DataFormatJS; @@ -2053,25 +2059,25 @@ void SpeculativeJIT::compile(Node& node) break; } - PredictedType predictedType = node.variableAccessData()->argumentAwarePrediction(); - if (isInt32Prediction(predictedType)) { + SpeculatedType predictedType = node.variableAccessData()->argumentAwarePrediction(); + if (isInt32Speculation(predictedType)) { SpeculateIntegerOperand value(this, node.child1()); m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local())); noResult(m_compileIndex); valueSourceReferenceForOperand(node.local()) = ValueSource(Int32InRegisterFile); break; } - if (isArrayPrediction(predictedType)) { + if (isArraySpeculation(predictedType)) { SpeculateCellOperand cell(this, node.child1()); GPRReg cellGPR = cell.gpr(); - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + 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); valueSourceReferenceForOperand(node.local()) = ValueSource(CellInRegisterFile); break; } - if (isBooleanPrediction(predictedType)) { + if (isBooleanSpeculation(predictedType)) { SpeculateBooleanOperand boolean(this, node.child1()); m_jit.storePtr(boolean.gpr(), JITCompiler::addressFor(node.local())); noResult(m_compileIndex); @@ -2170,7 +2176,7 @@ void SpeculativeJIT::compile(Node& node) } case CheckNumber: { - if (!isNumberPrediction(m_state.forNode(node.child1()).m_type)) { + if (!isNumberSpeculation(m_state.forNode(node.child1()).m_type)) { JSValueOperand op1(this, node.child1()); JITCompiler::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, op1.gpr(), GPRInfo::tagTypeNumberRegister); speculationCheck( @@ -2370,7 +2376,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (!at(node.child2()).shouldSpeculateInteger() || !isActionableArrayPrediction(at(node.child1()).prediction())) { + if (!at(node.child2()).shouldSpeculateInteger() || !isActionableArraySpeculation(at(node.child1()).prediction())) { JSValueOperand base(this, node.child1()); JSValueOperand property(this, node.child2()); GPRReg baseGPR = base.gpr(); @@ -2391,7 +2397,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (at(node.child1()).prediction() == PredictString) { + if (at(node.child1()).prediction() == SpecString) { compileGetByValOnString(node); if (!m_compileOkay) return; @@ -2399,63 +2405,63 @@ void SpeculativeJIT::compile(Node& node) } if (at(node.child1()).shouldSpeculateInt8Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), node, sizeof(int8_t), isInt8ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), node, sizeof(int8_t), isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateInt16Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), node, sizeof(int16_t), isInt16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), node, sizeof(int16_t), isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateInt32Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), node, sizeof(int32_t), isInt32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), node, sizeof(int32_t), isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint8Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), node, sizeof(uint8_t), isUint8ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), node, sizeof(uint8_t), isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint8ClampedArray()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, sizeof(uint8_t), isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, sizeof(uint8_t), isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint16Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), node, sizeof(uint16_t), isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), node, sizeof(uint16_t), isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint32Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), node, sizeof(uint32_t), isUint32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compileGetByValOnIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), node, sizeof(uint32_t), isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateFloat32Array()) { - compileGetByValOnFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), node, sizeof(float), isFloat32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); + compileGetByValOnFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), node, sizeof(float), isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateFloat64Array()) { - compileGetByValOnFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), node, sizeof(double), isFloat64ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); + compileGetByValOnFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), node, sizeof(double), isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); if (!m_compileOkay) return; break; @@ -2474,7 +2480,7 @@ void SpeculativeJIT::compile(Node& node) if (!m_compileOkay) return; - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + 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))); speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()))); @@ -2495,7 +2501,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (!at(node.child2()).shouldSpeculateInteger() || !isActionableMutableArrayPrediction(at(node.child1()).prediction())) { + if (!at(node.child2()).shouldSpeculateInteger() || !isActionableMutableArraySpeculation(at(node.child1()).prediction())) { JSValueOperand arg1(this, node.child1()); JSValueOperand arg2(this, node.child2()); JSValueOperand arg3(this, node.child3()); @@ -2528,7 +2534,7 @@ void SpeculativeJIT::compile(Node& node) if (!m_compileOkay) return; - if (!isArgumentsPrediction(m_state.forNode(node.child1()).m_type)) { + if (!isArgumentsSpeculation(m_state.forNode(node.child1()).m_type)) { speculationCheck( BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr( @@ -2572,61 +2578,61 @@ void SpeculativeJIT::compile(Node& node) } if (at(node.child1()).shouldSpeculateInt8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), isInt8ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateInt16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), isInt16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateInt32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), isInt32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint8ClampedArray()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray, ClampRounding); + compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray, ClampRounding); break; } if (at(node.child1()).shouldSpeculateUint16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateUint32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), isUint32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); + compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateFloat32Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float), isFloat32ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); + compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float), isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); if (!m_compileOkay) return; break; } if (at(node.child1()).shouldSpeculateFloat64Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double), isFloat64ArrayPrediction(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); + compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double), isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); if (!m_compileOkay) return; break; @@ -2650,7 +2656,7 @@ void SpeculativeJIT::compile(Node& node) // 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 (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + 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))); base.use(); @@ -2695,7 +2701,7 @@ void SpeculativeJIT::compile(Node& node) break; } - ASSERT(isActionableMutableArrayPrediction(at(node.child1()).prediction())); + ASSERT(isActionableMutableArraySpeculation(at(node.child1()).prediction())); ASSERT(at(node.child2()).shouldSpeculateInteger()); SpeculateCellOperand base(this, node.child1()); @@ -2847,7 +2853,7 @@ void SpeculativeJIT::compile(Node& node) writeBarrier(baseGPR, valueGPR, node.child2(), WriteBarrierForPropertyAccess, storageGPR, storageLengthGPR); - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + 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))); m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR); @@ -2885,7 +2891,7 @@ void SpeculativeJIT::compile(Node& node) GPRReg storageGPR = storage.gpr(); GPRReg storageLengthGPR = storageLength.gpr(); - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + 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))); m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR); @@ -3012,7 +3018,7 @@ void SpeculativeJIT::compile(Node& node) op1.use(); - if (!(m_state.forNode(node.child1()).m_type & ~(PredictNumber | PredictBoolean))) + if (!(m_state.forNode(node.child1()).m_type & ~(SpecNumber | SpecBoolean))) m_jit.move(op1GPR, resultGPR); else { MacroAssembler::Jump alreadyPrimitive = m_jit.branchTestPtr(MacroAssembler::NonZero, op1GPR, GPRInfo::tagMaskRegister); @@ -3106,7 +3112,7 @@ void SpeculativeJIT::compile(Node& node) } case ConvertThis: { - if (isObjectPrediction(m_state.forNode(node.child1()).m_type)) { + if (isObjectSpeculation(m_state.forNode(node.child1()).m_type)) { SpeculateCellOperand thisValue(this, node.child1()); GPRTemporary result(this, thisValue); m_jit.move(thisValue.gpr(), result.gpr()); @@ -3114,13 +3120,13 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isOtherPrediction(at(node.child1()).prediction())) { + if (isOtherSpeculation(at(node.child1()).prediction())) { JSValueOperand thisValue(this, node.child1()); GPRTemporary scratch(this, thisValue); GPRReg thisValueGPR = thisValue.gpr(); GPRReg scratchGPR = scratch.gpr(); - if (!isOtherPrediction(m_state.forNode(node.child1()).m_type)) { + if (!isOtherSpeculation(m_state.forNode(node.child1()).m_type)) { m_jit.move(thisValueGPR, scratchGPR); m_jit.andPtr(MacroAssembler::TrustedImm32(~TagBitUndefined), scratchGPR); speculationCheck(BadType, JSValueRegs(thisValueGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, scratchGPR, MacroAssembler::TrustedImmPtr(reinterpret_cast<void*>(ValueNull)))); @@ -3131,13 +3137,13 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isObjectPrediction(at(node.child1()).prediction())) { + if (isObjectSpeculation(at(node.child1()).prediction())) { SpeculateCellOperand thisValue(this, node.child1()); GPRTemporary result(this, thisValue); GPRReg thisValueGPR = thisValue.gpr(); GPRReg resultGPR = result.gpr(); - if (!isObjectPrediction(m_state.forNode(node.child1()).m_type)) + if (!isObjectSpeculation(m_state.forNode(node.child1()).m_type)) speculationCheck(BadType, JSValueRegs(thisValueGPR), node.child1(), m_jit.branchPtr(JITCompiler::Equal, JITCompiler::Address(thisValueGPR, JSCell::classInfoOffset()), JITCompiler::TrustedImmPtr(&JSString::s_info))); m_jit.move(thisValueGPR, resultGPR); @@ -3259,7 +3265,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isCellPrediction(at(node.child1()).prediction())) { + if (isCellSpeculation(at(node.child1()).prediction())) { SpeculateCellOperand base(this, node.child1()); GPRTemporary result(this, base); @@ -3309,7 +3315,7 @@ void SpeculativeJIT::compile(Node& node) break; } - if (isCellPrediction(at(node.child1()).prediction())) { + if (isCellSpeculation(at(node.child1()).prediction())) { SpeculateCellOperand base(this, node.child1()); GPRReg baseGPR = base.gpr(); @@ -3356,7 +3362,7 @@ void SpeculativeJIT::compile(Node& node) GPRReg baseGPR = base.gpr(); GPRReg resultGPR = result.gpr(); - if (!isArrayPrediction(m_state.forNode(node.child1()).m_type)) + 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))); m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), resultGPR); @@ -3380,7 +3386,7 @@ void SpeculativeJIT::compile(Node& node) GPRReg baseGPR = base.gpr(); GPRReg resultGPR = result.gpr(); - if (!isStringPrediction(m_state.forNode(node.child1()).m_type)) + if (!isStringSpeculation(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(&JSString::s_info))); m_jit.load32(MacroAssembler::Address(baseGPR, JSString::offsetOfLength()), resultGPR); @@ -3390,39 +3396,39 @@ void SpeculativeJIT::compile(Node& node) } case GetInt8ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int8ArrayDescriptor(), node, !isInt8ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->int8ArrayDescriptor(), node, !isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetInt16ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int16ArrayDescriptor(), node, !isInt16ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->int16ArrayDescriptor(), node, !isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetInt32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int32ArrayDescriptor(), node, !isInt32ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->int32ArrayDescriptor(), node, !isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetUint8ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint8ArrayDescriptor(), node, !isUint8ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->uint8ArrayDescriptor(), node, !isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetUint8ClampedArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, !isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, !isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetUint16ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint16ArrayDescriptor(), node, !isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->uint16ArrayDescriptor(), node, !isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetUint32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint32ArrayDescriptor(), node, !isUint32ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->uint32ArrayDescriptor(), node, !isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetFloat32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->float32ArrayDescriptor(), node, !isFloat32ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->float32ArrayDescriptor(), node, !isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case GetFloat64ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->float64ArrayDescriptor(), node, !isFloat64ArrayPrediction(m_state.forNode(node.child1()).m_type)); + compileGetTypedArrayLength(m_jit.globalData()->float64ArrayDescriptor(), node, !isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type)); break; } case CheckFunction: { @@ -3434,7 +3440,7 @@ void SpeculativeJIT::compile(Node& node) case CheckStructure: { AbstractValue& value = m_state.forNode(node.child1()); if (value.m_structure.isSubsetOf(node.structureSet()) - && isCellPrediction(value.m_type)) { + && isCellSpeculation(value.m_type)) { noResult(m_compileIndex); break; } @@ -3464,7 +3470,23 @@ void SpeculativeJIT::compile(Node& node) break; } + case StructureTransitionWatchpoint: { + m_jit.addWeakReference(node.structure()); + node.structure()->addTransitionWatchpoint(speculationWatchpoint()); + +#if !ASSERT_DISABLED + SpeculateCellOperand op1(this, node.child1()); + JITCompiler::Jump isOK = m_jit.branchPtr(JITCompiler::Equal, JITCompiler::Address(op1.gpr(), JSCell::structureOffset()), TrustedImmPtr(node.structure())); + m_jit.breakpoint(); + isOK.link(&m_jit); +#endif + + noResult(m_compileIndex); + break; + } + case PhantomPutStructure: { + ASSERT(node.structureTransitionData().previousStructure->transitionWatchpointSetHasBeenInvalidated()); m_jit.addWeakReferenceTransition( node.codeOrigin.codeOriginOwner(), node.structureTransitionData().previousStructure, @@ -3474,6 +3496,8 @@ void SpeculativeJIT::compile(Node& node) } case PutStructure: { + ASSERT(node.structureTransitionData().previousStructure->transitionWatchpointSetHasBeenInvalidated()); + SpeculateCellOperand base(this, node.child1()); GPRReg baseGPR = base.gpr(); @@ -3587,9 +3611,7 @@ void SpeculativeJIT::compile(Node& node) case GetGlobalVar: { GPRTemporary result(this); - JSVariableObject* globalObject = m_jit.globalObjectFor(node.codeOrigin); - m_jit.loadPtr(globalObject->addressOfRegisters(), result.gpr()); - m_jit.loadPtr(JITCompiler::addressForGlobalVar(result.gpr(), node.varNumber()), result.gpr()); + m_jit.loadPtr(node.registerPointer(), result.gpr()); jsValueResult(result.gpr(), m_compileIndex); break; @@ -3597,22 +3619,65 @@ void SpeculativeJIT::compile(Node& node) case PutGlobalVar: { JSValueOperand value(this, node.child1()); - GPRTemporary globalObject(this); - GPRTemporary scratch(this); - GPRReg globalObjectReg = globalObject.gpr(); - GPRReg scratchReg = scratch.gpr(); - - m_jit.move(MacroAssembler::TrustedImmPtr(m_jit.globalObjectFor(node.codeOrigin)), globalObjectReg); + if (Heap::isWriteBarrierEnabled()) { + GPRTemporary scratch(this); + GPRReg scratchReg = scratch.gpr(); + + writeBarrier(m_jit.globalObjectFor(node.codeOrigin), value.gpr(), node.child1(), WriteBarrierForVariableAccess, scratchReg); + } + + m_jit.storePtr(value.gpr(), node.registerPointer()); - writeBarrier(m_jit.globalObjectFor(node.codeOrigin), value.gpr(), node.child1(), WriteBarrierForVariableAccess, scratchReg); + noResult(m_compileIndex); + break; + } - m_jit.loadPtr(MacroAssembler::Address(globalObjectReg, JSVariableObject::offsetOfRegisters()), scratchReg); - m_jit.storePtr(value.gpr(), JITCompiler::addressForGlobalVar(scratchReg, node.varNumber())); + case PutGlobalVarCheck: { + JSValueOperand value(this, node.child1()); + + WatchpointSet* watchpointSet = + m_jit.globalObjectFor(node.codeOrigin)->symbolTable().get( + identifier(node.identifierNumberForCheck())->impl()).watchpointSet(); + addSlowPathGenerator( + slowPathCall( + m_jit.branchTest8( + JITCompiler::NonZero, + JITCompiler::AbsoluteAddress(watchpointSet->addressOfIsWatched())), + this, operationNotifyGlobalVarWrite, NoResult, watchpointSet)); + + if (Heap::isWriteBarrierEnabled()) { + GPRTemporary scratch(this); + GPRReg scratchReg = scratch.gpr(); + + writeBarrier(m_jit.globalObjectFor(node.codeOrigin), value.gpr(), node.child1(), WriteBarrierForVariableAccess, scratchReg); + } + + m_jit.storePtr(value.gpr(), node.registerPointer()); noResult(m_compileIndex); break; } + + case GlobalVarWatchpoint: { + m_jit.globalObjectFor(node.codeOrigin)->symbolTable().get( + identifier(node.identifierNumberForCheck())->impl()).addWatchpoint( + speculationWatchpoint()); + +#if DFG_ENABLE(JIT_ASSERT) + GPRTemporary scratch(this); + GPRReg scratchGPR = scratch.gpr(); + m_jit.loadPtr(node.registerPointer(), scratchGPR); + JITCompiler::Jump ok = m_jit.branchPtr( + JITCompiler::Equal, scratchGPR, + TrustedImmPtr(bitwise_cast<void*>(JSValue::encode(node.registerPointer()->get())))); + m_jit.breakpoint(); + ok.link(&m_jit); +#endif + + noResult(m_compileIndex); + break; + } case CheckHasInstance: { SpeculateCellOperand base(this, node.child1()); @@ -3880,7 +3945,7 @@ void SpeculativeJIT::compile(Node& node) GPRTemporary result(this); GPRReg resultGPR = result.gpr(); - if (!isEmptyPrediction( + if (!isEmptySpeculation( m_state.variables().operand( m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) { speculationCheck( @@ -3939,7 +4004,7 @@ void SpeculativeJIT::compile(Node& node) GPRReg indexGPR = index.gpr(); GPRReg resultGPR = result.gpr(); - if (!isEmptyPrediction( + if (!isEmptySpeculation( m_state.variables().operand( m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) { speculationCheck( @@ -4021,27 +4086,35 @@ void SpeculativeJIT::compile(Node& node) : 0) + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register)), resultGPR); - addSlowPathGenerator( - slowPathCall( - slowPath, this, operationGetArgumentByVal, resultGPR, - m_jit.argumentsRegisterFor(node.codeOrigin), - indexGPR)); + if (node.codeOrigin.inlineCallFrame) { + addSlowPathGenerator( + slowPathCall( + slowPath, this, operationGetInlinedArgumentByVal, resultGPR, + m_jit.argumentsRegisterFor(node.codeOrigin), + node.codeOrigin.inlineCallFrame, + indexGPR)); + } else { + addSlowPathGenerator( + slowPathCall( + slowPath, this, operationGetArgumentByVal, resultGPR, + m_jit.argumentsRegisterFor(node.codeOrigin), + indexGPR)); + } jsValueResult(resultGPR, m_compileIndex); break; } case CheckArgumentsNotCreated: { - if (!isEmptyPrediction( - m_state.variables().operand( - m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) { - speculationCheck( - ArgumentsEscaped, JSValueRegs(), NoNode, - m_jit.branchTestPtr( - JITCompiler::NonZero, - JITCompiler::addressFor( - m_jit.argumentsRegisterFor(node.codeOrigin)))); - } + ASSERT(!isEmptySpeculation( + m_state.variables().operand( + m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)); + speculationCheck( + ArgumentsEscaped, JSValueRegs(), NoNode, + m_jit.branchTestPtr( + JITCompiler::NonZero, + JITCompiler::addressFor( + m_jit.argumentsRegisterFor(node.codeOrigin)))); noResult(m_compileIndex); break; } diff --git a/Source/JavaScriptCore/dfg/DFGThunks.cpp b/Source/JavaScriptCore/dfg/DFGThunks.cpp index 1ed46c11f..08ca6eaa1 100644 --- a/Source/JavaScriptCore/dfg/DFGThunks.cpp +++ b/Source/JavaScriptCore/dfg/DFGThunks.cpp @@ -79,7 +79,7 @@ MacroAssemblerCodeRef osrExitGenerationThunkGenerator(JSGlobalData* globalData) patchBuffer.link(functionCall, compileOSRExit); - return patchBuffer.finalizeCode(); + return FINALIZE_CODE(patchBuffer, ("DFG OSR exit generation thunk")); } } } // namespace JSC::DFG diff --git a/Source/JavaScriptCore/dfg/DFGVariableAccessData.h b/Source/JavaScriptCore/dfg/DFGVariableAccessData.h index 3dfd94d01..382907d27 100644 --- a/Source/JavaScriptCore/dfg/DFGVariableAccessData.h +++ b/Source/JavaScriptCore/dfg/DFGVariableAccessData.h @@ -29,7 +29,7 @@ #include "DFGDoubleFormatState.h" #include "DFGNodeFlags.h" #include "Operands.h" -#include "PredictedType.h" +#include "SpeculatedType.h" #include "VirtualRegister.h" #include <wtf/Platform.h> #include <wtf/UnionFind.h> @@ -43,8 +43,8 @@ public: VariableAccessData() : m_local(static_cast<VirtualRegister>(std::numeric_limits<int>::min())) - , m_prediction(PredictNone) - , m_argumentAwarePrediction(PredictNone) + , m_prediction(SpecNone) + , m_argumentAwarePrediction(SpecNone) , m_flags(0) , m_doubleFormatState(EmptyDoubleFormatState) , m_isCaptured(false) @@ -55,8 +55,8 @@ public: VariableAccessData(VirtualRegister local, bool isCaptured) : m_local(local) - , m_prediction(PredictNone) - , m_argumentAwarePrediction(PredictNone) + , m_prediction(SpecNone) + , m_argumentAwarePrediction(SpecNone) , m_flags(0) , m_doubleFormatState(EmptyDoubleFormatState) , m_isCaptured(isCaptured) @@ -104,33 +104,33 @@ public: return m_isArgumentsAlias; } - bool predict(PredictedType prediction) + bool predict(SpeculatedType prediction) { VariableAccessData* self = find(); - bool result = mergePrediction(self->m_prediction, prediction); + bool result = mergeSpeculation(self->m_prediction, prediction); if (result) - mergePrediction(m_argumentAwarePrediction, m_prediction); + mergeSpeculation(m_argumentAwarePrediction, m_prediction); return result; } - PredictedType nonUnifiedPrediction() + SpeculatedType nonUnifiedPrediction() { return m_prediction; } - PredictedType prediction() + SpeculatedType prediction() { return find()->m_prediction; } - PredictedType argumentAwarePrediction() + SpeculatedType argumentAwarePrediction() { return find()->m_argumentAwarePrediction; } - bool mergeArgumentAwarePrediction(PredictedType prediction) + bool mergeArgumentAwarePrediction(SpeculatedType prediction) { - return mergePrediction(find()->m_argumentAwarePrediction, prediction); + return mergeSpeculation(find()->m_argumentAwarePrediction, prediction); } void clearVotes() @@ -161,12 +161,12 @@ public: // If the variable is not a number prediction, then this doesn't // make any sense. - if (!isNumberPrediction(prediction())) + if (!isNumberSpeculation(prediction())) return false; // If the variable is predicted to hold only doubles, then it's a // no-brainer: it should be formatted as a double. - if (isDoublePrediction(prediction())) + if (isDoubleSpeculation(prediction())) return true; // If the variable is known to be used as an integer, then be safe - @@ -225,7 +225,7 @@ public: if (m_doubleFormatState != UsingDoubleFormat) return false; - return mergePrediction(m_prediction, PredictDouble); + return mergeSpeculation(m_prediction, SpecDouble); } NodeFlags flags() const { return m_flags; } @@ -246,8 +246,8 @@ private: // usage for variable access nodes do be significant. VirtualRegister m_local; - PredictedType m_prediction; - PredictedType m_argumentAwarePrediction; + SpeculatedType m_prediction; + SpeculatedType m_argumentAwarePrediction; NodeFlags m_flags; float m_votes[2]; diff --git a/Source/JavaScriptCore/disassembler/Disassembler.h b/Source/JavaScriptCore/disassembler/Disassembler.h new file mode 100644 index 000000000..7d7400ac8 --- /dev/null +++ b/Source/JavaScriptCore/disassembler/Disassembler.h @@ -0,0 +1,49 @@ +/* + * 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 Disassembler_h +#define Disassembler_h + +#include <stdio.h> +#include <wtf/Platform.h> +#include <wtf/StdLibExtras.h> + +namespace JSC { + +class MacroAssemblerCodePtr; + +#if ENABLE(DISASSEMBLER) +bool tryToDisassemble(const MacroAssemblerCodePtr&, size_t, const char* prefix, FILE* out); +#else +inline bool tryToDisassemble(const MacroAssemblerCodePtr&, size_t, const char*, FILE*) +{ + return false; +} +#endif + +} // namespace JSC + +#endif // Disassembler_h + diff --git a/Source/JavaScriptCore/disassembler/UDis86Disassembler.cpp b/Source/JavaScriptCore/disassembler/UDis86Disassembler.cpp new file mode 100644 index 000000000..b6baed4a2 --- /dev/null +++ b/Source/JavaScriptCore/disassembler/UDis86Disassembler.cpp @@ -0,0 +1,63 @@ +/* + * 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 "Disassembler.h" + +#if USE(UDIS86) + +#include "MacroAssemblerCodeRef.h" +#include "udis86.h" + +namespace JSC { + +bool tryToDisassemble(const MacroAssemblerCodePtr& codePtr, size_t size, const char* prefix, FILE* out) +{ + ud_t disassembler; + ud_init(&disassembler); + ud_set_input_buffer(&disassembler, static_cast<unsigned char*>(codePtr.executableAddress()), size); +#if CPU(X86_64) + ud_set_mode(&disassembler, 64); +#else + ud_set_mode(&disassembler, 32); +#endif + ud_set_pc(&disassembler, bitwise_cast<uintptr_t>(codePtr.executableAddress())); + ud_set_syntax(&disassembler, UD_SYN_ATT); + + uint64_t currentPC = disassembler.pc; + while (ud_disassemble(&disassembler)) { + char pcString[20]; + snprintf(pcString, sizeof(pcString), "0x%lx", static_cast<unsigned long>(currentPC)); + fprintf(out, "%s%16s: %s\n", prefix, pcString, ud_insn_asm(&disassembler)); + currentPC = disassembler.pc; + } + + return true; +} + +} // namespace JSC + +#endif // USE(UDIS86) + diff --git a/Source/JavaScriptCore/disassembler/udis86/differences.txt b/Source/JavaScriptCore/disassembler/udis86/differences.txt new file mode 100644 index 000000000..3ef51efcf --- /dev/null +++ b/Source/JavaScriptCore/disassembler/udis86/differences.txt @@ -0,0 +1,22 @@ +This documents the differences between the stock version of udis86 and the one found +here: + +- All files not named "udis86" were prefixed with "udis86". + +- assert() has been changed to ASSERT() + +- Mass rename of udis86_input.h inp_ prefixed functions and macros to ud_inp_ to + avoid namespace pollution. + +- Removal of KERNEL checks. + +- Added #include of udis86_extern.h in udis86_decode.c. + +- Removed s_ie__pause and s_ie__nop from udis86_decode.c, since they weren't used. + +- Made udis86_syn.h use WTF_ATTRIBUTE_PRINTF. This required making a bunch of little + fixes to make the compiler's format string warnings go away. + +- Made the code in udis86_syn.h use vsnprintf() instead of vsprintf(). + +- Fixed udis86_syn-att.c's jump destination printing to work correctly in 64-bit mode. diff --git a/Source/JavaScriptCore/disassembler/udis86/itab.py b/Source/JavaScriptCore/disassembler/udis86/itab.py new file mode 100644 index 000000000..27fa9b3f3 --- /dev/null +++ b/Source/JavaScriptCore/disassembler/udis86/itab.py @@ -0,0 +1,354 @@ +# udis86 - scripts/itab.py +# +# Copyright (c) 2009 Vivek Thampi +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. + +import sys + +sys.path.append( '../scripts' ); + +import ud_optable +import ud_opcode + +class UdItabGenerator( ud_opcode.UdOpcodeTables ): + + OperandDict = { + "Ap" : [ "OP_A" , "SZ_P" ], + "E" : [ "OP_E" , "SZ_NA" ], + "Eb" : [ "OP_E" , "SZ_B" ], + "Ew" : [ "OP_E" , "SZ_W" ], + "Ev" : [ "OP_E" , "SZ_V" ], + "Ed" : [ "OP_E" , "SZ_D" ], + "Eq" : [ "OP_E" , "SZ_Q" ], + "Ez" : [ "OP_E" , "SZ_Z" ], + "Ex" : [ "OP_E" , "SZ_MDQ" ], + "Ep" : [ "OP_E" , "SZ_P" ], + "G" : [ "OP_G" , "SZ_NA" ], + "Gb" : [ "OP_G" , "SZ_B" ], + "Gw" : [ "OP_G" , "SZ_W" ], + "Gv" : [ "OP_G" , "SZ_V" ], + "Gy" : [ "OP_G" , "SZ_MDQ" ], + "Gy" : [ "OP_G" , "SZ_MDQ" ], + "Gd" : [ "OP_G" , "SZ_D" ], + "Gq" : [ "OP_G" , "SZ_Q" ], + "Gx" : [ "OP_G" , "SZ_MDQ" ], + "Gz" : [ "OP_G" , "SZ_Z" ], + "M" : [ "OP_M" , "SZ_NA" ], + "Mb" : [ "OP_M" , "SZ_B" ], + "Mw" : [ "OP_M" , "SZ_W" ], + "Ms" : [ "OP_M" , "SZ_W" ], + "Md" : [ "OP_M" , "SZ_D" ], + "Mq" : [ "OP_M" , "SZ_Q" ], + "Mt" : [ "OP_M" , "SZ_T" ], + "Mo" : [ "OP_M" , "SZ_O" ], + "MwRv" : [ "OP_MR" , "SZ_WV" ], + "MdRy" : [ "OP_MR" , "SZ_DY" ], + "MbRv" : [ "OP_MR" , "SZ_BV" ], + "I1" : [ "OP_I1" , "SZ_NA" ], + "I3" : [ "OP_I3" , "SZ_NA" ], + "Ib" : [ "OP_I" , "SZ_B" ], + "Isb" : [ "OP_I" , "SZ_SB" ], + "Iw" : [ "OP_I" , "SZ_W" ], + "Iv" : [ "OP_I" , "SZ_V" ], + "Iz" : [ "OP_I" , "SZ_Z" ], + "Jv" : [ "OP_J" , "SZ_V" ], + "Jz" : [ "OP_J" , "SZ_Z" ], + "Jb" : [ "OP_J" , "SZ_B" ], + "R" : [ "OP_R" , "SZ_RDQ" ], + "C" : [ "OP_C" , "SZ_NA" ], + "D" : [ "OP_D" , "SZ_NA" ], + "S" : [ "OP_S" , "SZ_NA" ], + "Ob" : [ "OP_O" , "SZ_B" ], + "Ow" : [ "OP_O" , "SZ_W" ], + "Ov" : [ "OP_O" , "SZ_V" ], + "V" : [ "OP_V" , "SZ_O" ], + "W" : [ "OP_W" , "SZ_O" ], + "Wsd" : [ "OP_W" , "SZ_O" ], + "Wss" : [ "OP_W" , "SZ_O" ], + "P" : [ "OP_P" , "SZ_Q" ], + "Q" : [ "OP_Q" , "SZ_Q" ], + "VR" : [ "OP_VR" , "SZ_O" ], + "PR" : [ "OP_PR" , "SZ_Q" ], + "AL" : [ "OP_AL" , "SZ_NA" ], + "CL" : [ "OP_CL" , "SZ_NA" ], + "DL" : [ "OP_DL" , "SZ_NA" ], + "BL" : [ "OP_BL" , "SZ_NA" ], + "AH" : [ "OP_AH" , "SZ_NA" ], + "CH" : [ "OP_CH" , "SZ_NA" ], + "DH" : [ "OP_DH" , "SZ_NA" ], + "BH" : [ "OP_BH" , "SZ_NA" ], + "AX" : [ "OP_AX" , "SZ_NA" ], + "CX" : [ "OP_CX" , "SZ_NA" ], + "DX" : [ "OP_DX" , "SZ_NA" ], + "BX" : [ "OP_BX" , "SZ_NA" ], + "SI" : [ "OP_SI" , "SZ_NA" ], + "DI" : [ "OP_DI" , "SZ_NA" ], + "SP" : [ "OP_SP" , "SZ_NA" ], + "BP" : [ "OP_BP" , "SZ_NA" ], + "eAX" : [ "OP_eAX" , "SZ_NA" ], + "eCX" : [ "OP_eCX" , "SZ_NA" ], + "eDX" : [ "OP_eDX" , "SZ_NA" ], + "eBX" : [ "OP_eBX" , "SZ_NA" ], + "eSI" : [ "OP_eSI" , "SZ_NA" ], + "eDI" : [ "OP_eDI" , "SZ_NA" ], + "eSP" : [ "OP_eSP" , "SZ_NA" ], + "eBP" : [ "OP_eBP" , "SZ_NA" ], + "rAX" : [ "OP_rAX" , "SZ_NA" ], + "rCX" : [ "OP_rCX" , "SZ_NA" ], + "rBX" : [ "OP_rBX" , "SZ_NA" ], + "rDX" : [ "OP_rDX" , "SZ_NA" ], + "rSI" : [ "OP_rSI" , "SZ_NA" ], + "rDI" : [ "OP_rDI" , "SZ_NA" ], + "rSP" : [ "OP_rSP" , "SZ_NA" ], + "rBP" : [ "OP_rBP" , "SZ_NA" ], + "ES" : [ "OP_ES" , "SZ_NA" ], + "CS" : [ "OP_CS" , "SZ_NA" ], + "DS" : [ "OP_DS" , "SZ_NA" ], + "SS" : [ "OP_SS" , "SZ_NA" ], + "GS" : [ "OP_GS" , "SZ_NA" ], + "FS" : [ "OP_FS" , "SZ_NA" ], + "ST0" : [ "OP_ST0" , "SZ_NA" ], + "ST1" : [ "OP_ST1" , "SZ_NA" ], + "ST2" : [ "OP_ST2" , "SZ_NA" ], + "ST3" : [ "OP_ST3" , "SZ_NA" ], + "ST4" : [ "OP_ST4" , "SZ_NA" ], + "ST5" : [ "OP_ST5" , "SZ_NA" ], + "ST6" : [ "OP_ST6" , "SZ_NA" ], + "ST7" : [ "OP_ST7" , "SZ_NA" ], + "NONE" : [ "OP_NONE" , "SZ_NA" ], + "ALr8b" : [ "OP_ALr8b" , "SZ_NA" ], + "CLr9b" : [ "OP_CLr9b" , "SZ_NA" ], + "DLr10b" : [ "OP_DLr10b" , "SZ_NA" ], + "BLr11b" : [ "OP_BLr11b" , "SZ_NA" ], + "AHr12b" : [ "OP_AHr12b" , "SZ_NA" ], + "CHr13b" : [ "OP_CHr13b" , "SZ_NA" ], + "DHr14b" : [ "OP_DHr14b" , "SZ_NA" ], + "BHr15b" : [ "OP_BHr15b" , "SZ_NA" ], + "rAXr8" : [ "OP_rAXr8" , "SZ_NA" ], + "rCXr9" : [ "OP_rCXr9" , "SZ_NA" ], + "rDXr10" : [ "OP_rDXr10" , "SZ_NA" ], + "rBXr11" : [ "OP_rBXr11" , "SZ_NA" ], + "rSPr12" : [ "OP_rSPr12" , "SZ_NA" ], + "rBPr13" : [ "OP_rBPr13" , "SZ_NA" ], + "rSIr14" : [ "OP_rSIr14" , "SZ_NA" ], + "rDIr15" : [ "OP_rDIr15" , "SZ_NA" ], + "jWP" : [ "OP_J" , "SZ_WP" ], + "jDP" : [ "OP_J" , "SZ_DP" ], + + } + + # + # opcode prefix dictionary + # + PrefixDict = { + "aso" : "P_aso", + "oso" : "P_oso", + "rexw" : "P_rexw", + "rexb" : "P_rexb", + "rexx" : "P_rexx", + "rexr" : "P_rexr", + "seg" : "P_seg", + "inv64" : "P_inv64", + "def64" : "P_def64", + "depM" : "P_depM", + "cast1" : "P_c1", + "cast2" : "P_c2", + "cast3" : "P_c3", + "cast" : "P_cast", + "sext" : "P_sext" + } + + InvalidEntryIdx = 0 + InvalidEntry = { 'type' : 'invalid', + 'mnemonic' : 'invalid', + 'operands' : '', + 'prefixes' : '', + 'meta' : '' } + + Itab = [] # instruction table + ItabIdx = 1 # instruction table index + GtabIdx = 0 # group table index + GtabMeta = [] + + ItabLookup = {} + + MnemonicAliases = ( "invalid", "3dnow", "none", "db", "pause" ) + + def __init__( self ): + # first itab entry (0) is Invalid + self.Itab.append( self.InvalidEntry ) + self.MnemonicsTable.extend( self.MnemonicAliases ) + + def toGroupId( self, id ): + return 0x8000 | id + + def genLookupTable( self, table, scope = '' ): + idxArray = [ ] + ( tabIdx, self.GtabIdx ) = ( self.GtabIdx, self.GtabIdx + 1 ) + self.GtabMeta.append( { 'type' : table[ 'type' ], 'meta' : table[ 'meta' ] } ) + + for _idx in range( self.sizeOfTable( table[ 'type' ] ) ): + idx = "%02x" % _idx + + e = self.InvalidEntry + i = self.InvalidEntryIdx + + if idx in table[ 'entries' ].keys(): + e = table[ 'entries' ][ idx ] + + # leaf node (insn) + if e[ 'type' ] == 'insn': + ( i, self.ItabIdx ) = ( self.ItabIdx, self.ItabIdx + 1 ) + self.Itab.append( e ) + elif e[ 'type' ] != 'invalid': + i = self.genLookupTable( e, 'static' ) + + idxArray.append( i ) + + name = "ud_itab__%s" % tabIdx + self.ItabLookup[ tabIdx ] = name + + self.ItabC.write( "\n" ); + if len( scope ): + self.ItabC.write( scope + ' ' ) + self.ItabC.write( "const uint16_t %s[] = {\n" % name ) + for i in range( len( idxArray ) ): + if i > 0 and i % 4 == 0: + self.ItabC.write( "\n" ) + if ( i%4 == 0 ): + self.ItabC.write( " /* %2x */" % i) + if idxArray[ i ] >= 0x8000: + self.ItabC.write( "%12s," % ("GROUP(%d)" % ( ~0x8000 & idxArray[ i ] ))) + else: + self.ItabC.write( "%12d," % ( idxArray[ i ] )) + self.ItabC.write( "\n" ) + self.ItabC.write( "};\n" ) + + return self.toGroupId( tabIdx ) + + def genLookupTableList( self ): + self.ItabC.write( "\n\n" ); + self.ItabC.write( "struct ud_lookup_table_list_entry ud_lookup_table_list[] = {\n" ) + for i in range( len( self.GtabMeta ) ): + f0 = self.ItabLookup[ i ] + "," + f1 = ( self.nameOfTable( self.GtabMeta[ i ][ 'type' ] ) ) + "," + f2 = "\"%s\"" % self.GtabMeta[ i ][ 'meta' ] + self.ItabC.write( " /* %03d */ { %s %s %s },\n" % ( i, f0, f1, f2 ) ) + self.ItabC.write( "};" ) + + def genInsnTable( self ): + self.ItabC.write( "struct ud_itab_entry ud_itab[] = {\n" ); + idx = 0 + for e in self.Itab: + opr_c = [ "O_NONE", "O_NONE", "O_NONE" ] + pfx_c = [] + opr = e[ 'operands' ] + for i in range(len(opr)): + if not (opr[i] in self.OperandDict.keys()): + print "error: invalid operand declaration: %s\n" % opr[i] + opr_c[i] = "O_" + opr[i] + opr = "%s %s %s" % (opr_c[0] + ",", opr_c[1] + ",", opr_c[2]) + + for p in e['prefixes']: + if not ( p in self.PrefixDict.keys() ): + print "error: invalid prefix specification: %s \n" % pfx + pfx_c.append( self.PrefixDict[p] ) + if len(e['prefixes']) == 0: + pfx_c.append( "P_none" ) + pfx = "|".join( pfx_c ) + + self.ItabC.write( " /* %04d */ { UD_I%s %s, %s },\n" \ + % ( idx, e[ 'mnemonic' ] + ',', opr, pfx ) ) + idx += 1 + self.ItabC.write( "};\n" ) + + self.ItabC.write( "\n\n" ); + self.ItabC.write( "const char * ud_mnemonics_str[] = {\n" ) + self.ItabC.write( ",\n ".join( [ "\"%s\"" % m for m in self.MnemonicsTable ] ) ) + self.ItabC.write( "\n};\n" ) + + + def genItabH( self ): + self.ItabH = open( "udis86_itab.h", "w" ) + + # Generate Table Type Enumeration + self.ItabH.write( "#ifndef UD_ITAB_H\n" ) + self.ItabH.write( "#define UD_ITAB_H\n\n" ) + + # table type enumeration + self.ItabH.write( "/* ud_table_type -- lookup table types (see lookup.c) */\n" ) + self.ItabH.write( "enum ud_table_type {\n " ) + enum = [ self.TableInfo[ k ][ 'name' ] for k in self.TableInfo.keys() ] + self.ItabH.write( ",\n ".join( enum ) ) + self.ItabH.write( "\n};\n\n" ); + + # mnemonic enumeration + self.ItabH.write( "/* ud_mnemonic -- mnemonic constants */\n" ) + enum = "enum ud_mnemonic_code {\n " + enum += ",\n ".join( [ "UD_I%s" % m for m in self.MnemonicsTable ] ) + enum += "\n} UD_ATTR_PACKED;\n" + self.ItabH.write( enum ) + self.ItabH.write( "\n" ) + + self.ItabH.write("\n/* itab entry operand definitions */\n"); + operands = self.OperandDict.keys() + operands.sort() + for o in operands: + self.ItabH.write("#define O_%-7s { %-12s %-8s }\n" % + (o, self.OperandDict[o][0] + ",", self.OperandDict[o][1])); + self.ItabH.write("\n\n"); + + self.ItabH.write( "extern const char * ud_mnemonics_str[];\n" ) + + self.ItabH.write( "#define GROUP(n) (0x8000 | (n))" ) + + self.ItabH.write( "\n#endif /* UD_ITAB_H */\n" ) + + self.ItabH.close() + + + def genItabC( self ): + self.ItabC = open( "udis86_itab.c", "w" ) + self.ItabC.write( "/* itab.c -- generated by itab.py, do no edit" ) + self.ItabC.write( " */\n" ); + self.ItabC.write( "#include \"udis86_decode.h\"\n\n" ); + + self.genLookupTable( self.OpcodeTable0 ) + self.genLookupTableList() + self.genInsnTable() + + self.ItabC.close() + + def genItab( self ): + self.genItabC() + self.genItabH() + +def main(): + generator = UdItabGenerator() + optableXmlParser = ud_optable.UdOptableXmlParser() + optableXmlParser.parse( sys.argv[ 1 ], generator.addInsnDef ) + + generator.genItab() + +if __name__ == '__main__': + main() diff --git a/Source/JavaScriptCore/disassembler/udis86/optable.xml b/Source/JavaScriptCore/disassembler/udis86/optable.xml new file mode 100644 index 000000000..14b4ac593 --- /dev/null +++ b/Source/JavaScriptCore/disassembler/udis86/optable.xml @@ -0,0 +1,8959 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="optable.xsl" type="text/xsl"?> +<x86optable> + + <instruction> + <mnemonic>aaa</mnemonic> + <def> + <opc>37</opc> + <mode>inv64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>aad</mnemonic> + <def> + <opc>d5</opc> + <opr>Ib</opr> + <mode>inv64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>aam</mnemonic> + <def> + <opc>d4</opc> + <opr>Ib</opr> + <mode>inv64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>aas</mnemonic> + <def> + <opc>3f</opc> + <mode>inv64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>adc</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>10</opc> + <opr>Eb Gb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>11</opc> + <opr>Ev Gv</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>12</opc> + <opr>Gb Eb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>13</opc> + <opr>Gv Ev</opr> + </def> + <def> + <opc>14</opc> + <opr>AL Ib</opr> + </def> + <def> + <pfx>oso rexw</pfx> + <opc>15</opc> + <opr>rAX Iz</opr> + <syn>sext</syn> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>80 /reg=2</opc> + <opr>Eb Ib</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>82 /reg=2</opc> + <opr>Eb Ib</opr> + <mode>inv64</mode> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>81 /reg=2</opc> + <opr>Ev Iz</opr> + <syn>sext</syn> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>83 /reg=2</opc> + <opr>Ev Ib</opr> + <syn>sext</syn> + </def> + </instruction> + + <instruction> + <mnemonic>add</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>00</opc> + <opr>Eb Gb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>01</opc> + <opr>Ev Gv</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>02</opc> + <opr>Gb Eb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>03</opc> + <opr>Gv Ev</opr> + </def> + <def> + <opc>04</opc> + <opr>AL Ib</opr> + </def> + <def> + <pfx>oso rexw</pfx> + <opc>05</opc> + <opr>rAX Iz</opr> + <syn>sext</syn> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>80 /reg=0</opc> + <opr>Eb Ib</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>82 /reg=0</opc> + <opr>Eb Ib</opr> + <mode>inv64</mode> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>81 /reg=0</opc> + <opr>Ev Iz</opr> + <syn>sext</syn> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>83 /reg=0</opc> + <opr>Ev Ib</opr> + <syn>sext</syn> + </def> + </instruction> + + <!-- + SSE2 + --> + + <instruction> + <mnemonic>addpd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 58</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>addps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 58</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>addsd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef2 0f 58</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>addss</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f 58</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>and</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>20</opc> + <opr>Eb Gb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>21</opc> + <opr>Ev Gv</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>22</opc> + <opr>Gb Eb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>23</opc> + <opr>Gv Ev</opr> + </def> + <def> + <opc>24</opc> + <opr>AL Ib</opr> + </def> + <def> + <pfx>oso rexw</pfx> + <opc>25</opc> + <opr>rAX Iz</opr> + <syn>sext</syn> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>80 /reg=4</opc> + <opr>Eb Ib</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>82 /reg=4</opc> + <opr>Eb Ib</opr> + <mode>inv64</mode> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>81 /reg=4</opc> + <opr>Ev Iz</opr> + <syn>sext</syn> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>83 /reg=4</opc> + <opr>Ev Ib</opr> + <syn>sext</syn> + </def> + </instruction> + + <instruction> + <mnemonic>andpd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 54</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>andps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 54</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>andnpd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 55</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>andnps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 55</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>arpl</mnemonic> + <def> + <pfx>aso</pfx> + <opc>63 /m=16</opc> + <opr>Ew Gw</opr> + <mode>inv64</mode> + </def> + <def> + <pfx>aso</pfx> + <opc>63 /m=32</opc> + <opr>Ew Gw</opr> + <mode>inv64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>movsxd</mnemonic> + <def> + <pfx>aso oso rexw rexx rexr rexb</pfx> + <opc>63 /m=64</opc> + <opr>Gv Ed</opr> + </def> + </instruction> + + <instruction> + <mnemonic>bound</mnemonic> + <def> + <pfx>aso oso</pfx> + <opc>62</opc> + <opr>Gv M</opr> + <mode>inv64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>bsf</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f bc</opc> + <opr>Gv Ev</opr> + </def> + </instruction> + + <instruction> + <mnemonic>bsr</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f bd</opc> + <opr>Gv Ev</opr> + </def> + </instruction> + + <instruction> + <mnemonic>bswap</mnemonic> + <def> + <pfx>oso rexw rexb</pfx> + <opc>0f c8</opc> + <opr>rAXr8</opr> + </def> + <def> + <pfx>oso rexw rexb</pfx> + <opc>0f c9</opc> + <opr>rCXr9</opr> + </def> + <def> + <pfx>oso rexw rexb</pfx> + <opc>0f ca</opc> + <opr>rDXr10</opr> + </def> + <def> + <pfx>oso rexw rexb</pfx> + <opc>0f cb</opc> + <opr>rBXr11</opr> + </def> + <def> + <pfx>oso rexw rexb</pfx> + <opc>0f cc</opc> + <opr>rSPr12</opr> + </def> + <def> + <pfx>oso rexw rexb</pfx> + <opc>0f cd</opc> + <opr>rBPr13</opr> + </def> + <def> + <pfx>oso rexw rexb</pfx> + <opc>0f ce</opc> + <opr>rSIr14</opr> + </def> + <def> + <pfx>oso rexw rexb</pfx> + <opc>0f cf</opc> + <opr>rDIr15</opr> + </def> + </instruction> + + <instruction> + <mnemonic>bt</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f ba /reg=4</opc> + <opr>Ev Ib</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f a3</opc> + <opr>Ev Gv</opr> + </def> + </instruction> + + <instruction> + <mnemonic>btc</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f bb</opc> + <opr>Ev Gv</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f ba /reg=7</opc> + <opr>Ev Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>btr</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f b3</opc> + <opr>Ev Gv</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f ba /reg=6</opc> + <opr>Ev Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>bts</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f ab</opc> + <opr>Ev Gv</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f ba /reg=5</opc> + <opr>Ev Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>call</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>ff /reg=2</opc> + <opr>Ev</opr> + <mode>def64</mode> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>ff /reg=3</opc> + <opr>Ep</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>e8</opc> + <opr>Jz</opr> + <mode>def64</mode> + </def> + <def> + <pfx>oso</pfx> + <opc>9a</opc> + <opr>Ap</opr> + <mode>inv64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>cbw</mnemonic> + <def> + <pfx>oso rexw</pfx> + <opc>98 /o=16</opc> + </def> + </instruction> + + <instruction> + <mnemonic>cwde</mnemonic> + <def> + <pfx>oso rexw</pfx> + <opc>98 /o=32</opc> + </def> + </instruction> + + <instruction> + <mnemonic>cdqe</mnemonic> + <def> + <pfx>oso rexw</pfx> + <opc>98 /o=64</opc> + </def> + </instruction> + + <instruction> + <mnemonic>clc</mnemonic> + <def> + <opc>f8</opc> + </def> + </instruction> + + <instruction> + <mnemonic>cld</mnemonic> + <def> + <opc>fc</opc> + </def> + </instruction> + + <instruction> + <mnemonic>clflush</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>0f ae /reg=7 /mod=!11</opc> + <opr>M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>clgi</mnemonic> + <vendor>amd</vendor> + <def> + <opc>0f 01 /reg=3 /mod=11 /rm=5</opc> + </def> + </instruction> + + <instruction> + <mnemonic>cli</mnemonic> + <def> + <opc>fa</opc> + </def> + </instruction> + + <instruction> + <mnemonic>clts</mnemonic> + <def> + <opc>0f 06</opc> + </def> + </instruction> + + <instruction> + <mnemonic>cmc</mnemonic> + <def> + <opc>f5</opc> + </def> + </instruction> + + <instruction> + <mnemonic>cmovo</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f 40</opc> + <opr>Gv Ev</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cmovno</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f 41</opc> + <opr>Gv Ev</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cmovb</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f 42</opc> + <opr>Gv Ev</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cmovae</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f 43</opc> + <opr>Gv Ev</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cmovz</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f 44</opc> + <opr>Gv Ev</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cmovnz</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f 45</opc> + <opr>Gv Ev</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cmovbe</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f 46</opc> + <opr>Gv Ev</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cmova</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f 47</opc> + <opr>Gv Ev</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cmovs</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f 48</opc> + <opr>Gv Ev</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cmovns</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f 49</opc> + <opr>Gv Ev</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cmovp</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f 4a</opc> + <opr>Gv Ev</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cmovnp</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f 4b</opc> + <opr>Gv Ev</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cmovl</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f 4c</opc> + <opr>Gv Ev</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cmovge</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f 4d</opc> + <opr>Gv Ev</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cmovle</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f 4e</opc> + <opr>Gv Ev</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cmovg</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f 4f</opc> + <opr>Gv Ev</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cmp</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>38</opc> + <opr>Eb Gb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>39</opc> + <opr>Ev Gv</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>3a</opc> + <opr>Gb Eb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>3b</opc> + <opr>Gv Ev</opr> + </def> + <def> + <opc>3c</opc> + <opr>AL Ib</opr> + </def> + <def> + <pfx>oso rexw</pfx> + <opc>3d</opc> + <opr>rAX Iz</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>80 /reg=7</opc> + <opr>Eb Ib</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>82 /reg=7</opc> + <opr>Eb Ib</opr> + <mode>inv64</mode> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>81 /reg=7</opc> + <opr>Ev Iz</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>83 /reg=7</opc> + <opr>Ev Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cmppd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f c2</opc> + <opr>V W Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cmpps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f c2</opc> + <opr>V W Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cmpsb</mnemonic> + <def> + <opc>a6</opc> + </def> + </instruction> + + <instruction> + <mnemonic>cmpsw</mnemonic> + <def> + <pfx>oso rexw</pfx> + <opc>a7 /o=16</opc> + </def> + </instruction> + + <instruction> + <mnemonic>cmpsd</mnemonic> + <def> + <pfx>oso rexw</pfx> + <opc>a7 /o=32</opc> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef2 0f c2</opc> + <opr>V W Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cmpsq</mnemonic> + <def> + <pfx>oso rexw</pfx> + <opc>a7 /o=64</opc> + </def> + </instruction> + + <instruction> + <mnemonic>cmpss</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f c2</opc> + <opr>V W Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cmpxchg</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f b0</opc> + <opr>Eb Gb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f b1</opc> + <opr>Ev Gv</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cmpxchg8b</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f c7 /reg=1</opc> + <opr>M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>comisd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 2f</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>comiss</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 2f</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cpuid</mnemonic> + <def> + <opc>0f a2</opc> + </def> + </instruction> + + <instruction> + <mnemonic>cvtdq2pd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f e6</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cvtdq2ps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 5b</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cvtpd2dq</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef2 0f e6</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cvtpd2pi</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 2d</opc> + <opr>P W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cvtpd2ps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 5a</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cvtpi2ps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 2a</opc> + <opr>V Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cvtpi2pd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 2a</opc> + <opr>V Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cvtps2dq</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 5b</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cvtps2pi</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 2d</opc> + <opr>P W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cvtps2pd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 5a</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cvtsd2si</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>ssef2 0f 2d</opc> + <opr>Gy W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cvtsd2ss</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef2 0f 5a</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cvtsi2ss</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>ssef3 0f 2a</opc> + <opr>V Ex</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cvtss2si</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>ssef3 0f 2d</opc> + <opr>Gy W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cvtss2sd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f 5a</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cvttpd2pi</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 2c</opc> + <opr>P W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cvttpd2dq</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f e6</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cvttps2dq</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f 5b</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cvttps2pi</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 2c</opc> + <opr>P W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cvttsd2si</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>ssef2 0f 2c</opc> + <opr>Gy Wsd</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cvtsi2sd</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>ssef2 0f 2a</opc> + <opr>V Ex</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cvttss2si</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>ssef3 0f 2c</opc> + <opr>Gy Wsd</opr> + </def> + </instruction> + + <instruction> + <mnemonic>cwd</mnemonic> + <def> + <pfx>oso rexw</pfx> + <opc>99 /o=16</opc> + </def> + </instruction> + + <instruction> + <mnemonic>cdq</mnemonic> + <def> + <pfx>oso rexw</pfx> + <opc>99 /o=32</opc> + </def> + </instruction> + + <instruction> + <mnemonic>cqo</mnemonic> + <def> + <pfx>oso rexw</pfx> + <opc>99 /o=64</opc> + </def> + </instruction> + + <instruction> + <mnemonic>daa</mnemonic> + <def> + <opc>27</opc> + <mode>inv64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>das</mnemonic> + <def> + <opc>2f</opc> + <mode>inv64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>dec</mnemonic> + <def> + <pfx>oso</pfx> + <opc>48</opc> + <opr>eAX</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>49</opc> + <opr>eCX</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>4a</opc> + <opr>eDX</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>4b</opc> + <opr>eBX</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>4c</opc> + <opr>eSP</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>4d</opc> + <opr>eBP</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>4e</opc> + <opr>eSI</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>4f</opc> + <opr>eDI</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>fe /reg=1</opc> + <opr>Eb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>ff /reg=1</opc> + <opr>Ev</opr> + </def> + </instruction> + + <instruction> + <mnemonic>div</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>f7 /reg=6</opc> + <opr>Ev</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>f6 /reg=6</opc> + <opr>Eb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>divpd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 5e</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>divps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 5e</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>divsd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef2 0f 5e</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>divss</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f 5e</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>emms</mnemonic> + <def> + <opc>0f 77</opc> + </def> + </instruction> + + <instruction> + <mnemonic>enter</mnemonic> + <def> + <opc>c8</opc> + <opr>Iw Ib</opr> + <mode>def64 depM</mode> + </def> + </instruction> + + <instruction> + <mnemonic>f2xm1</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=30</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fabs</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=21</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fadd</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>dc /mod=!11 /reg=0</opc> + <opr>Mq</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>d8 /mod=!11 /reg=0</opc> + <opr>Md</opr> + </def> + <def> + <opc>dc /mod=11 /x87=00</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=01</opc> + <opr>ST1 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=02</opc> + <opr>ST2 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=03</opc> + <opr>ST3 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=04</opc> + <opr>ST4 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=05</opc> + <opr>ST5 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=06</opc> + <opr>ST6 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=07</opc> + <opr>ST7 ST0</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=00</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=01</opc> + <opr>ST0 ST1</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=02</opc> + <opr>ST0 ST2</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=03</opc> + <opr>ST0 ST3</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=04</opc> + <opr>ST0 ST4</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=05</opc> + <opr>ST0 ST5</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=06</opc> + <opr>ST0 ST6</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=07</opc> + <opr>ST0 ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>faddp</mnemonic> + <class>X87</class> + <def> + <opc>de /mod=11 /x87=00</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=01</opc> + <opr>ST1 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=02</opc> + <opr>ST2 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=03</opc> + <opr>ST3 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=04</opc> + <opr>ST4 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=05</opc> + <opr>ST5 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=06</opc> + <opr>ST6 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=07</opc> + <opr>ST7 ST0</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fbld</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>df /mod=!11 /reg=4</opc> + <opr>Mt</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fbstp</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>df /mod=!11 /reg=6</opc> + <opr>Mt</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fchs</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=20</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fclex</mnemonic> + <class>X87</class> + <def> + <opc>db /mod=11 /x87=22</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fcmovb</mnemonic> + <class>X87</class> + <def> + <opc>da /mod=11 /x87=00</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>da /mod=11 /x87=01</opc> + <opr>ST0 ST1</opr> + </def> + <def> + <opc>da /mod=11 /x87=02</opc> + <opr>ST0 ST2</opr> + </def> + <def> + <opc>da /mod=11 /x87=03</opc> + <opr>ST0 ST3</opr> + </def> + <def> + <opc>da /mod=11 /x87=04</opc> + <opr>ST0 ST4</opr> + </def> + <def> + <opc>da /mod=11 /x87=05</opc> + <opr>ST0 ST5</opr> + </def> + <def> + <opc>da /mod=11 /x87=06</opc> + <opr>ST0 ST6</opr> + </def> + <def> + <opc>da /mod=11 /x87=07</opc> + <opr>ST0 ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fcmove</mnemonic> + <class>X87</class> + <def> + <opc>da /mod=11 /x87=08</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>da /mod=11 /x87=09</opc> + <opr>ST0 ST1</opr> + </def> + <def> + <opc>da /mod=11 /x87=0a</opc> + <opr>ST0 ST2</opr> + </def> + <def> + <opc>da /mod=11 /x87=0b</opc> + <opr>ST0 ST3</opr> + </def> + <def> + <opc>da /mod=11 /x87=0c</opc> + <opr>ST0 ST4</opr> + </def> + <def> + <opc>da /mod=11 /x87=0d</opc> + <opr>ST0 ST5</opr> + </def> + <def> + <opc>da /mod=11 /x87=0e</opc> + <opr>ST0 ST6</opr> + </def> + <def> + <opc>da /mod=11 /x87=0f</opc> + <opr>ST0 ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fcmovbe</mnemonic> + <class>X87</class> + <def> + <opc>da /mod=11 /x87=10</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>da /mod=11 /x87=11</opc> + <opr>ST0 ST1</opr> + </def> + <def> + <opc>da /mod=11 /x87=12</opc> + <opr>ST0 ST2</opr> + </def> + <def> + <opc>da /mod=11 /x87=13</opc> + <opr>ST0 ST3</opr> + </def> + <def> + <opc>da /mod=11 /x87=14</opc> + <opr>ST0 ST4</opr> + </def> + <def> + <opc>da /mod=11 /x87=15</opc> + <opr>ST0 ST5</opr> + </def> + <def> + <opc>da /mod=11 /x87=16</opc> + <opr>ST0 ST6</opr> + </def> + <def> + <opc>da /mod=11 /x87=17</opc> + <opr>ST0 ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fcmovu</mnemonic> + <class>X87</class> + <def> + <opc>da /mod=11 /x87=18</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>da /mod=11 /x87=19</opc> + <opr>ST0 ST1</opr> + </def> + <def> + <opc>da /mod=11 /x87=1a</opc> + <opr>ST0 ST2</opr> + </def> + <def> + <opc>da /mod=11 /x87=1b</opc> + <opr>ST0 ST3</opr> + </def> + <def> + <opc>da /mod=11 /x87=1c</opc> + <opr>ST0 ST4</opr> + </def> + <def> + <opc>da /mod=11 /x87=1d</opc> + <opr>ST0 ST5</opr> + </def> + <def> + <opc>da /mod=11 /x87=1e</opc> + <opr>ST0 ST6</opr> + </def> + <def> + <opc>da /mod=11 /x87=1f</opc> + <opr>ST0 ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fcmovnb</mnemonic> + <class>X87</class> + <def> + <opc>db /mod=11 /x87=00</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>db /mod=11 /x87=01</opc> + <opr>ST0 ST1</opr> + </def> + <def> + <opc>db /mod=11 /x87=02</opc> + <opr>ST0 ST2</opr> + </def> + <def> + <opc>db /mod=11 /x87=03</opc> + <opr>ST0 ST3</opr> + </def> + <def> + <opc>db /mod=11 /x87=04</opc> + <opr>ST0 ST4</opr> + </def> + <def> + <opc>db /mod=11 /x87=05</opc> + <opr>ST0 ST5</opr> + </def> + <def> + <opc>db /mod=11 /x87=06</opc> + <opr>ST0 ST6</opr> + </def> + <def> + <opc>db /mod=11 /x87=07</opc> + <opr>ST0 ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fcmovne</mnemonic> + <class>X87</class> + <def> + <opc>db /mod=11 /x87=08</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>db /mod=11 /x87=09</opc> + <opr>ST0 ST1</opr> + </def> + <def> + <opc>db /mod=11 /x87=0a</opc> + <opr>ST0 ST2</opr> + </def> + <def> + <opc>db /mod=11 /x87=0b</opc> + <opr>ST0 ST3</opr> + </def> + <def> + <opc>db /mod=11 /x87=0c</opc> + <opr>ST0 ST4</opr> + </def> + <def> + <opc>db /mod=11 /x87=0d</opc> + <opr>ST0 ST5</opr> + </def> + <def> + <opc>db /mod=11 /x87=0e</opc> + <opr>ST0 ST6</opr> + </def> + <def> + <opc>db /mod=11 /x87=0f</opc> + <opr>ST0 ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fcmovnbe</mnemonic> + <class>X87</class> + <def> + <opc>db /mod=11 /x87=10</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>db /mod=11 /x87=11</opc> + <opr>ST0 ST1</opr> + </def> + <def> + <opc>db /mod=11 /x87=12</opc> + <opr>ST0 ST2</opr> + </def> + <def> + <opc>db /mod=11 /x87=13</opc> + <opr>ST0 ST3</opr> + </def> + <def> + <opc>db /mod=11 /x87=14</opc> + <opr>ST0 ST4</opr> + </def> + <def> + <opc>db /mod=11 /x87=15</opc> + <opr>ST0 ST5</opr> + </def> + <def> + <opc>db /mod=11 /x87=16</opc> + <opr>ST0 ST6</opr> + </def> + <def> + <opc>db /mod=11 /x87=17</opc> + <opr>ST0 ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fcmovnu</mnemonic> + <class>X87</class> + <def> + <opc>db /mod=11 /x87=18</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>db /mod=11 /x87=19</opc> + <opr>ST0 ST1</opr> + </def> + <def> + <opc>db /mod=11 /x87=1a</opc> + <opr>ST0 ST2</opr> + </def> + <def> + <opc>db /mod=11 /x87=1b</opc> + <opr>ST0 ST3</opr> + </def> + <def> + <opc>db /mod=11 /x87=1c</opc> + <opr>ST0 ST4</opr> + </def> + <def> + <opc>db /mod=11 /x87=1d</opc> + <opr>ST0 ST5</opr> + </def> + <def> + <opc>db /mod=11 /x87=1e</opc> + <opr>ST0 ST6</opr> + </def> + <def> + <opc>db /mod=11 /x87=1f</opc> + <opr>ST0 ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fucomi</mnemonic> + <class>X87</class> + <def> + <opc>db /mod=11 /x87=28</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>db /mod=11 /x87=29</opc> + <opr>ST0 ST1</opr> + </def> + <def> + <opc>db /mod=11 /x87=2a</opc> + <opr>ST0 ST2</opr> + </def> + <def> + <opc>db /mod=11 /x87=2b</opc> + <opr>ST0 ST3</opr> + </def> + <def> + <opc>db /mod=11 /x87=2c</opc> + <opr>ST0 ST4</opr> + </def> + <def> + <opc>db /mod=11 /x87=2d</opc> + <opr>ST0 ST5</opr> + </def> + <def> + <opc>db /mod=11 /x87=2e</opc> + <opr>ST0 ST6</opr> + </def> + <def> + <opc>db /mod=11 /x87=2f</opc> + <opr>ST0 ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fcom</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>d8 /mod=!11 /reg=2</opc> + <opr>Md</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>dc /mod=!11 /reg=2</opc> + <opr>Mq</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=10</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=11</opc> + <opr>ST0 ST1</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=12</opc> + <opr>ST0 ST2</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=13</opc> + <opr>ST0 ST3</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=14</opc> + <opr>ST0 ST4</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=15</opc> + <opr>ST0 ST5</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=16</opc> + <opr>ST0 ST6</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=17</opc> + <opr>ST0 ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fcom2</mnemonic> + <class>X87 UNDOC</class> + <def> + <opc>dc /mod=11 /x87=10</opc> + <opr>ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=11</opc> + <opr>ST1</opr> + </def> + <def> + <opc>dc /mod=11 /x87=12</opc> + <opr>ST2</opr> + </def> + <def> + <opc>dc /mod=11 /x87=13</opc> + <opr>ST3</opr> + </def> + <def> + <opc>dc /mod=11 /x87=14</opc> + <opr>ST4</opr> + </def> + <def> + <opc>dc /mod=11 /x87=15</opc> + <opr>ST5</opr> + </def> + <def> + <opc>dc /mod=11 /x87=16</opc> + <opr>ST6</opr> + </def> + <def> + <opc>dc /mod=11 /x87=17</opc> + <opr>ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fcomp3</mnemonic> + <class>X87 UNDOC</class> + <def> + <opc>dc /mod=11 /x87=18</opc> + <opr>ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=19</opc> + <opr>ST1</opr> + </def> + <def> + <opc>dc /mod=11 /x87=1a</opc> + <opr>ST2</opr> + </def> + <def> + <opc>dc /mod=11 /x87=1b</opc> + <opr>ST3</opr> + </def> + <def> + <opc>dc /mod=11 /x87=1c</opc> + <opr>ST4</opr> + </def> + <def> + <opc>dc /mod=11 /x87=1d</opc> + <opr>ST5</opr> + </def> + <def> + <opc>dc /mod=11 /x87=1e</opc> + <opr>ST6</opr> + </def> + <def> + <opc>dc /mod=11 /x87=1f</opc> + <opr>ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fcomi</mnemonic> + <class>X87</class> + <def> + <opc>db /mod=11 /x87=30</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>db /mod=11 /x87=31</opc> + <opr>ST0 ST1</opr> + </def> + <def> + <opc>db /mod=11 /x87=32</opc> + <opr>ST0 ST2</opr> + </def> + <def> + <opc>db /mod=11 /x87=33</opc> + <opr>ST0 ST3</opr> + </def> + <def> + <opc>db /mod=11 /x87=34</opc> + <opr>ST0 ST4</opr> + </def> + <def> + <opc>db /mod=11 /x87=35</opc> + <opr>ST0 ST5</opr> + </def> + <def> + <opc>db /mod=11 /x87=36</opc> + <opr>ST0 ST6</opr> + </def> + <def> + <opc>db /mod=11 /x87=37</opc> + <opr>ST0 ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fucomip</mnemonic> + <class>X87</class> + <def> + <opc>df /mod=11 /x87=28</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>df /mod=11 /x87=29</opc> + <opr>ST0 ST1</opr> + </def> + <def> + <opc>df /mod=11 /x87=2a</opc> + <opr>ST0 ST2</opr> + </def> + <def> + <opc>df /mod=11 /x87=2b</opc> + <opr>ST0 ST3</opr> + </def> + <def> + <opc>df /mod=11 /x87=2c</opc> + <opr>ST0 ST4</opr> + </def> + <def> + <opc>df /mod=11 /x87=2d</opc> + <opr>ST0 ST5</opr> + </def> + <def> + <opc>df /mod=11 /x87=2e</opc> + <opr>ST0 ST6</opr> + </def> + <def> + <opc>df /mod=11 /x87=2f</opc> + <opr>ST0 ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fcomip</mnemonic> + <class>X87</class> + <def> + <opc>df /mod=11 /x87=30</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>df /mod=11 /x87=31</opc> + <opr>ST0 ST1</opr> + </def> + <def> + <opc>df /mod=11 /x87=32</opc> + <opr>ST0 ST2</opr> + </def> + <def> + <opc>df /mod=11 /x87=33</opc> + <opr>ST0 ST3</opr> + </def> + <def> + <opc>df /mod=11 /x87=34</opc> + <opr>ST0 ST4</opr> + </def> + <def> + <opc>df /mod=11 /x87=35</opc> + <opr>ST0 ST5</opr> + </def> + <def> + <opc>df /mod=11 /x87=36</opc> + <opr>ST0 ST6</opr> + </def> + <def> + <opc>df /mod=11 /x87=37</opc> + <opr>ST0 ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fcomp</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>d8 /mod=!11 /reg=3</opc> + <opr>Md</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>dc /mod=!11 /reg=3</opc> + <opr>Mq</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=18</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=19</opc> + <opr>ST0 ST1</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=1a</opc> + <opr>ST0 ST2</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=1b</opc> + <opr>ST0 ST3</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=1c</opc> + <opr>ST0 ST4</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=1d</opc> + <opr>ST0 ST5</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=1e</opc> + <opr>ST0 ST6</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=1f</opc> + <opr>ST0 ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fcomp5</mnemonic> + <class>X87 UNDOC</class> + <def> + <opc>de /mod=11 /x87=10</opc> + <opr>ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=11</opc> + <opr>ST1</opr> + </def> + <def> + <opc>de /mod=11 /x87=12</opc> + <opr>ST2</opr> + </def> + <def> + <opc>de /mod=11 /x87=13</opc> + <opr>ST3</opr> + </def> + <def> + <opc>de /mod=11 /x87=14</opc> + <opr>ST4</opr> + </def> + <def> + <opc>de /mod=11 /x87=15</opc> + <opr>ST5</opr> + </def> + <def> + <opc>de /mod=11 /x87=16</opc> + <opr>ST6</opr> + </def> + <def> + <opc>de /mod=11 /x87=17</opc> + <opr>ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fcompp</mnemonic> + <class>X87</class> + <def> + <opc>de /mod=11 /x87=19</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fcos</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=3f</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fdecstp</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=36</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fdiv</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>dc /mod=!11 /reg=6</opc> + <opr>Mq</opr> + </def> + <def> + <opc>dc /mod=11 /x87=38</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=39</opc> + <opr>ST1 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=3a</opc> + <opr>ST2 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=3b</opc> + <opr>ST3 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=3c</opc> + <opr>ST4 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=3d</opc> + <opr>ST5 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=3e</opc> + <opr>ST6 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=3f</opc> + <opr>ST7 ST0</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>d8 /mod=!11 /reg=6</opc> + <opr>Md</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=30</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=31</opc> + <opr>ST0 ST1</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=32</opc> + <opr>ST0 ST2</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=33</opc> + <opr>ST0 ST3</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=34</opc> + <opr>ST0 ST4</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=35</opc> + <opr>ST0 ST5</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=36</opc> + <opr>ST0 ST6</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=37</opc> + <opr>ST0 ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fdivp</mnemonic> + <class>X87</class> + <def> + <opc>de /mod=11 /x87=38</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=39</opc> + <opr>ST1 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=3a</opc> + <opr>ST2 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=3b</opc> + <opr>ST3 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=3c</opc> + <opr>ST4 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=3d</opc> + <opr>ST5 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=3e</opc> + <opr>ST6 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=3f</opc> + <opr>ST7 ST0</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fdivr</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>dc /mod=!11 /reg=7</opc> + <opr>Mq</opr> + </def> + <def> + <opc>dc /mod=11 /x87=30</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=31</opc> + <opr>ST1 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=32</opc> + <opr>ST2 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=33</opc> + <opr>ST3 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=34</opc> + <opr>ST4 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=35</opc> + <opr>ST5 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=36</opc> + <opr>ST6 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=37</opc> + <opr>ST7 ST0</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>d8 /mod=!11 /reg=7</opc> + <opr>Md</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=38</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=39</opc> + <opr>ST0 ST1</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=3a</opc> + <opr>ST0 ST2</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=3b</opc> + <opr>ST0 ST3</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=3c</opc> + <opr>ST0 ST4</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=3d</opc> + <opr>ST0 ST5</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=3e</opc> + <opr>ST0 ST6</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=3f</opc> + <opr>ST0 ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fdivrp</mnemonic> + <class>X87</class> + <def> + <opc>de /mod=11 /x87=30</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=31</opc> + <opr>ST1 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=32</opc> + <opr>ST2 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=33</opc> + <opr>ST3 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=34</opc> + <opr>ST4 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=35</opc> + <opr>ST5 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=36</opc> + <opr>ST6 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=37</opc> + <opr>ST7 ST0</opr> + </def> + </instruction> + + <instruction> + <mnemonic>femms</mnemonic> + <def> + <opc>0f 0e</opc> + </def> + </instruction> + + <instruction> + <mnemonic>ffree</mnemonic> + <class>X87</class> + <def> + <opc>dd /mod=11 /x87=00</opc> + <opr>ST0</opr> + </def> + <def> + <opc>dd /mod=11 /x87=01</opc> + <opr>ST1</opr> + </def> + <def> + <opc>dd /mod=11 /x87=02</opc> + <opr>ST2</opr> + </def> + <def> + <opc>dd /mod=11 /x87=03</opc> + <opr>ST3</opr> + </def> + <def> + <opc>dd /mod=11 /x87=04</opc> + <opr>ST4</opr> + </def> + <def> + <opc>dd /mod=11 /x87=05</opc> + <opr>ST5</opr> + </def> + <def> + <opc>dd /mod=11 /x87=06</opc> + <opr>ST6</opr> + </def> + <def> + <opc>dd /mod=11 /x87=07</opc> + <opr>ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>ffreep</mnemonic> + <class>X87</class> + <def> + <opc>df /mod=11 /x87=00</opc> + <opr>ST0</opr> + </def> + <def> + <opc>df /mod=11 /x87=01</opc> + <opr>ST1</opr> + </def> + <def> + <opc>df /mod=11 /x87=02</opc> + <opr>ST2</opr> + </def> + <def> + <opc>df /mod=11 /x87=03</opc> + <opr>ST3</opr> + </def> + <def> + <opc>df /mod=11 /x87=04</opc> + <opr>ST4</opr> + </def> + <def> + <opc>df /mod=11 /x87=05</opc> + <opr>ST5</opr> + </def> + <def> + <opc>df /mod=11 /x87=06</opc> + <opr>ST6</opr> + </def> + <def> + <opc>df /mod=11 /x87=07</opc> + <opr>ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>ficom</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>de /mod=!11 /reg=2</opc> + <opr>Mw</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>da /mod=!11 /reg=2</opc> + <opr>Md</opr> + </def> + </instruction> + + <instruction> + <mnemonic>ficomp</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>de /mod=!11 /reg=3</opc> + <opr>Mw</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>da /mod=!11 /reg=3</opc> + <opr>Md</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fild</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>df /mod=!11 /reg=0</opc> + <opr>Mw</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>df /mod=!11 /reg=5</opc> + <opr>Mq</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>db /mod=!11 /reg=0</opc> + <opr>Md</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fncstp</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=37</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fninit</mnemonic> + <class>X87</class> + <def> + <opc>db /mod=11 /x87=23</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fiadd</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>da /mod=!11 /reg=0</opc> + <opr>Md</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>de /mod=!11 /reg=0</opc> + <opr>Mw</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fidivr</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>da /mod=!11 /reg=7</opc> + <opr>Md</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>de /mod=!11 /reg=7</opc> + <opr>Mw</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fidiv</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>da /mod=!11 /reg=6</opc> + <opr>Md</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>de /mod=!11 /reg=6</opc> + <opr>Mw</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fisub</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>da /mod=!11 /reg=4</opc> + <opr>Md</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>de /mod=!11 /reg=4</opc> + <opr>Mw</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fisubr</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>da /mod=!11 /reg=5</opc> + <opr>Md</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>de /mod=!11 /reg=5</opc> + <opr>Mw</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fist</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>df /mod=!11 /reg=2</opc> + <opr>Mw</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>db /mod=!11 /reg=2</opc> + <opr>Md</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fistp</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>df /mod=!11 /reg=3</opc> + <opr>Mw</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>df /mod=!11 /reg=7</opc> + <opr>Mq</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>db /mod=!11 /reg=3</opc> + <opr>Md</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fisttp</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>db /mod=!11 /reg=1</opc> + <opr>Md</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>dd /mod=!11 /reg=1</opc> + <opr>Mq</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>df /mod=!11 /reg=1</opc> + <opr>Mw</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fld</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>db /mod=!11 /reg=5</opc> + <opr>Mt</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>dd /mod=!11 /reg=0</opc> + <opr>Mq</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>d9 /mod=!11 /reg=0</opc> + <opr>Md</opr> + </def> + <def> + <opc>d9 /mod=11 /x87=00</opc> + <opr>ST0</opr> + </def> + <def> + <opc>d9 /mod=11 /x87=01</opc> + <opr>ST1</opr> + </def> + <def> + <opc>d9 /mod=11 /x87=02</opc> + <opr>ST2</opr> + </def> + <def> + <opc>d9 /mod=11 /x87=03</opc> + <opr>ST3</opr> + </def> + <def> + <opc>d9 /mod=11 /x87=04</opc> + <opr>ST4</opr> + </def> + <def> + <opc>d9 /mod=11 /x87=05</opc> + <opr>ST5</opr> + </def> + <def> + <opc>d9 /mod=11 /x87=06</opc> + <opr>ST6</opr> + </def> + <def> + <opc>d9 /mod=11 /x87=07</opc> + <opr>ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fld1</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=28</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fldl2t</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=29</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fldl2e</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=2a</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fldlpi</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=2b</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fldlg2</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=2c</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fldln2</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=2d</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fldz</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=2e</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fldcw</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>d9 /mod=!11 /reg=5</opc> + <opr>Mw</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fldenv</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>d9 /mod=!11 /reg=4</opc> + <opr>M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fmul</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>dc /mod=!11 /reg=1</opc> + <opr>Mq</opr> + </def> + <def> + <opc>dc /mod=11 /x87=08</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=09</opc> + <opr>ST1 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=0a</opc> + <opr>ST2 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=0b</opc> + <opr>ST3 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=0c</opc> + <opr>ST4 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=0d</opc> + <opr>ST5 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=0e</opc> + <opr>ST6 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=0f</opc> + <opr>ST7 ST0</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>d8 /mod=!11 /reg=1</opc> + <opr>Md</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=08</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=09</opc> + <opr>ST0 ST1</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=0a</opc> + <opr>ST0 ST2</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=0b</opc> + <opr>ST0 ST3</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=0c</opc> + <opr>ST0 ST4</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=0d</opc> + <opr>ST0 ST5</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=0e</opc> + <opr>ST0 ST6</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=0f</opc> + <opr>ST0 ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fmulp</mnemonic> + <class>X87</class> + <def> + <opc>de /mod=11 /x87=08</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=09</opc> + <opr>ST1 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=0a</opc> + <opr>ST2 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=0b</opc> + <opr>ST3 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=0c</opc> + <opr>ST4 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=0d</opc> + <opr>ST5 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=0e</opc> + <opr>ST6 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=0f</opc> + <opr>ST7 ST0</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fimul</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>da /mod=!11 /reg=1</opc> + <opr>Md</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>de /mod=!11 /reg=1</opc> + <opr>Mw</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fnop</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=10</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fpatan</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=33</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fprem</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=38</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fprem1</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=35</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fptan</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=32</opc> + </def> + </instruction> + + <instruction> + <mnemonic>frndint</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=3c</opc> + </def> + </instruction> + + <instruction> + <mnemonic>frstor</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>dd /mod=!11 /reg=4</opc> + <opr>M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fnsave</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>dd /mod=!11 /reg=6</opc> + <opr>M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fscale</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=3d</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fsin</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=3e</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fsincos</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=3b</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fsqrt</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=3a</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fstp</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>db /mod=!11 /reg=7</opc> + <opr>Mt</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>dd /mod=!11 /reg=3</opc> + <opr>Mq</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>d9 /mod=!11 /reg=3</opc> + <opr>Md</opr> + </def> + <def> + <opc>dd /mod=11 /x87=18</opc> + <opr>ST0</opr> + </def> + <def> + <opc>dd /mod=11 /x87=19</opc> + <opr>ST1</opr> + </def> + <def> + <opc>dd /mod=11 /x87=1a</opc> + <opr>ST2</opr> + </def> + <def> + <opc>dd /mod=11 /x87=1b</opc> + <opr>ST3</opr> + </def> + <def> + <opc>dd /mod=11 /x87=1c</opc> + <opr>ST4</opr> + </def> + <def> + <opc>dd /mod=11 /x87=1d</opc> + <opr>ST5</opr> + </def> + <def> + <opc>dd /mod=11 /x87=1e</opc> + <opr>ST6</opr> + </def> + <def> + <opc>dd /mod=11 /x87=1f</opc> + <opr>ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fstp1</mnemonic> + <def> + <opc>d9 /mod=11 /x87=18</opc> + <opr>ST0</opr> + </def> + <def> + <opc>d9 /mod=11 /x87=19</opc> + <opr>ST1</opr> + </def> + <def> + <opc>d9 /mod=11 /x87=1a</opc> + <opr>ST2</opr> + </def> + <def> + <opc>d9 /mod=11 /x87=1b</opc> + <opr>ST3</opr> + </def> + <def> + <opc>d9 /mod=11 /x87=1c</opc> + <opr>ST4</opr> + </def> + <def> + <opc>d9 /mod=11 /x87=1d</opc> + <opr>ST5</opr> + </def> + <def> + <opc>d9 /mod=11 /x87=1e</opc> + <opr>ST6</opr> + </def> + <def> + <opc>d9 /mod=11 /x87=1f</opc> + <opr>ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fstp8</mnemonic> + <def> + <opc>df /mod=11 /x87=10</opc> + <opr>ST0</opr> + </def> + <def> + <opc>df /mod=11 /x87=11</opc> + <opr>ST1</opr> + </def> + <def> + <opc>df /mod=11 /x87=12</opc> + <opr>ST2</opr> + </def> + <def> + <opc>df /mod=11 /x87=13</opc> + <opr>ST3</opr> + </def> + <def> + <opc>df /mod=11 /x87=14</opc> + <opr>ST4</opr> + </def> + <def> + <opc>df /mod=11 /x87=15</opc> + <opr>ST5</opr> + </def> + <def> + <opc>df /mod=11 /x87=16</opc> + <opr>ST6</opr> + </def> + <def> + <opc>df /mod=11 /x87=17</opc> + <opr>ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fstp9</mnemonic> + <def> + <opc>df /mod=11 /x87=18</opc> + <opr>ST0</opr> + </def> + <def> + <opc>df /mod=11 /x87=19</opc> + <opr>ST1</opr> + </def> + <def> + <opc>df /mod=11 /x87=1a</opc> + <opr>ST2</opr> + </def> + <def> + <opc>df /mod=11 /x87=1b</opc> + <opr>ST3</opr> + </def> + <def> + <opc>df /mod=11 /x87=1c</opc> + <opr>ST4</opr> + </def> + <def> + <opc>df /mod=11 /x87=1d</opc> + <opr>ST5</opr> + </def> + <def> + <opc>df /mod=11 /x87=1e</opc> + <opr>ST6</opr> + </def> + <def> + <opc>df /mod=11 /x87=1f</opc> + <opr>ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fst</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>d9 /mod=!11 /reg=2</opc> + <opr>Md</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>dd /mod=!11 /reg=2</opc> + <opr>Mq</opr> + </def> + <def> + <opc>dd /mod=11 /x87=10</opc> + <opr>ST0</opr> + </def> + <def> + <opc>dd /mod=11 /x87=11</opc> + <opr>ST1</opr> + </def> + <def> + <opc>dd /mod=11 /x87=12</opc> + <opr>ST2</opr> + </def> + <def> + <opc>dd /mod=11 /x87=13</opc> + <opr>ST3</opr> + </def> + <def> + <opc>dd /mod=11 /x87=14</opc> + <opr>ST4</opr> + </def> + <def> + <opc>dd /mod=11 /x87=15</opc> + <opr>ST5</opr> + </def> + <def> + <opc>dd /mod=11 /x87=16</opc> + <opr>ST6</opr> + </def> + <def> + <opc>dd /mod=11 /x87=17</opc> + <opr>ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fnstcw</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>d9 /mod=!11 /reg=7</opc> + <opr>Mw</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fnstenv</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>d9 /mod=!11 /reg=6</opc> + <opr>M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fnstsw</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>dd /mod=!11 /reg=7</opc> + <opr>Mw</opr> + </def> + <def> + <opc>df /mod=11 /x87=20</opc> + <opr>AX</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fsub</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>d8 /mod=!11 /reg=4</opc> + <opr>Md</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>dc /mod=!11 /reg=4</opc> + <opr>Mq</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=20</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=21</opc> + <opr>ST0 ST1</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=22</opc> + <opr>ST0 ST2</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=23</opc> + <opr>ST0 ST3</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=24</opc> + <opr>ST0 ST4</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=25</opc> + <opr>ST0 ST5</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=26</opc> + <opr>ST0 ST6</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=27</opc> + <opr>ST0 ST7</opr> + </def> + <def> + <opc>dc /mod=11 /x87=28</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=29</opc> + <opr>ST1 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=2a</opc> + <opr>ST2 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=2b</opc> + <opr>ST3 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=2c</opc> + <opr>ST4 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=2d</opc> + <opr>ST5 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=2e</opc> + <opr>ST6 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=2f</opc> + <opr>ST7 ST0</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fsubp</mnemonic> + <class>X87</class> + <def> + <opc>de /mod=11 /x87=28</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=29</opc> + <opr>ST1 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=2a</opc> + <opr>ST2 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=2b</opc> + <opr>ST3 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=2c</opc> + <opr>ST4 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=2d</opc> + <opr>ST5 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=2e</opc> + <opr>ST6 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=2f</opc> + <opr>ST7 ST0</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fsubr</mnemonic> + <class>X87</class> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>dc /mod=!11 /reg=5</opc> + <opr>Mq</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=28</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=29</opc> + <opr>ST0 ST1</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=2a</opc> + <opr>ST0 ST2</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=2b</opc> + <opr>ST0 ST3</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=2c</opc> + <opr>ST0 ST4</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=2d</opc> + <opr>ST0 ST5</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=2e</opc> + <opr>ST0 ST6</opr> + </def> + <def> + <opc>d8 /mod=11 /x87=2f</opc> + <opr>ST0 ST7</opr> + </def> + <def> + <opc>dc /mod=11 /x87=20</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=21</opc> + <opr>ST1 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=22</opc> + <opr>ST2 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=23</opc> + <opr>ST3 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=24</opc> + <opr>ST4 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=25</opc> + <opr>ST5 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=26</opc> + <opr>ST6 ST0</opr> + </def> + <def> + <opc>dc /mod=11 /x87=27</opc> + <opr>ST7 ST0</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>d8 /mod=!11 /reg=5</opc> + <opr>Md</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fsubrp</mnemonic> + <class>X87</class> + <def> + <opc>de /mod=11 /x87=20</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=21</opc> + <opr>ST1 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=22</opc> + <opr>ST2 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=23</opc> + <opr>ST3 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=24</opc> + <opr>ST4 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=25</opc> + <opr>ST5 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=26</opc> + <opr>ST6 ST0</opr> + </def> + <def> + <opc>de /mod=11 /x87=27</opc> + <opr>ST7 ST0</opr> + </def> + </instruction> + + <instruction> + <mnemonic>ftst</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=24</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fucom</mnemonic> + <class>X87</class> + <def> + <opc>dd /mod=11 /x87=20</opc> + <opr>ST0</opr> + </def> + <def> + <opc>dd /mod=11 /x87=21</opc> + <opr>ST1</opr> + </def> + <def> + <opc>dd /mod=11 /x87=22</opc> + <opr>ST2</opr> + </def> + <def> + <opc>dd /mod=11 /x87=23</opc> + <opr>ST3</opr> + </def> + <def> + <opc>dd /mod=11 /x87=24</opc> + <opr>ST4</opr> + </def> + <def> + <opc>dd /mod=11 /x87=25</opc> + <opr>ST5</opr> + </def> + <def> + <opc>dd /mod=11 /x87=26</opc> + <opr>ST6</opr> + </def> + <def> + <opc>dd /mod=11 /x87=27</opc> + <opr>ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fucomp</mnemonic> + <class>X87</class> + <def> + <opc>dd /mod=11 /x87=28</opc> + <opr>ST0</opr> + </def> + <def> + <opc>dd /mod=11 /x87=29</opc> + <opr>ST1</opr> + </def> + <def> + <opc>dd /mod=11 /x87=2a</opc> + <opr>ST2</opr> + </def> + <def> + <opc>dd /mod=11 /x87=2b</opc> + <opr>ST3</opr> + </def> + <def> + <opc>dd /mod=11 /x87=2c</opc> + <opr>ST4</opr> + </def> + <def> + <opc>dd /mod=11 /x87=2d</opc> + <opr>ST5</opr> + </def> + <def> + <opc>dd /mod=11 /x87=2e</opc> + <opr>ST6</opr> + </def> + <def> + <opc>dd /mod=11 /x87=2f</opc> + <opr>ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fucompp</mnemonic> + <class>X87</class> + <def> + <opc>da /mod=11 /x87=29</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fxam</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=25</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fxch</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=08</opc> + <opr>ST0 ST0</opr> + </def> + <def> + <opc>d9 /mod=11 /x87=09</opc> + <opr>ST0 ST1</opr> + </def> + <def> + <opc>d9 /mod=11 /x87=0a</opc> + <opr>ST0 ST2</opr> + </def> + <def> + <opc>d9 /mod=11 /x87=0b</opc> + <opr>ST0 ST3</opr> + </def> + <def> + <opc>d9 /mod=11 /x87=0c</opc> + <opr>ST0 ST4</opr> + </def> + <def> + <opc>d9 /mod=11 /x87=0d</opc> + <opr>ST0 ST5</opr> + </def> + <def> + <opc>d9 /mod=11 /x87=0e</opc> + <opr>ST0 ST6</opr> + </def> + <def> + <opc>d9 /mod=11 /x87=0f</opc> + <opr>ST0 ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fxch4</mnemonic> + <class>X87</class> + <def> + <opc>dd /mod=11 /x87=08</opc> + <opr>ST0</opr> + </def> + <def> + <opc>dd /mod=11 /x87=09</opc> + <opr>ST1</opr> + </def> + <def> + <opc>dd /mod=11 /x87=0a</opc> + <opr>ST2</opr> + </def> + <def> + <opc>dd /mod=11 /x87=0b</opc> + <opr>ST3</opr> + </def> + <def> + <opc>dd /mod=11 /x87=0c</opc> + <opr>ST4</opr> + </def> + <def> + <opc>dd /mod=11 /x87=0d</opc> + <opr>ST5</opr> + </def> + <def> + <opc>dd /mod=11 /x87=0e</opc> + <opr>ST6</opr> + </def> + <def> + <opc>dd /mod=11 /x87=0f</opc> + <opr>ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fxch7</mnemonic> + <class>X87</class> + <def> + <opc>df /mod=11 /x87=08</opc> + <opr>ST0</opr> + </def> + <def> + <opc>df /mod=11 /x87=09</opc> + <opr>ST1</opr> + </def> + <def> + <opc>df /mod=11 /x87=0a</opc> + <opr>ST2</opr> + </def> + <def> + <opc>df /mod=11 /x87=0b</opc> + <opr>ST3</opr> + </def> + <def> + <opc>df /mod=11 /x87=0c</opc> + <opr>ST4</opr> + </def> + <def> + <opc>df /mod=11 /x87=0d</opc> + <opr>ST5</opr> + </def> + <def> + <opc>df /mod=11 /x87=0e</opc> + <opr>ST6</opr> + </def> + <def> + <opc>df /mod=11 /x87=0f</opc> + <opr>ST7</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fxrstor</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>0f ae /mod=11 /reg=1</opc> + <opr>M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fxsave</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>0f ae /mod=11 /reg=0</opc> + <opr>M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>fpxtract</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=34</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fyl2x</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=31</opc> + </def> + </instruction> + + <instruction> + <mnemonic>fyl2xp1</mnemonic> + <class>X87</class> + <def> + <opc>d9 /mod=11 /x87=39</opc> + </def> + </instruction> + + <instruction> + <mnemonic>hlt</mnemonic> + <def> + <opc>f4</opc> + </def> + </instruction> + + <instruction> + <mnemonic>idiv</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>f7 /reg=7</opc> + <opr>Ev</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>f6 /reg=7</opc> + <opr>Eb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>in</mnemonic> + <def> + <opc>e4</opc> + <opr>AL Ib</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>e5</opc> + <opr>eAX Ib</opr> + </def> + <def> + <opc>ec</opc> + <opr>AL DX</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>ed</opc> + <opr>eAX DX</opr> + </def> + </instruction> + + <instruction> + <mnemonic>imul</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f af</opc> + <opr>Gv Ev</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>f6 /reg=5</opc> + <opr>Eb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>f7 /reg=5</opc> + <opr>Ev</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>69</opc> + <opr>Gv Ev Iz</opr> + <syn>sext</syn> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>6b</opc> + <opr>Gv Ev Ib</opr> + <syn>sext</syn> + </def> + </instruction> + + <instruction> + <mnemonic>inc</mnemonic> + <def> + <pfx>oso</pfx> + <opc>40</opc> + <opr>eAX</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>41</opc> + <opr>eCX</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>42</opc> + <opr>eDX</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>43</opc> + <opr>eBX</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>44</opc> + <opr>eSP</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>45</opc> + <opr>eBP</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>46</opc> + <opr>eSI</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>47</opc> + <opr>eDI</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>ff /reg=0</opc> + <opr>Ev</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>fe /reg=0</opc> + <opr>Eb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>insb</mnemonic> + <def> + <opc>6c</opc> + </def> + </instruction> + + <instruction> + <mnemonic>insw</mnemonic> + <def> + <pfx>oso</pfx> + <opc>6d /o=16</opc> + </def> + </instruction> + + <instruction> + <mnemonic>insd</mnemonic> + <def> + <pfx>oso</pfx> + <opc>6d /o=32</opc> + </def> + </instruction> + + <instruction> + <mnemonic>int1</mnemonic> + <def> + <opc>f1</opc> + </def> + </instruction> + + <instruction> + <mnemonic>int3</mnemonic> + <def> + <opc>cc</opc> + </def> + </instruction> + + <instruction> + <mnemonic>int</mnemonic> + <def> + <opc>cd</opc> + <opr>Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>into</mnemonic> + <def> + <opc>ce</opc> + <mode>inv64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>invd</mnemonic> + <def> + <opc>0f 08</opc> + </def> + </instruction> + + <instruction> + <mnemonic>invept</mnemonic> + <vendor>intel</vendor> + <def> + <opc>sse66 0f 38 80 /m=32</opc> + <opr>Gd Mo</opr> + </def> + <def> + <opc>sse66 0f 38 80 /m=64</opc> + <opr>Gq Mo</opr> + </def> + </instruction> + + <instruction> + <mnemonic>invlpg</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 01 /reg=7 /mod=!11</opc> + <opr>M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>invlpga</mnemonic> + <vendor>amd</vendor> + <def> + <opc>0f 01 /reg=3 /mod=11 /rm=7</opc> + </def> + </instruction> + + <instruction> + <mnemonic>invvpid</mnemonic> + <vendor>intel</vendor> + <def> + <opc>sse66 0f 38 81 /m=32</opc> + <opr>Gd Mo</opr> + </def> + <def> + <opc>sse66 0f 38 81 /m=64</opc> + <opr>Gq Mo</opr> + </def> + </instruction> + + <instruction> + <mnemonic>iretw</mnemonic> + <def> + <pfx>oso rexw</pfx> + <opc>cf /o=16</opc> + </def> + </instruction> + + <instruction> + <mnemonic>iretd</mnemonic> + <def> + <pfx>oso rexw</pfx> + <opc>cf /o=32</opc> + </def> + </instruction> + + <instruction> + <mnemonic>iretq</mnemonic> + <def> + <pfx>oso rexw</pfx> + <opc>cf /o=64</opc> + </def> + </instruction> + + <instruction> + <mnemonic>jo</mnemonic> + <def> + <opc>70</opc> + <opr>Jb</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>0f 80</opc> + <opr>Jz</opr> + <mode>def64 depM</mode> + </def> + </instruction> + + <instruction> + <mnemonic>jno</mnemonic> + <def> + <opc>71</opc> + <opr>Jb</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>0f 81</opc> + <opr>Jz</opr> + <mode>def64 depM</mode> + </def> + </instruction> + + <instruction> + <mnemonic>jb</mnemonic> + <def> + <opc>72</opc> + <opr>Jb</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>0f 82</opc> + <opr>Jz</opr> + <mode>def64 depM</mode> + </def> + </instruction> + + <instruction> + <mnemonic>jae</mnemonic> + <def> + <opc>73</opc> + <opr>Jb</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>0f 83</opc> + <opr>Jz</opr> + <mode>def64 depM</mode> + </def> + </instruction> + + <instruction> + <mnemonic>jz</mnemonic> + <def> + <opc>74</opc> + <opr>Jb</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>0f 84</opc> + <opr>Jz</opr> + <mode>def64 depM</mode> + </def> + </instruction> + + <instruction> + <mnemonic>jnz</mnemonic> + <def> + <opc>75</opc> + <opr>Jb</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>0f 85</opc> + <opr>Jz</opr> + <mode>def64 depM</mode> + </def> + </instruction> + + <instruction> + <mnemonic>jbe</mnemonic> + <def> + <opc>76</opc> + <opr>Jb</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>0f 86</opc> + <opr>Jz</opr> + <mode>def64 depM</mode> + </def> + </instruction> + + <instruction> + <mnemonic>ja</mnemonic> + <def> + <opc>77</opc> + <opr>Jb</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>0f 87</opc> + <opr>Jz</opr> + <mode>def64 depM</mode> + </def> + </instruction> + + <instruction> + <mnemonic>js</mnemonic> + <def> + <opc>78</opc> + <opr>Jb</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>0f 88</opc> + <opr>Jz</opr> + <mode>def64 depM</mode> + </def> + </instruction> + + <instruction> + <mnemonic>jns</mnemonic> + <def> + <opc>79</opc> + <opr>Jb</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>0f 89</opc> + <opr>Jz</opr> + <mode>def64 depM</mode> + </def> + </instruction> + + <instruction> + <mnemonic>jp</mnemonic> + <def> + <opc>7a</opc> + <opr>Jb</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>0f 8a</opc> + <opr>Jz</opr> + <mode>def64 depM</mode> + </def> + </instruction> + + <instruction> + <mnemonic>jnp</mnemonic> + <def> + <opc>7b</opc> + <opr>Jb</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>0f 8b</opc> + <opr>Jz</opr> + <mode>def64 depM</mode> + </def> + </instruction> + + <instruction> + <mnemonic>jl</mnemonic> + <def> + <opc>7c</opc> + <opr>Jb</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>0f 8c</opc> + <opr>Jz</opr> + <mode>def64 depM</mode> + </def> + </instruction> + + <instruction> + <mnemonic>jge</mnemonic> + <def> + <opc>7d</opc> + <opr>Jb</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>0f 8d</opc> + <opr>Jz</opr> + <mode>def64 depM</mode> + </def> + </instruction> + + <instruction> + <mnemonic>jle</mnemonic> + <def> + <opc>7e</opc> + <opr>Jb</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>0f 8e</opc> + <opr>Jz</opr> + <mode>def64 depM</mode> + </def> + </instruction> + + <instruction> + <mnemonic>jg</mnemonic> + <def> + <opc>7f</opc> + <opr>Jb</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>0f 8f</opc> + <opr>Jz</opr> + <mode>def64 depM</mode> + </def> + </instruction> + + <instruction> + <mnemonic>jcxz</mnemonic> + <def> + <pfx>aso</pfx> + <opc>e3 /a=16</opc> + <opr>Jb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>jecxz</mnemonic> + <def> + <pfx>aso</pfx> + <opc>e3 /a=32</opc> + <opr>Jb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>jrcxz</mnemonic> + <def> + <pfx>aso</pfx> + <opc>e3 /a=64</opc> + <opr>Jb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>jmp</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>ff /reg=4</opc> + <opr>Ev</opr> + <mode>def64 depM</mode> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>ff /reg=5</opc> + <opr>Ep</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>e9</opc> + <opr>Jz</opr> + <mode>def64 depM</mode> + <syn>cast</syn> + </def> + <def> + <opc>ea</opc> + <opr>Ap</opr> + <mode>inv64</mode> + </def> + <def> + <opc>eb</opc> + <opr>Jb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>lahf</mnemonic> + <def> + <opc>9f</opc> + </def> + </instruction> + + <instruction> + <mnemonic>lar</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f 02</opc> + <opr>Gv Ew</opr> + </def> + </instruction> + + <instruction> + <mnemonic>lddqu</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef2 0f f0</opc> + <opr>V M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>ldmxcsr</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>0f ae /reg=2 /mod=11</opc> + <opr>Md</opr> + </def> + </instruction> + + <instruction> + <mnemonic>lds</mnemonic> + <def> + <pfx>aso oso</pfx> + <opc>c5</opc> + <opr>Gv M</opr> + <mode>inv64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>lea</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>8d</opc> + <opr>Gv M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>les</mnemonic> + <def> + <pfx>aso oso</pfx> + <opc>c4</opc> + <opr>Gv M</opr> + <mode>inv64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>lfs</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f b4</opc> + <opr>Gz M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>lgs</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f b5</opc> + <opr>Gz M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>lidt</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 01 /reg=3 /mod=!11</opc> + <opr>M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>lss</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f b2</opc> + <opr>Gz M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>leave</mnemonic> + <def> + <opc>c9</opc> + </def> + </instruction> + + <instruction> + <mnemonic>lfence</mnemonic> + <def> + <opc>0f ae /reg=5 /mod=11 /rm=0</opc> + </def> + <def> + <opc>0f ae /reg=5 /mod=11 /rm=1</opc> + </def> + <def> + <opc>0f ae /reg=5 /mod=11 /rm=2</opc> + </def> + <def> + <opc>0f ae /reg=5 /mod=11 /rm=3</opc> + </def> + <def> + <opc>0f ae /reg=5 /mod=11 /rm=4</opc> + </def> + <def> + <opc>0f ae /reg=5 /mod=11 /rm=5</opc> + </def> + <def> + <opc>0f ae /reg=5 /mod=11 /rm=6</opc> + </def> + <def> + <opc>0f ae /reg=5 /mod=11 /rm=7</opc> + </def> + </instruction> + + <instruction> + <mnemonic>lgdt</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 01 /reg=2 /mod=!11</opc> + <opr>M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>lldt</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 00 /reg=2</opc> + <opr>Ew</opr> + </def> + </instruction> + + <instruction> + <mnemonic>lmsw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 01 /reg=6 /mod=!11</opc> + <opr>Ew</opr> + </def> + </instruction> + + <instruction> + <mnemonic>lock</mnemonic> + <def> + <opc>f0</opc> + </def> + </instruction> + + <instruction> + <mnemonic>lodsb</mnemonic> + <def> + <pfx>seg</pfx> + <opc>ac</opc> + </def> + </instruction> + + <instruction> + <mnemonic>lodsw</mnemonic> + <def> + <pfx>seg oso rexw</pfx> + <opc>ad /o=16</opc> + </def> + </instruction> + + <instruction> + <mnemonic>lodsd</mnemonic> + <def> + <pfx>seg oso rexw</pfx> + <opc>ad /o=32</opc> + </def> + </instruction> + + <instruction> + <mnemonic>lodsq</mnemonic> + <def> + <pfx>seg oso rexw</pfx> + <opc>ad /o=64</opc> + </def> + </instruction> + + <instruction> + <mnemonic>loopnz</mnemonic> + <def> + <opc>e0</opc> + <opr>Jb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>loope</mnemonic> + <def> + <opc>e1</opc> + <opr>Jb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>loop</mnemonic> + <def> + <opc>e2</opc> + <opr>Jb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>lsl</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f 03</opc> + <opr>Gv Ew</opr> + </def> + </instruction> + + <instruction> + <mnemonic>ltr</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 00 /reg=3</opc> + <opr>Ew</opr> + </def> + </instruction> + + <instruction> + <mnemonic>maskmovq</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f f7</opc> + <opr>P PR</opr> + </def> + </instruction> + + <instruction> + <mnemonic>maxpd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 5f</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>maxps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 5f</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>maxsd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef2 0f 5f</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>maxss</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f 5f</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>mfence</mnemonic> + <def> + <opc>0f ae /reg=6 /mod=11 /rm=0</opc> + </def> + <def> + <opc>0f ae /reg=6 /mod=11 /rm=1</opc> + </def> + <def> + <opc>0f ae /reg=6 /mod=11 /rm=2</opc> + </def> + <def> + <opc>0f ae /reg=6 /mod=11 /rm=3</opc> + </def> + <def> + <opc>0f ae /reg=6 /mod=11 /rm=4</opc> + </def> + <def> + <opc>0f ae /reg=6 /mod=11 /rm=5</opc> + </def> + <def> + <opc>0f ae /reg=6 /mod=11 /rm=6</opc> + </def> + <def> + <opc>0f ae /reg=6 /mod=11 /rm=7</opc> + </def> + </instruction> + + <instruction> + <mnemonic>minpd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 5d</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>minps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 5d</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>minsd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef2 0f 5d</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>minss</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f 5d</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>monitor</mnemonic> + <def> + <opc>0f 01 /reg=1 /mod=11 /rm=0</opc> + </def> + </instruction> + + <instruction> + <mnemonic>montmul</mnemonic> + <def> + <opc>0f a6 /mod=11 /rm=0 /reg=0</opc> + </def> + </instruction> + + <instruction> + <mnemonic>mov</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>c6 /reg=0</opc> + <opr>Eb Ib</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>c7 /reg=0</opc> + <opr>Ev Iz</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>88</opc> + <opr>Eb Gb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>89</opc> + <opr>Ev Gv</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>8a</opc> + <opr>Gb Eb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>8b</opc> + <opr>Gv Ev</opr> + </def> + <def> + <pfx>aso oso rexr rexx rexb</pfx> + <opc>8c</opc> + <opr>Ev S</opr> + </def> + <def> + <pfx>aso oso rexr rexx rexb</pfx> + <opc>8e</opc> + <opr>S Ev</opr> + </def> + <def> + <opc>a0</opc> + <opr>AL Ob</opr> + </def> + <def> + <pfx>aso oso rexw</pfx> + <opc>a1</opc> + <opr>rAX Ov</opr> + </def> + <def> + <opc>a2</opc> + <opr>Ob AL</opr> + </def> + <def> + <pfx>aso oso rexw</pfx> + <opc>a3</opc> + <opr>Ov rAX</opr> + </def> + <def> + <pfx>rexb</pfx> + <opc>b0</opc> + <opr>ALr8b Ib</opr> + </def> + <def> + <pfx>rexb</pfx> + <opc>b1</opc> + <opr>CLr9b Ib</opr> + </def> + <def> + <pfx>rexb</pfx> + <opc>b2</opc> + <opr>DLr10b Ib</opr> + </def> + <def> + <pfx>rexb</pfx> + <opc>b3</opc> + <opr>BLr11b Ib</opr> + </def> + <def> + <pfx>rexb</pfx> + <opc>b4</opc> + <opr>AHr12b Ib</opr> + </def> + <def> + <pfx>rexb</pfx> + <opc>b5</opc> + <opr>CHr13b Ib</opr> + </def> + <def> + <pfx>rexb</pfx> + <opc>b6</opc> + <opr>DHr14b Ib</opr> + </def> + <def> + <pfx>rexb</pfx> + <opc>b7</opc> + <opr>BHr15b Ib</opr> + </def> + <def> + <pfx>oso rexw rexb</pfx> + <opc>b8</opc> + <opr>rAXr8 Iv</opr> + </def> + <def> + <pfx>oso rexw rexb</pfx> + <opc>b9</opc> + <opr>rCXr9 Iv</opr> + </def> + <def> + <pfx>oso rexw rexb</pfx> + <opc>ba</opc> + <opr>rDXr10 Iv</opr> + </def> + <def> + <pfx>oso rexw rexb</pfx> + <opc>bb</opc> + <opr>rBXr11 Iv</opr> + </def> + <def> + <pfx>oso rexw rexb</pfx> + <opc>bc</opc> + <opr>rSPr12 Iv</opr> + </def> + <def> + <pfx>oso rexw rexb</pfx> + <opc>bd</opc> + <opr>rBPr13 Iv</opr> + </def> + <def> + <pfx>oso rexw rexb</pfx> + <opc>be</opc> + <opr>rSIr14 Iv</opr> + </def> + <def> + <pfx>oso rexw rexb</pfx> + <opc>bf</opc> + <opr>rDIr15 Iv</opr> + </def> + <def> + <pfx>rexr</pfx> + <opc>0f 20</opc> + <opr>R C</opr> + </def> + <def> + <pfx>rexr</pfx> + <opc>0f 21</opc> + <opr>R D</opr> + </def> + <def> + <pfx>rexr</pfx> + <opc>0f 22</opc> + <opr>C R</opr> + </def> + <def> + <pfx>rexr</pfx> + <opc>0f 23</opc> + <opr>D R</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movapd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 28</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 29</opc> + <opr>W V</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movaps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 28</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 29</opc> + <opr>W V</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movd</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>sse66 0f 6e</opc> + <opr>V Ex</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 6e</opc> + <opr>P Ex</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>sse66 0f 7e</opc> + <opr>Ex V</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 7e</opc> + <opr>Ex P</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movhpd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 16 /mod=!11</opc> + <opr>V M</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 17</opc> + <opr>M V</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movhps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 16 /mod=!11</opc> + <opr>V M</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 17</opc> + <opr>M V</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movlhps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 16 /mod=11</opc> + <opr>V VR</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movlpd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 12 /mod=!11</opc> + <opr>V M</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 13</opc> + <opr>M V</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movlps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 12 /mod=!11</opc> + <opr>V M</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 13</opc> + <opr>M V</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movhlps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 12 /mod=11</opc> + <opr>V VR</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movmskpd</mnemonic> + <def> + <pfx>oso rexr rexb</pfx> + <opc>sse66 0f 50</opc> + <opr>Gd VR</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movmskps</mnemonic> + <def> + <pfx>oso rexr rexb</pfx> + <opc>0f 50</opc> + <opr>Gd VR</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movntdq</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f e7</opc> + <opr>M V</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movnti</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>0f c3</opc> + <opr>M Gy</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movntpd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 2b</opc> + <opr>M V</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movntps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 2b</opc> + <opr>M V</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movntq</mnemonic> + <def> + <opc>0f e7</opc> + <opr>M P</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movq</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 6f</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f d6</opc> + <opr>W V</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f 7e</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 7f</opc> + <opr>Q P</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movsb</mnemonic> + <def> + <pfx>seg</pfx> + <opc>a4</opc> + </def> + </instruction> + + <instruction> + <mnemonic>movsw</mnemonic> + <def> + <pfx>seg oso rexw</pfx> + <opc>a5 /o=16</opc> + </def> + </instruction> + + <instruction> + <mnemonic>movsd</mnemonic> + <def> + <pfx>seg oso rexw</pfx> + <opc>a5 /o=32</opc> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef2 0f 10</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef2 0f 11</opc> + <opr>W V</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movsq</mnemonic> + <def> + <pfx>seg oso rexw</pfx> + <opc>a5 /o=64</opc> + </def> + </instruction> + + <instruction> + <mnemonic>movss</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f 10</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f 11</opc> + <opr>W V</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movsx</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f be</opc> + <opr>Gv Eb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f bf</opc> + <opr>Gv Ew</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movupd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 10</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 11</opc> + <opr>W V</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movups</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 10</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 11</opc> + <opr>W V</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movzx</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f b6</opc> + <opr>Gv Eb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f b7</opc> + <opr>Gv Ew</opr> + </def> + </instruction> + + <instruction> + <mnemonic>mul</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>f6 /reg=4</opc> + <opr>Eb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>f7 /reg=4</opc> + <opr>Ev</opr> + </def> + </instruction> + + <instruction> + <mnemonic>mulpd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 59</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>mulps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 59</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>mulsd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef2 0f 59</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>mulss</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f 59</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>mwait</mnemonic> + <def> + <opc>0f 01 /reg=1 /mod=11 /rm=1</opc> + </def> + </instruction> + + <instruction> + <mnemonic>neg</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>f6 /reg=3</opc> + <opr>Eb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>f7 /reg=3</opc> + <opr>Ev</opr> + </def> + </instruction> + + <instruction> + <mnemonic>nop</mnemonic> + <def> + <opc>90</opc> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 19</opc> + <opr>M</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 1a</opc> + <opr>M</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 1b</opc> + <opr>M</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 1c</opc> + <opr>M</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 1d</opc> + <opr>M</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 1e</opc> + <opr>M</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 1f</opc> + <opr>M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>not</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>f6 /reg=2</opc> + <opr>Eb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>f7 /reg=2</opc> + <opr>Ev</opr> + </def> + </instruction> + + <instruction> + <mnemonic>or</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>08</opc> + <opr>Eb Gb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>09</opc> + <opr>Ev Gv</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0a</opc> + <opr>Gb Eb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0b</opc> + <opr>Gv Ev</opr> + </def> + <def> + <opc>0c</opc> + <opr>AL Ib</opr> + </def> + <def> + <pfx>oso rexw</pfx> + <opc>0d</opc> + <opr>rAX Iz</opr> + <syn>sext</syn> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>80 /reg=1</opc> + <opr>Eb Ib</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>81 /reg=1</opc> + <opr>Ev Iz</opr> + <syn>sext</syn> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>82 /reg=1</opc> + <opr>Eb Ib</opr> + <mode>inv64</mode> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>83 /reg=1</opc> + <opr>Ev Ib</opr> + <syn>sext</syn> + </def> + </instruction> + + <instruction> + <mnemonic>orpd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 56</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>orps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 56</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>out</mnemonic> + <def> + <opc>e6</opc> + <opr>Ib AL</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>e7</opc> + <opr>Ib eAX</opr> + </def> + <def> + <opc>ee</opc> + <opr>DX AL</opr> + </def> + <def> + <pfx>oso</pfx> + <opc>ef</opc> + <opr>DX eAX</opr> + </def> + </instruction> + + <instruction> + <mnemonic>outsb</mnemonic> + <def> + <opc>6e</opc> + </def> + </instruction> + + <instruction> + <mnemonic>outsw</mnemonic> + <def> + <pfx>oso</pfx> + <opc>6f /o=16</opc> + </def> + </instruction> + + <instruction> + <mnemonic>outsd</mnemonic> + <def> + <pfx>oso</pfx> + <opc>6f /o=32</opc> + </def> + </instruction> + + <instruction> + <mnemonic>outsq</mnemonic> + <def> + <pfx>oso</pfx> + <opc>6f /o=64</opc> + </def> + </instruction> + + <instruction> + <mnemonic>packsswb</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 63</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 63</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>packssdw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 6b</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 6b</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>packuswb</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 67</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 67</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>paddb</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f fc</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f fc</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>paddw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f fd</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f fd</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>paddd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f fe</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f fe</opc> + <opr>V W</opr> + </def> + </instruction> + + + <instruction> + <mnemonic>paddsb</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f ec</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f ec</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>paddsw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f ed</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f ed</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>paddusb</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f dc</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f dc</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>paddusw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f dd</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f dd</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pand</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f db</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f db</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pandn</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f df</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f df</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pavgb</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f e0</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f e0</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pavgw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f e3</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f e3</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pcmpeqb</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 74</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 74</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pcmpeqw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 75</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 75</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pcmpeqd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 76</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 76</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pcmpgtb</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 64</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 64</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pcmpgtw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 65</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 65</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pcmpgtd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 66</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 66</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pextrb</mnemonic> + <def> + <pfx>aso rexr rexb</pfx> + <opc>sse66 0f 3a 14</opc> + <opr>MbRv V Ib</opr> + <mode>def64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>pextrd</mnemonic> + <def> + <pfx>aso rexr rexw rexb</pfx> + <opc>sse66 0f 3a 16 /o=16</opc> + <opr>Ev V Ib</opr> + </def> + <def> + <pfx>aso rexr rexw rexb</pfx> + <opc>sse66 0f 3a 16 /o=32</opc> + <opr>Ev V Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pextrq</mnemonic> + <def> + <pfx>aso rexr rexw rexb</pfx> + <opc>sse66 0f 3a 16 /o=64</opc> + <opr>Ev V Ib</opr> + <mode>def64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>pextrw</mnemonic> + <def> + <pfx>aso rexr rexb</pfx> + <opc>sse66 0f c5</opc> + <opr>Gd VR Ib</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f c5</opc> + <opr>Gd PR Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pinsrw</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f c4</opc> + <opr>P Ew Ib</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>sse66 0f c4</opc> + <opr>V Ew Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pmaddwd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f f5</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f f5</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pmaxsw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f ee</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f ee</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pmaxub</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f de</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f de</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pminsw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f ea</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f ea</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pminub</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f da</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f da</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pmovmskb</mnemonic> + <def> + <pfx>rexr rexb</pfx> + <opc>sse66 0f d7</opc> + <opr>Gd VR</opr> + </def> + <def> + <pfx>oso rexr rexb</pfx> + <opc>0f d7</opc> + <opr>Gd PR</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pmulhuw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f e4</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f e4</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pmulhw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f e5</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f e5</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pmullw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f d5</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f d5</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pop</mnemonic> + <def> + <opc>07</opc> + <opr>ES</opr> + <mode>inv64</mode> + </def> + <def> + <opc>17</opc> + <opr>SS</opr> + <mode>inv64</mode> + </def> + <def> + <opc>1f</opc> + <opr>DS</opr> + <mode>inv64</mode> + </def> + <def> + <opc>0f a9</opc> + <opr>GS</opr> + </def> + <def> + <opc>0f a1</opc> + <opr>FS</opr> + </def> + <def> + <pfx>oso rexb</pfx> + <opc>58</opc> + <opr>rAXr8</opr> + <mode>def64 depM</mode> + </def> + <def> + <pfx>oso rexb</pfx> + <opc>59</opc> + <opr>rCXr9</opr> + <mode>def64 depM</mode> + </def> + <def> + <pfx>oso rexb</pfx> + <opc>5a</opc> + <opr>rDXr10</opr> + <mode>def64 depM</mode> + </def> + <def> + <pfx>oso rexb</pfx> + <opc>5b</opc> + <opr>rBXr11</opr> + <mode>def64 depM</mode> + </def> + <def> + <pfx>oso rexb</pfx> + <opc>5c</opc> + <opr>rSPr12</opr> + <mode>def64 depM</mode> + </def> + <def> + <pfx>oso rexb</pfx> + <opc>5d</opc> + <opr>rBPr13</opr> + <mode>def64 depM</mode> + </def> + <def> + <pfx>oso rexb</pfx> + <opc>5e</opc> + <opr>rSIr14</opr> + <mode>def64 depM</mode> + </def> + <def> + <pfx>oso rexb</pfx> + <opc>5f</opc> + <opr>rDIr15</opr> + <mode>def64 depM</mode> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>8f /reg=0</opc> + <opr>Ev</opr> + <mode>def64 depM</mode> + </def> + </instruction> + + <instruction> + <mnemonic>popa</mnemonic> + <def> + <pfx>oso</pfx> + <opc>61 /o=16</opc> + <mode>inv64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>popad</mnemonic> + <def> + <pfx>oso</pfx> + <opc>61 /o=32</opc> + <mode>inv64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>popfw</mnemonic> + <def> + <pfx>oso</pfx> + <opc>9d /m=32 /o=16</opc> + <mode>def64 depM</mode> + </def> + <def> + <pfx>oso</pfx> + <opc>9d /m=16 /o=16</opc> + <mode>def64 depM</mode> + </def> + </instruction> + + <instruction> + <mnemonic>popfd</mnemonic> + <def> + <pfx>oso</pfx> + <opc>9d /m=16 /o=32</opc> + <mode>def64 depM</mode> + </def> + <def> + <pfx>oso</pfx> + <opc>9d /m=32 /o=32</opc> + <mode>def64 depM</mode> + </def> + </instruction> + + <instruction> + <mnemonic>popfq</mnemonic> + <def> + <pfx>oso</pfx> + <opc>9d /m=64 /o=64</opc> + <mode>def64 depM</mode> + </def> + </instruction> + + <instruction> + <mnemonic>por</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f eb</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f eb</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>prefetch</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>0f 0d /reg=0</opc> + <opr>M</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>0f 0d /reg=1</opc> + <opr>M</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>0f 0d /reg=2</opc> + <opr>M</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>0f 0d /reg=3</opc> + <opr>M</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>0f 0d /reg=4</opc> + <opr>M</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>0f 0d /reg=5</opc> + <opr>M</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>0f 0d /reg=6</opc> + <opr>M</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>0f 0d /reg=7</opc> + <opr>M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>prefetchnta</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>0f 18 /reg=0</opc> + <opr>M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>prefetcht0</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>0f 18 /reg=1</opc> + <opr>M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>prefetcht1</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>0f 18 /reg=2</opc> + <opr>M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>prefetcht2</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>0f 18 /reg=3</opc> + <opr>M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>psadbw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f f6</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f f6</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pshufw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 70</opc> + <opr>P Q Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>psllw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f f1</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f f1</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>rexb</pfx> + <opc>sse66 0f 71 /reg=6</opc> + <opr>VR Ib</opr> + </def> + <def> + <opc>0f 71 /reg=6</opc> + <opr>PR Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pslld</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f f2</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f f2</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>rexb</pfx> + <opc>sse66 0f 72 /reg=6</opc> + <opr>VR Ib</opr> + </def> + <def> + <opc>0f 72 /reg=6</opc> + <opr>PR Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>psllq</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f f3</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f f3</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>rexb</pfx> + <opc>sse66 0f 73 /reg=6</opc> + <opr>VR Ib</opr> + </def> + <def> + <opc>0f 73 /reg=6</opc> + <opr>PR Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>psraw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f e1</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f e1</opc> + <opr>V W</opr> + </def> + <def> + <pfx>rexb</pfx> + <opc>sse66 0f 71 /reg=4</opc> + <opr>VR Ib</opr> + </def> + <def> + <opc>0f 71 /reg=4</opc> + <opr>PR Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>psrad</mnemonic> + <def> + <opc>0f 72 /reg=4</opc> + <opr>PR Ib</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f e2</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f e2</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>rexb</pfx> + <opc>sse66 0f 72 /reg=4</opc> + <opr>VR Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>psrlw</mnemonic> + <def> + <opc>0f 71 /reg=2</opc> + <opr>PR Ib</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f d1</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f d1</opc> + <opr>V W</opr> + </def> + <def> + <pfx>rexb</pfx> + <opc>sse66 0f 71 /reg=2</opc> + <opr>VR Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>psrld</mnemonic> + <def> + <opc>0f 72 /reg=2</opc> + <opr>PR Ib</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f d2</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f d2</opc> + <opr>V W</opr> + </def> + <def> + <pfx>rexb</pfx> + <opc>sse66 0f 72 /reg=2</opc> + <opr>VR Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>psrlq</mnemonic> + <def> + <opc>0f 73 /reg=2</opc> + <opr>PR Ib</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f d3</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f d3</opc> + <opr>V W</opr> + </def> + <def> + <pfx>rexb</pfx> + <opc>sse66 0f 73 /reg=2</opc> + <opr>VR Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>psubb</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f f8</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f f8</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>psubw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f f9</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f f9</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>psubd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f fa</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f fa</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>psubsb</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f e8</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f e8</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>psubsw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f e9</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f e9</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>psubusb</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f d8</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f d8</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>psubusw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f d9</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f d9</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>punpckhbw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 68</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 68</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>punpckhwd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 69</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 69</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>punpckhdq</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 6a</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 6a</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>punpcklbw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 60</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 60</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>punpcklwd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 61</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 61</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>punpckldq</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 62</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 62</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pi2fw</mnemonic> + <def> + <opc>0f 0f /3dnow=0c</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pi2fd</mnemonic> + <def> + <opc>0f 0f /3dnow=0d</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pf2iw</mnemonic> + <def> + <opc>0f 0f /3dnow=1c</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pf2id</mnemonic> + <def> + <opc>0f 0f /3dnow=1d</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pfnacc</mnemonic> + <def> + <opc>0f 0f /3dnow=8a</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pfpnacc</mnemonic> + <def> + <opc>0f 0f /3dnow=8e</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pfcmpge</mnemonic> + <def> + <opc>0f 0f /3dnow=90</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pfmin</mnemonic> + <def> + <opc>0f 0f /3dnow=94</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pfrcp</mnemonic> + <def> + <opc>0f 0f /3dnow=96</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pfrsqrt</mnemonic> + <def> + <opc>0f 0f /3dnow=97</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pfsub</mnemonic> + <def> + <opc>0f 0f /3dnow=9a</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pfadd</mnemonic> + <def> + <opc>0f 0f /3dnow=9e</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pfcmpgt</mnemonic> + <def> + <opc>0f 0f /3dnow=a0</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pfmax</mnemonic> + <def> + <opc>0f 0f /3dnow=a4</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pfrcpit1</mnemonic> + <def> + <opc>0f 0f /3dnow=a6</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pfrsqit1</mnemonic> + <def> + <opc>0f 0f /3dnow=a7</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pfsubr</mnemonic> + <def> + <opc>0f 0f /3dnow=aa</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pfacc</mnemonic> + <def> + <opc>0f 0f /3dnow=ae</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pfcmpeq</mnemonic> + <def> + <opc>0f 0f /3dnow=b0</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pfmul</mnemonic> + <def> + <opc>0f 0f /3dnow=b4</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pfrcpit2</mnemonic> + <def> + <opc>0f 0f /3dnow=b6</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pmulhrw</mnemonic> + <def> + <opc>0f 0f /3dnow=b7</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pswapd</mnemonic> + <def> + <opc>0f 0f /3dnow=bb</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pavgusb</mnemonic> + <def> + <opc>0f 0f /3dnow=bf</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>push</mnemonic> + <def> + <opc>06</opc> + <opr>ES</opr> + <mode>inv64</mode> + </def> + <def> + <opc>0e</opc> + <opr>CS</opr> + <mode>inv64</mode> + </def> + <def> + <opc>16</opc> + <opr>SS</opr> + <mode>inv64</mode> + </def> + <def> + <opc>1e</opc> + <opr>DS</opr> + <mode>inv64</mode> + </def> + <def> + <opc>0f a8</opc> + <opr>GS</opr> + </def> + <def> + <opc>0f a0</opc> + <opr>FS</opr> + </def> + <def> + <pfx>oso rexb</pfx> + <opc>50</opc> + <opr>rAXr8</opr> + <mode>def64 depM</mode> + </def> + <def> + <pfx>oso rexb</pfx> + <opc>51</opc> + <opr>rCXr9</opr> + <mode>def64 depM</mode> + </def> + <def> + <pfx>oso rexb</pfx> + <opc>52</opc> + <opr>rDXr10</opr> + <mode>def64 depM</mode> + </def> + <def> + <pfx>oso rexb</pfx> + <opc>53</opc> + <opr>rBXr11</opr> + <mode>def64 depM</mode> + </def> + <def> + <pfx>oso rexb</pfx> + <opc>54</opc> + <opr>rSPr12</opr> + <mode>def64 depM</mode> + </def> + <def> + <pfx>oso rexb</pfx> + <opc>55</opc> + <opr>rBPr13</opr> + <mode>def64 depM</mode> + </def> + <def> + <pfx>oso rexb</pfx> + <opc>56</opc> + <opr>rSIr14</opr> + <mode>def64 depM</mode> + </def> + <def> + <pfx>oso rexb</pfx> + <opc>57</opc> + <opr>rDIr15</opr> + <mode>def64 depM</mode> + </def> + <def> + <pfx>oso</pfx> + <opc>68</opc> + <opr>Iz</opr> + <syn>cast</syn> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>ff /reg=6</opc> + <opr>Ev</opr> + <mode>def64</mode> + </def> + <def> + <opc>6a</opc> + <opr>Ib</opr> + <syn>sext</syn> + </def> + </instruction> + + <instruction> + <mnemonic>pusha</mnemonic> + <def> + <pfx>oso</pfx> + <opc>60 /o=16</opc> + <mode>inv64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>pushad</mnemonic> + <def> + <pfx>oso</pfx> + <opc>60 /o=32</opc> + <mode>inv64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>pushfw</mnemonic> + <def> + <pfx>oso</pfx> + <opc>9c /m=32 /o=16</opc> + <mode>def64</mode> + </def> + <def> + <pfx>oso</pfx> + <opc>9c /m=16 /o=16</opc> + <mode>def64</mode> + </def> + <def> + <pfx>oso rexw</pfx> + <opc>9c /m=64 /o=16</opc> + <mode>def64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>pushfd</mnemonic> + <def> + <pfx>oso</pfx> + <opc>9c /m=16 /o=32</opc> + <mode>def64</mode> + </def> + <def> + <pfx>oso</pfx> + <opc>9c /m=32 /o=32</opc> + <mode>def64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>pushfq</mnemonic> + <def> + <pfx>oso rexw</pfx> + <opc>9c /m=64 /o=32</opc> + <mode>def64</mode> + </def> + <def> + <pfx>oso rexw</pfx> + <opc>9c /m=64 /o=64</opc> + <mode>def64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>pxor</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f ef</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f ef</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>rcl</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>c0 /reg=2</opc> + <opr>Eb Ib</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>c1 /reg=2</opc> + <opr>Ev Ib</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>d0 /reg=2</opc> + <opr>Eb I1</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>d2 /reg=2</opc> + <opr>Eb CL</opr> + <syn>cast</syn> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>d3 /reg=2</opc> + <opr>Ev CL</opr> + <syn>cast</syn> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>d1 /reg=2</opc> + <opr>Ev I1</opr> + </def> + </instruction> + + <instruction> + <mnemonic>rcr</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>d0 /reg=3</opc> + <opr>Eb I1</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>c1 /reg=3</opc> + <opr>Ev Ib</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>c0 /reg=3</opc> + <opr>Eb Ib</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>d1 /reg=3</opc> + <opr>Ev I1</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>d2 /reg=3</opc> + <opr>Eb CL</opr> + <syn>cast</syn> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>d3 /reg=3</opc> + <opr>Ev CL</opr> + <syn>cast</syn> + </def> + </instruction> + + <instruction> + <mnemonic>rol</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>c0 /reg=0</opc> + <opr>Eb Ib</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>d0 /reg=0</opc> + <opr>Eb I1</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>d1 /reg=0</opc> + <opr>Ev I1</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>d2 /reg=0</opc> + <opr>Eb CL</opr> + <syn>cast</syn> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>d3 /reg=0</opc> + <opr>Ev CL</opr> + <syn>cast</syn> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>c1 /reg=0</opc> + <opr>Ev Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>ror</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>d0 /reg=1</opc> + <opr>Eb I1</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>c0 /reg=1</opc> + <opr>Eb Ib</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>c1 /reg=1</opc> + <opr>Ev Ib</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>d1 /reg=1</opc> + <opr>Ev I1</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>d2 /reg=1</opc> + <opr>Eb CL</opr> + <syn>cast</syn> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>d3 /reg=1</opc> + <opr>Ev CL</opr> + <syn>cast</syn> + </def> + </instruction> + + <instruction> + <mnemonic>rcpps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 53</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>rcpss</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f 53</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>rdmsr</mnemonic> + <def> + <opc>0f 32</opc> + </def> + </instruction> + + <instruction> + <mnemonic>rdpmc</mnemonic> + <def> + <opc>0f 33</opc> + </def> + </instruction> + + <instruction> + <mnemonic>rdtsc</mnemonic> + <def> + <opc>0f 31</opc> + </def> + </instruction> + + <instruction> + <mnemonic>rdtscp</mnemonic> + <vendor>amd</vendor> + <def> + <opc>0f 01 /reg=7 /mod=11 /rm=1</opc> + </def> + </instruction> + + <instruction> + <mnemonic>repne</mnemonic> + <def> + <opc>f2</opc> + </def> + </instruction> + + <instruction> + <mnemonic>rep</mnemonic> + <def> + <opc>f3</opc> + </def> + </instruction> + + <instruction> + <mnemonic>ret</mnemonic> + <def> + <opc>c2</opc> + <opr>Iw</opr> + </def> + <def> + <opc>c3</opc> + </def> + </instruction> + + <instruction> + <mnemonic>retf</mnemonic> + <def> + <opc>ca</opc> + <opr>Iw</opr> + </def> + <def> + <opc>cb</opc> + </def> + </instruction> + + <instruction> + <mnemonic>rsm</mnemonic> + <def> + <opc>0f aa</opc> + </def> + </instruction> + + <instruction> + <mnemonic>rsqrtps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 52</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>rsqrtss</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f 52</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>sahf</mnemonic> + <def> + <opc>9e</opc> + </def> + </instruction> + + <instruction> + <mnemonic>sal</mnemonic> + </instruction> + + <instruction> + <mnemonic>salc</mnemonic> + <def> + <opc>d6</opc> + <mode>inv64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>sar</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>d1 /reg=7</opc> + <opr>Ev I1</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>c0 /reg=7</opc> + <opr>Eb Ib</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>d0 /reg=7</opc> + <opr>Eb I1</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>c1 /reg=7</opc> + <opr>Ev Ib</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>d2 /reg=7</opc> + <opr>Eb CL</opr> + <syn>cast</syn> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>d3 /reg=7</opc> + <opr>Ev CL</opr> + <syn>cast</syn> + </def> + </instruction> + + <instruction> + <mnemonic>shl</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>c0 /reg=6</opc> + <opr>Eb Ib</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>c1 /reg=6</opc> + <opr>Ev Ib</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>d0 /reg=6</opc> + <opr>Eb I1</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>d2 /reg=6</opc> + <opr>Eb CL</opr> + <syn>cast</syn> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>d3 /reg=6</opc> + <opr>Ev CL</opr> + <syn>cast</syn> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>c1 /reg=4</opc> + <opr>Ev Ib</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>d2 /reg=4</opc> + <opr>Eb CL</opr> + <syn>cast</syn> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>d1 /reg=4</opc> + <opr>Ev I1</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>d0 /reg=4</opc> + <opr>Eb I1</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>c0 /reg=4</opc> + <opr>Eb Ib</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>d3 /reg=4</opc> + <opr>Ev CL</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>d1 /reg=6</opc> + <opr>Ev I1</opr> + </def> + </instruction> + + <instruction> + <mnemonic>shr</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>c1 /reg=5</opc> + <opr>Ev Ib</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>d2 /reg=5</opc> + <opr>Eb CL</opr> + <syn>cast</syn> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>d1 /reg=5</opc> + <opr>Ev I1</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>d0 /reg=5</opc> + <opr>Eb I1</opr> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>c0 /reg=5</opc> + <opr>Eb Ib</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>d3 /reg=5</opc> + <opr>Ev CL</opr> + <syn>cast</syn> + </def> + </instruction> + + <instruction> + <mnemonic>sbb</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>18</opc> + <opr>Eb Gb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>19</opc> + <opr>Ev Gv</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>1a</opc> + <opr>Gb Eb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>1b</opc> + <opr>Gv Ev</opr> + </def> + <def> + <opc>1c</opc> + <opr>AL Ib</opr> + </def> + <def> + <pfx>oso rexw</pfx> + <opc>1d</opc> + <opr>rAX Iz</opr> + <syn>sext</syn> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>80 /reg=3</opc> + <opr>Eb Ib</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>81 /reg=3</opc> + <opr>Ev Iz</opr> + <syn>sext</syn> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>82 /reg=3</opc> + <opr>Eb Ib</opr> + <mode>inv64</mode> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>83 /reg=3</opc> + <opr>Ev Ib</opr> + <syn>sext</syn> + </def> + </instruction> + + <instruction> + <mnemonic>scasb</mnemonic> + <def> + <opc>ae</opc> + </def> + </instruction> + + <instruction> + <mnemonic>scasw</mnemonic> + <def> + <pfx>oso rexw</pfx> + <opc>af /o=16</opc> + </def> + </instruction> + + <instruction> + <mnemonic>scasd</mnemonic> + <def> + <pfx>oso rexw</pfx> + <opc>af /o=32</opc> + </def> + </instruction> + + <instruction> + <mnemonic>scasq</mnemonic> + <def> + <pfx>oso rexw</pfx> + <opc>af /o=64</opc> + </def> + </instruction> + + <instruction> + <mnemonic>seto</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 90</opc> + <opr>Eb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>setno</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 91</opc> + <opr>Eb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>setb</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 92</opc> + <opr>Eb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>setnb</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 93</opc> + <opr>Eb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>setz</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 94</opc> + <opr>Eb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>setnz</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 95</opc> + <opr>Eb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>setbe</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 96</opc> + <opr>Eb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>seta</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 97</opc> + <opr>Eb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>sets</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 98</opc> + <opr>Eb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>setns</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 99</opc> + <opr>Eb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>setp</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 9a</opc> + <opr>Eb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>setnp</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 9b</opc> + <opr>Eb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>setl</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 9c</opc> + <opr>Eb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>setge</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 9d</opc> + <opr>Eb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>setle</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 9e</opc> + <opr>Eb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>setg</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 9f</opc> + <opr>Eb</opr> + </def> + </instruction> + + <instruction> + <mnemonic>sfence</mnemonic> + <def> + <opc>0f ae /reg=7 /mod=11 /rm=0</opc> + </def> + <def> + <opc>0f ae /reg=7 /mod=11 /rm=1</opc> + </def> + <def> + <opc>0f ae /reg=7 /mod=11 /rm=2</opc> + </def> + <def> + <opc>0f ae /reg=7 /mod=11 /rm=3</opc> + </def> + <def> + <opc>0f ae /reg=7 /mod=11 /rm=4</opc> + </def> + <def> + <opc>0f ae /reg=7 /mod=11 /rm=5</opc> + </def> + <def> + <opc>0f ae /reg=7 /mod=11 /rm=6</opc> + </def> + <def> + <opc>0f ae /reg=7 /mod=11 /rm=7</opc> + </def> + </instruction> + + <instruction> + <mnemonic>sgdt</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 01 /reg=0 /mod=!11</opc> + <opr>M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>shld</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f a4</opc> + <opr>Ev Gv Ib</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f a5</opc> + <opr>Ev Gv CL</opr> + </def> + </instruction> + + <instruction> + <mnemonic>shrd</mnemonic> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f ac</opc> + <opr>Ev Gv Ib</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f ad</opc> + <opr>Ev Gv CL</opr> + </def> + </instruction> + + <instruction> + <mnemonic>shufpd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f c6</opc> + <opr>V W Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>shufps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f c6</opc> + <opr>V W Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>sidt</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 01 /reg=1 /mod=!11</opc> + <opr>M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>sldt</mnemonic> + <def> + <pfx>aso oso rexr rexx rexb</pfx> + <opc>0f 00 /reg=0</opc> + <opr>MwRv</opr> + </def> + </instruction> + + <instruction> + <mnemonic>smsw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 01 /reg=4 /mod=!11</opc> + <opr>M</opr> + </def> + </instruction> + + <instruction> + <mnemonic>sqrtps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 51</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>sqrtpd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 51</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>sqrtsd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef2 0f 51</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>sqrtss</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f 51</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>stc</mnemonic> + <def> + <opc>f9</opc> + </def> + </instruction> + + <instruction> + <mnemonic>std</mnemonic> + <def> + <opc>fd</opc> + </def> + </instruction> + + <instruction> + <mnemonic>stgi</mnemonic> + <vendor>amd</vendor> + <def> + <opc>0f 01 /reg=3 /mod=11 /rm=4</opc> + </def> + </instruction> + + <instruction> + <mnemonic>sti</mnemonic> + <def> + <opc>fb</opc> + </def> + </instruction> + + <instruction> + <mnemonic>skinit</mnemonic> + <vendor>amd</vendor> + <def> + <opc>0f 01 /reg=3 /mod=11 /rm=6</opc> + </def> + </instruction> + + <instruction> + <mnemonic>stmxcsr</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>0f ae /mod=11 /reg=3</opc> + <opr>Md</opr> + </def> + </instruction> + + <instruction> + <mnemonic>stosb</mnemonic> + <def> + <pfx>seg</pfx> + <opc>aa</opc> + </def> + </instruction> + + <instruction> + <mnemonic>stosw</mnemonic> + <def> + <pfx>seg oso rexw</pfx> + <opc>ab /o=16</opc> + </def> + </instruction> + + <instruction> + <mnemonic>stosd</mnemonic> + <def> + <pfx>seg oso rexw</pfx> + <opc>ab /o=32</opc> + </def> + </instruction> + + <instruction> + <mnemonic>stosq</mnemonic> + <def> + <pfx>seg oso rexw</pfx> + <opc>ab /o=64</opc> + </def> + </instruction> + + <instruction> + <mnemonic>str</mnemonic> + <def> + <pfx>aso oso rexr rexx rexb</pfx> + <opc>0f 00 /reg=1</opc> + <opr>Ev</opr> + </def> + </instruction> + + <instruction> + <mnemonic>sub</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>28</opc> + <opr>Eb Gb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>29</opc> + <opr>Ev Gv</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>2a</opc> + <opr>Gb Eb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>2b</opc> + <opr>Gv Ev</opr> + </def> + <def> + <opc>2c</opc> + <opr>AL Ib</opr> + </def> + <def> + <pfx>oso rexw</pfx> + <opc>2d</opc> + <opr>rAX Iz</opr> + <syn>sext</syn> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>80 /reg=5</opc> + <opr>Eb Ib</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>81 /reg=5</opc> + <opr>Ev Iz</opr> + <syn>sext</syn> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>82 /reg=5</opc> + <opr>Eb Ib</opr> + <mode>inv64</mode> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>83 /reg=5</opc> + <opr>Ev Ib</opr> + <syn>sext</syn> + </def> + </instruction> + + <instruction> + <mnemonic>subpd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 5c</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>subps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 5c</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>subsd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef2 0f 5c</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>subss</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f 5c</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>swapgs</mnemonic> + <def> + <opc>0f 01 /reg=7 /mod=11 /rm=0</opc> + </def> + </instruction> + + <instruction> + <mnemonic>syscall</mnemonic> + <def> + <opc>0f 05</opc> + </def> + </instruction> + + <instruction> + <mnemonic>sysenter</mnemonic> + <def> + <opc>0f 34</opc> + <mode>inv64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>sysexit</mnemonic> + <def> + <opc>0f 35</opc> + </def> + </instruction> + + <instruction> + <mnemonic>sysret</mnemonic> + <def> + <opc>0f 07</opc> + </def> + </instruction> + + <instruction> + <mnemonic>test</mnemonic> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>f6 /reg=0</opc> + <opr>Eb Ib</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>84</opc> + <opr>Eb Gb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>85</opc> + <opr>Ev Gv</opr> + </def> + <def> + <opc>a8</opc> + <opr>AL Ib</opr> + </def> + <def> + <pfx>oso rexw</pfx> + <opc>a9</opc> + <opr>rAX Iz</opr> + <syn>sext</syn> + </def> + <def> + <pfx>aso rexw rexr rexx rexb</pfx> + <opc>f6 /reg=1</opc> + <opr>Eb Ib</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>f7 /reg=0</opc> + <opr>Ev Iz</opr> + <syn>sext</syn> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>f7 /reg=1</opc> + <opr>Ev Iz</opr> + <syn>sext</syn> + </def> + </instruction> + + <instruction> + <mnemonic>ucomisd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 2e</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>ucomiss</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 2e</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>ud2</mnemonic> + <def> + <opc>0f 0b</opc> + </def> + </instruction> + + <instruction> + <mnemonic>unpckhpd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 15</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>unpckhps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 15</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>unpcklps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 14</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>unpcklpd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 14</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>verr</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 00 /reg=4</opc> + <opr>Ew</opr> + </def> + </instruction> + + <instruction> + <mnemonic>verw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 00 /reg=5</opc> + <opr>Ew</opr> + </def> + </instruction> + + <instruction> + <mnemonic>vmcall</mnemonic> + <vendor>intel</vendor> + <def> + <opc>0f 01 /reg=0 /mod=11 /rm=1</opc> + </def> + </instruction> + + <instruction> + <mnemonic>vmclear</mnemonic> + <vendor>intel</vendor> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f c7 /reg=6</opc> + <opr>Mq</opr> + </def> + </instruction> + + <instruction> + <mnemonic>vmxon</mnemonic> + <vendor>intel</vendor> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f c7 /reg=6</opc> + <opr>Mq</opr> + </def> + </instruction> + + <instruction> + <mnemonic>vmptrld</mnemonic> + <vendor>intel</vendor> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f c7 /reg=6</opc> + <opr>Mq</opr> + </def> + </instruction> + + <instruction> + <mnemonic>vmptrst</mnemonic> + <vendor>intel</vendor> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f c7 /reg=7</opc> + <opr>Mq</opr> + </def> + </instruction> + + <instruction> + <mnemonic>vmlaunch</mnemonic> + <vendor>intel</vendor> + <def> + <opc>0f 01 /reg=0 /mod=11 /rm=2</opc> + </def> + </instruction> + + <instruction> + <mnemonic>vmresume</mnemonic> + <vendor>intel</vendor> + <def> + <opc>0f 01 /reg=0 /mod=11 /rm=3</opc> + </def> + </instruction> + + <instruction> + <mnemonic>vmxoff</mnemonic> + <vendor>intel</vendor> + <def> + <opc>0f 01 /reg=0 /mod=11 /rm=4</opc> + </def> + </instruction> + + <instruction> + <mnemonic>vmread</mnemonic> + <vendor>intel</vendor> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 78 /m=16</opc> + <opr>Ed Gd</opr> + <mode>def64</mode> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 78 /m=32</opc> + <opr>Ed Gd</opr> + <mode>def64</mode> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 78 /m=64</opc> + <opr>Eq Gq</opr> + <mode>def64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>vmwrite</mnemonic> + <vendor>intel</vendor> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 79 /m=16</opc> + <opr>Gd Ed</opr> + <mode>def64</mode> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 79 /m=32</opc> + <opr>Gd Ed</opr> + <mode>def64</mode> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 79 /m=64</opc> + <opr>Gq Eq</opr> + <mode>def64</mode> + </def> + </instruction> + + <instruction> + <mnemonic>vmrun</mnemonic> + <vendor>amd</vendor> + <def> + <opc>0f 01 /reg=3 /mod=11 /rm=0</opc> + </def> + </instruction> + + <instruction> + <mnemonic>vmmcall</mnemonic> + <vendor>amd</vendor> + <def> + <opc>0f 01 /reg=3 /mod=11 /rm=1</opc> + </def> + </instruction> + + <instruction> + <mnemonic>vmload</mnemonic> + <vendor>amd</vendor> + <def> + <opc>0f 01 /reg=3 /mod=11 /rm=2</opc> + </def> + </instruction> + + <instruction> + <mnemonic>vmsave</mnemonic> + <vendor>amd</vendor> + <def> + <opc>0f 01 /reg=3 /mod=11 /rm=3</opc> + </def> + </instruction> + + <instruction> + <mnemonic>wait</mnemonic> + <def> + <opc>9b</opc> + </def> + </instruction> + + <instruction> + <mnemonic>wbinvd</mnemonic> + <def> + <opc>0f 09</opc> + </def> + </instruction> + + <instruction> + <mnemonic>wrmsr</mnemonic> + <def> + <opc>0f 30</opc> + </def> + </instruction> + + <instruction> + <mnemonic>xadd</mnemonic> + <def> + <pfx>aso oso rexr rexx rexb</pfx> + <opc>0f c0</opc> + <opr>Eb Gb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>0f c1</opc> + <opr>Ev Gv</opr> + </def> + </instruction> + + <instruction> + <mnemonic>xchg</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>86</opc> + <opr>Eb Gb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>87</opc> + <opr>Ev Gv</opr> + </def> + <def> + <pfx>oso rexw rexb</pfx> + <opc>90</opc> + <opr>rAXr8 rAX</opr> + </def> + <def> + <pfx>oso rexw rexb</pfx> + <opc>91</opc> + <opr>rCXr9 rAX</opr> + </def> + <def> + <pfx>oso rexw rexb</pfx> + <opc>92</opc> + <opr>rDXr10 rAX</opr> + </def> + <def> + <pfx>oso rexw rexb</pfx> + <opc>93</opc> + <opr>rBXr11 rAX</opr> + </def> + <def> + <pfx>oso rexw rexb</pfx> + <opc>94</opc> + <opr>rSPr12 rAX</opr> + </def> + <def> + <pfx>oso rexw rexb</pfx> + <opc>95</opc> + <opr>rBPr13 rAX</opr> + </def> + <def> + <pfx>oso rexw rexb</pfx> + <opc>96</opc> + <opr>rSIr14 rAX</opr> + </def> + <def> + <pfx>oso rexw rexb</pfx> + <opc>97</opc> + <opr>rDIr15 rAX</opr> + </def> + </instruction> + + <instruction> + <mnemonic>xlatb</mnemonic> + <def> + <pfx>rexw</pfx> + <opc>d7</opc> + </def> + </instruction> + + <instruction> + <mnemonic>xor</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>30</opc> + <opr>Eb Gb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>31</opc> + <opr>Ev Gv</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>32</opc> + <opr>Gb Eb</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>33</opc> + <opr>Gv Ev</opr> + </def> + <def> + <opc>34</opc> + <opr>AL Ib</opr> + </def> + <def> + <pfx>oso rexw</pfx> + <opc>35</opc> + <opr>rAX Iz</opr> + <syn>sext</syn> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>80 /reg=6</opc> + <opr>Eb Ib</opr> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>81 /reg=6</opc> + <opr>Ev Iz</opr> + <syn>sext</syn> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>82 /reg=6</opc> + <opr>Eb Ib</opr> + <mode>inv64</mode> + </def> + <def> + <pfx>aso oso rexw rexr rexx rexb</pfx> + <opc>83 /reg=6</opc> + <opr>Ev Ib</opr> + <syn>sext</syn> + </def> + </instruction> + + <instruction> + <mnemonic>xorpd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 57</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>xorps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 57</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>xcryptecb</mnemonic> + <def> + <opc>0f a7 /mod=11 /rm=0 /reg=1</opc> + </def> + </instruction> + + <instruction> + <mnemonic>xcryptcbc</mnemonic> + <def> + <opc>0f a7 /mod=11 /rm=0 /reg=2</opc> + </def> + </instruction> + + <instruction> + <mnemonic>xcryptctr</mnemonic> + <def> + <opc>0f a7 /mod=11 /rm=0 /reg=3</opc> + </def> + </instruction> + + <instruction> + <mnemonic>xcryptcfb</mnemonic> + <def> + <opc>0f a7 /mod=11 /rm=0 /reg=4</opc> + </def> + </instruction> + + <instruction> + <mnemonic>xcryptofb</mnemonic> + <def> + <opc>0f a7 /mod=11 /rm=0 /reg=5</opc> + </def> + </instruction> + + <instruction> + <mnemonic>xsha1</mnemonic> + <def> + <opc>0f a6 /mod=11 /rm=0 /reg=1</opc> + </def> + </instruction> + + <instruction> + <mnemonic>xsha256</mnemonic> + <def> + <opc>0f a6 /mod=11 /rm=0 /reg=2</opc> + </def> + </instruction> + + <instruction> + <mnemonic>xstore</mnemonic> + <def> + <opc>0f a7 /mod=11 /rm=0 /reg=0</opc> + </def> + </instruction> + + <instruction> + <mnemonic>db</mnemonic> + </instruction> + + <!-- + SSE 2 + --> + + <instruction> + <mnemonic>movdqa</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 7f</opc> + <opr>W V</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 6f</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movdq2q</mnemonic> + <def> + <pfx>aso rexb</pfx> + <opc>ssef2 0f d6</opc> + <opr>P VR</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movdqu</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f 6f</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f 7f</opc> + <opr>W V</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movq2dq</mnemonic> + <def> + <pfx>aso</pfx> + <opc>ssef3 0f d6</opc> + <opr>V PR</opr> + </def> + </instruction> + + <instruction> + <mnemonic>paddq</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f d4</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f d4</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>psubq</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f fb</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f fb</opc> + <opr>P Q</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pmuludq</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f f4</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f f4</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pshufhw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f 70</opc> + <opr>V W Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pshuflw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef2 0f 70</opc> + <opr>V W Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pshufd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 70</opc> + <opr>V W Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pslldq</mnemonic> + <def> + <pfx>rexb</pfx> + <opc>sse66 0f 73 /reg=7</opc> + <opr>VR Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>psrldq</mnemonic> + <def> + <pfx>rexb</pfx> + <opc>sse66 0f 73 /reg=3</opc> + <opr>VR Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>punpckhqdq</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 6d</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>punpcklqdq</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 6c</opc> + <opr>V W</opr> + </def> + </instruction> + + <!-- + SSE 3 + --> + + <instruction> + <mnemonic>addsubpd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f d0</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>addsubps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef2 0f d0</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>haddpd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 7c</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>haddps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef2 0f 7c</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>hsubpd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 7d</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>hsubps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef2 0f 7d</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movddup</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef2 0f 12 /mod=11</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef2 0f 12 /mod=!11</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movshdup</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f 16 /mod=11</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f 16 /mod=!11</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>movsldup</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f 12 /mod=11</opc> + <opr>V W</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>ssef3 0f 12 /mod=!11</opc> + <opr>V W</opr> + </def> + </instruction> + + <!-- + SSSE 3 + --> + + <instruction> + <mnemonic>pabsb</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 38 1c</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 1c</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pabsw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 38 1d</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 1d</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pabsd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 38 1e</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 1e</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>psignb</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 38 00</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 00</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>phaddw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 38 01</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 01</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>phaddd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 38 02</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 02</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>phaddsw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 38 03</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 03</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pmaddubsw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 38 04</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 04</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>phsubw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 38 05</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 05</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>phsubd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 38 06</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 06</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>phsubsw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 38 07</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 07</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>psignb</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 38 08</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 08</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>psignd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 38 0a</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 0a</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>psignw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 38 09</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 09</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pmulhrsw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 38 0b</opc> + <opr>P Q</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 0b</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>palignr</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>0f 3a 0f</opc> + <opr>P Q Ib</opr> + </def> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 3a 0f</opc> + <opr>V W Ib</opr> + </def> + </instruction> + + <!-- + SSE 4.1 + --> + + <instruction> + <mnemonic>pblendvb</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 10</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pmuldq</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 28</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pminsb</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 38</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pminsd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 39</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pminuw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 3a</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pminud</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 3b</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pmaxsb</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 3c</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pmaxsd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 3d</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pmaxud</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 3f</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pmulld</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 40</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>phminposuw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 41</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>roundps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 3a 08</opc> + <opr>V W Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>roundpd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 3a 09</opc> + <opr>V W Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>roundss</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 3a 0a</opc> + <opr>V W Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>roundsd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 3a 0b</opc> + <opr>V W Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>blendpd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 3a 0d</opc> + <opr>V W Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>pblendw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 3a 0e</opc> + <opr>V W Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>blendps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 3a 0c</opc> + <opr>V W Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>blendvpd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 15</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>blendvps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 38 14</opc> + <opr>V W</opr> + </def> + </instruction> + + <instruction> + <mnemonic>dpps</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 3a 40</opc> + <opr>V W Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>dppd</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 3a 41</opc> + <opr>V W Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>mpsadbw</mnemonic> + <def> + <pfx>aso rexr rexx rexb</pfx> + <opc>sse66 0f 3a 42</opc> + <opr>V W Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>extractps</mnemonic> + <def> + <pfx>aso rexr rexw rexb</pfx> + <opc>sse66 0f 3a 17</opc> + <opr>MdRy V Ib</opr> + </def> + </instruction> + + <instruction> + <mnemonic>invalid</mnemonic> + </instruction> + +</x86optable> diff --git a/Source/JavaScriptCore/disassembler/udis86/ud_opcode.py b/Source/JavaScriptCore/disassembler/udis86/ud_opcode.py new file mode 100644 index 000000000..f301b5246 --- /dev/null +++ b/Source/JavaScriptCore/disassembler/udis86/ud_opcode.py @@ -0,0 +1,235 @@ +# udis86 - scripts/ud_opcode.py +# +# Copyright (c) 2009 Vivek Thampi +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. + +class UdOpcodeTables: + + TableInfo = { + 'opctbl' : { 'name' : 'UD_TAB__OPC_TABLE', 'size' : 256 }, + '/sse' : { 'name' : 'UD_TAB__OPC_SSE', 'size' : 4 }, + '/reg' : { 'name' : 'UD_TAB__OPC_REG', 'size' : 8 }, + '/rm' : { 'name' : 'UD_TAB__OPC_RM', 'size' : 8 }, + '/mod' : { 'name' : 'UD_TAB__OPC_MOD', 'size' : 2 }, + '/m' : { 'name' : 'UD_TAB__OPC_MODE', 'size' : 3 }, + '/x87' : { 'name' : 'UD_TAB__OPC_X87', 'size' : 64 }, + '/a' : { 'name' : 'UD_TAB__OPC_ASIZE', 'size' : 3 }, + '/o' : { 'name' : 'UD_TAB__OPC_OSIZE', 'size' : 3 }, + '/3dnow' : { 'name' : 'UD_TAB__OPC_3DNOW', 'size' : 256 }, + 'vendor' : { 'name' : 'UD_TAB__OPC_VENDOR', 'size' : 3 }, + } + + OpcodeTable0 = { + 'type' : 'opctbl', + 'entries' : {}, + 'meta' : 'table0' + } + + OpcExtIndex = { + + # ssef2, ssef3, sse66 + 'sse': { + 'none' : '00', + 'f2' : '01', + 'f3' : '02', + '66' : '03' + }, + + # /mod= + 'mod': { + '!11' : '00', + '11' : '01' + }, + + # /m=, /o=, /a= + 'mode': { + '16' : '00', + '32' : '01', + '64' : '02' + }, + + 'vendor' : { + 'amd' : '00', + 'intel' : '01', + 'any' : '02' + } + } + + InsnTable = [] + MnemonicsTable = [] + + ThreeDNowTable = {} + + def sizeOfTable( self, t ): + return self.TableInfo[ t ][ 'size' ] + + def nameOfTable( self, t ): + return self.TableInfo[ t ][ 'name' ] + + # + # Updates a table entry: If the entry doesn't exist + # it will create the entry, otherwise, it will walk + # while validating the path. + # + def updateTable( self, table, index, type, meta ): + if not index in table[ 'entries' ]: + table[ 'entries' ][ index ] = { 'type' : type, 'entries' : {}, 'meta' : meta } + if table[ 'entries' ][ index ][ 'type' ] != type: + raise NameError( "error: violation in opcode mapping (overwrite) %s with %s." % + ( table[ 'entries' ][ index ][ 'type' ], type) ) + return table[ 'entries' ][ index ] + + class Insn: + """An abstract type representing an instruction in the opcode map. + """ + + # A mapping of opcode extensions to their representational + # values used in the opcode map. + OpcExtMap = { + '/rm' : lambda v: "%02x" % int(v, 16), + '/x87' : lambda v: "%02x" % int(v, 16), + '/3dnow' : lambda v: "%02x" % int(v, 16), + '/reg' : lambda v: "%02x" % int(v, 16), + # modrm.mod + # (!11, 11) => (00, 01) + '/mod' : lambda v: '00' if v == '!11' else '01', + # Mode extensions: + # (16, 32, 64) => (00, 01, 02) + '/o' : lambda v: "%02x" % (int(v) / 32), + '/a' : lambda v: "%02x" % (int(v) / 32), + '/m' : lambda v: "%02x" % (int(v) / 32), + '/sse' : lambda v: UdOpcodeTables.OpcExtIndex['sse'][v] + } + + def __init__(self, prefixes, mnemonic, opcodes, operands, vendor): + self.opcodes = opcodes + self.prefixes = prefixes + self.mnemonic = mnemonic + self.operands = operands + self.vendor = vendor + self.opcext = {} + + ssePrefix = None + if self.opcodes[0] in ('ssef2', 'ssef3', 'sse66'): + ssePrefix = self.opcodes[0][3:] + self.opcodes.pop(0) + + # do some preliminary decoding of the instruction type + # 1byte, 2byte or 3byte instruction? + self.nByteInsn = 1 + if self.opcodes[0] == '0f': # 2byte + # 2+ byte opcodes are always disambiguated by an + # sse prefix, unless it is a 3d now instruction + # which is 0f 0f ... + if self.opcodes[1] != '0f' and ssePrefix is None: + ssePrefix = 'none' + if self.opcodes[1] in ('38', '3a'): # 3byte + self.nByteInsn = 3 + else: + self.nByteInsn = 2 + + # The opcode that indexes into the opcode table. + self.opcode = self.opcodes[self.nByteInsn - 1] + + # Record opcode extensions + for opcode in self.opcodes[self.nByteInsn:]: + arg, val = opcode.split('=') + self.opcext[arg] = self.OpcExtMap[arg](val) + + # Record sse extension: the reason sse extension is handled + # separately is that historically sse was handled as a first + # class opcode, not as an extension. Now that sse is handled + # as an extension, we do the manual conversion here, as opposed + # to modifying the opcode xml file. + if ssePrefix is not None: + self.opcext['/sse'] = self.OpcExtMap['/sse'](ssePrefix) + + def parse(self, table, insn): + index = insn.opcodes[0]; + if insn.nByteInsn > 1: + assert index == '0f' + table = self.updateTable(table, index, 'opctbl', '0f') + index = insn.opcodes[1] + + if insn.nByteInsn == 3: + table = self.updateTable(table, index, 'opctbl', index) + index = insn.opcodes[2] + + # Walk down the tree, create levels as needed, for opcode + # extensions. The order is important, and determines how + # well the opcode table is packed. Also note, /sse must be + # before /o, because /sse may consume operand size prefix + # affect the outcome of /o. + for ext in ('/mod', '/x87', '/reg', '/rm', '/sse', + '/o', '/a', '/m', '/3dnow'): + if ext in insn.opcext: + table = self.updateTable(table, index, ext, ext) + index = insn.opcext[ext] + + # additional table for disambiguating vendor + if len(insn.vendor): + table = self.updateTable(table, index, 'vendor', insn.vendor) + index = self.OpcExtIndex['vendor'][insn.vendor] + + # make leaf node entries + leaf = self.updateTable(table, index, 'insn', '') + + leaf['mnemonic'] = insn.mnemonic + leaf['prefixes'] = insn.prefixes + leaf['operands'] = insn.operands + + # add instruction to linear table of instruction forms + self.InsnTable.append({ 'prefixes' : insn.prefixes, + 'mnemonic' : insn.mnemonic, + 'operands' : insn.operands }) + + # add mnemonic to mnemonic table + if not insn.mnemonic in self.MnemonicsTable: + self.MnemonicsTable.append(insn.mnemonic) + + + # Adds an instruction definition to the opcode tables + def addInsnDef( self, prefixes, mnemonic, opcodes, operands, vendor ): + insn = self.Insn(prefixes=prefixes, + mnemonic=mnemonic, + opcodes=opcodes, + operands=operands, + vendor=vendor) + self.parse(self.OpcodeTable0, insn) + + def print_table( self, table, pfxs ): + print "%s |" % pfxs + keys = table[ 'entries' ].keys() + if ( len( keys ) ): + keys.sort() + for idx in keys: + e = table[ 'entries' ][ idx ] + if e[ 'type' ] == 'insn': + print "%s |-<%s>" % ( pfxs, idx ), + print "%s %s" % ( e[ 'mnemonic' ], ' '.join( e[ 'operands'] ) ) + else: + print "%s |-<%s> %s" % ( pfxs, idx, e['type'] ) + self.print_table( e, pfxs + ' |' ) + + def print_tree( self ): + self.print_table( self.OpcodeTable0, '' ) diff --git a/Source/JavaScriptCore/disassembler/udis86/ud_optable.py b/Source/JavaScriptCore/disassembler/udis86/ud_optable.py new file mode 100644 index 000000000..5b5c55d3b --- /dev/null +++ b/Source/JavaScriptCore/disassembler/udis86/ud_optable.py @@ -0,0 +1,103 @@ +# udis86 - scripts/ud_optable.py (optable.xml parser) +# +# Copyright (c) 2009 Vivek Thampi +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. + +import os +import sys +from xml.dom import minidom + +class UdOptableXmlParser: + + def parseDef( self, node ): + ven = '' + pfx = [] + opc = [] + opr = [] + for def_node in node.childNodes: + if not def_node.localName: + continue + if def_node.localName == 'pfx': + pfx = def_node.firstChild.data.split(); + elif def_node.localName == 'opc': + opc = def_node.firstChild.data.split(); + elif def_node.localName == 'opr': + opr = def_node.firstChild.data.split(); + elif def_node.localName == 'mode': + pfx.extend( def_node.firstChild.data.split() ); + elif def_node.localName == 'syn': + pfx.extend( def_node.firstChild.data.split() ); + elif def_node.localName == 'vendor': + ven = ( def_node.firstChild.data ); + else: + print "warning: invalid node - %s" % def_node.localName + continue + return ( pfx, opc, opr, ven ) + + def parse( self, xml, fn ): + xmlDoc = minidom.parse( xml ) + self.TlNode = xmlDoc.firstChild + + while self.TlNode and self.TlNode.localName != "x86optable": + self.TlNode = self.TlNode.nextSibling + + for insnNode in self.TlNode.childNodes: + if not insnNode.localName: + continue + if insnNode.localName != "instruction": + print "warning: invalid insn node - %s" % insnNode.localName + continue + + mnemonic = insnNode.getElementsByTagName( 'mnemonic' )[ 0 ].firstChild.data + vendor = '' + + for node in insnNode.childNodes: + if node.localName == 'vendor': + vendor = node.firstChild.data + elif node.localName == 'def': + ( prefixes, opcodes, operands, local_vendor ) = \ + self.parseDef( node ) + if ( len( local_vendor ) ): + vendor = local_vendor + # callback + fn( prefixes, mnemonic, opcodes, operands, vendor ) + + +def printFn( pfx, mnm, opc, opr, ven ): + print 'def: ', + if len( pfx ): + print ' '.join( pfx ), + print "%s %s %s %s" % \ + ( mnm, ' '.join( opc ), ' '.join( opr ), ven ) + + +def parse( xml, callback ): + parser = UdOptableXmlParser() + parser.parse( xml, callback ) + +def main(): + parser = UdOptableXmlParser() + parser.parse( sys.argv[ 1 ], printFn ) + +if __name__ == "__main__": + main() diff --git a/Source/JavaScriptCore/disassembler/udis86/udis86.c b/Source/JavaScriptCore/disassembler/udis86/udis86.c new file mode 100644 index 000000000..fbf76707a --- /dev/null +++ b/Source/JavaScriptCore/disassembler/udis86/udis86.c @@ -0,0 +1,183 @@ +/* udis86 - libudis86/udis86.c + * + * Copyright (c) 2002-2009 Vivek Thampi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 <wtf/Platform.h> + +#if USE(UDIS86) + +#include "udis86_input.h" +#include "udis86_extern.h" + +#ifndef __UD_STANDALONE__ +# include <stdlib.h> +# include <string.h> +#endif /* __UD_STANDALONE__ */ + +/* ============================================================================= + * ud_init() - Initializes ud_t object. + * ============================================================================= + */ +extern void +ud_init(struct ud* u) +{ + memset((void*)u, 0, sizeof(struct ud)); + ud_set_mode(u, 16); + u->mnemonic = UD_Iinvalid; + ud_set_pc(u, 0); +#ifndef __UD_STANDALONE__ + ud_set_input_file(u, stdin); +#endif /* __UD_STANDALONE__ */ +} + +/* ============================================================================= + * ud_disassemble() - disassembles one instruction and returns the number of + * bytes disassembled. A zero means end of disassembly. + * ============================================================================= + */ +extern unsigned int +ud_disassemble(struct ud* u) +{ + if (ud_input_end(u)) + return 0; + + + u->insn_buffer[0] = u->insn_hexcode[0] = 0; + + + if (ud_decode(u) == 0) + return 0; + if (u->translator) + u->translator(u); + return ud_insn_len(u); +} + +/* ============================================================================= + * ud_set_mode() - Set Disassemly Mode. + * ============================================================================= + */ +extern void +ud_set_mode(struct ud* u, uint8_t m) +{ + switch(m) { + case 16: + case 32: + case 64: u->dis_mode = m ; return; + default: u->dis_mode = 16; return; + } +} + +/* ============================================================================= + * ud_set_vendor() - Set vendor. + * ============================================================================= + */ +extern void +ud_set_vendor(struct ud* u, unsigned v) +{ + switch(v) { + case UD_VENDOR_INTEL: + u->vendor = v; + break; + case UD_VENDOR_ANY: + u->vendor = v; + break; + default: + u->vendor = UD_VENDOR_AMD; + } +} + +/* ============================================================================= + * ud_set_pc() - Sets code origin. + * ============================================================================= + */ +extern void +ud_set_pc(struct ud* u, uint64_t o) +{ + u->pc = o; +} + +/* ============================================================================= + * ud_set_syntax() - Sets the output syntax. + * ============================================================================= + */ +extern void +ud_set_syntax(struct ud* u, void (*t)(struct ud*)) +{ + u->translator = t; +} + +/* ============================================================================= + * ud_insn() - returns the disassembled instruction + * ============================================================================= + */ +extern char* +ud_insn_asm(struct ud* u) +{ + return u->insn_buffer; +} + +/* ============================================================================= + * ud_insn_offset() - Returns the offset. + * ============================================================================= + */ +extern uint64_t +ud_insn_off(struct ud* u) +{ + return u->insn_offset; +} + + +/* ============================================================================= + * ud_insn_hex() - Returns hex form of disassembled instruction. + * ============================================================================= + */ +extern char* +ud_insn_hex(struct ud* u) +{ + return u->insn_hexcode; +} + +/* ============================================================================= + * ud_insn_ptr() - Returns code disassembled. + * ============================================================================= + */ +extern uint8_t* +ud_insn_ptr(struct ud* u) +{ + return u->inp_sess; +} + +/* ============================================================================= + * ud_insn_len() - Returns the count of bytes disassembled. + * ============================================================================= + */ +extern unsigned int +ud_insn_len(struct ud* u) +{ + return u->inp_ctr; +} + +#endif // USE(UDIS86) diff --git a/Source/JavaScriptCore/disassembler/udis86/udis86.h b/Source/JavaScriptCore/disassembler/udis86/udis86.h new file mode 100644 index 000000000..baaf495e0 --- /dev/null +++ b/Source/JavaScriptCore/disassembler/udis86/udis86.h @@ -0,0 +1,33 @@ +/* udis86 - udis86.h + * + * Copyright (c) 2002-2009 Vivek Thampi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 UDIS86_H +#define UDIS86_H + +#include "udis86_types.h" +#include "udis86_extern.h" +#include "udis86_itab.h" + +#endif diff --git a/Source/JavaScriptCore/disassembler/udis86/udis86_decode.c b/Source/JavaScriptCore/disassembler/udis86/udis86_decode.c new file mode 100644 index 000000000..a3fd57665 --- /dev/null +++ b/Source/JavaScriptCore/disassembler/udis86/udis86_decode.c @@ -0,0 +1,1142 @@ +/* udis86 - libudis86/decode.c + * + * Copyright (c) 2002-2009 Vivek Thampi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 <wtf/Platform.h> + +#if USE(UDIS86) + +#include "udis86_extern.h" +#include "udis86_types.h" +#include "udis86_input.h" +#include "udis86_decode.h" +#include <wtf/Assertions.h> + +#define dbg(x, n...) +/* #define dbg printf */ + +#ifndef __UD_STANDALONE__ +# include <string.h> +#endif /* __UD_STANDALONE__ */ + +/* The max number of prefixes to an instruction */ +#define MAX_PREFIXES 15 + +/* instruction aliases and special cases */ +static struct ud_itab_entry s_ie__invalid = + { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }; + +static int +decode_ext(struct ud *u, uint16_t ptr); + + +static inline int +eff_opr_mode(int dis_mode, int rex_w, int pfx_opr) +{ + if (dis_mode == 64) { + return rex_w ? 64 : (pfx_opr ? 16 : 32); + } else if (dis_mode == 32) { + return pfx_opr ? 16 : 32; + } else { + ASSERT(dis_mode == 16); + return pfx_opr ? 32 : 16; + } +} + + +static inline int +eff_adr_mode(int dis_mode, int pfx_adr) +{ + if (dis_mode == 64) { + return pfx_adr ? 32 : 64; + } else if (dis_mode == 32) { + return pfx_adr ? 16 : 32; + } else { + ASSERT(dis_mode == 16); + return pfx_adr ? 32 : 16; + } +} + + +/* Looks up mnemonic code in the mnemonic string table + * Returns NULL if the mnemonic code is invalid + */ +const char * ud_lookup_mnemonic( enum ud_mnemonic_code c ) +{ + return ud_mnemonics_str[ c ]; +} + + +/* + * decode_prefixes + * + * Extracts instruction prefixes. + */ +static int +decode_prefixes(struct ud *u) +{ + unsigned int have_pfx = 1; + unsigned int i; + uint8_t curr; + + /* if in error state, bail out */ + if ( u->error ) + return -1; + + /* keep going as long as there are prefixes available */ + for ( i = 0; have_pfx ; ++i ) { + + /* Get next byte. */ + ud_inp_next(u); + if ( u->error ) + return -1; + curr = ud_inp_curr( u ); + + /* rex prefixes in 64bit mode */ + if ( u->dis_mode == 64 && ( curr & 0xF0 ) == 0x40 ) { + u->pfx_rex = curr; + } else { + switch ( curr ) + { + case 0x2E : + u->pfx_seg = UD_R_CS; + u->pfx_rex = 0; + break; + case 0x36 : + u->pfx_seg = UD_R_SS; + u->pfx_rex = 0; + break; + case 0x3E : + u->pfx_seg = UD_R_DS; + u->pfx_rex = 0; + break; + case 0x26 : + u->pfx_seg = UD_R_ES; + u->pfx_rex = 0; + break; + case 0x64 : + u->pfx_seg = UD_R_FS; + u->pfx_rex = 0; + break; + case 0x65 : + u->pfx_seg = UD_R_GS; + u->pfx_rex = 0; + break; + case 0x67 : /* adress-size override prefix */ + u->pfx_adr = 0x67; + u->pfx_rex = 0; + break; + case 0xF0 : + u->pfx_lock = 0xF0; + u->pfx_rex = 0; + break; + case 0x66: + /* the 0x66 sse prefix is only effective if no other sse prefix + * has already been specified. + */ + if ( !u->pfx_insn ) u->pfx_insn = 0x66; + u->pfx_opr = 0x66; + u->pfx_rex = 0; + break; + case 0xF2: + u->pfx_insn = 0xF2; + u->pfx_repne = 0xF2; + u->pfx_rex = 0; + break; + case 0xF3: + u->pfx_insn = 0xF3; + u->pfx_rep = 0xF3; + u->pfx_repe = 0xF3; + u->pfx_rex = 0; + break; + default : + /* No more prefixes */ + have_pfx = 0; + break; + } + } + + /* check if we reached max instruction length */ + if ( i + 1 == MAX_INSN_LENGTH ) { + u->error = 1; + break; + } + } + + /* return status */ + if ( u->error ) + return -1; + + /* rewind back one byte in stream, since the above loop + * stops with a non-prefix byte. + */ + ud_inp_back(u); + return 0; +} + + +static inline unsigned int modrm( struct ud * u ) +{ + if ( !u->have_modrm ) { + u->modrm = ud_inp_next( u ); + u->have_modrm = 1; + } + return u->modrm; +} + + +static unsigned int resolve_operand_size( const struct ud * u, unsigned int s ) +{ + switch ( s ) + { + case SZ_V: + return ( u->opr_mode ); + case SZ_Z: + return ( u->opr_mode == 16 ) ? 16 : 32; + case SZ_P: + return ( u->opr_mode == 16 ) ? SZ_WP : SZ_DP; + case SZ_MDQ: + return ( u->opr_mode == 16 ) ? 32 : u->opr_mode; + case SZ_RDQ: + return ( u->dis_mode == 64 ) ? 64 : 32; + default: + return s; + } +} + + +static int resolve_mnemonic( struct ud* u ) +{ + /* far/near flags */ + u->br_far = 0; + u->br_near = 0; + /* readjust operand sizes for call/jmp instrcutions */ + if ( u->mnemonic == UD_Icall || u->mnemonic == UD_Ijmp ) { + /* WP: 16:16 pointer */ + if ( u->operand[ 0 ].size == SZ_WP ) { + u->operand[ 0 ].size = 16; + u->br_far = 1; + u->br_near= 0; + /* DP: 32:32 pointer */ + } else if ( u->operand[ 0 ].size == SZ_DP ) { + u->operand[ 0 ].size = 32; + u->br_far = 1; + u->br_near= 0; + } else { + u->br_far = 0; + u->br_near= 1; + } + /* resolve 3dnow weirdness. */ + } else if ( u->mnemonic == UD_I3dnow ) { + u->mnemonic = ud_itab[ u->le->table[ ud_inp_curr( u ) ] ].mnemonic; + } + /* SWAPGS is only valid in 64bits mode */ + if ( u->mnemonic == UD_Iswapgs && u->dis_mode != 64 ) { + u->error = 1; + return -1; + } + + if (u->mnemonic == UD_Ixchg) { + if ((u->operand[0].type == UD_OP_REG && u->operand[0].base == UD_R_AX && + u->operand[1].type == UD_OP_REG && u->operand[1].base == UD_R_AX) || + (u->operand[0].type == UD_OP_REG && u->operand[0].base == UD_R_EAX && + u->operand[1].type == UD_OP_REG && u->operand[1].base == UD_R_EAX)) { + u->operand[0].type = UD_NONE; + u->operand[1].type = UD_NONE; + u->mnemonic = UD_Inop; + } + } + + if (u->mnemonic == UD_Inop && u->pfx_rep) { + u->pfx_rep = 0; + u->mnemonic = UD_Ipause; + } + return 0; +} + + +/* ----------------------------------------------------------------------------- + * decode_a()- Decodes operands of the type seg:offset + * ----------------------------------------------------------------------------- + */ +static void +decode_a(struct ud* u, struct ud_operand *op) +{ + if (u->opr_mode == 16) { + /* seg16:off16 */ + op->type = UD_OP_PTR; + op->size = 32; + op->lval.ptr.off = ud_inp_uint16(u); + op->lval.ptr.seg = ud_inp_uint16(u); + } else { + /* seg16:off32 */ + op->type = UD_OP_PTR; + op->size = 48; + op->lval.ptr.off = ud_inp_uint32(u); + op->lval.ptr.seg = ud_inp_uint16(u); + } +} + +/* ----------------------------------------------------------------------------- + * decode_gpr() - Returns decoded General Purpose Register + * ----------------------------------------------------------------------------- + */ +static enum ud_type +decode_gpr(register struct ud* u, unsigned int s, unsigned char rm) +{ + s = resolve_operand_size(u, s); + + switch (s) { + case 64: + return UD_R_RAX + rm; + case SZ_DP: + case 32: + return UD_R_EAX + rm; + case SZ_WP: + case 16: + return UD_R_AX + rm; + case 8: + if (u->dis_mode == 64 && u->pfx_rex) { + if (rm >= 4) + return UD_R_SPL + (rm-4); + return UD_R_AL + rm; + } else return UD_R_AL + rm; + default: + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * resolve_gpr64() - 64bit General Purpose Register-Selection. + * ----------------------------------------------------------------------------- + */ +static enum ud_type +resolve_gpr64(struct ud* u, enum ud_operand_code gpr_op, enum ud_operand_size * size) +{ + if (gpr_op >= OP_rAXr8 && gpr_op <= OP_rDIr15) + gpr_op = (gpr_op - OP_rAXr8) | (REX_B(u->pfx_rex) << 3); + else gpr_op = (gpr_op - OP_rAX); + + if (u->opr_mode == 16) { + *size = 16; + return gpr_op + UD_R_AX; + } + if (u->dis_mode == 32 || + (u->opr_mode == 32 && ! (REX_W(u->pfx_rex) || u->default64))) { + *size = 32; + return gpr_op + UD_R_EAX; + } + + *size = 64; + return gpr_op + UD_R_RAX; +} + +/* ----------------------------------------------------------------------------- + * resolve_gpr32 () - 32bit General Purpose Register-Selection. + * ----------------------------------------------------------------------------- + */ +static enum ud_type +resolve_gpr32(struct ud* u, enum ud_operand_code gpr_op) +{ + gpr_op = gpr_op - OP_eAX; + + if (u->opr_mode == 16) + return gpr_op + UD_R_AX; + + return gpr_op + UD_R_EAX; +} + +/* ----------------------------------------------------------------------------- + * resolve_reg() - Resolves the register type + * ----------------------------------------------------------------------------- + */ +static enum ud_type +resolve_reg(struct ud* u, unsigned int type, unsigned char i) +{ + switch (type) { + case T_MMX : return UD_R_MM0 + (i & 7); + case T_XMM : return UD_R_XMM0 + i; + case T_CRG : return UD_R_CR0 + i; + case T_DBG : return UD_R_DR0 + i; + case T_SEG : { + /* + * Only 6 segment registers, anything else is an error. + */ + if ((i & 7) > 5) { + u->error = 1; + } else { + return UD_R_ES + (i & 7); + } + } + case T_NONE: + default: return UD_NONE; + } +} + +/* ----------------------------------------------------------------------------- + * decode_imm() - Decodes Immediate values. + * ----------------------------------------------------------------------------- + */ +static void +decode_imm(struct ud* u, unsigned int s, struct ud_operand *op) +{ + op->size = resolve_operand_size(u, s); + op->type = UD_OP_IMM; + + switch (op->size) { + case 8: op->lval.sbyte = ud_inp_uint8(u); break; + case 16: op->lval.uword = ud_inp_uint16(u); break; + case 32: op->lval.udword = ud_inp_uint32(u); break; + case 64: op->lval.uqword = ud_inp_uint64(u); break; + default: return; + } +} + + +/* + * decode_modrm_reg + * + * Decodes reg field of mod/rm byte + * + */ +static void +decode_modrm_reg(struct ud *u, + struct ud_operand *operand, + unsigned int type, + unsigned int size) +{ + uint8_t reg = (REX_R(u->pfx_rex) << 3) | MODRM_REG(modrm(u)); + operand->type = UD_OP_REG; + operand->size = resolve_operand_size(u, size); + + if (type == T_GPR) { + operand->base = decode_gpr(u, operand->size, reg); + } else { + operand->base = resolve_reg(u, type, reg); + } +} + + +/* + * decode_modrm_rm + * + * Decodes rm field of mod/rm byte + * + */ +static void +decode_modrm_rm(struct ud *u, + struct ud_operand *op, + unsigned char type, + unsigned int size) + +{ + unsigned char mod, rm, reg; + + /* get mod, r/m and reg fields */ + mod = MODRM_MOD(modrm(u)); + rm = (REX_B(u->pfx_rex) << 3) | MODRM_RM(modrm(u)); + reg = (REX_R(u->pfx_rex) << 3) | MODRM_REG(modrm(u)); + + op->size = resolve_operand_size(u, size); + + /* + * If mod is 11b, then the modrm.rm specifies a register. + * + */ + if (mod == 3) { + op->type = UD_OP_REG; + if (type == T_GPR) { + op->base = decode_gpr(u, op->size, rm); + } else { + op->base = resolve_reg(u, type, (REX_B(u->pfx_rex) << 3) | (rm & 7)); + } + return; + } + + + /* + * !11 => Memory Address + */ + op->type = UD_OP_MEM; + + if (u->adr_mode == 64) { + op->base = UD_R_RAX + rm; + if (mod == 1) { + op->offset = 8; + } else if (mod == 2) { + op->offset = 32; + } else if (mod == 0 && (rm & 7) == 5) { + op->base = UD_R_RIP; + op->offset = 32; + } else { + op->offset = 0; + } + /* + * Scale-Index-Base (SIB) + */ + if ((rm & 7) == 4) { + ud_inp_next(u); + + op->scale = (1 << SIB_S(ud_inp_curr(u))) & ~1; + op->index = UD_R_RAX + (SIB_I(ud_inp_curr(u)) | (REX_X(u->pfx_rex) << 3)); + op->base = UD_R_RAX + (SIB_B(ud_inp_curr(u)) | (REX_B(u->pfx_rex) << 3)); + + /* special conditions for base reference */ + if (op->index == UD_R_RSP) { + op->index = UD_NONE; + op->scale = UD_NONE; + } + + if (op->base == UD_R_RBP || op->base == UD_R_R13) { + if (mod == 0) { + op->base = UD_NONE; + } + if (mod == 1) { + op->offset = 8; + } else { + op->offset = 32; + } + } + } + } else if (u->adr_mode == 32) { + op->base = UD_R_EAX + rm; + if (mod == 1) { + op->offset = 8; + } else if (mod == 2) { + op->offset = 32; + } else if (mod == 0 && rm == 5) { + op->base = UD_NONE; + op->offset = 32; + } else { + op->offset = 0; + } + + /* Scale-Index-Base (SIB) */ + if ((rm & 7) == 4) { + ud_inp_next(u); + + op->scale = (1 << SIB_S(ud_inp_curr(u))) & ~1; + op->index = UD_R_EAX + (SIB_I(ud_inp_curr(u)) | (REX_X(u->pfx_rex) << 3)); + op->base = UD_R_EAX + (SIB_B(ud_inp_curr(u)) | (REX_B(u->pfx_rex) << 3)); + + if (op->index == UD_R_ESP) { + op->index = UD_NONE; + op->scale = UD_NONE; + } + + /* special condition for base reference */ + if (op->base == UD_R_EBP) { + if (mod == 0) { + op->base = UD_NONE; + } + if (mod == 1) { + op->offset = 8; + } else { + op->offset = 32; + } + } + } + } else { + const unsigned int bases[] = { UD_R_BX, UD_R_BX, UD_R_BP, UD_R_BP, + UD_R_SI, UD_R_DI, UD_R_BP, UD_R_BX }; + const unsigned int indices[] = { UD_R_SI, UD_R_DI, UD_R_SI, UD_R_DI, + UD_NONE, UD_NONE, UD_NONE, UD_NONE }; + op->base = bases[rm & 7]; + op->index = indices[rm & 7]; + if (mod == 0 && rm == 6) { + op->offset= 16; + op->base = UD_NONE; + } else if (mod == 1) { + op->offset = 8; + } else if (mod == 2) { + op->offset = 16; + } + } + + /* + * extract offset, if any + */ + switch (op->offset) { + case 8 : op->lval.ubyte = ud_inp_uint8(u); break; + case 16: op->lval.uword = ud_inp_uint16(u); break; + case 32: op->lval.udword = ud_inp_uint32(u); break; + case 64: op->lval.uqword = ud_inp_uint64(u); break; + default: break; + } +} + +/* ----------------------------------------------------------------------------- + * decode_o() - Decodes offset + * ----------------------------------------------------------------------------- + */ +static void +decode_o(struct ud* u, unsigned int s, struct ud_operand *op) +{ + switch (u->adr_mode) { + case 64: + op->offset = 64; + op->lval.uqword = ud_inp_uint64(u); + break; + case 32: + op->offset = 32; + op->lval.udword = ud_inp_uint32(u); + break; + case 16: + op->offset = 16; + op->lval.uword = ud_inp_uint16(u); + break; + default: + return; + } + op->type = UD_OP_MEM; + op->size = resolve_operand_size(u, s); +} + +/* ----------------------------------------------------------------------------- + * decode_operands() - Disassembles Operands. + * ----------------------------------------------------------------------------- + */ +static int +decode_operand(struct ud *u, + struct ud_operand *operand, + enum ud_operand_code type, + unsigned int size) +{ + switch (type) { + case OP_A : + decode_a(u, operand); + break; + case OP_MR: + if (MODRM_MOD(modrm(u)) == 3) { + decode_modrm_rm(u, operand, T_GPR, + size == SZ_DY ? SZ_MDQ : SZ_V); + } else if (size == SZ_WV) { + decode_modrm_rm( u, operand, T_GPR, SZ_W); + } else if (size == SZ_BV) { + decode_modrm_rm( u, operand, T_GPR, SZ_B); + } else if (size == SZ_DY) { + decode_modrm_rm( u, operand, T_GPR, SZ_D); + } else { + ASSERT(!"unexpected size"); + } + break; + case OP_M: + if (MODRM_MOD(modrm(u)) == 3) { + u->error = 1; + } + /* intended fall through */ + case OP_E: + decode_modrm_rm(u, operand, T_GPR, size); + break; + break; + case OP_G: + decode_modrm_reg(u, operand, T_GPR, size); + break; + case OP_I: + decode_imm(u, size, operand); + break; + case OP_I1: + operand->type = UD_OP_CONST; + operand->lval.udword = 1; + break; + case OP_PR: + if (MODRM_MOD(modrm(u)) != 3) { + u->error = 1; + } + decode_modrm_rm(u, operand, T_MMX, size); + break; + case OP_P: + decode_modrm_reg(u, operand, T_MMX, size); + break; + case OP_VR: + if (MODRM_MOD(modrm(u)) != 3) { + u->error = 1; + } + /* intended fall through */ + case OP_W: + decode_modrm_rm(u, operand, T_XMM, size); + break; + case OP_V: + decode_modrm_reg(u, operand, T_XMM, size); + break; + case OP_S: + decode_modrm_reg(u, operand, T_SEG, size); + break; + case OP_AL: + case OP_CL: + case OP_DL: + case OP_BL: + case OP_AH: + case OP_CH: + case OP_DH: + case OP_BH: + operand->type = UD_OP_REG; + operand->base = UD_R_AL + (type - OP_AL); + operand->size = 8; + break; + case OP_DX: + operand->type = UD_OP_REG; + operand->base = UD_R_DX; + operand->size = 16; + break; + case OP_O: + decode_o(u, size, operand); + break; + case OP_rAXr8: + case OP_rCXr9: + case OP_rDXr10: + case OP_rBXr11: + case OP_rSPr12: + case OP_rBPr13: + case OP_rSIr14: + case OP_rDIr15: + case OP_rAX: + case OP_rCX: + case OP_rDX: + case OP_rBX: + case OP_rSP: + case OP_rBP: + case OP_rSI: + case OP_rDI: + operand->type = UD_OP_REG; + operand->base = resolve_gpr64(u, type, &operand->size); + break; + case OP_ALr8b: + case OP_CLr9b: + case OP_DLr10b: + case OP_BLr11b: + case OP_AHr12b: + case OP_CHr13b: + case OP_DHr14b: + case OP_BHr15b: { + ud_type_t gpr = (type - OP_ALr8b) + UD_R_AL + + (REX_B(u->pfx_rex) << 3); + if (UD_R_AH <= gpr && u->pfx_rex) { + gpr = gpr + 4; + } + operand->type = UD_OP_REG; + operand->base = gpr; + break; + } + case OP_eAX: + case OP_eCX: + case OP_eDX: + case OP_eBX: + case OP_eSP: + case OP_eBP: + case OP_eSI: + case OP_eDI: + operand->type = UD_OP_REG; + operand->base = resolve_gpr32(u, type); + operand->size = u->opr_mode == 16 ? 16 : 32; + break; + case OP_ES: + case OP_CS: + case OP_DS: + case OP_SS: + case OP_FS: + case OP_GS: + /* in 64bits mode, only fs and gs are allowed */ + if (u->dis_mode == 64) { + if (type != OP_FS && type != OP_GS) { + u->error= 1; + } + } + operand->type = UD_OP_REG; + operand->base = (type - OP_ES) + UD_R_ES; + operand->size = 16; + break; + case OP_J : + decode_imm(u, size, operand); + operand->type = UD_OP_JIMM; + break ; + case OP_Q: + decode_modrm_rm(u, operand, T_MMX, size); + break; + case OP_R : + decode_modrm_rm(u, operand, T_GPR, size); + break; + case OP_C: + decode_modrm_reg(u, operand, T_CRG, size); + break; + case OP_D: + decode_modrm_reg(u, operand, T_DBG, size); + break; + case OP_I3 : + operand->type = UD_OP_CONST; + operand->lval.sbyte = 3; + break; + case OP_ST0: + case OP_ST1: + case OP_ST2: + case OP_ST3: + case OP_ST4: + case OP_ST5: + case OP_ST6: + case OP_ST7: + operand->type = UD_OP_REG; + operand->base = (type - OP_ST0) + UD_R_ST0; + operand->size = 0; + break; + case OP_AX: + operand->type = UD_OP_REG; + operand->base = UD_R_AX; + operand->size = 16; + break; + default : + operand->type = UD_NONE; + break; + } + return 0; +} + + +/* + * decode_operands + * + * Disassemble upto 3 operands of the current instruction being + * disassembled. By the end of the function, the operand fields + * of the ud structure will have been filled. + */ +static int +decode_operands(struct ud* u) +{ + decode_operand(u, &u->operand[0], + u->itab_entry->operand1.type, + u->itab_entry->operand1.size); + decode_operand(u, &u->operand[1], + u->itab_entry->operand2.type, + u->itab_entry->operand2.size); + decode_operand(u, &u->operand[2], + u->itab_entry->operand3.type, + u->itab_entry->operand3.size); + return 0; +} + +/* ----------------------------------------------------------------------------- + * clear_insn() - clear instruction structure + * ----------------------------------------------------------------------------- + */ +static void +clear_insn(register struct ud* u) +{ + u->error = 0; + u->pfx_seg = 0; + u->pfx_opr = 0; + u->pfx_adr = 0; + u->pfx_lock = 0; + u->pfx_repne = 0; + u->pfx_rep = 0; + u->pfx_repe = 0; + u->pfx_rex = 0; + u->pfx_insn = 0; + u->mnemonic = UD_Inone; + u->itab_entry = NULL; + u->have_modrm = 0; + + memset( &u->operand[ 0 ], 0, sizeof( struct ud_operand ) ); + memset( &u->operand[ 1 ], 0, sizeof( struct ud_operand ) ); + memset( &u->operand[ 2 ], 0, sizeof( struct ud_operand ) ); +} + +static int +resolve_mode( struct ud* u ) +{ + /* if in error state, bail out */ + if ( u->error ) return -1; + + /* propagate prefix effects */ + if ( u->dis_mode == 64 ) { /* set 64bit-mode flags */ + + /* Check validity of instruction m64 */ + if ( P_INV64( u->itab_entry->prefix ) ) { + u->error = 1; + return -1; + } + + /* effective rex prefix is the effective mask for the + * instruction hard-coded in the opcode map. + */ + u->pfx_rex = ( u->pfx_rex & 0x40 ) | + ( u->pfx_rex & REX_PFX_MASK( u->itab_entry->prefix ) ); + + /* whether this instruction has a default operand size of + * 64bit, also hardcoded into the opcode map. + */ + u->default64 = P_DEF64( u->itab_entry->prefix ); + /* calculate effective operand size */ + if ( REX_W( u->pfx_rex ) ) { + u->opr_mode = 64; + } else if ( u->pfx_opr ) { + u->opr_mode = 16; + } else { + /* unless the default opr size of instruction is 64, + * the effective operand size in the absence of rex.w + * prefix is 32. + */ + u->opr_mode = ( u->default64 ) ? 64 : 32; + } + + /* calculate effective address size */ + u->adr_mode = (u->pfx_adr) ? 32 : 64; + } else if ( u->dis_mode == 32 ) { /* set 32bit-mode flags */ + u->opr_mode = ( u->pfx_opr ) ? 16 : 32; + u->adr_mode = ( u->pfx_adr ) ? 16 : 32; + } else if ( u->dis_mode == 16 ) { /* set 16bit-mode flags */ + u->opr_mode = ( u->pfx_opr ) ? 32 : 16; + u->adr_mode = ( u->pfx_adr ) ? 32 : 16; + } + + /* These flags determine which operand to apply the operand size + * cast to. + */ + u->c1 = ( P_C1( u->itab_entry->prefix ) ) ? 1 : 0; + u->c2 = ( P_C2( u->itab_entry->prefix ) ) ? 1 : 0; + u->c3 = ( P_C3( u->itab_entry->prefix ) ) ? 1 : 0; + + /* set flags for implicit addressing */ + u->implicit_addr = P_IMPADDR( u->itab_entry->prefix ); + + return 0; +} + +static int gen_hex( struct ud *u ) +{ + unsigned int i; + unsigned char *src_ptr = ud_inp_sess( u ); + char* src_hex; + + /* bail out if in error stat. */ + if ( u->error ) return -1; + /* output buffer pointe */ + src_hex = ( char* ) u->insn_hexcode; + /* for each byte used to decode instruction */ + for ( i = 0; i < u->inp_ctr; ++i, ++src_ptr) { + sprintf( src_hex, "%02x", *src_ptr & 0xFF ); + src_hex += 2; + } + return 0; +} + + +static inline int +decode_insn(struct ud *u, uint16_t ptr) +{ + ASSERT((ptr & 0x8000) == 0); + u->itab_entry = &ud_itab[ ptr ]; + u->mnemonic = u->itab_entry->mnemonic; + return (resolve_mode(u) == 0 && + decode_operands(u) == 0 && + resolve_mnemonic(u) == 0) ? 0 : -1; +} + + +/* + * decode_3dnow() + * + * Decoding 3dnow is a little tricky because of its strange opcode + * structure. The final opcode disambiguation depends on the last + * byte that comes after the operands have been decoded. Fortunately, + * all 3dnow instructions have the same set of operand types. So we + * go ahead and decode the instruction by picking an arbitrarily chosen + * valid entry in the table, decode the operands, and read the final + * byte to resolve the menmonic. + */ +static inline int +decode_3dnow(struct ud* u) +{ + uint16_t ptr; + ASSERT(u->le->type == UD_TAB__OPC_3DNOW); + ASSERT(u->le->table[0xc] != 0); + decode_insn(u, u->le->table[0xc]); + ud_inp_next(u); + if (u->error) { + return -1; + } + ptr = u->le->table[ud_inp_curr(u)]; + ASSERT((ptr & 0x8000) == 0); + u->mnemonic = ud_itab[ptr].mnemonic; + return 0; +} + + +static int +decode_ssepfx(struct ud *u) +{ + uint8_t idx = ((u->pfx_insn & 0xf) + 1) / 2; + if (u->le->table[idx] == 0) { + idx = 0; + } + if (idx && u->le->table[idx] != 0) { + /* + * "Consume" the prefix as a part of the opcode, so it is no + * longer exported as an instruction prefix. + */ + switch (u->pfx_insn) { + case 0xf2: + u->pfx_repne = 0; + break; + case 0xf3: + u->pfx_rep = 0; + u->pfx_repe = 0; + break; + case 0x66: + u->pfx_opr = 0; + break; + } + } + return decode_ext(u, u->le->table[idx]); +} + + +/* + * decode_ext() + * + * Decode opcode extensions (if any) + */ +static int +decode_ext(struct ud *u, uint16_t ptr) +{ + uint8_t idx = 0; + if ((ptr & 0x8000) == 0) { + return decode_insn(u, ptr); + } + u->le = &ud_lookup_table_list[(~0x8000 & ptr)]; + if (u->le->type == UD_TAB__OPC_3DNOW) { + return decode_3dnow(u); + } + + switch (u->le->type) { + case UD_TAB__OPC_MOD: + /* !11 = 0, 11 = 1 */ + idx = (MODRM_MOD(modrm(u)) + 1) / 4; + break; + /* disassembly mode/operand size/address size based tables. + * 16 = 0,, 32 = 1, 64 = 2 + */ + case UD_TAB__OPC_MODE: + idx = u->dis_mode / 32; + break; + case UD_TAB__OPC_OSIZE: + idx = eff_opr_mode(u->dis_mode, REX_W(u->pfx_rex), u->pfx_opr) / 32; + break; + case UD_TAB__OPC_ASIZE: + idx = eff_adr_mode(u->dis_mode, u->pfx_adr) / 32; + break; + case UD_TAB__OPC_X87: + idx = modrm(u) - 0xC0; + break; + case UD_TAB__OPC_VENDOR: + if (u->vendor == UD_VENDOR_ANY) { + /* choose a valid entry */ + idx = (u->le->table[idx] != 0) ? 0 : 1; + } else if (u->vendor == UD_VENDOR_AMD) { + idx = 0; + } else { + idx = 1; + } + break; + case UD_TAB__OPC_RM: + idx = MODRM_RM(modrm(u)); + break; + case UD_TAB__OPC_REG: + idx = MODRM_REG(modrm(u)); + break; + case UD_TAB__OPC_SSE: + return decode_ssepfx(u); + default: + ASSERT(!"not reached"); + break; + } + + return decode_ext(u, u->le->table[idx]); +} + + +static inline int +decode_opcode(struct ud *u) +{ + uint16_t ptr; + ASSERT(u->le->type == UD_TAB__OPC_TABLE); + ud_inp_next(u); + if (u->error) { + return -1; + } + ptr = u->le->table[ud_inp_curr(u)]; + if (ptr & 0x8000) { + u->le = &ud_lookup_table_list[ptr & ~0x8000]; + if (u->le->type == UD_TAB__OPC_TABLE) { + return decode_opcode(u); + } + } + return decode_ext(u, ptr); +} + + +/* ============================================================================= + * ud_decode() - Instruction decoder. Returns the number of bytes decoded. + * ============================================================================= + */ +unsigned int +ud_decode(struct ud *u) +{ + ud_inp_start(u); + clear_insn(u); + u->le = &ud_lookup_table_list[0]; + u->error = decode_prefixes(u) == -1 || + decode_opcode(u) == -1 || + u->error; + /* Handle decode error. */ + if (u->error) { + /* clear out the decode data. */ + clear_insn(u); + /* mark the sequence of bytes as invalid. */ + u->itab_entry = & s_ie__invalid; + u->mnemonic = u->itab_entry->mnemonic; + } + + /* maybe this stray segment override byte + * should be spewed out? + */ + if ( !P_SEG( u->itab_entry->prefix ) && + u->operand[0].type != UD_OP_MEM && + u->operand[1].type != UD_OP_MEM ) + u->pfx_seg = 0; + + u->insn_offset = u->pc; /* set offset of instruction */ + u->insn_fill = 0; /* set translation buffer index to 0 */ + u->pc += u->inp_ctr; /* move program counter by bytes decoded */ + gen_hex( u ); /* generate hex code */ + + /* return number of bytes disassembled. */ + return u->inp_ctr; +} + +/* +vim: set ts=2 sw=2 expandtab +*/ + +#endif // USE(UDIS86) diff --git a/Source/JavaScriptCore/disassembler/udis86/udis86_decode.h b/Source/JavaScriptCore/disassembler/udis86/udis86_decode.h new file mode 100644 index 000000000..940ed5ad6 --- /dev/null +++ b/Source/JavaScriptCore/disassembler/udis86/udis86_decode.h @@ -0,0 +1,258 @@ +/* udis86 - libudis86/decode.h + * + * Copyright (c) 2002-2009 Vivek Thampi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 UD_DECODE_H +#define UD_DECODE_H + +#include "udis86_types.h" +#include "udis86_itab.h" + +#define MAX_INSN_LENGTH 15 + +/* register classes */ +#define T_NONE 0 +#define T_GPR 1 +#define T_MMX 2 +#define T_CRG 3 +#define T_DBG 4 +#define T_SEG 5 +#define T_XMM 6 + +/* itab prefix bits */ +#define P_none ( 0 ) +#define P_cast ( 1 << 0 ) +#define P_CAST(n) ( ( n >> 0 ) & 1 ) +#define P_c1 ( 1 << 0 ) +#define P_C1(n) ( ( n >> 0 ) & 1 ) +#define P_rexb ( 1 << 1 ) +#define P_REXB(n) ( ( n >> 1 ) & 1 ) +#define P_depM ( 1 << 2 ) +#define P_DEPM(n) ( ( n >> 2 ) & 1 ) +#define P_c3 ( 1 << 3 ) +#define P_C3(n) ( ( n >> 3 ) & 1 ) +#define P_inv64 ( 1 << 4 ) +#define P_INV64(n) ( ( n >> 4 ) & 1 ) +#define P_rexw ( 1 << 5 ) +#define P_REXW(n) ( ( n >> 5 ) & 1 ) +#define P_c2 ( 1 << 6 ) +#define P_C2(n) ( ( n >> 6 ) & 1 ) +#define P_def64 ( 1 << 7 ) +#define P_DEF64(n) ( ( n >> 7 ) & 1 ) +#define P_rexr ( 1 << 8 ) +#define P_REXR(n) ( ( n >> 8 ) & 1 ) +#define P_oso ( 1 << 9 ) +#define P_OSO(n) ( ( n >> 9 ) & 1 ) +#define P_aso ( 1 << 10 ) +#define P_ASO(n) ( ( n >> 10 ) & 1 ) +#define P_rexx ( 1 << 11 ) +#define P_REXX(n) ( ( n >> 11 ) & 1 ) +#define P_ImpAddr ( 1 << 12 ) +#define P_IMPADDR(n) ( ( n >> 12 ) & 1 ) +#define P_seg ( 1 << 13 ) +#define P_SEG(n) ( ( n >> 13 ) & 1 ) +#define P_sext ( 1 << 14 ) +#define P_SEXT(n) ( ( n >> 14 ) & 1 ) + +/* rex prefix bits */ +#define REX_W(r) ( ( 0xF & ( r ) ) >> 3 ) +#define REX_R(r) ( ( 0x7 & ( r ) ) >> 2 ) +#define REX_X(r) ( ( 0x3 & ( r ) ) >> 1 ) +#define REX_B(r) ( ( 0x1 & ( r ) ) >> 0 ) +#define REX_PFX_MASK(n) ( ( P_REXW(n) << 3 ) | \ + ( P_REXR(n) << 2 ) | \ + ( P_REXX(n) << 1 ) | \ + ( P_REXB(n) << 0 ) ) + +/* scable-index-base bits */ +#define SIB_S(b) ( ( b ) >> 6 ) +#define SIB_I(b) ( ( ( b ) >> 3 ) & 7 ) +#define SIB_B(b) ( ( b ) & 7 ) + +/* modrm bits */ +#define MODRM_REG(b) ( ( ( b ) >> 3 ) & 7 ) +#define MODRM_NNN(b) ( ( ( b ) >> 3 ) & 7 ) +#define MODRM_MOD(b) ( ( ( b ) >> 6 ) & 3 ) +#define MODRM_RM(b) ( ( b ) & 7 ) + +/* operand type constants -- order is important! */ + +enum ud_operand_code { + OP_NONE, + + OP_A, OP_E, OP_M, OP_G, + OP_I, + + OP_AL, OP_CL, OP_DL, OP_BL, + OP_AH, OP_CH, OP_DH, OP_BH, + + OP_ALr8b, OP_CLr9b, OP_DLr10b, OP_BLr11b, + OP_AHr12b, OP_CHr13b, OP_DHr14b, OP_BHr15b, + + OP_AX, OP_CX, OP_DX, OP_BX, + OP_SI, OP_DI, OP_SP, OP_BP, + + OP_rAX, OP_rCX, OP_rDX, OP_rBX, + OP_rSP, OP_rBP, OP_rSI, OP_rDI, + + OP_rAXr8, OP_rCXr9, OP_rDXr10, OP_rBXr11, + OP_rSPr12, OP_rBPr13, OP_rSIr14, OP_rDIr15, + + OP_eAX, OP_eCX, OP_eDX, OP_eBX, + OP_eSP, OP_eBP, OP_eSI, OP_eDI, + + OP_ES, OP_CS, OP_SS, OP_DS, + OP_FS, OP_GS, + + OP_ST0, OP_ST1, OP_ST2, OP_ST3, + OP_ST4, OP_ST5, OP_ST6, OP_ST7, + + OP_J, OP_S, OP_O, + OP_I1, OP_I3, + + OP_V, OP_W, OP_Q, OP_P, + + OP_R, OP_C, OP_D, OP_VR, OP_PR, + + OP_MR +} UD_ATTR_PACKED; + + +/* operand size constants */ + +enum ud_operand_size { + SZ_NA = 0, + SZ_Z = 1, + SZ_V = 2, + SZ_P = 3, + SZ_WP = 4, + SZ_DP = 5, + SZ_MDQ = 6, + SZ_RDQ = 7, + + /* the following values are used as is, + * and thus hard-coded. changing them + * will break internals + */ + SZ_B = 8, + SZ_W = 16, + SZ_D = 32, + SZ_Q = 64, + SZ_T = 80, + SZ_O = 128, + + SZ_WV = 17, + SZ_BV = 18, + SZ_DY = 19 + +} UD_ATTR_PACKED; + + +/* A single operand of an entry in the instruction table. + * (internal use only) + */ +struct ud_itab_entry_operand +{ + enum ud_operand_code type; + enum ud_operand_size size; +}; + + +/* A single entry in an instruction table. + *(internal use only) + */ +struct ud_itab_entry +{ + enum ud_mnemonic_code mnemonic; + struct ud_itab_entry_operand operand1; + struct ud_itab_entry_operand operand2; + struct ud_itab_entry_operand operand3; + uint32_t prefix; +}; + +struct ud_lookup_table_list_entry { + const uint16_t *table; + enum ud_table_type type; + const char *meta; +}; + + +static inline unsigned int sse_pfx_idx( const unsigned int pfx ) +{ + /* 00 = 0 + * f2 = 1 + * f3 = 2 + * 66 = 3 + */ + return ( ( pfx & 0xf ) + 1 ) / 2; +} + +static inline unsigned int mode_idx( const unsigned int mode ) +{ + /* 16 = 0 + * 32 = 1 + * 64 = 2 + */ + return ( mode / 32 ); +} + +static inline unsigned int modrm_mod_idx( const unsigned int mod ) +{ + /* !11 = 0 + * 11 = 1 + */ + return ( mod + 1 ) / 4; +} + +static inline unsigned int vendor_idx( const unsigned int vendor ) +{ + switch ( vendor ) { + case UD_VENDOR_AMD: return 0; + case UD_VENDOR_INTEL: return 1; + case UD_VENDOR_ANY: return 2; + default: return 2; + } +} + +static inline unsigned int is_group_ptr( uint16_t ptr ) +{ + return ( 0x8000 & ptr ); +} + +static inline unsigned int group_idx( uint16_t ptr ) +{ + return ( ~0x8000 & ptr ); +} + + +extern struct ud_itab_entry ud_itab[]; +extern struct ud_lookup_table_list_entry ud_lookup_table_list[]; + +#endif /* UD_DECODE_H */ + +/* vim:cindent + * vim:expandtab + * vim:ts=4 + * vim:sw=4 + */ diff --git a/Source/JavaScriptCore/disassembler/udis86/udis86_extern.h b/Source/JavaScriptCore/disassembler/udis86/udis86_extern.h new file mode 100644 index 000000000..8e87721e8 --- /dev/null +++ b/Source/JavaScriptCore/disassembler/udis86/udis86_extern.h @@ -0,0 +1,88 @@ +/* udis86 - libudis86/extern.h + * + * Copyright (c) 2002-2009 Vivek Thampi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 UD_EXTERN_H +#define UD_EXTERN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "udis86_types.h" + +/* ============================= PUBLIC API ================================= */ + +extern void ud_init(struct ud*); + +extern void ud_set_mode(struct ud*, uint8_t); + +extern void ud_set_pc(struct ud*, uint64_t); + +extern void ud_set_input_hook(struct ud*, int (*)(struct ud*)); + +extern void ud_set_input_buffer(struct ud*, uint8_t*, size_t); + +#ifndef __UD_STANDALONE__ +extern void ud_set_input_file(struct ud*, FILE*); +#endif /* __UD_STANDALONE__ */ + +extern void ud_set_vendor(struct ud*, unsigned); + +extern void ud_set_syntax(struct ud*, void (*)(struct ud*)); + +extern void ud_input_skip(struct ud*, size_t); + +extern int ud_input_end(struct ud*); + +extern unsigned int ud_decode(struct ud*); + +extern unsigned int ud_disassemble(struct ud*); + +extern void ud_translate_intel(struct ud*); + +extern void ud_translate_att(struct ud*); + +extern char* ud_insn_asm(struct ud* u); + +extern uint8_t* ud_insn_ptr(struct ud* u); + +extern uint64_t ud_insn_off(struct ud*); + +extern char* ud_insn_hex(struct ud*); + +extern unsigned int ud_insn_len(struct ud* u); + +extern const char* ud_lookup_mnemonic(enum ud_mnemonic_code c); + +extern void ud_set_user_opaque_data(struct ud*, void*); + +extern void *ud_get_user_opaque_data(struct ud*); + +/* ========================================================================== */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Source/JavaScriptCore/disassembler/udis86/udis86_input.c b/Source/JavaScriptCore/disassembler/udis86/udis86_input.c new file mode 100644 index 000000000..76c6cccf3 --- /dev/null +++ b/Source/JavaScriptCore/disassembler/udis86/udis86_input.c @@ -0,0 +1,263 @@ +/* udis86 - libudis86/input.c + * + * Copyright (c) 2002-2009 Vivek Thampi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 <wtf/Platform.h> + +#if USE(UDIS86) + +#include "udis86_extern.h" +#include "udis86_types.h" +#include "udis86_input.h" + +/* ----------------------------------------------------------------------------- + * inp_buff_hook() - Hook for buffered inputs. + * ----------------------------------------------------------------------------- + */ +static int +inp_buff_hook(struct ud* u) +{ + if (u->inp_buff < u->inp_buff_end) + return *u->inp_buff++; + else return -1; +} + +#ifndef __UD_STANDALONE__ +/* ----------------------------------------------------------------------------- + * inp_file_hook() - Hook for FILE inputs. + * ----------------------------------------------------------------------------- + */ +static int +inp_file_hook(struct ud* u) +{ + return fgetc(u->inp_file); +} +#endif /* __UD_STANDALONE__*/ + +/* ============================================================================= + * ud_inp_set_hook() - Sets input hook. + * ============================================================================= + */ +extern void +ud_set_input_hook(register struct ud* u, int (*hook)(struct ud*)) +{ + u->inp_hook = hook; + ud_inp_init(u); +} + +extern void +ud_set_user_opaque_data( struct ud * u, void * opaque ) +{ + u->user_opaque_data = opaque; +} + +extern void * +ud_get_user_opaque_data( struct ud * u ) +{ + return u->user_opaque_data; +} + +/* ============================================================================= + * ud_inp_set_buffer() - Set buffer as input. + * ============================================================================= + */ +extern void +ud_set_input_buffer(register struct ud* u, uint8_t* buf, size_t len) +{ + u->inp_hook = inp_buff_hook; + u->inp_buff = buf; + u->inp_buff_end = buf + len; + ud_inp_init(u); +} + +#ifndef __UD_STANDALONE__ +/* ============================================================================= + * ud_input_set_file() - Set buffer as input. + * ============================================================================= + */ +extern void +ud_set_input_file(register struct ud* u, FILE* f) +{ + u->inp_hook = inp_file_hook; + u->inp_file = f; + ud_inp_init(u); +} +#endif /* __UD_STANDALONE__ */ + +/* ============================================================================= + * ud_input_skip() - Skip n input bytes. + * ============================================================================= + */ +extern void +ud_input_skip(struct ud* u, size_t n) +{ + while (n--) { + u->inp_hook(u); + } +} + +/* ============================================================================= + * ud_input_end() - Test for end of input. + * ============================================================================= + */ +extern int +ud_input_end(struct ud* u) +{ + return (u->inp_curr == u->inp_fill) && u->inp_end; +} + +/* ----------------------------------------------------------------------------- + * ud_inp_next() - Loads and returns the next byte from input. + * + * inp_curr and inp_fill are pointers to the cache. The program is written based + * on the property that they are 8-bits in size, and will eventually wrap around + * forming a circular buffer. So, the size of the cache is 256 in size, kind of + * unnecessary yet optimized. + * + * A buffer inp_sess stores the bytes disassembled for a single session. + * ----------------------------------------------------------------------------- + */ +extern uint8_t ud_inp_next(struct ud* u) +{ + int c = -1; + /* if current pointer is not upto the fill point in the + * input cache. + */ + if ( u->inp_curr != u->inp_fill ) { + c = u->inp_cache[ ++u->inp_curr ]; + /* if !end-of-input, call the input hook and get a byte */ + } else if ( u->inp_end || ( c = u->inp_hook( u ) ) == -1 ) { + /* end-of-input, mark it as an error, since the decoder, + * expected a byte more. + */ + u->error = 1; + /* flag end of input */ + u->inp_end = 1; + return 0; + } else { + /* increment pointers, we have a new byte. */ + u->inp_curr = ++u->inp_fill; + /* add the byte to the cache */ + u->inp_cache[ u->inp_fill ] = c; + } + /* record bytes input per decode-session. */ + u->inp_sess[ u->inp_ctr++ ] = c; + /* return byte */ + return ( uint8_t ) c; +} + +/* ----------------------------------------------------------------------------- + * ud_inp_back() - Move back a single byte in the stream. + * ----------------------------------------------------------------------------- + */ +extern void +ud_inp_back(struct ud* u) +{ + if ( u->inp_ctr > 0 ) { + --u->inp_curr; + --u->inp_ctr; + } +} + +/* ----------------------------------------------------------------------------- + * ud_inp_peek() - Peek into the next byte in source. + * ----------------------------------------------------------------------------- + */ +extern uint8_t +ud_inp_peek(struct ud* u) +{ + uint8_t r = ud_inp_next(u); + if ( !u->error ) ud_inp_back(u); /* Don't backup if there was an error */ + return r; +} + +/* ----------------------------------------------------------------------------- + * ud_inp_move() - Move ahead n input bytes. + * ----------------------------------------------------------------------------- + */ +extern void +ud_inp_move(struct ud* u, size_t n) +{ + while (n--) + ud_inp_next(u); +} + +/*------------------------------------------------------------------------------ + * ud_inp_uintN() - return uintN from source. + *------------------------------------------------------------------------------ + */ +extern uint8_t +ud_inp_uint8(struct ud* u) +{ + return ud_inp_next(u); +} + +extern uint16_t +ud_inp_uint16(struct ud* u) +{ + uint16_t r, ret; + + ret = ud_inp_next(u); + r = ud_inp_next(u); + return ret | (r << 8); +} + +extern uint32_t +ud_inp_uint32(struct ud* u) +{ + uint32_t r, ret; + + ret = ud_inp_next(u); + r = ud_inp_next(u); + ret = ret | (r << 8); + r = ud_inp_next(u); + ret = ret | (r << 16); + r = ud_inp_next(u); + return ret | (r << 24); +} + +extern uint64_t +ud_inp_uint64(struct ud* u) +{ + uint64_t r, ret; + + ret = ud_inp_next(u); + r = ud_inp_next(u); + ret = ret | (r << 8); + r = ud_inp_next(u); + ret = ret | (r << 16); + r = ud_inp_next(u); + ret = ret | (r << 24); + r = ud_inp_next(u); + ret = ret | (r << 32); + r = ud_inp_next(u); + ret = ret | (r << 40); + r = ud_inp_next(u); + ret = ret | (r << 48); + r = ud_inp_next(u); + return ret | (r << 56); +} + +#endif // USE(UDIS86) diff --git a/Source/JavaScriptCore/disassembler/udis86/udis86_input.h b/Source/JavaScriptCore/disassembler/udis86/udis86_input.h new file mode 100644 index 000000000..96865a88b --- /dev/null +++ b/Source/JavaScriptCore/disassembler/udis86/udis86_input.h @@ -0,0 +1,67 @@ +/* udis86 - libudis86/input.h + * + * Copyright (c) 2002-2009 Vivek Thampi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 UD_INPUT_H +#define UD_INPUT_H + +#include "udis86_types.h" + +uint8_t ud_inp_next(struct ud*); +uint8_t ud_inp_peek(struct ud*); +uint8_t ud_inp_uint8(struct ud*); +uint16_t ud_inp_uint16(struct ud*); +uint32_t ud_inp_uint32(struct ud*); +uint64_t ud_inp_uint64(struct ud*); +void ud_inp_move(struct ud*, size_t); +void ud_inp_back(struct ud*); + +/* ud_inp_init() - Initializes the input system. */ +#define ud_inp_init(u) \ +do { \ + u->inp_curr = 0; \ + u->inp_fill = 0; \ + u->inp_ctr = 0; \ + u->inp_end = 0; \ +} while (0) + +/* ud_inp_start() - Should be called before each de-code operation. */ +#define ud_inp_start(u) u->inp_ctr = 0 + +/* ud_inp_back() - Resets the current pointer to its position before the current + * instruction disassembly was started. + */ +#define ud_inp_reset(u) \ +do { \ + u->inp_curr -= u->inp_ctr; \ + u->inp_ctr = 0; \ +} while (0) + +/* ud_inp_sess() - Returns the pointer to current session. */ +#define ud_inp_sess(u) (u->inp_sess) + +/* inp_cur() - Returns the current input byte. */ +#define ud_inp_curr(u) ((u)->inp_cache[(u)->inp_curr]) + +#endif diff --git a/Source/JavaScriptCore/disassembler/udis86/udis86_itab_holder.c b/Source/JavaScriptCore/disassembler/udis86/udis86_itab_holder.c new file mode 100644 index 000000000..d5d8726d6 --- /dev/null +++ b/Source/JavaScriptCore/disassembler/udis86/udis86_itab_holder.c @@ -0,0 +1,34 @@ +/* + * 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 <wtf/Platform.h> + +#if USE(UDIS86) + +#include "udis86_itab.c" + +#endif + diff --git a/Source/JavaScriptCore/disassembler/udis86/udis86_syn-att.c b/Source/JavaScriptCore/disassembler/udis86/udis86_syn-att.c new file mode 100644 index 000000000..132d6ff84 --- /dev/null +++ b/Source/JavaScriptCore/disassembler/udis86/udis86_syn-att.c @@ -0,0 +1,253 @@ +/* udis86 - libudis86/syn-att.c + * + * Copyright (c) 2002-2009 Vivek Thampi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 <wtf/Platform.h> + +#if USE(UDIS86) + +#include "udis86_types.h" +#include "udis86_extern.h" +#include "udis86_decode.h" +#include "udis86_itab.h" +#include "udis86_syn.h" + +/* ----------------------------------------------------------------------------- + * opr_cast() - Prints an operand cast. + * ----------------------------------------------------------------------------- + */ +static void +opr_cast(struct ud* u, struct ud_operand* op) +{ + switch(op->size) { + case 16 : case 32 : + mkasm(u, "*"); break; + default: break; + } +} + +/* ----------------------------------------------------------------------------- + * gen_operand() - Generates assembly output for each operand. + * ----------------------------------------------------------------------------- + */ +static void +gen_operand(struct ud* u, struct ud_operand* op) +{ + switch(op->type) { + case UD_OP_REG: + mkasm(u, "%%%s", ud_reg_tab[op->base - UD_R_AL]); + break; + + case UD_OP_MEM: + if (u->br_far) opr_cast(u, op); + if (u->pfx_seg) + mkasm(u, "%%%s:", ud_reg_tab[u->pfx_seg - UD_R_AL]); + if (op->offset == 8) { + if (op->lval.sbyte < 0) + mkasm(u, "-0x%x", (-op->lval.sbyte) & 0xff); + else mkasm(u, "0x%x", op->lval.sbyte); + } + else if (op->offset == 16) + mkasm(u, "0x%x", op->lval.uword); + else if (op->offset == 32) + mkasm(u, "0x%lx", (unsigned long)op->lval.udword); + else if (op->offset == 64) + mkasm(u, "0x" FMT64 "x", op->lval.uqword); + + if (op->base) + mkasm(u, "(%%%s", ud_reg_tab[op->base - UD_R_AL]); + if (op->index) { + if (op->base) + mkasm(u, ","); + else mkasm(u, "("); + mkasm(u, "%%%s", ud_reg_tab[op->index - UD_R_AL]); + } + if (op->scale) + mkasm(u, ",%d", op->scale); + if (op->base || op->index) + mkasm(u, ")"); + break; + + case UD_OP_IMM: { + int64_t imm = 0; + uint64_t sext_mask = 0xffffffffffffffffull; + unsigned sext_size = op->size; + + switch (op->size) { + case 8: imm = op->lval.sbyte; break; + case 16: imm = op->lval.sword; break; + case 32: imm = op->lval.sdword; break; + case 64: imm = op->lval.sqword; break; + } + if ( P_SEXT( u->itab_entry->prefix ) ) { + sext_size = u->operand[ 0 ].size; + if ( u->mnemonic == UD_Ipush ) + /* push sign-extends to operand size */ + sext_size = u->opr_mode; + } + if ( sext_size < 64 ) + sext_mask = ( 1ull << sext_size ) - 1; + mkasm( u, "0x" FMT64 "x", imm & sext_mask ); + + break; + } + + case UD_OP_JIMM: + switch (op->size) { + case 8: + mkasm(u, "0x" FMT64 "x", u->pc + op->lval.sbyte); + break; + case 16: + mkasm(u, "0x" FMT64 "x", (u->pc + op->lval.sword) & 0xffff ); + break; + case 32: + if (u->dis_mode == 32) + mkasm(u, "0x" FMT64 "x", (u->pc + op->lval.sdword) & 0xffffffff); + else + mkasm(u, "0x" FMT64 "x", u->pc + op->lval.sdword); + break; + default:break; + } + break; + + case UD_OP_PTR: + switch (op->size) { + case 32: + mkasm(u, "$0x%x, $0x%x", op->lval.ptr.seg, + op->lval.ptr.off & 0xFFFF); + break; + case 48: + mkasm(u, "$0x%x, $0x%lx", op->lval.ptr.seg, + (unsigned long)op->lval.ptr.off); + break; + } + break; + + default: return; + } +} + +/* ============================================================================= + * translates to AT&T syntax + * ============================================================================= + */ +extern void +ud_translate_att(struct ud *u) +{ + int size = 0; + + /* check if P_OSO prefix is used */ + if (! P_OSO(u->itab_entry->prefix) && u->pfx_opr) { + switch (u->dis_mode) { + case 16: + mkasm(u, "o32 "); + break; + case 32: + case 64: + mkasm(u, "o16 "); + break; + } + } + + /* check if P_ASO prefix was used */ + if (! P_ASO(u->itab_entry->prefix) && u->pfx_adr) { + switch (u->dis_mode) { + case 16: + mkasm(u, "a32 "); + break; + case 32: + mkasm(u, "a16 "); + break; + case 64: + mkasm(u, "a32 "); + break; + } + } + + if (u->pfx_lock) + mkasm(u, "lock "); + if (u->pfx_rep) + mkasm(u, "rep "); + if (u->pfx_repne) + mkasm(u, "repne "); + + /* special instructions */ + switch (u->mnemonic) { + case UD_Iretf: + mkasm(u, "lret "); + break; + case UD_Idb: + mkasm(u, ".byte 0x%x", u->operand[0].lval.ubyte); + return; + case UD_Ijmp: + case UD_Icall: + if (u->br_far) mkasm(u, "l"); + mkasm(u, "%s", ud_lookup_mnemonic(u->mnemonic)); + break; + case UD_Ibound: + case UD_Ienter: + if (u->operand[0].type != UD_NONE) + gen_operand(u, &u->operand[0]); + if (u->operand[1].type != UD_NONE) { + mkasm(u, ","); + gen_operand(u, &u->operand[1]); + } + return; + default: + mkasm(u, "%s", ud_lookup_mnemonic(u->mnemonic)); + } + + if (u->c1) + size = u->operand[0].size; + else if (u->c2) + size = u->operand[1].size; + else if (u->c3) + size = u->operand[2].size; + + if (size == 8) + mkasm(u, "b"); + else if (size == 16) + mkasm(u, "w"); + else if (size == 64) + mkasm(u, "q"); + + mkasm(u, " "); + + if (u->operand[2].type != UD_NONE) { + gen_operand(u, &u->operand[2]); + mkasm(u, ", "); + } + + if (u->operand[1].type != UD_NONE) { + gen_operand(u, &u->operand[1]); + mkasm(u, ", "); + } + + if (u->operand[0].type != UD_NONE) + gen_operand(u, &u->operand[0]); +} + +#endif // USE(UDIS86) + diff --git a/Source/JavaScriptCore/disassembler/udis86/udis86_syn-intel.c b/Source/JavaScriptCore/disassembler/udis86/udis86_syn-intel.c new file mode 100644 index 000000000..d250bd449 --- /dev/null +++ b/Source/JavaScriptCore/disassembler/udis86/udis86_syn-intel.c @@ -0,0 +1,279 @@ +/* udis86 - libudis86/syn-intel.c + * + * Copyright (c) 2002-2009 Vivek Thampi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 <wtf/Platform.h> + +#if USE(UDIS86) + +#include "udis86_types.h" +#include "udis86_extern.h" +#include "udis86_decode.h" +#include "udis86_itab.h" +#include "udis86_syn.h" + +/* ----------------------------------------------------------------------------- + * opr_cast() - Prints an operand cast. + * ----------------------------------------------------------------------------- + */ +static void +opr_cast(struct ud* u, struct ud_operand* op) +{ + switch(op->size) { + case 8: mkasm(u, "byte " ); break; + case 16: mkasm(u, "word " ); break; + case 32: mkasm(u, "dword "); break; + case 64: mkasm(u, "qword "); break; + case 80: mkasm(u, "tword "); break; + default: break; + } + if (u->br_far) + mkasm(u, "far "); +} + +/* ----------------------------------------------------------------------------- + * gen_operand() - Generates assembly output for each operand. + * ----------------------------------------------------------------------------- + */ +static void gen_operand(struct ud* u, struct ud_operand* op, int syn_cast) +{ + switch(op->type) { + case UD_OP_REG: + mkasm(u, "%s", ud_reg_tab[op->base - UD_R_AL]); + break; + + case UD_OP_MEM: { + + int op_f = 0; + + if (syn_cast) + opr_cast(u, op); + + mkasm(u, "["); + + if (u->pfx_seg) + mkasm(u, "%s:", ud_reg_tab[u->pfx_seg - UD_R_AL]); + + if (op->base) { + mkasm(u, "%s", ud_reg_tab[op->base - UD_R_AL]); + op_f = 1; + } + + if (op->index) { + if (op_f) + mkasm(u, "+"); + mkasm(u, "%s", ud_reg_tab[op->index - UD_R_AL]); + op_f = 1; + } + + if (op->scale) + mkasm(u, "*%d", op->scale); + + if (op->offset == 8) { + if (op->lval.sbyte < 0) + mkasm(u, "-0x%x", -op->lval.sbyte); + else mkasm(u, "%s0x%x", (op_f) ? "+" : "", op->lval.sbyte); + } + else if (op->offset == 16) + mkasm(u, "%s0x%x", (op_f) ? "+" : "", op->lval.uword); + else if (op->offset == 32) { + if (u->adr_mode == 64) { + if (op->lval.sdword < 0) + mkasm(u, "-0x%x", -op->lval.sdword); + else mkasm(u, "%s0x%x", (op_f) ? "+" : "", op->lval.sdword); + } + else mkasm(u, "%s0x%lx", (op_f) ? "+" : "", (unsigned long)op->lval.udword); + } + else if (op->offset == 64) + mkasm(u, "%s0x" FMT64 "x", (op_f) ? "+" : "", op->lval.uqword); + + mkasm(u, "]"); + break; + } + + case UD_OP_IMM: { + int64_t imm = 0; + uint64_t sext_mask = 0xffffffffffffffffull; + unsigned sext_size = op->size; + + if (syn_cast) + opr_cast(u, op); + switch (op->size) { + case 8: imm = op->lval.sbyte; break; + case 16: imm = op->lval.sword; break; + case 32: imm = op->lval.sdword; break; + case 64: imm = op->lval.sqword; break; + } + if ( P_SEXT( u->itab_entry->prefix ) ) { + sext_size = u->operand[ 0 ].size; + if ( u->mnemonic == UD_Ipush ) + /* push sign-extends to operand size */ + sext_size = u->opr_mode; + } + if ( sext_size < 64 ) + sext_mask = ( 1ull << sext_size ) - 1; + mkasm( u, "0x" FMT64 "x", imm & sext_mask ); + + break; + } + + + case UD_OP_JIMM: + if (syn_cast) opr_cast(u, op); + switch (op->size) { + case 8: + mkasm(u, "0x" FMT64 "x", u->pc + op->lval.sbyte); + break; + case 16: + mkasm(u, "0x" FMT64 "x", ( u->pc + op->lval.sword ) & 0xffff ); + break; + case 32: + mkasm(u, "0x" FMT64 "x", ( u->pc + op->lval.sdword ) & 0xfffffffful ); + break; + default:break; + } + break; + + case UD_OP_PTR: + switch (op->size) { + case 32: + mkasm(u, "word 0x%x:0x%x", op->lval.ptr.seg, + op->lval.ptr.off & 0xFFFF); + break; + case 48: + mkasm(u, "dword 0x%x:0x%lx", op->lval.ptr.seg, + (unsigned long)op->lval.ptr.off); + break; + } + break; + + case UD_OP_CONST: + if (syn_cast) opr_cast(u, op); + mkasm(u, "%d", op->lval.udword); + break; + + default: return; + } +} + +/* ============================================================================= + * translates to intel syntax + * ============================================================================= + */ +extern void ud_translate_intel(struct ud* u) +{ + /* -- prefixes -- */ + + /* check if P_OSO prefix is used */ + if (! P_OSO(u->itab_entry->prefix) && u->pfx_opr) { + switch (u->dis_mode) { + case 16: + mkasm(u, "o32 "); + break; + case 32: + case 64: + mkasm(u, "o16 "); + break; + } + } + + /* check if P_ASO prefix was used */ + if (! P_ASO(u->itab_entry->prefix) && u->pfx_adr) { + switch (u->dis_mode) { + case 16: + mkasm(u, "a32 "); + break; + case 32: + mkasm(u, "a16 "); + break; + case 64: + mkasm(u, "a32 "); + break; + } + } + + if ( u->pfx_seg && + u->operand[0].type != UD_OP_MEM && + u->operand[1].type != UD_OP_MEM ) { + mkasm(u, "%s ", ud_reg_tab[u->pfx_seg - UD_R_AL]); + } + if (u->pfx_lock) + mkasm(u, "lock "); + if (u->pfx_rep) + mkasm(u, "rep "); + if (u->pfx_repne) + mkasm(u, "repne "); + + /* print the instruction mnemonic */ + mkasm(u, "%s ", ud_lookup_mnemonic(u->mnemonic)); + + /* operand 1 */ + if (u->operand[0].type != UD_NONE) { + int cast = 0; + if ( u->operand[0].type == UD_OP_IMM && + u->operand[1].type == UD_NONE ) + cast = u->c1; + if ( u->operand[0].type == UD_OP_MEM ) { + cast = u->c1; + if ( u->operand[1].type == UD_OP_IMM || + u->operand[1].type == UD_OP_CONST ) + cast = 1; + if ( u->operand[1].type == UD_NONE ) + cast = 1; + if ( ( u->operand[0].size != u->operand[1].size ) && u->operand[1].size ) + cast = 1; + } else if ( u->operand[ 0 ].type == UD_OP_JIMM ) { + if ( u->operand[ 0 ].size > 8 ) cast = 1; + } + gen_operand(u, &u->operand[0], cast); + } + /* operand 2 */ + if (u->operand[1].type != UD_NONE) { + int cast = 0; + mkasm(u, ", "); + if ( u->operand[1].type == UD_OP_MEM ) { + cast = u->c1; + + if ( u->operand[0].type != UD_OP_REG ) + cast = 1; + if ( u->operand[0].size != u->operand[1].size && u->operand[1].size ) + cast = 1; + if ( u->operand[0].type == UD_OP_REG && + u->operand[0].base >= UD_R_ES && + u->operand[0].base <= UD_R_GS ) + cast = 0; + } + gen_operand(u, &u->operand[1], cast ); + } + + /* operand 3 */ + if (u->operand[2].type != UD_NONE) { + mkasm(u, ", "); + gen_operand(u, &u->operand[2], u->c3); + } +} + +#endif // USE(UDIS86) + diff --git a/Source/JavaScriptCore/disassembler/udis86/udis86_syn.c b/Source/JavaScriptCore/disassembler/udis86/udis86_syn.c new file mode 100644 index 000000000..80391b4a0 --- /dev/null +++ b/Source/JavaScriptCore/disassembler/udis86/udis86_syn.c @@ -0,0 +1,87 @@ +/* udis86 - libudis86/syn.c + * + * Copyright (c) 2002-2009 Vivek Thampi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 <wtf/Platform.h> + +#if USE(UDIS86) + +/* ----------------------------------------------------------------------------- + * Intel Register Table - Order Matters (types.h)! + * ----------------------------------------------------------------------------- + */ +const char* ud_reg_tab[] = +{ + "al", "cl", "dl", "bl", + "ah", "ch", "dh", "bh", + "spl", "bpl", "sil", "dil", + "r8b", "r9b", "r10b", "r11b", + "r12b", "r13b", "r14b", "r15b", + + "ax", "cx", "dx", "bx", + "sp", "bp", "si", "di", + "r8w", "r9w", "r10w", "r11w", + "r12w", "r13W" , "r14w", "r15w", + + "eax", "ecx", "edx", "ebx", + "esp", "ebp", "esi", "edi", + "r8d", "r9d", "r10d", "r11d", + "r12d", "r13d", "r14d", "r15d", + + "rax", "rcx", "rdx", "rbx", + "rsp", "rbp", "rsi", "rdi", + "r8", "r9", "r10", "r11", + "r12", "r13", "r14", "r15", + + "es", "cs", "ss", "ds", + "fs", "gs", + + "cr0", "cr1", "cr2", "cr3", + "cr4", "cr5", "cr6", "cr7", + "cr8", "cr9", "cr10", "cr11", + "cr12", "cr13", "cr14", "cr15", + + "dr0", "dr1", "dr2", "dr3", + "dr4", "dr5", "dr6", "dr7", + "dr8", "dr9", "dr10", "dr11", + "dr12", "dr13", "dr14", "dr15", + + "mm0", "mm1", "mm2", "mm3", + "mm4", "mm5", "mm6", "mm7", + + "st0", "st1", "st2", "st3", + "st4", "st5", "st6", "st7", + + "xmm0", "xmm1", "xmm2", "xmm3", + "xmm4", "xmm5", "xmm6", "xmm7", + "xmm8", "xmm9", "xmm10", "xmm11", + "xmm12", "xmm13", "xmm14", "xmm15", + + "rip" +}; + +#endif // USE(UDIS86) + diff --git a/Source/JavaScriptCore/disassembler/udis86/udis86_syn.h b/Source/JavaScriptCore/disassembler/udis86/udis86_syn.h new file mode 100644 index 000000000..e8636163e --- /dev/null +++ b/Source/JavaScriptCore/disassembler/udis86/udis86_syn.h @@ -0,0 +1,47 @@ +/* udis86 - libudis86/syn.h + * + * Copyright (c) 2002-2009 + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 UD_SYN_H +#define UD_SYN_H + +#include "udis86_types.h" +#include <wtf/Assertions.h> + +#ifndef __UD_STANDALONE__ +# include <stdarg.h> +#endif /* __UD_STANDALONE__ */ + +extern const char* ud_reg_tab[]; + +static void mkasm(struct ud* u, const char* fmt, ...) WTF_ATTRIBUTE_PRINTF(2, 3); +static void mkasm(struct ud* u, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + u->insn_fill += vsnprintf((char*) u->insn_buffer + u->insn_fill, UD_STRING_BUFFER_SIZE - u->insn_fill, fmt, ap); + va_end(ap); +} + +#endif diff --git a/Source/JavaScriptCore/disassembler/udis86/udis86_types.h b/Source/JavaScriptCore/disassembler/udis86/udis86_types.h new file mode 100644 index 000000000..320d1ca49 --- /dev/null +++ b/Source/JavaScriptCore/disassembler/udis86/udis86_types.h @@ -0,0 +1,238 @@ +/* udis86 - libudis86/types.h + * + * Copyright (c) 2002-2009 Vivek Thampi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 UD_TYPES_H +#define UD_TYPES_H + +#ifndef __UD_STANDALONE__ +# include <stdio.h> +#endif /* __UD_STANDALONE__ */ + +/* gcc specific extensions */ +#ifdef __GNUC__ +# define UD_ATTR_PACKED __attribute__((packed)) +#else +# define UD_ATTR_PACKED +#endif /* UD_ATTR_PACKED */ + +#ifdef _MSC_VER +# define FMT64 "%I64" + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int64 uint64_t; + typedef __int8 int8_t; + typedef __int16 int16_t; + typedef __int32 int32_t; + typedef __int64 int64_t; +#else +# define FMT64 "%ll" +# ifndef __UD_STANDALONE__ +# include <inttypes.h> +# endif /* __UD_STANDALONE__ */ +#endif + +/* ----------------------------------------------------------------------------- + * All possible "types" of objects in udis86. Order is Important! + * ----------------------------------------------------------------------------- + */ +enum ud_type +{ + UD_NONE, + + /* 8 bit GPRs */ + UD_R_AL, UD_R_CL, UD_R_DL, UD_R_BL, + UD_R_AH, UD_R_CH, UD_R_DH, UD_R_BH, + UD_R_SPL, UD_R_BPL, UD_R_SIL, UD_R_DIL, + UD_R_R8B, UD_R_R9B, UD_R_R10B, UD_R_R11B, + UD_R_R12B, UD_R_R13B, UD_R_R14B, UD_R_R15B, + + /* 16 bit GPRs */ + UD_R_AX, UD_R_CX, UD_R_DX, UD_R_BX, + UD_R_SP, UD_R_BP, UD_R_SI, UD_R_DI, + UD_R_R8W, UD_R_R9W, UD_R_R10W, UD_R_R11W, + UD_R_R12W, UD_R_R13W, UD_R_R14W, UD_R_R15W, + + /* 32 bit GPRs */ + UD_R_EAX, UD_R_ECX, UD_R_EDX, UD_R_EBX, + UD_R_ESP, UD_R_EBP, UD_R_ESI, UD_R_EDI, + UD_R_R8D, UD_R_R9D, UD_R_R10D, UD_R_R11D, + UD_R_R12D, UD_R_R13D, UD_R_R14D, UD_R_R15D, + + /* 64 bit GPRs */ + UD_R_RAX, UD_R_RCX, UD_R_RDX, UD_R_RBX, + UD_R_RSP, UD_R_RBP, UD_R_RSI, UD_R_RDI, + UD_R_R8, UD_R_R9, UD_R_R10, UD_R_R11, + UD_R_R12, UD_R_R13, UD_R_R14, UD_R_R15, + + /* segment registers */ + UD_R_ES, UD_R_CS, UD_R_SS, UD_R_DS, + UD_R_FS, UD_R_GS, + + /* control registers*/ + UD_R_CR0, UD_R_CR1, UD_R_CR2, UD_R_CR3, + UD_R_CR4, UD_R_CR5, UD_R_CR6, UD_R_CR7, + UD_R_CR8, UD_R_CR9, UD_R_CR10, UD_R_CR11, + UD_R_CR12, UD_R_CR13, UD_R_CR14, UD_R_CR15, + + /* debug registers */ + UD_R_DR0, UD_R_DR1, UD_R_DR2, UD_R_DR3, + UD_R_DR4, UD_R_DR5, UD_R_DR6, UD_R_DR7, + UD_R_DR8, UD_R_DR9, UD_R_DR10, UD_R_DR11, + UD_R_DR12, UD_R_DR13, UD_R_DR14, UD_R_DR15, + + /* mmx registers */ + UD_R_MM0, UD_R_MM1, UD_R_MM2, UD_R_MM3, + UD_R_MM4, UD_R_MM5, UD_R_MM6, UD_R_MM7, + + /* x87 registers */ + UD_R_ST0, UD_R_ST1, UD_R_ST2, UD_R_ST3, + UD_R_ST4, UD_R_ST5, UD_R_ST6, UD_R_ST7, + + /* extended multimedia registers */ + UD_R_XMM0, UD_R_XMM1, UD_R_XMM2, UD_R_XMM3, + UD_R_XMM4, UD_R_XMM5, UD_R_XMM6, UD_R_XMM7, + UD_R_XMM8, UD_R_XMM9, UD_R_XMM10, UD_R_XMM11, + UD_R_XMM12, UD_R_XMM13, UD_R_XMM14, UD_R_XMM15, + + UD_R_RIP, + + /* Operand Types */ + UD_OP_REG, UD_OP_MEM, UD_OP_PTR, UD_OP_IMM, + UD_OP_JIMM, UD_OP_CONST +}; + +#include "udis86_itab.h" + +/* ----------------------------------------------------------------------------- + * struct ud_operand - Disassembled instruction Operand. + * ----------------------------------------------------------------------------- + */ +struct ud_operand +{ + enum ud_type type; + uint8_t size; + union { + int8_t sbyte; + uint8_t ubyte; + int16_t sword; + uint16_t uword; + int32_t sdword; + uint32_t udword; + int64_t sqword; + uint64_t uqword; + + struct { + uint16_t seg; + uint32_t off; + } ptr; + } lval; + + enum ud_type base; + enum ud_type index; + uint8_t offset; + uint8_t scale; +}; + +#define UD_STRING_BUFFER_SIZE 64 + +/* ----------------------------------------------------------------------------- + * struct ud - The udis86 object. + * ----------------------------------------------------------------------------- + */ +struct ud +{ + int (*inp_hook) (struct ud*); + uint8_t inp_curr; + uint8_t inp_fill; +#ifndef __UD_STANDALONE__ + FILE* inp_file; +#endif + uint8_t inp_ctr; + uint8_t* inp_buff; + uint8_t* inp_buff_end; + uint8_t inp_end; + void (*translator)(struct ud*); + uint64_t insn_offset; + char insn_hexcode[32]; + char insn_buffer[UD_STRING_BUFFER_SIZE]; + unsigned int insn_fill; + uint8_t dis_mode; + uint64_t pc; + uint8_t vendor; + struct map_entry* mapen; + enum ud_mnemonic_code mnemonic; + struct ud_operand operand[3]; + uint8_t error; + uint8_t pfx_rex; + uint8_t pfx_seg; + uint8_t pfx_opr; + uint8_t pfx_adr; + uint8_t pfx_lock; + uint8_t pfx_rep; + uint8_t pfx_repe; + uint8_t pfx_repne; + uint8_t pfx_insn; + uint8_t default64; + uint8_t opr_mode; + uint8_t adr_mode; + uint8_t br_far; + uint8_t br_near; + uint8_t implicit_addr; + uint8_t c1; + uint8_t c2; + uint8_t c3; + uint8_t inp_cache[256]; + uint8_t inp_sess[64]; + uint8_t have_modrm; + uint8_t modrm; + void * user_opaque_data; + struct ud_itab_entry * itab_entry; + struct ud_lookup_table_list_entry *le; +}; + +/* ----------------------------------------------------------------------------- + * Type-definitions + * ----------------------------------------------------------------------------- + */ +typedef enum ud_type ud_type_t; +typedef enum ud_mnemonic_code ud_mnemonic_code_t; + +typedef struct ud ud_t; +typedef struct ud_operand ud_operand_t; + +#define UD_SYN_INTEL ud_translate_intel +#define UD_SYN_ATT ud_translate_att +#define UD_EOI -1 +#define UD_INP_CACHE_SZ 32 +#define UD_VENDOR_AMD 0 +#define UD_VENDOR_INTEL 1 +#define UD_VENDOR_ANY 2 + +#define bail_out(ud,error_code) longjmp( (ud)->bailout, error_code ) +#define try_decode(ud) if ( setjmp( (ud)->bailout ) == 0 ) +#define catch_error() else + +#endif diff --git a/Source/JavaScriptCore/gyp/JavaScriptCore.gyp b/Source/JavaScriptCore/gyp/JavaScriptCore.gyp deleted file mode 100644 index 8a93f1d53..000000000 --- a/Source/JavaScriptCore/gyp/JavaScriptCore.gyp +++ /dev/null @@ -1,227 +0,0 @@ -{ - 'includes': [ - '../../gyp/common.gypi', - '../JavaScriptCore.gypi', - ], - 'configurations': { - 'Production': { - 'xcode_config_file': '<(project_dir)/Configurations/Base.xcconfig', - }, - 'Profiling': { - 'xcode_config_file': '<(project_dir)/Configurations/DebugRelease.xcconfig', - 'xcode_settings': { - 'STRIP_INSTALLED_PRODUCT': 'NO', - }, - }, - 'Release': { - 'xcode_config_file': '<(project_dir)/Configurations/DebugRelease.xcconfig', - 'xcode_settings': { - 'STRIP_INSTALLED_PRODUCT': 'NO', - }, - }, - 'Debug': { - 'xcode_config_file': '<(project_dir)/Configurations/DebugRelease.xcconfig', - 'xcode_settings': { - 'DEAD_CODE_STRIPPING': '$(DEAD_CODE_STRIPPING_debug)', - 'DEBUG_DEFINES': '$(DEBUG_DEFINES_debug)', - 'GCC_OPTIMIZATION_LEVEL': '$(GCC_OPTIMIZATION_LEVEL_debug)', - 'STRIP_INSTALLED_PRODUCT': '$(STRIP_INSTALLED_PRODUCT_debug)', - }, - }, - }, - 'variables': { - 'javascriptcore_include_dirs': [ - '<(project_dir)', - '<(project_dir)/icu', - ], - }, - 'target_defaults': { - 'configurations': { - 'Profiling': {}, - }, - }, - 'targets': [ - { - 'target_name': 'JavaScriptCore', - 'type': 'shared_library', - 'dependencies': [ - 'Derived Sources', - 'Update Version', - ], - 'include_dirs': [ - '<@(javascriptcore_include_dirs)', - '<(PRODUCT_DIR)/DerivedSources/JavaScriptCore', - ], - 'configurations': { - 'Production': { - 'INSTALL_PATH': '$(BUILT_PRODUCTS_DIR)', - }, - }, - 'sources': [ - '<@(javascriptcore_files)', - '<@(javascriptcore_publicheader_files)', - '<@(javascriptcore_privateheader_files)', - '<@(javascriptcore_derived_source_files)', - '$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework', - '$(SDKROOT)/System/Library/Frameworks/Foundation.framework', - '/usr/lib/libicucore.dylib', - '/usr/lib/libobjc.dylib', - ], - 'mac_framework_headers': [ - '<@(javascriptcore_publicheader_files)', - ], - 'mac_framework_private_headers': [ - '<@(javascriptcore_privateheader_files)', - ], - 'xcode_config_file': '<(project_dir)/Configurations/JavaScriptCore.xcconfig', - 'sources/': [ - ['exclude', 'API/tests/'], - ['exclude', 'ForwardingHeaders/'], - ['exclude', '(?<!unicode)/icu/'], - ['exclude', 'os-win32/'], - ['exclude', 'qt/'], - ['exclude', 'wtf/(efl|gtk|qt|wince|wx)/'], - ['exclude', 'wtf/unicode/glib/'], - ['exclude', 'wtf/unicode/qt4/'], - ['exclude', 'wtf/unicode/wince/'], - ['exclude', 'wtf/url/'], - ['exclude', '/(gtk|glib|gobject)/.*\\.(cpp|h)$'], - ['exclude', '(Default|Gtk|Chromium|None|Qt|Win|Wx|Symbian)\\.(cpp|mm|h)$'], - ['exclude', 'GCActivityCallback\.cpp$'], - ['exclude', 'BSTR[^/]*$'], - ], - 'postbuilds': [ - { - 'postbuild_name': 'Check For Global Initializers', - 'action': [ - 'sh', '<(project_dir)/gyp/run-if-exists.sh', '<(DEPTH)/../Tools/Scripts/check-for-global-initializers' - ], - }, - { - 'postbuild_name': 'Check For Exit Time Destructors', - 'action': [ - 'sh', '<(project_dir)/gyp/run-if-exists.sh', '<(DEPTH)/../Tools/Scripts/check-for-exit-time-destructors' - ], - }, - { - 'postbuild_name': 'Check For Weak VTables and Externals', - 'action': [ - 'sh', '<(project_dir)/gyp/run-if-exists.sh', '<(DEPTH)/../Tools/Scripts/check-for-weak-vtables-and-externals' - ], - }, - ], - 'conditions': [ - ['OS=="mac"', { - 'mac_bundle': 1, - 'xcode_settings': { - # FIXME: Remove these overrides once JavaScriptCore.xcconfig is - # used only by this project. - 'GCC_PREFIX_HEADER': '<(project_dir)/JavaScriptCorePrefix.h', - 'INFOPLIST_FILE': '<(project_dir)/Info.plist', - }, - }], - ], - }, - { - 'target_name': 'Derived Sources', - 'type': 'none', - 'actions': [ - { - 'action_name': 'Generate Derived Sources', - 'inputs': [], - 'outputs': [ - '<@(javascriptcore_derived_source_files)', - ], - 'action': [ - 'sh', 'generate-derived-sources.sh' - ], - }, - { - 'action_name': 'Generate DTrace Header', - 'inputs': [], - 'outputs': [], - 'action': [ - 'sh', '<(project_dir)/gyp/generate-dtrace-header.sh', '<(project_dir)' - ] - } - ], - }, - { - 'target_name': 'Update Version', - 'type': 'none', - 'actions': [{ - 'action_name': 'Update Info.plist with version information', - 'inputs': [], - 'outputs': [], - 'action': [ - 'sh', '<(project_dir)/gyp/update-info-plist.sh', '<(project_dir)/Info.plist' - ] - }], - }, - { - 'target_name': 'minidom', - 'type': 'executable', - 'dependencies': [ - 'JavaScriptCore', - ], - # FIXME: We should use a header map instead of listing these explicitly. - 'include_dirs': [ - '<@(javascriptcore_include_dirs)', - ], - 'sources': [ - '<@(minidom_files)', - '$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework', - ], - 'copies': [{ - 'destination': '<(PRODUCT_DIR)', - 'files': [ - '<@(minidom_support_files)', - ], - }], - }, - { - 'target_name': 'testapi', - 'type': 'executable', - 'dependencies': [ - 'JavaScriptCore', - ], - # FIXME: We should use a header map instead of listing these explicitly. - 'include_dirs': [ - '<@(javascriptcore_include_dirs)', - ], - 'sources': [ - '<@(testapi_files)', - '$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework', - ], - 'copies': [{ - 'destination': '<(PRODUCT_DIR)', - 'files': [ - '<@(testapi_support_files)', - ], - }], - }, - { - 'target_name': 'jsc', - 'type': 'executable', - 'dependencies': [ - 'JavaScriptCore', - ], - # FIXME: We should use a header map instead of listing these explicitly. - 'include_dirs': [ - '<@(javascriptcore_include_dirs)', - ], - 'configurations': { - 'Production': { - 'xcode_settings': { - 'INSTALL_PATH': '$(JAVASCRIPTCORE_FRAMEWORKS_DIR)/JavaScriptCore.framework/Resources', - }, - }, - }, - 'sources': [ - '<@(jsc_files)', - '$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework', - '/usr/lib/libedit.dylib', - ], - }, - ], # targets -} diff --git a/Source/JavaScriptCore/gyp/gtk.gyp b/Source/JavaScriptCore/gyp/gtk.gyp deleted file mode 100644 index 33eaa17a2..000000000 --- a/Source/JavaScriptCore/gyp/gtk.gyp +++ /dev/null @@ -1,18 +0,0 @@ -{ # Just a stub file to allow Source/gyp/configure to run successfully for testing. - 'includes': [ - '../../gyp/common.gypi', - '../JavaScriptCore.gypi', - ], - 'targets': [ - { - 'target_name': 'JavaScriptCore', - 'type': 'static_library', - 'sources': [ - '<@(javascriptcore_files)', - '<@(javascriptcore_publicheader_files)', - '<@(javascriptcore_privateheader_files)', - '<@(javascriptcore_derived_source_files)', - ], - }, - ], # targets -} diff --git a/Source/JavaScriptCore/heap/BlockAllocator.cpp b/Source/JavaScriptCore/heap/BlockAllocator.cpp index 485ec8dd1..fc4f8a4c6 100644 --- a/Source/JavaScriptCore/heap/BlockAllocator.cpp +++ b/Source/JavaScriptCore/heap/BlockAllocator.cpp @@ -37,13 +37,15 @@ BlockAllocator::BlockAllocator() , m_blockFreeingThread(createThread(blockFreeingThreadStartFunc, this, "JavaScriptCore::BlockFree")) { ASSERT(m_blockFreeingThread); + m_freeBlockLock.Init(); } BlockAllocator::~BlockAllocator() { releaseFreeBlocks(); { - MutexLocker locker(m_freeBlockLock); + MutexLocker locker(m_freeBlockConditionLock); + m_blockFreeingThreadShouldQuit = true; m_freeBlockCondition.broadcast(); } @@ -55,7 +57,7 @@ void BlockAllocator::releaseFreeBlocks() while (true) { HeapBlock* block; { - MutexLocker locker(m_freeBlockLock); + SpinLockHolder locker(&m_freeBlockLock); if (!m_numberOfFreeBlocks) block = 0; else { @@ -76,7 +78,8 @@ void BlockAllocator::waitForRelativeTimeWhileHoldingLock(double relative) { if (m_blockFreeingThreadShouldQuit) return; - m_freeBlockCondition.timedWait(m_freeBlockLock, currentTime() + relative); + + m_freeBlockCondition.timedWait(m_freeBlockConditionLock, currentTime() + relative); } void BlockAllocator::waitForRelativeTime(double relative) @@ -85,7 +88,7 @@ void BlockAllocator::waitForRelativeTime(double relative) // frequently. It would only be a bug if this function failed to return // when it was asked to do so. - MutexLocker locker(m_freeBlockLock); + MutexLocker locker(m_freeBlockConditionLock); waitForRelativeTimeWhileHoldingLock(relative); } @@ -120,7 +123,7 @@ void BlockAllocator::blockFreeingThreadMain() while (!m_blockFreeingThreadShouldQuit) { HeapBlock* block; { - MutexLocker locker(m_freeBlockLock); + SpinLockHolder locker(&m_freeBlockLock); if (m_numberOfFreeBlocks <= desiredNumberOfFreeBlocks) block = 0; else { diff --git a/Source/JavaScriptCore/heap/BlockAllocator.h b/Source/JavaScriptCore/heap/BlockAllocator.h index 846bdfa2a..7a99d2edd 100644 --- a/Source/JavaScriptCore/heap/BlockAllocator.h +++ b/Source/JavaScriptCore/heap/BlockAllocator.h @@ -30,6 +30,7 @@ #include <wtf/DoublyLinkedList.h> #include <wtf/Forward.h> #include <wtf/PageAllocationAligned.h> +#include <wtf/TCSpinLock.h> #include <wtf/Threading.h> namespace JSC { @@ -58,19 +59,22 @@ private: size_t m_numberOfFreeBlocks; bool m_isCurrentlyAllocating; bool m_blockFreeingThreadShouldQuit; - Mutex m_freeBlockLock; + SpinLock m_freeBlockLock; + Mutex m_freeBlockConditionLock; ThreadCondition m_freeBlockCondition; ThreadIdentifier m_blockFreeingThread; }; inline PageAllocationAligned BlockAllocator::allocate() { - MutexLocker locker(m_freeBlockLock); - m_isCurrentlyAllocating = true; - if (m_numberOfFreeBlocks) { - ASSERT(!m_freeBlocks.isEmpty()); - m_numberOfFreeBlocks--; - return m_freeBlocks.removeHead()->m_allocation; + { + SpinLockHolder locker(&m_freeBlockLock); + m_isCurrentlyAllocating = true; + if (m_numberOfFreeBlocks) { + ASSERT(!m_freeBlocks.isEmpty()); + m_numberOfFreeBlocks--; + return m_freeBlocks.removeHead()->m_allocation; + } } ASSERT(m_freeBlocks.isEmpty()); @@ -82,7 +86,7 @@ inline PageAllocationAligned BlockAllocator::allocate() inline void BlockAllocator::deallocate(PageAllocationAligned allocation) { - MutexLocker locker(m_freeBlockLock); + SpinLockHolder locker(&m_freeBlockLock); HeapBlock* heapBlock = new(NotNull, allocation.base()) HeapBlock(allocation); m_freeBlocks.push(heapBlock); m_numberOfFreeBlocks++; diff --git a/Source/JavaScriptCore/heap/CopiedBlock.h b/Source/JavaScriptCore/heap/CopiedBlock.h index b408aa40b..5ed58008e 100644 --- a/Source/JavaScriptCore/heap/CopiedBlock.h +++ b/Source/JavaScriptCore/heap/CopiedBlock.h @@ -39,6 +39,7 @@ class CopiedBlock : public HeapBlock { friend class CopiedAllocator; public: static CopiedBlock* create(const PageAllocationAligned&); + static CopiedBlock* createNoZeroFill(const PageAllocationAligned&); static PageAllocationAligned destroy(CopiedBlock*); char* payload(); @@ -47,16 +48,37 @@ public: private: CopiedBlock(const PageAllocationAligned&); + void zeroFillToEnd(); // Can be called at any time to zero-fill to the end of the block. void* m_offset; uintptr_t m_isPinned; }; -inline CopiedBlock* CopiedBlock::create(const PageAllocationAligned& allocation) +inline CopiedBlock* CopiedBlock::createNoZeroFill(const PageAllocationAligned& allocation) { return new(NotNull, allocation.base()) CopiedBlock(allocation); } +inline CopiedBlock* CopiedBlock::create(const PageAllocationAligned& allocation) +{ + CopiedBlock* block = createNoZeroFill(allocation); + block->zeroFillToEnd(); + return block; +} + +inline void CopiedBlock::zeroFillToEnd() +{ +#if USE(JSVALUE64) + char* offset = static_cast<char*>(m_offset); + memset(static_cast<void*>(offset), 0, static_cast<size_t>((reinterpret_cast<char*>(this) + m_allocation.size()) - offset)); +#else + JSValue emptyValue; + JSValue* limit = reinterpret_cast_ptr<JSValue*>(reinterpret_cast<char*>(this) + m_allocation.size()); + for (JSValue* currentValue = reinterpret_cast<JSValue*>(m_offset); currentValue < limit; currentValue++) + *currentValue = emptyValue; +#endif +} + inline PageAllocationAligned CopiedBlock::destroy(CopiedBlock* block) { PageAllocationAligned allocation; @@ -72,15 +94,6 @@ inline CopiedBlock::CopiedBlock(const PageAllocationAligned& allocation) , m_isPinned(false) { ASSERT(is8ByteAligned(static_cast<void*>(m_offset))); -#if USE(JSVALUE64) - char* offset = static_cast<char*>(m_offset); - memset(static_cast<void*>(offset), 0, static_cast<size_t>((reinterpret_cast<char*>(this) + allocation.size()) - offset)); -#else - JSValue emptyValue; - JSValue* limit = reinterpret_cast_ptr<JSValue*>(reinterpret_cast<char*>(this) + allocation.size()); - for (JSValue* currentValue = reinterpret_cast<JSValue*>(m_offset); currentValue < limit; currentValue++) - *currentValue = emptyValue; -#endif } inline char* CopiedBlock::payload() diff --git a/Source/JavaScriptCore/heap/CopiedSpace.cpp b/Source/JavaScriptCore/heap/CopiedSpace.cpp index 7f5a665df..631e829ec 100644 --- a/Source/JavaScriptCore/heap/CopiedSpace.cpp +++ b/Source/JavaScriptCore/heap/CopiedSpace.cpp @@ -38,6 +38,7 @@ CopiedSpace::CopiedSpace(Heap* heap) , m_inCopyingPhase(false) , m_numberOfLoanedBlocks(0) { + m_toSpaceLock.Init(); } CopiedSpace::~CopiedSpace() @@ -57,8 +58,7 @@ void CopiedSpace::init() m_toSpace = &m_blocks1; m_fromSpace = &m_blocks2; - if (!addNewBlock()) - CRASH(); + allocateBlock(); } CheckedBoolean CopiedSpace::tryAllocateSlowCase(size_t bytes, void** outPtr) @@ -68,10 +68,8 @@ CheckedBoolean CopiedSpace::tryAllocateSlowCase(size_t bytes, void** outPtr) m_heap->didAllocate(m_allocator.currentCapacity()); - if (!addNewBlock()) { - *outPtr = 0; - return false; - } + allocateBlock(); + *outPtr = m_allocator.allocate(bytes); ASSERT(*outPtr); return true; @@ -167,8 +165,10 @@ void CopiedSpace::doneFillingBlock(CopiedBlock* block) return; } + block->zeroFillToEnd(); + { - MutexLocker locker(m_toSpaceLock); + SpinLockHolder locker(&m_toSpaceLock); m_toSpace->push(block); m_blockSet.add(block); m_blockFilter.add(reinterpret_cast<Bits>(block)); @@ -222,35 +222,12 @@ void CopiedSpace::doneCopying() curr = next; } - if (!m_toSpace->head()) { - if (!addNewBlock()) - CRASH(); - } else + if (!m_toSpace->head()) + allocateBlock(); + else m_allocator.resetCurrentBlock(static_cast<CopiedBlock*>(m_toSpace->head())); } -CheckedBoolean CopiedSpace::getFreshBlock(AllocationEffort allocationEffort, CopiedBlock** outBlock) -{ - CopiedBlock* block = 0; - if (allocationEffort == AllocationMustSucceed) - block = CopiedBlock::create(m_heap->blockAllocator().allocate()); - else { - ASSERT(allocationEffort == AllocationCanFail); - if (m_heap->shouldCollect()) - m_heap->collect(Heap::DoNotSweep); - - if (!getFreshBlock(AllocationMustSucceed, &block)) { - *outBlock = 0; - ASSERT_NOT_REACHED(); - return false; - } - } - ASSERT(block); - ASSERT(is8ByteAligned(block->m_offset)); - *outBlock = block; - return true; -} - size_t CopiedSpace::size() { size_t calculatedSize = 0; diff --git a/Source/JavaScriptCore/heap/CopiedSpace.h b/Source/JavaScriptCore/heap/CopiedSpace.h index 27011781d..530e989da 100644 --- a/Source/JavaScriptCore/heap/CopiedSpace.h +++ b/Source/JavaScriptCore/heap/CopiedSpace.h @@ -37,6 +37,7 @@ #include <wtf/PageAllocationAligned.h> #include <wtf/PageBlock.h> #include <wtf/StdLibExtras.h> +#include <wtf/TCSpinLock.h> #include <wtf/ThreadingPrimitives.h> namespace JSC { @@ -76,22 +77,20 @@ public: static CopiedBlock* blockFor(void*); private: - CheckedBoolean tryAllocateSlowCase(size_t, void**); - CheckedBoolean addNewBlock(); - CheckedBoolean allocateNewBlock(CopiedBlock**); - static void* allocateFromBlock(CopiedBlock*, size_t); + static bool isOversize(size_t); + static bool fitsInBlock(CopiedBlock*, size_t); + static CopiedBlock* oversizeBlockFor(void* ptr); + + CheckedBoolean tryAllocateSlowCase(size_t, void**); CheckedBoolean tryAllocateOversize(size_t, void**); CheckedBoolean tryReallocateOversize(void**, size_t, size_t); - static bool isOversize(size_t); - - CheckedBoolean borrowBlock(CopiedBlock**); - CheckedBoolean getFreshBlock(AllocationEffort, CopiedBlock**); + void allocateBlock(); + CopiedBlock* allocateBlockForCopyingPhase(); + void doneFillingBlock(CopiedBlock*); void recycleBlock(CopiedBlock*); - static bool fitsInBlock(CopiedBlock*, size_t); - static CopiedBlock* oversizeBlockFor(void* ptr); Heap* m_heap; @@ -100,7 +99,7 @@ private: TinyBloomFilter m_blockFilter; HashSet<CopiedBlock*> m_blockSet; - Mutex m_toSpaceLock; + SpinLock m_toSpaceLock; DoublyLinkedList<HeapBlock>* m_toSpace; DoublyLinkedList<HeapBlock>* m_fromSpace; diff --git a/Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h b/Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h index c97762598..1366cd8a7 100644 --- a/Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h +++ b/Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h @@ -84,46 +84,31 @@ inline void CopiedSpace::recycleBlock(CopiedBlock* block) } } -inline CheckedBoolean CopiedSpace::borrowBlock(CopiedBlock** outBlock) +inline CopiedBlock* CopiedSpace::allocateBlockForCopyingPhase() { - CopiedBlock* block = 0; - if (!getFreshBlock(AllocationMustSucceed, &block)) { - *outBlock = 0; - return false; - } - ASSERT(m_inCopyingPhase); - MutexLocker locker(m_loanedBlocksLock); - m_numberOfLoanedBlocks++; + CopiedBlock* block = CopiedBlock::createNoZeroFill(m_heap->blockAllocator().allocate()); + + { + MutexLocker locker(m_loanedBlocksLock); + m_numberOfLoanedBlocks++; + } ASSERT(block->m_offset == block->payload()); - *outBlock = block; - return true; + return block; } -inline CheckedBoolean CopiedSpace::addNewBlock() +inline void CopiedSpace::allocateBlock() { - CopiedBlock* block = 0; - if (!getFreshBlock(AllocationCanFail, &block)) - return false; + if (m_heap->shouldCollect()) + m_heap->collect(Heap::DoNotSweep); + + CopiedBlock* block = CopiedBlock::create(m_heap->blockAllocator().allocate()); m_toSpace->push(block); m_blockFilter.add(reinterpret_cast<Bits>(block)); m_blockSet.add(block); m_allocator.resetCurrentBlock(block); - return true; -} - -inline CheckedBoolean CopiedSpace::allocateNewBlock(CopiedBlock** outBlock) -{ - PageAllocationAligned allocation = PageAllocationAligned::allocate(HeapBlock::s_blockSize, HeapBlock::s_blockSize, OSAllocator::JSGCHeapPages); - if (!static_cast<bool>(allocation)) { - *outBlock = 0; - return false; - } - - *outBlock = new (NotNull, allocation.base()) CopiedBlock(allocation); - return true; } inline bool CopiedSpace::fitsInBlock(CopiedBlock* block, size_t bytes) diff --git a/Source/JavaScriptCore/heap/Handle.h b/Source/JavaScriptCore/heap/Handle.h index 8bf2bd896..62f267e12 100644 --- a/Source/JavaScriptCore/heap/Handle.h +++ b/Source/JavaScriptCore/heap/Handle.h @@ -114,7 +114,7 @@ private: template <typename T> class Handle : public HandleBase, public HandleConverter<Handle<T>, T> { public: - template <typename A, typename B> friend class HandleConverter; + template <typename A, typename B> friend struct HandleConverter; typedef typename HandleTypes<T>::ExternalType ExternalType; template <typename U> Handle(Handle<U> o) { diff --git a/Source/JavaScriptCore/heap/Heap.cpp b/Source/JavaScriptCore/heap/Heap.cpp index 90c4bb72c..ef062c9ce 100644 --- a/Source/JavaScriptCore/heap/Heap.cpp +++ b/Source/JavaScriptCore/heap/Heap.cpp @@ -245,8 +245,6 @@ Heap::Heap(JSGlobalData* globalData, HeapType heapType) , m_operationInProgress(NoOperation) , m_objectSpace(this) , m_storageSpace(this) - , m_activityCallback(DefaultGCActivityCallback::create(this)) - , m_sweeper(IncrementalSweeper::create(this)) , m_machineThreads(this) , m_sharedData(globalData) , m_slotVisitor(m_sharedData) @@ -255,6 +253,8 @@ Heap::Heap(JSGlobalData* globalData, HeapType heapType) , m_globalData(globalData) , m_lastGCLength(0) , m_lastCodeDiscardTime(WTF::currentTime()) + , m_activityCallback(DefaultGCActivityCallback::create(this)) + , m_sweeper(IncrementalSweeper::create(this)) { m_storageSpace.init(); } @@ -403,9 +403,6 @@ inline RegisterFile& Heap::registerFile() void Heap::getConservativeRegisterRoots(HashSet<JSCell*>& roots) { ASSERT(isValidThreadState(m_globalData)); - if (m_operationInProgress != NoOperation) - CRASH(); - m_operationInProgress = Collection; ConservativeRoots registerFileRoots(&m_objectSpace.blocks(), &m_storageSpace); registerFile().gatherConservativeRoots(registerFileRoots); size_t registerFileRootCount = registerFileRoots.size(); @@ -414,7 +411,6 @@ void Heap::getConservativeRegisterRoots(HashSet<JSCell*>& roots) setMarked(registerRoots[i]); roots.add(registerRoots[i]); } - m_operationInProgress = NoOperation; } void Heap::markRoots(bool fullGC) @@ -424,9 +420,10 @@ void Heap::markRoots(bool fullGC) COND_GCPHASE(fullGC, MarkFullRoots, MarkYoungRoots); UNUSED_PARAM(fullGC); ASSERT(isValidThreadState(m_globalData)); - if (m_operationInProgress != NoOperation) - CRASH(); - m_operationInProgress = Collection; + +#if ENABLE(OBJECT_MARK_LOGGING) + double gcStartTime = WTF::currentTime(); +#endif void* dummy; @@ -491,28 +488,33 @@ void Heap::markRoots(bool fullGC) { GCPHASE(VisitMachineRoots); + MARK_LOG_ROOT(visitor, "C++ Stack"); visitor.append(machineThreadRoots); visitor.donateAndDrain(); } { GCPHASE(VisitRegisterFileRoots); + MARK_LOG_ROOT(visitor, "Register File"); visitor.append(registerFileRoots); visitor.donateAndDrain(); } #if ENABLE(DFG_JIT) { GCPHASE(VisitScratchBufferRoots); + MARK_LOG_ROOT(visitor, "Scratch Buffers"); visitor.append(scratchBufferRoots); visitor.donateAndDrain(); } #endif { GCPHASE(VisitProtectedObjects); + MARK_LOG_ROOT(visitor, "Protected Objects"); markProtectedObjects(heapRootVisitor); visitor.donateAndDrain(); } { GCPHASE(VisitTempSortVectors); + MARK_LOG_ROOT(visitor, "Temp Sort Vectors"); markTempSortVectors(heapRootVisitor); visitor.donateAndDrain(); } @@ -520,30 +522,35 @@ void Heap::markRoots(bool fullGC) { GCPHASE(MarkingArgumentBuffers); if (m_markListSet && m_markListSet->size()) { + MARK_LOG_ROOT(visitor, "Argument Buffers"); MarkedArgumentBuffer::markLists(heapRootVisitor, *m_markListSet); visitor.donateAndDrain(); } } if (m_globalData->exception) { GCPHASE(MarkingException); + MARK_LOG_ROOT(visitor, "Exceptions"); heapRootVisitor.visit(&m_globalData->exception); visitor.donateAndDrain(); } { GCPHASE(VisitStrongHandles); + MARK_LOG_ROOT(visitor, "Strong Handles"); m_handleSet.visitStrongHandles(heapRootVisitor); visitor.donateAndDrain(); } { GCPHASE(HandleStack); + MARK_LOG_ROOT(visitor, "Handle Stack"); m_handleStack.visit(heapRootVisitor); visitor.donateAndDrain(); } { GCPHASE(TraceCodeBlocks); + MARK_LOG_ROOT(visitor, "Trace Code Blocks"); m_dfgCodeBlocks.traceMarkedCodeBlocks(visitor); visitor.donateAndDrain(); } @@ -560,6 +567,7 @@ void Heap::markRoots(bool fullGC) // the liveness of the rest of the object graph. { GCPHASE(VisitingLiveWeakHandles); + MARK_LOG_ROOT(visitor, "Live Weak Handles"); while (true) { m_objectSpace.visitWeakSets(heapRootVisitor); harvestWeakReferences(); @@ -578,11 +586,21 @@ void Heap::markRoots(bool fullGC) GCCOUNTER(VisitedValueCount, visitor.visitCount()); visitor.doneCopying(); +#if ENABLE(OBJECT_MARK_LOGGING) + size_t visitCount = visitor.visitCount(); +#if ENABLE(PARALLEL_GC) + visitCount += m_sharedData.childVisitCount(); +#endif + MARK_LOG_MESSAGE2("\nNumber of live Objects after full GC %lu, took %.6f secs\n", visitCount, WTF::currentTime() - gcStartTime); +#endif + visitor.reset(); m_sharedData.reset(); +#if ENABLE(PARALLEL_GC) + m_sharedData.resetChildren(); +#endif m_storageSpace.doneCopying(); - m_operationInProgress = NoOperation; } size_t Heap::objectCount() @@ -625,15 +643,38 @@ PassOwnPtr<TypeCountSet> Heap::objectTypeCounts() return m_objectSpace.forEachCell<RecordType>(); } -void Heap::discardAllCompiledCode() +void Heap::deleteAllCompiledCode() { - // If JavaScript is running, it's not safe to recompile, since we'll end - // up throwing away code that is live on the stack. + // If JavaScript is running, it's not safe to delete code, since we'll end + // up deleting code that is live on the stack. if (m_globalData->dynamicGlobalObject) return; - for (FunctionExecutable* current = m_functions.head(); current; current = current->next()) - current->discardCode(); + for (ExecutableBase* current = m_compiledCode.head(); current; current = current->next()) { + if (!current->isFunctionExecutable()) + continue; + static_cast<FunctionExecutable*>(current)->clearCodeIfNotCompiling(); + } + + m_dfgCodeBlocks.clearMarks(); + m_dfgCodeBlocks.deleteUnmarkedJettisonedCodeBlocks(); +} + +void Heap::deleteUnmarkedCompiledCode() +{ + ExecutableBase* next; + for (ExecutableBase* current = m_compiledCode.head(); current; current = next) { + next = current->next(); + if (isMarked(current)) + continue; + + // We do this because executable memory is limited on some platforms and because + // CodeBlock requires eager finalization. + ExecutableBase::clearCodeVirtual(current); + m_compiledCode.remove(current); + } + + m_dfgCodeBlocks.deleteUnmarkedJettisonedCodeBlocks(); } void Heap::collectAllGarbage() @@ -654,12 +695,15 @@ void Heap::collect(SweepToggle sweepToggle) ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable()); ASSERT(m_isSafeToCollect); JAVASCRIPTCORE_GC_BEGIN(); + if (m_operationInProgress != NoOperation) + CRASH(); + m_operationInProgress = Collection; m_activityCallback->willCollect(); double lastGCStartTime = WTF::currentTime(); if (lastGCStartTime - m_lastCodeDiscardTime > minute) { - discardAllCompiledCode(); + deleteAllCompiledCode(); m_lastCodeDiscardTime = WTF::currentTime(); } @@ -682,22 +726,21 @@ void Heap::collect(SweepToggle sweepToggle) m_objectSpace.reapWeakSets(); } + JAVASCRIPTCORE_GC_MARKED(); + { GCPHASE(FinalizeUnconditionalFinalizers); finalizeUnconditionalFinalizers(); } { - GCPHASE(FinalizeWeakHandles); - m_objectSpace.sweepWeakSets(); + GCPHASE(finalizeSmallStrings); m_globalData->smallStrings.finalizeSmallStrings(); } - - JAVASCRIPTCORE_GC_MARKED(); { GCPHASE(DeleteCodeBlocks); - m_dfgCodeBlocks.deleteUnmarkedJettisonedCodeBlocks(); + deleteUnmarkedCompiledCode(); } if (sweepToggle == DoSweep) { @@ -728,6 +771,9 @@ void Heap::collect(SweepToggle sweepToggle) m_bytesAllocated = 0; double lastGCEndTime = WTF::currentTime(); m_lastGCLength = lastGCEndTime - lastGCStartTime; + if (m_operationInProgress != Collection) + CRASH(); + m_operationInProgress = NoOperation; JAVASCRIPTCORE_GC_END(); } @@ -784,14 +830,9 @@ void Heap::FinalizerOwner::finalize(Handle<Unknown> handle, void* context) WeakSet::deallocate(WeakImpl::asWeakImpl(slot)); } -void Heap::addFunctionExecutable(FunctionExecutable* executable) -{ - m_functions.append(executable); -} - -void Heap::removeFunctionExecutable(FunctionExecutable* executable) +void Heap::addCompiledCode(ExecutableBase* executable) { - m_functions.remove(executable); + m_compiledCode.append(executable); } } // namespace JSC diff --git a/Source/JavaScriptCore/heap/Heap.h b/Source/JavaScriptCore/heap/Heap.h index 296447d7b..91c3aa58f 100644 --- a/Source/JavaScriptCore/heap/Heap.h +++ b/Source/JavaScriptCore/heap/Heap.h @@ -42,7 +42,7 @@ namespace JSC { class CopiedSpace; class CodeBlock; - class FunctionExecutable; + class ExecutableBase; class GCActivityCallback; class GlobalCodeBlock; class Heap; @@ -85,6 +85,7 @@ namespace JSC { static bool testAndSetMarked(const void*); static void setMarked(const void*); + static bool isWriteBarrierEnabled(); static void writeBarrier(const JSCell*, JSValue); static void writeBarrier(const JSCell*, JSCell*); static uint8_t* addressOfCardFor(JSCell*); @@ -115,10 +116,10 @@ namespace JSC { typedef void (*Finalizer)(JSCell*); JS_EXPORT_PRIVATE void addFinalizer(JSCell*, Finalizer); - void addFunctionExecutable(FunctionExecutable*); - void removeFunctionExecutable(FunctionExecutable*); + void addCompiledCode(ExecutableBase*); void notifyIsSafeToCollect() { m_isSafeToCollect = true; } + bool isSafeToCollect() const { return m_isSafeToCollect; } JS_EXPORT_PRIVATE void collectAllGarbage(); enum SweepToggle { DoNotSweep, DoSweep }; @@ -158,7 +159,7 @@ namespace JSC { double lastGCLength() { return m_lastGCLength; } void increaseLastGCLength(double amount) { m_lastGCLength += amount; } - JS_EXPORT_PRIVATE void discardAllCompiledCode(); + JS_EXPORT_PRIVATE void deleteAllCompiledCode(); void didAllocate(size_t); void didAbandon(size_t); @@ -193,6 +194,7 @@ namespace JSC { void markTempSortVectors(HeapRootVisitor&); void harvestWeakReferences(); void finalizeUnconditionalFinalizers(); + void deleteUnmarkedCompiledCode(); RegisterFile& registerFile(); BlockAllocator& blockAllocator(); @@ -219,9 +221,6 @@ namespace JSC { Vector<Vector<ValueStringPair>* > m_tempSortingVectors; OwnPtr<HashSet<MarkedArgumentBuffer*> > m_markListSet; - OwnPtr<GCActivityCallback> m_activityCallback; - OwnPtr<IncrementalSweeper> m_sweeper; - MachineThreads m_machineThreads; MarkStackThreadSharedData m_sharedData; @@ -238,7 +237,10 @@ namespace JSC { double m_lastGCLength; double m_lastCodeDiscardTime; - DoublyLinkedList<FunctionExecutable> m_functions; + OwnPtr<GCActivityCallback> m_activityCallback; + OwnPtr<IncrementalSweeper> m_sweeper; + + DoublyLinkedList<ExecutableBase> m_compiledCode; }; inline bool Heap::shouldCollect() @@ -282,6 +284,15 @@ namespace JSC { MarkedBlock::blockFor(cell)->setMarked(cell); } + inline bool Heap::isWriteBarrierEnabled() + { +#if ENABLE(GGC) || ENABLE(WRITE_BARRIER_PROFILING) + return true; +#else + return false; +#endif + } + #if ENABLE(GGC) inline uint8_t* Heap::addressOfCardFor(JSCell* cell) { diff --git a/Source/JavaScriptCore/heap/HeapTimer.cpp b/Source/JavaScriptCore/heap/HeapTimer.cpp new file mode 100644 index 000000000..bc42032f5 --- /dev/null +++ b/Source/JavaScriptCore/heap/HeapTimer.cpp @@ -0,0 +1,71 @@ +#include "config.h" +#include "HeapTimer.h" + +#include <wtf/Threading.h> + +namespace JSC { + +#if USE(CF) + +const CFTimeInterval HeapTimer::s_decade = 60 * 60 * 24 * 365 * 10; + +HeapTimer::HeapTimer(JSGlobalData* globalData, CFRunLoopRef runLoop) + : m_globalData(globalData) + , m_runLoop(runLoop) +{ + memset(&m_context, 0, sizeof(CFRunLoopTimerContext)); + m_context.info = this; + m_timer.adoptCF(CFRunLoopTimerCreate(0, s_decade, s_decade, 0, 0, HeapTimer::timerDidFire, &m_context)); + CFRunLoopAddTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes); +} + +HeapTimer::~HeapTimer() +{ + invalidate(); +} + +void HeapTimer::synchronize() +{ + if (CFRunLoopGetCurrent() == m_runLoop.get()) + return; + CFRunLoopRemoveTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes); + m_runLoop = CFRunLoopGetCurrent(); + CFRunLoopAddTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes); +} + +void HeapTimer::invalidate() +{ + CFRunLoopRemoveTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes); + CFRunLoopTimerInvalidate(m_timer.get()); +} + +void HeapTimer::timerDidFire(CFRunLoopTimerRef, void* info) +{ + HeapTimer* agent = static_cast<HeapTimer*>(info); + agent->doWork(); +} + +#else + +HeapTimer::HeapTimer(JSGlobalData* globalData) + : m_globalData(globalData) +{ +} + +HeapTimer::~HeapTimer() +{ +} + +void HeapTimer::synchronize() +{ +} + +void HeapTimer::invalidate() +{ +} + + +#endif + + +} // namespace JSC diff --git a/Source/JavaScriptCore/heap/HeapTimer.h b/Source/JavaScriptCore/heap/HeapTimer.h new file mode 100644 index 000000000..ccd6ba8c5 --- /dev/null +++ b/Source/JavaScriptCore/heap/HeapTimer.h @@ -0,0 +1,45 @@ +#ifndef HeapTimer_h +#define HeapTimer_h + +#include <wtf/RetainPtr.h> + +#if USE(CF) +#include <CoreFoundation/CoreFoundation.h> +#endif + +namespace JSC { + +class JSGlobalData; + +class HeapTimer { +public: +#if USE(CF) + HeapTimer(JSGlobalData*, CFRunLoopRef); + static void timerDidFire(CFRunLoopTimerRef, void*); +#else + HeapTimer(JSGlobalData*); +#endif + + virtual ~HeapTimer(); + + virtual void synchronize(); + virtual void doWork() = 0; + +protected: + JSGlobalData* m_globalData; + +#if USE(CF) + static const CFTimeInterval s_decade; + + RetainPtr<CFRunLoopTimerRef> m_timer; + RetainPtr<CFRunLoopRef> m_runLoop; + CFRunLoopTimerContext m_context; +#endif + +private: + void invalidate(); +}; + +} // namespace JSC + +#endif diff --git a/Source/JavaScriptCore/heap/IncrementalSweeper.cpp b/Source/JavaScriptCore/heap/IncrementalSweeper.cpp index 08a9f6c73..0d0116f42 100644 --- a/Source/JavaScriptCore/heap/IncrementalSweeper.cpp +++ b/Source/JavaScriptCore/heap/IncrementalSweeper.cpp @@ -14,33 +14,20 @@ namespace JSC { #if USE(CF) -static const CFTimeInterval decade = 60 * 60 * 24 * 365 * 10; static const CFTimeInterval sweepTimeSlicePerBlock = 0.01; static const CFTimeInterval sweepTimeMultiplier = 1.0 / sweepTimeSlicePerBlock; -void IncrementalSweeper::timerDidFire(CFRunLoopTimerRef, void* info) +void IncrementalSweeper::doWork() { - Heap* heap = static_cast<Heap*>(info); - APIEntryShim shim(heap->globalData()); - heap->sweeper()->doSweep(WTF::monotonicallyIncreasingTime()); + APIEntryShim shim(m_globalData); + doSweep(WTF::monotonicallyIncreasingTime()); } IncrementalSweeper::IncrementalSweeper(Heap* heap, CFRunLoopRef runLoop) - : m_heap(heap) + : HeapTimer(heap->globalData(), runLoop) , m_currentBlockToSweepIndex(0) , m_lengthOfLastSweepIncrement(0.0) { - memset(&m_context, 0, sizeof(CFRunLoopTimerContext)); - m_context.info = m_heap; - m_runLoop = runLoop; - m_timer.adoptCF(CFRunLoopTimerCreate(0, CFAbsoluteTimeGetCurrent(), decade, 0, 0, &timerDidFire, &m_context)); - CFRunLoopAddTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes); -} - -IncrementalSweeper::~IncrementalSweeper() -{ - CFRunLoopRemoveTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes); - CFRunLoopTimerInvalidate(m_timer.get()); } PassOwnPtr<IncrementalSweeper> IncrementalSweeper::create(Heap* heap) @@ -55,7 +42,7 @@ void IncrementalSweeper::scheduleTimer() void IncrementalSweeper::cancelTimer() { - CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + decade); + CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + s_decade); } void IncrementalSweeper::doSweep(double sweepBeginTime) @@ -85,17 +72,18 @@ void IncrementalSweeper::startSweeping(const HashSet<MarkedBlock*>& blockSnapsho #else -IncrementalSweeper::IncrementalSweeper() +IncrementalSweeper::IncrementalSweeper(JSGlobalData* globalData) + : HeapTimer(globalData) { } -IncrementalSweeper::~IncrementalSweeper() +void IncrementalSweeper::doWork() { } -PassOwnPtr<IncrementalSweeper> IncrementalSweeper::create(Heap*) +PassOwnPtr<IncrementalSweeper> IncrementalSweeper::create(Heap* heap) { - return adoptPtr(new IncrementalSweeper()); + return adoptPtr(new IncrementalSweeper(heap->globalData())); } void IncrementalSweeper::startSweeping(const HashSet<MarkedBlock*>&) diff --git a/Source/JavaScriptCore/heap/IncrementalSweeper.h b/Source/JavaScriptCore/heap/IncrementalSweeper.h index 48f040409..80d674ca9 100644 --- a/Source/JavaScriptCore/heap/IncrementalSweeper.h +++ b/Source/JavaScriptCore/heap/IncrementalSweeper.h @@ -1,47 +1,37 @@ #ifndef IncrementalSweeper_h #define IncrementalSweeper_h +#include "HeapTimer.h" #include "MarkedBlock.h" #include <wtf/HashSet.h> #include <wtf/PassOwnPtr.h> #include <wtf/RetainPtr.h> #include <wtf/Vector.h> -#if USE(CF) -#include <CoreFoundation/CoreFoundation.h> -#endif - namespace JSC { class Heap; -class IncrementalSweeper { +class IncrementalSweeper : public HeapTimer { public: - ~IncrementalSweeper(); - static PassOwnPtr<IncrementalSweeper> create(Heap*); void startSweeping(const HashSet<MarkedBlock*>& blockSnapshot); + virtual void doWork(); private: #if USE(CF) IncrementalSweeper(Heap*, CFRunLoopRef); - static void timerDidFire(CFRunLoopTimerRef, void*); void doSweep(double startTime); void scheduleTimer(); void cancelTimer(); - Heap* m_heap; unsigned m_currentBlockToSweepIndex; - RetainPtr<CFRunLoopTimerRef> m_timer; - RetainPtr<CFRunLoopRef> m_runLoop; - CFRunLoopTimerContext m_context; - double m_lengthOfLastSweepIncrement; Vector<MarkedBlock*> m_blocksToSweep; #else - IncrementalSweeper(); + IncrementalSweeper(JSGlobalData*); #endif }; diff --git a/Source/JavaScriptCore/heap/ListableHandler.h b/Source/JavaScriptCore/heap/ListableHandler.h index 41f18fbce..2cb03251f 100644 --- a/Source/JavaScriptCore/heap/ListableHandler.h +++ b/Source/JavaScriptCore/heap/ListableHandler.h @@ -24,6 +24,7 @@ #include <wtf/Locker.h> #include <wtf/Noncopyable.h> #include <wtf/ThreadingPrimitives.h> +#include <wtf/TCSpinLock.h> namespace JSC { @@ -60,15 +61,12 @@ private: List() : m_first(0) { + m_lock.Init(); } void addThreadSafe(T* handler) { - // NOTE: If we ever want this to be faster, we could turn it into - // a CAS loop, since this is a singly-linked-list that, in parallel - // tracing mode, can only grow. I.e. we don't have to worry about - // any ABA problems. - MutexLocker locker(m_lock); + SpinLockHolder locker(&m_lock); addNotThreadSafe(handler); } @@ -106,7 +104,7 @@ private: m_first = handler; } - Mutex m_lock; + SpinLock m_lock; T* m_first; }; diff --git a/Source/JavaScriptCore/heap/MarkStack.cpp b/Source/JavaScriptCore/heap/MarkStack.cpp index 678f1cb45..3eb02c4e8 100644 --- a/Source/JavaScriptCore/heap/MarkStack.cpp +++ b/Source/JavaScriptCore/heap/MarkStack.cpp @@ -36,6 +36,7 @@ #include "JSObject.h" #include "ScopeChain.h" #include "Structure.h" +#include "UString.h" #include "WriteBarrier.h" #include <wtf/DataLog.h> #include <wtf/MainThread.h> @@ -45,6 +46,7 @@ namespace JSC { MarkStackSegmentAllocator::MarkStackSegmentAllocator() : m_nextFreeSegment(0) { + m_lock.Init(); } MarkStackSegmentAllocator::~MarkStackSegmentAllocator() @@ -55,7 +57,7 @@ MarkStackSegmentAllocator::~MarkStackSegmentAllocator() MarkStackSegment* MarkStackSegmentAllocator::allocate() { { - MutexLocker locker(m_lock); + SpinLockHolder locker(&m_lock); if (m_nextFreeSegment) { MarkStackSegment* result = m_nextFreeSegment; m_nextFreeSegment = result->m_previous; @@ -68,7 +70,7 @@ MarkStackSegment* MarkStackSegmentAllocator::allocate() void MarkStackSegmentAllocator::release(MarkStackSegment* segment) { - MutexLocker locker(m_lock); + SpinLockHolder locker(&m_lock); segment->m_previous = m_nextFreeSegment; m_nextFreeSegment = segment; } @@ -77,7 +79,7 @@ void MarkStackSegmentAllocator::shrinkReserve() { MarkStackSegment* segments; { - MutexLocker locker(m_lock); + SpinLockHolder locker(&m_lock); segments = m_nextFreeSegment; m_nextFreeSegment = 0; } @@ -141,23 +143,31 @@ bool MarkStackArray::refill() return true; } -bool MarkStackArray::donateSomeCellsTo(MarkStackArray& other) +void MarkStackArray::donateSomeCellsTo(MarkStackArray& other) { + // Try to donate about 1 / 2 of our cells. To reduce copying costs, + // we prefer donating whole segments over donating individual cells, + // even if this skews away from our 1 / 2 target. + ASSERT(m_segmentCapacity == other.m_segmentCapacity); + + size_t segmentsToDonate = (m_numberOfPreviousSegments + 2 - 1) / 2; // Round up to donate 1 / 1 previous segments. + + if (!segmentsToDonate) { + size_t cellsToDonate = m_top / 2; // Round down to donate 0 / 1 cells. + while (cellsToDonate--) { + ASSERT(m_top); + other.append(removeLast()); + } + return; + } + validatePrevious(); other.validatePrevious(); - - // Fast check: see if the other mark stack already has enough segments. - if (other.m_numberOfPreviousSegments + 1 >= Options::maximumNumberOfSharedSegments) - return false; - - size_t numberOfCellsToKeep = Options::minimumNumberOfCellsToKeep; - ASSERT(m_top > numberOfCellsToKeep || m_topSegment->m_previous); - - // Looks like we should donate! Give the other mark stack all of our - // previous segments, and then top it off. + MarkStackSegment* previous = m_topSegment->m_previous; - while (previous) { + while (segmentsToDonate--) { + ASSERT(previous); ASSERT(m_numberOfPreviousSegments); MarkStackSegment* current = previous; @@ -169,23 +179,18 @@ bool MarkStackArray::donateSomeCellsTo(MarkStackArray& other) m_numberOfPreviousSegments--; other.m_numberOfPreviousSegments++; } - ASSERT(!m_numberOfPreviousSegments); - m_topSegment->m_previous = 0; + m_topSegment->m_previous = previous; + validatePrevious(); other.validatePrevious(); - - // Now top off. We want to keep at a minimum numberOfCellsToKeep, but if - // we really have a lot of work, we give up half. - if (m_top > numberOfCellsToKeep * 2) - numberOfCellsToKeep = m_top / 2; - while (m_top > numberOfCellsToKeep) - other.append(removeLast()); - - return true; } -void MarkStackArray::stealSomeCellsFrom(MarkStackArray& other) +void MarkStackArray::stealSomeCellsFrom(MarkStackArray& other, size_t idleThreadCount) { + // Try to steal 1 / Nth of the shared array, where N is the number of idle threads. + // To reduce copying costs, we prefer stealing a whole segment over stealing + // individual cells, even if this skews away from our 1 / N target. + ASSERT(m_segmentCapacity == other.m_segmentCapacity); validatePrevious(); other.validatePrevious(); @@ -210,28 +215,42 @@ void MarkStackArray::stealSomeCellsFrom(MarkStackArray& other) other.validatePrevious(); return; } - - // Otherwise drain 1/Nth of the shared array where N is the number of - // workers, or Options::minimumNumberOfCellsToKeep, whichever is bigger. - size_t numberOfCellsToSteal = std::max((size_t)Options::minimumNumberOfCellsToKeep, other.size() / Options::numberOfGCMarkers); + + size_t numberOfCellsToSteal = (other.size() + idleThreadCount - 1) / idleThreadCount; // Round up to steal 1 / 1. while (numberOfCellsToSteal-- > 0 && other.canRemoveLast()) append(other.removeLast()); } #if ENABLE(PARALLEL_GC) -void MarkStackThreadSharedData::markingThreadMain() +void MarkStackThreadSharedData::resetChildren() +{ + for (unsigned i = 0; i < m_markingThreadsMarkStack.size(); ++i) + m_markingThreadsMarkStack[i]->reset(); +} + +size_t MarkStackThreadSharedData::childVisitCount() +{ + unsigned long result = 0; + for (unsigned i = 0; i < m_markingThreadsMarkStack.size(); ++i) + result += m_markingThreadsMarkStack[i]->visitCount(); + return result; +} + +void MarkStackThreadSharedData::markingThreadMain(SlotVisitor* slotVisitor) { WTF::registerGCThread(); { - SlotVisitor slotVisitor(*this); - ParallelModeEnabler enabler(slotVisitor); - slotVisitor.drainFromShared(SlotVisitor::SlaveDrain); + ParallelModeEnabler enabler(*slotVisitor); + slotVisitor->drainFromShared(SlotVisitor::SlaveDrain); } + delete slotVisitor; } -void MarkStackThreadSharedData::markingThreadStartFunc(void* shared) -{ - static_cast<MarkStackThreadSharedData*>(shared)->markingThreadMain(); +void MarkStackThreadSharedData::markingThreadStartFunc(void* myVisitor) +{ + SlotVisitor* slotVisitor = static_cast<SlotVisitor*>(myVisitor); + + slotVisitor->sharedData().markingThreadMain(slotVisitor); } #endif @@ -244,7 +263,9 @@ MarkStackThreadSharedData::MarkStackThreadSharedData(JSGlobalData* globalData) { #if ENABLE(PARALLEL_GC) for (unsigned i = 1; i < Options::numberOfGCMarkers; ++i) { - m_markingThreads.append(createThread(markingThreadStartFunc, this, "JavaScriptCore::Marking")); + SlotVisitor* slotVisitor = new SlotVisitor(*this); + m_markingThreadsMarkStack.append(slotVisitor); + m_markingThreads.append(createThread(markingThreadStartFunc, slotVisitor, "JavaScriptCore::Marking")); ASSERT(m_markingThreads.last()); } #endif @@ -276,7 +297,6 @@ void MarkStackThreadSharedData::reset() #else ASSERT(m_opaqueRoots.isEmpty()); #endif - m_weakReferenceHarvesters.removeAll(); } @@ -325,18 +345,31 @@ ALWAYS_INLINE static void visitChildren(SlotVisitor& visitor, const JSCell* cell cell->methodTable()->visitChildren(const_cast<JSCell*>(cell), visitor); } -void SlotVisitor::donateSlow() +void SlotVisitor::donateKnownParallel() { - // Refuse to donate if shared has more entries than I do. - if (m_shared.m_sharedMarkStack.size() > m_stack.size()) + // NOTE: Because we re-try often, we can afford to be conservative, and + // assume that donating is not profitable. + + // Avoid locking when a thread reaches a dead end in the object graph. + if (m_stack.size() < 2) return; - MutexLocker locker(m_shared.m_markingLock); - if (m_stack.donateSomeCellsTo(m_shared.m_sharedMarkStack)) { - // Only wake up threads if the shared stack is big enough; otherwise assume that - // it's more profitable for us to just scan this ourselves later. - if (m_shared.m_sharedMarkStack.size() >= Options::sharedStackWakeupThreshold) - m_shared.m_markingCondition.broadcast(); - } + + // If there's already some shared work queued up, be conservative and assume + // that donating more is not profitable. + if (m_shared.m_sharedMarkStack.size()) + return; + + // If we're contending on the lock, be conservative and assume that another + // thread is already donating. + MutexTryLocker locker(m_shared.m_markingLock); + if (!locker.locked()) + return; + + // Otherwise, assume that a thread will go idle soon, and donate. + m_stack.donateSomeCellsTo(m_shared.m_sharedMarkStack); + + if (m_shared.m_numberOfActiveParallelMarkers < Options::numberOfGCMarkers) + m_shared.m_markingCondition.broadcast(); } void SlotVisitor::drain() @@ -436,7 +469,8 @@ void SlotVisitor::drainFromShared(SharedDrainMode sharedDrainMode) } } - m_stack.stealSomeCellsFrom(m_shared.m_sharedMarkStack); + size_t idleThreadCount = Options::numberOfGCMarkers - m_shared.m_numberOfActiveParallelMarkers; + m_stack.stealSomeCellsFrom(m_shared.m_sharedMarkStack, idleThreadCount); m_shared.m_numberOfActiveParallelMarkers++; } @@ -461,8 +495,7 @@ void MarkStack::mergeOpaqueRoots() void SlotVisitor::startCopying() { ASSERT(!m_copyBlock); - if (!m_shared.m_copiedSpace->borrowBlock(&m_copyBlock)) - CRASH(); + m_copyBlock = m_shared.m_copiedSpace->allocateBlockForCopyingPhase(); } void* SlotVisitor::allocateNewSpace(void* ptr, size_t bytes) @@ -483,8 +516,7 @@ void* SlotVisitor::allocateNewSpace(void* ptr, size_t bytes) // We don't need to lock across these two calls because the master thread won't // call doneCopying() because this thread is considered active. m_shared.m_copiedSpace->doneFillingBlock(m_copyBlock); - if (!m_shared.m_copiedSpace->borrowBlock(&m_copyBlock)) - CRASH(); + m_copyBlock = m_shared.m_copiedSpace->allocateBlockForCopyingPhase(); } return CopiedSpace::allocateFromBlock(m_copyBlock, bytes); } diff --git a/Source/JavaScriptCore/heap/MarkStack.h b/Source/JavaScriptCore/heap/MarkStack.h index 0695b1b32..c3065e7d6 100644 --- a/Source/JavaScriptCore/heap/MarkStack.h +++ b/Source/JavaScriptCore/heap/MarkStack.h @@ -28,18 +28,46 @@ #include "CopiedSpace.h" #include "HandleTypes.h" -#include "Options.h" #include "JSValue.h" +#include "Options.h" #include "Register.h" #include "UnconditionalFinalizer.h" #include "VTableSpectrum.h" #include "WeakReferenceHarvester.h" +#include <wtf/DataLog.h> +#include <wtf/Forward.h> #include <wtf/HashMap.h> #include <wtf/HashSet.h> -#include <wtf/Vector.h> #include <wtf/Noncopyable.h> #include <wtf/OSAllocator.h> #include <wtf/PageBlock.h> +#include <wtf/TCSpinLock.h> +#include <wtf/text/StringHash.h> +#include <wtf/Vector.h> + +#if ENABLE(OBJECT_MARK_LOGGING) +#define MARK_LOG_MESSAGE0(message) dataLog(message) +#define MARK_LOG_MESSAGE1(message, arg1) dataLog(message, arg1) +#define MARK_LOG_MESSAGE2(message, arg1, arg2) dataLog(message, arg1, arg2) +#define MARK_LOG_ROOT(visitor, rootName) \ + dataLog("\n%s: ", rootName); \ + (visitor).resetChildCount() +#define MARK_LOG_PARENT(visitor, parent) \ + dataLog("\n%p (%s): ", parent, parent->className() ? parent->className() : "unknown"); \ + (visitor).resetChildCount() +#define MARK_LOG_CHILD(visitor, child) \ + if ((visitor).childCount()) \ + dataLogString(", "); \ + dataLog("%p", child); \ + (visitor).incrementChildCount() +#else +#define MARK_LOG_MESSAGE0(message) do { } while (false) +#define MARK_LOG_MESSAGE1(message, arg1) do { } while (false) +#define MARK_LOG_MESSAGE2(message, arg1, arg2) do { } while (false) +#define MARK_LOG_ROOT(visitor, rootName) do { } while (false) +#define MARK_LOG_PARENT(visitor, parent) do { } while (false) +#define MARK_LOG_CHILD(visitor, child) do { } while (false) +#endif namespace JSC { @@ -85,7 +113,7 @@ namespace JSC { void shrinkReserve(); private: - Mutex m_lock; + SpinLock m_lock; MarkStackSegment* m_nextFreeSegment; }; @@ -102,10 +130,9 @@ namespace JSC { bool isEmpty(); - bool canDonateSomeCells(); // Returns false if you should definitely not call doanteSomeCellsTo(). - bool donateSomeCellsTo(MarkStackArray& other); // Returns true if some cells were donated. + void donateSomeCellsTo(MarkStackArray& other); - void stealSomeCellsFrom(MarkStackArray& other); + void stealSomeCellsFrom(MarkStackArray& other, size_t idleThreadCount); size_t size(); @@ -171,13 +198,19 @@ namespace JSC { ~MarkStackThreadSharedData(); void reset(); + +#if ENABLE(PARALLEL_GC) + void resetChildren(); + size_t childVisitCount(); + size_t childDupStrings(); +#endif private: friend class MarkStack; friend class SlotVisitor; #if ENABLE(PARALLEL_GC) - void markingThreadMain(); + void markingThreadMain(SlotVisitor*); static void markingThreadStartFunc(void* heap); #endif @@ -187,6 +220,7 @@ namespace JSC { MarkStackSegmentAllocator m_segmentAllocator; Vector<ThreadIdentifier> m_markingThreads; + Vector<MarkStack*> m_markingThreadsMarkStack; Mutex m_markingLock; ThreadCondition m_markingCondition; @@ -221,7 +255,8 @@ namespace JSC { void addOpaqueRoot(void*); bool containsOpaqueRoot(void*); int opaqueRootCount(); - + + MarkStackThreadSharedData& sharedData() { return m_shared; } bool isEmpty() { return m_stack.isEmpty(); } void reset(); @@ -242,6 +277,12 @@ namespace JSC { m_shared.m_unconditionalFinalizers.addThreadSafe(unconditionalFinalizer); } +#if ENABLE(OBJECT_MARK_LOGGING) + inline void resetChildCount() { m_logChildCount = 0; } + inline unsigned childCount() { return m_logChildCount; } + inline void incrementChildCount() { m_logChildCount++; } +#endif + protected: JS_EXPORT_PRIVATE static void validate(JSCell*); @@ -283,6 +324,10 @@ namespace JSC { bool m_isInParallelMode; MarkStackThreadSharedData& m_shared; + +#if ENABLE(OBJECT_MARK_LOGGING) + unsigned m_logChildCount; +#endif }; inline MarkStack::MarkStack(MarkStackThreadSharedData& shared) @@ -369,22 +414,6 @@ namespace JSC { return true; } - inline bool MarkStackArray::canDonateSomeCells() - { - size_t numberOfCellsToKeep = Options::minimumNumberOfCellsToKeep; - // Another check: see if we have enough cells to warrant donation. - if (m_top <= numberOfCellsToKeep) { - // This indicates that we might not want to donate anything; check if we have - // another full segment. If not, then don't donate. - if (!m_topSegment->m_previous) - return false; - - ASSERT(m_topSegment->m_previous->m_top == m_segmentCapacity); - } - - return true; - } - inline size_t MarkStackArray::size() { return m_top + m_segmentCapacity * m_numberOfPreviousSegments; diff --git a/Source/JavaScriptCore/heap/MarkedAllocator.cpp b/Source/JavaScriptCore/heap/MarkedAllocator.cpp index ac0cf570a..9552a54ea 100644 --- a/Source/JavaScriptCore/heap/MarkedAllocator.cpp +++ b/Source/JavaScriptCore/heap/MarkedAllocator.cpp @@ -47,6 +47,7 @@ inline void* MarkedAllocator::tryAllocateHelper() inline void* MarkedAllocator::tryAllocate() { + ASSERT(!m_heap->isBusy()); m_heap->m_operationInProgress = Allocation; void* result = tryAllocateHelper(); m_heap->m_operationInProgress = NoOperation; diff --git a/Source/JavaScriptCore/heap/MarkedBlock.cpp b/Source/JavaScriptCore/heap/MarkedBlock.cpp index 0075f78d7..01e4237cb 100644 --- a/Source/JavaScriptCore/heap/MarkedBlock.cpp +++ b/Source/JavaScriptCore/heap/MarkedBlock.cpp @@ -114,6 +114,8 @@ MarkedBlock::FreeList MarkedBlock::sweep(SweepMode sweepMode) { HEAP_LOG_BLOCK_STATE_TRANSITION(this); + m_weakSet.sweep(); + if (sweepMode == SweepOnly && !m_cellsNeedDestruction) return FreeList(); diff --git a/Source/JavaScriptCore/heap/MarkedBlock.h b/Source/JavaScriptCore/heap/MarkedBlock.h index b94c1e2b0..eb1cb681b 100644 --- a/Source/JavaScriptCore/heap/MarkedBlock.h +++ b/Source/JavaScriptCore/heap/MarkedBlock.h @@ -129,11 +129,9 @@ namespace JSC { FreeList sweep(SweepMode = SweepOnly); void shrink(); - void resetAllocator(); void visitWeakSet(HeapRootVisitor&); void reapWeakSet(); - void sweepWeakSet(); // While allocating from a free list, MarkedBlock temporarily has bogus // cell liveness data. To restore accurate cell liveness data, call one @@ -274,11 +272,6 @@ namespace JSC { m_weakSet.shrink(); } - inline void MarkedBlock::resetAllocator() - { - m_weakSet.resetAllocator(); - } - inline void MarkedBlock::visitWeakSet(HeapRootVisitor& heapRootVisitor) { m_weakSet.visit(heapRootVisitor); @@ -289,11 +282,6 @@ namespace JSC { m_weakSet.reap(); } - inline void MarkedBlock::sweepWeakSet() - { - m_weakSet.sweep(); - } - inline void MarkedBlock::didConsumeFreeList() { HEAP_LOG_BLOCK_STATE_TRANSITION(this); diff --git a/Source/JavaScriptCore/heap/MarkedSpace.cpp b/Source/JavaScriptCore/heap/MarkedSpace.cpp index 1604d2d63..42247a385 100644 --- a/Source/JavaScriptCore/heap/MarkedSpace.cpp +++ b/Source/JavaScriptCore/heap/MarkedSpace.cpp @@ -77,10 +77,6 @@ struct ReapWeakSet : MarkedBlock::VoidFunctor { void operator()(MarkedBlock* block) { block->reapWeakSet(); } }; -struct SweepWeakSet : MarkedBlock::VoidFunctor { - void operator()(MarkedBlock* block) { block->sweepWeakSet(); } -}; - MarkedSpace::MarkedSpace(Heap* heap) : m_heap(heap) { @@ -112,10 +108,6 @@ void MarkedSpace::lastChanceToFinalize() forEachBlock<LastChanceToFinalize>(); } -struct ResetAllocator : MarkedBlock::VoidFunctor { - void operator()(MarkedBlock* block) { block->resetAllocator(); } -}; - void MarkedSpace::resetAllocators() { for (size_t cellSize = preciseStep; cellSize <= preciseCutoff; cellSize += preciseStep) { @@ -127,8 +119,6 @@ void MarkedSpace::resetAllocators() allocatorFor(cellSize).reset(); destructorAllocatorFor(cellSize).reset(); } - - forEachBlock<ResetAllocator>(); } void MarkedSpace::visitWeakSets(HeapRootVisitor& heapRootVisitor) @@ -142,11 +132,6 @@ void MarkedSpace::reapWeakSets() forEachBlock<ReapWeakSet>(); } -void MarkedSpace::sweepWeakSets() -{ - forEachBlock<SweepWeakSet>(); -} - void MarkedSpace::canonicalizeCellLivenessData() { for (size_t cellSize = preciseStep; cellSize <= preciseCutoff; cellSize += preciseStep) { diff --git a/Source/JavaScriptCore/heap/MarkedSpace.h b/Source/JavaScriptCore/heap/MarkedSpace.h index 18b57c6d0..3f82bac96 100644 --- a/Source/JavaScriptCore/heap/MarkedSpace.h +++ b/Source/JavaScriptCore/heap/MarkedSpace.h @@ -85,7 +85,6 @@ public: void visitWeakSets(HeapRootVisitor&); void reapWeakSets(); - void sweepWeakSets(); MarkedBlockSet& blocks() { return m_blocks; } diff --git a/Source/JavaScriptCore/heap/SlotVisitor.h b/Source/JavaScriptCore/heap/SlotVisitor.h index 01eb219fc..715e2008c 100644 --- a/Source/JavaScriptCore/heap/SlotVisitor.h +++ b/Source/JavaScriptCore/heap/SlotVisitor.h @@ -68,15 +68,8 @@ public: private: void* allocateNewSpace(void*, size_t); - void donateSlow(); - - void donateKnownParallel() - { - if (!m_stack.canDonateSomeCells()) - return; - donateSlow(); - } - + void donateKnownParallel(); + CopiedBlock* m_copyBlock; }; diff --git a/Source/JavaScriptCore/heap/Weak.h b/Source/JavaScriptCore/heap/Weak.h index e5e0a97ec..07698fd06 100644 --- a/Source/JavaScriptCore/heap/Weak.h +++ b/Source/JavaScriptCore/heap/Weak.h @@ -153,15 +153,15 @@ template<typename T> inline WeakImpl* Weak<T>::hashTableDeletedValue() // This function helps avoid modifying a weak table while holding an iterator into it. (Object allocation // can run a finalizer that modifies the table. We avoid that by requiring a pre-constructed object as our value.) -template<typename T, typename U> inline void weakAdd(HashMap<T, Weak<U> >& map, const T& key, PassWeak<U> value) +template<typename Map, typename Key, typename Value> inline void weakAdd(Map& map, const Key& key, Value value) { ASSERT(!map.get(key)); map.set(key, value); // The table may still have a zombie for value. } -template<typename T, typename U> inline void weakRemove(HashMap<T, Weak<U> >& map, const T& key, typename Weak<U>::GetType value) +template<typename Map, typename Key, typename Value> inline void weakRemove(Map& map, const Key& key, Value value) { - typename HashMap<T, Weak<U> >::iterator it = map.find(key); + typename Map::iterator it = map.find(key); ASSERT_UNUSED(value, value); ASSERT(it != map.end()); ASSERT(it->second.was(value)); diff --git a/Source/JavaScriptCore/heap/WeakBlock.cpp b/Source/JavaScriptCore/heap/WeakBlock.cpp index 685779d3a..8900e73df 100644 --- a/Source/JavaScriptCore/heap/WeakBlock.cpp +++ b/Source/JavaScriptCore/heap/WeakBlock.cpp @@ -69,7 +69,8 @@ void WeakBlock::lastChanceToFinalize() void WeakBlock::sweep() { - if (!m_sweepResult.isNull()) + // If a block is completely empty, a sweep won't have any effect. + if (isEmpty()) return; SweepResult sweepResult; diff --git a/Source/JavaScriptCore/heap/WeakSet.cpp b/Source/JavaScriptCore/heap/WeakSet.cpp index 9374fd8ff..4a510b899 100644 --- a/Source/JavaScriptCore/heap/WeakSet.cpp +++ b/Source/JavaScriptCore/heap/WeakSet.cpp @@ -42,17 +42,10 @@ WeakSet::~WeakSet() void WeakSet::sweep() { - WeakBlock* next; - for (WeakBlock* block = m_blocks.head(); block; block = next) { - next = block->next(); - - // If a block is completely empty, a new sweep won't have any effect. - if (block->isEmpty()) - continue; - - block->takeSweepResult(); // Force a new sweep by discarding the last sweep. + for (WeakBlock* block = m_blocks.head(); block; block = block->next()) block->sweep(); - } + + resetAllocator(); } WeakBlock::FreeCell* WeakSet::findAllocator() @@ -69,7 +62,6 @@ WeakBlock::FreeCell* WeakSet::tryFindAllocator() WeakBlock* block = m_nextAllocator; m_nextAllocator = m_nextAllocator->next(); - block->sweep(); WeakBlock::SweepResult sweepResult = block->takeSweepResult(); if (sweepResult.freeList) return sweepResult.freeList; diff --git a/Source/JavaScriptCore/heap/WeakSet.h b/Source/JavaScriptCore/heap/WeakSet.h index be9844a64..291d0aebd 100644 --- a/Source/JavaScriptCore/heap/WeakSet.h +++ b/Source/JavaScriptCore/heap/WeakSet.h @@ -118,6 +118,8 @@ inline void WeakSet::shrink() if (block->isEmpty()) removeAllocator(block); } + + resetAllocator(); } inline void WeakSet::resetAllocator() diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp index ba72e9bba..b8610e7bf 100644 --- a/Source/JavaScriptCore/interpreter/Interpreter.cpp +++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp @@ -1043,7 +1043,7 @@ NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSV HandlerInfo* handler = 0; while (isInterrupt || !(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) { if (!unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) { - if (Profiler* profiler = *Profiler::enabledProfilerReference()) + if (Profiler* profiler = callFrame->globalData().enabledProfiler()) profiler->exceptionUnwind(callFrame); callFrame->globalData().topCallFrame = callFrame; return 0; @@ -1051,7 +1051,7 @@ NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSV } callFrame->globalData().topCallFrame = callFrame; - if (Profiler* profiler = *Profiler::enabledProfilerReference()) + if (Profiler* profiler = callFrame->globalData().enabledProfiler()) profiler->exceptionUnwind(callFrame); // Shrink the JS stack, in case stack overflow made it huge. @@ -1097,7 +1097,7 @@ JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, S ASSERT(!scopeChain->globalData->exception); ASSERT(!callFrame->globalData().isCollectorBusy()); if (callFrame->globalData().isCollectorBusy()) - return jsNull(); + CRASH(); if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth) return checkedReturn(throwStackOverflowError(callFrame)); @@ -1218,9 +1218,8 @@ failedJSONP: newCallFrame->setThisValue(thisObj); TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame); - Profiler** profiler = Profiler::enabledProfilerReference(); - if (*profiler) - (*profiler)->willExecute(callFrame, program->sourceURL(), program->lineNo()); + if (Profiler* profiler = callFrame->globalData().enabledProfiler()) + profiler->willExecute(callFrame, program->sourceURL(), program->lineNo()); JSValue result; { @@ -1237,8 +1236,8 @@ failedJSONP: m_reentryDepth--; } - if (*profiler) - (*profiler)->didExecute(callFrame, program->sourceURL(), program->lineNo()); + if (Profiler* profiler = callFrame->globalData().enabledProfiler()) + profiler->didExecute(callFrame, program->sourceURL(), program->lineNo()); m_registerFile.shrink(oldEnd); @@ -1291,9 +1290,8 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame); - Profiler** profiler = Profiler::enabledProfilerReference(); - if (*profiler) - (*profiler)->willExecute(callFrame, function); + if (Profiler* profiler = callFrame->globalData().enabledProfiler()) + profiler->willExecute(callFrame, function); JSValue result; { @@ -1309,8 +1307,8 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT m_reentryDepth--; } - if (*profiler) - (*profiler)->didExecute(callFrame, function); + if (Profiler* profiler = callFrame->globalData().enabledProfiler()) + profiler->didExecute(callFrame, function); m_registerFile.shrink(oldEnd); return checkedReturn(result); @@ -1324,9 +1322,8 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get()); - Profiler** profiler = Profiler::enabledProfilerReference(); - if (*profiler) - (*profiler)->willExecute(callFrame, function); + if (Profiler* profiler = callFrame->globalData().enabledProfiler()) + profiler->willExecute(callFrame, function); JSValue result; { @@ -1334,8 +1331,8 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT result = JSValue::decode(callData.native.function(newCallFrame)); } - if (*profiler) - (*profiler)->didExecute(callFrame, function); + if (Profiler* profiler = callFrame->globalData().enabledProfiler()) + profiler->didExecute(callFrame, function); m_registerFile.shrink(oldEnd); return checkedReturn(result); @@ -1387,9 +1384,8 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame); - Profiler** profiler = Profiler::enabledProfilerReference(); - if (*profiler) - (*profiler)->willExecute(callFrame, constructor); + if (Profiler* profiler = callFrame->globalData().enabledProfiler()) + profiler->willExecute(callFrame, constructor); JSValue result; { @@ -1405,8 +1401,8 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc m_reentryDepth--; } - if (*profiler) - (*profiler)->didExecute(callFrame, constructor); + if (Profiler* profiler = callFrame->globalData().enabledProfiler()) + profiler->didExecute(callFrame, constructor); m_registerFile.shrink(oldEnd); if (callFrame->hadException()) @@ -1423,9 +1419,8 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get()); - Profiler** profiler = Profiler::enabledProfilerReference(); - if (*profiler) - (*profiler)->willExecute(callFrame, constructor); + if (Profiler* profiler = callFrame->globalData().enabledProfiler()) + profiler->willExecute(callFrame, constructor); JSValue result; { @@ -1433,8 +1428,8 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc result = JSValue::decode(constructData.native.function(newCallFrame)); } - if (*profiler) - (*profiler)->didExecute(callFrame, constructor); + if (Profiler* profiler = callFrame->globalData().enabledProfiler()) + profiler->didExecute(callFrame, constructor); m_registerFile.shrink(oldEnd); if (callFrame->hadException()) @@ -1490,9 +1485,8 @@ JSValue Interpreter::execute(CallFrameClosure& closure) if (closure.oldCallFrame->globalData().isCollectorBusy()) return jsNull(); closure.resetCallFrame(); - Profiler** profiler = Profiler::enabledProfilerReference(); - if (*profiler) - (*profiler)->willExecute(closure.oldCallFrame, closure.function); + if (Profiler* profiler = closure.oldCallFrame->globalData().enabledProfiler()) + profiler->willExecute(closure.oldCallFrame, closure.function); TopCallFrameSetter topCallFrame(*closure.globalData, closure.newCallFrame); @@ -1516,8 +1510,8 @@ JSValue Interpreter::execute(CallFrameClosure& closure) m_reentryDepth--; } - if (*profiler) - (*profiler)->didExecute(closure.oldCallFrame, closure.function); + if (Profiler* profiler = closure.oldCallFrame->globalData().enabledProfiler()) + profiler->didExecute(closure.oldCallFrame, closure.function); return checkedReturn(result); } @@ -1549,7 +1543,7 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue for (ScopeChainNode* node = scopeChain; ; node = node->next.get()) { ASSERT(node); if (node->object->isVariableObject() && !node->object->isStaticScopeObject()) { - variableObject = jsCast<JSVariableObject*>(node->object.get()); + variableObject = jsCast<JSSymbolTableObject*>(node->object.get()); break; } } @@ -1597,9 +1591,8 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue TopCallFrameSetter topCallFrame(callFrame->globalData(), newCallFrame); - Profiler** profiler = Profiler::enabledProfilerReference(); - if (*profiler) - (*profiler)->willExecute(callFrame, eval->sourceURL(), eval->lineNo()); + if (Profiler* profiler = callFrame->globalData().enabledProfiler()) + profiler->willExecute(callFrame, eval->sourceURL(), eval->lineNo()); JSValue result; { @@ -1622,8 +1615,8 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue m_reentryDepth--; } - if (*profiler) - (*profiler)->didExecute(callFrame, eval->sourceURL(), eval->lineNo()); + if (Profiler* profiler = callFrame->globalData().enabledProfiler()) + profiler->didExecute(callFrame, eval->sourceURL(), eval->lineNo()); m_registerFile.shrink(oldEnd); if (pushedScope) @@ -1935,7 +1928,6 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi CodeBlock* codeBlock = callFrame->codeBlock(); Instruction* vPC = codeBlock->instructions().begin(); - Profiler** enabledProfilerReference = Profiler::enabledProfilerReference(); unsigned tickCount = globalData->timeoutChecker.ticksUntilNextCheck(); JSValue functionReturnValue; @@ -2868,33 +2860,59 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_get_global_var) { - /* get_global_var dst(r) globalObject(c) index(n) + /* get_global_var dst(r) globalObject(c) registerPointer(n) Gets the global var at global slot index and places it in register dst. */ int dst = vPC[1].u.operand; - JSGlobalObject* scope = codeBlock->globalObject(); - ASSERT(scope->isGlobalObject()); - int index = vPC[2].u.operand; + WriteBarrier<Unknown>* registerPointer = vPC[2].u.registerPointer; - callFrame->uncheckedR(dst) = scope->registerAt(index).get(); + callFrame->uncheckedR(dst) = registerPointer->get(); vPC += OPCODE_LENGTH(op_get_global_var); NEXT_INSTRUCTION(); } + DEFINE_OPCODE(op_get_global_var_watchable) { + /* get_global_var_watchable dst(r) globalObject(c) registerPointer(n) + + Gets the global var at global slot index and places it in register dst. + */ + int dst = vPC[1].u.operand; + WriteBarrier<Unknown>* registerPointer = vPC[2].u.registerPointer; + + callFrame->uncheckedR(dst) = registerPointer->get(); + vPC += OPCODE_LENGTH(op_get_global_var_watchable); + NEXT_INSTRUCTION(); + } DEFINE_OPCODE(op_put_global_var) { - /* put_global_var globalObject(c) index(n) value(r) + /* put_global_var globalObject(c) registerPointer(n) value(r) Puts value into global slot index. */ JSGlobalObject* scope = codeBlock->globalObject(); ASSERT(scope->isGlobalObject()); - int index = vPC[1].u.operand; + WriteBarrier<Unknown>* registerPointer = vPC[1].u.registerPointer; int value = vPC[2].u.operand; - scope->registerAt(index).set(*globalData, scope, callFrame->r(value).jsValue()); + registerPointer->set(*globalData, scope, callFrame->r(value).jsValue()); vPC += OPCODE_LENGTH(op_put_global_var); NEXT_INSTRUCTION(); } + DEFINE_OPCODE(op_put_global_var_check) { + /* put_global_var_check globalObject(c) registerPointer(n) value(r) + + Puts value into global slot index. In JIT configurations this will + perform a watchpoint check. If we're running with the old interpreter, + this is not necessary; the interpreter never uses these watchpoints. + */ + JSGlobalObject* scope = codeBlock->globalObject(); + ASSERT(scope->isGlobalObject()); + WriteBarrier<Unknown>* registerPointer = vPC[1].u.registerPointer; + int value = vPC[2].u.operand; + + registerPointer->set(*globalData, scope, callFrame->r(value).jsValue()); + vPC += OPCODE_LENGTH(op_put_global_var_check); + NEXT_INSTRUCTION(); + } DEFINE_OPCODE(op_get_scoped_var) { /* get_scoped_var dst(r) index(n) skip(n) @@ -5226,8 +5244,8 @@ skip_id_custom_self: */ int function = vPC[1].u.operand; - if (*enabledProfilerReference) - (*enabledProfilerReference)->willExecute(callFrame, callFrame->r(function).jsValue()); + if (Profiler* profiler = globalData->enabledProfiler()) + profiler->willExecute(callFrame, callFrame->r(function).jsValue()); vPC += OPCODE_LENGTH(op_profile_will_call); NEXT_INSTRUCTION(); @@ -5240,8 +5258,8 @@ skip_id_custom_self: */ int function = vPC[1].u.operand; - if (*enabledProfilerReference) - (*enabledProfilerReference)->didExecute(callFrame, callFrame->r(function).jsValue()); + if (Profiler* profiler = globalData->enabledProfiler()) + profiler->didExecute(callFrame, callFrame->r(function).jsValue()); vPC += OPCODE_LENGTH(op_profile_did_call); NEXT_INSTRUCTION(); diff --git a/Source/JavaScriptCore/jit/HostCallReturnValue.h b/Source/JavaScriptCore/jit/HostCallReturnValue.h index fc9127faf..b134c73da 100644 --- a/Source/JavaScriptCore/jit/HostCallReturnValue.h +++ b/Source/JavaScriptCore/jit/HostCallReturnValue.h @@ -43,10 +43,10 @@ namespace JSC { -extern "C" EncodedJSValue HOST_CALL_RETURN_VALUE_OPTION getHostCallReturnValue() REFERENCED_FROM_ASM; +extern "C" EncodedJSValue HOST_CALL_RETURN_VALUE_OPTION getHostCallReturnValue() REFERENCED_FROM_ASM WTF_INTERNAL; // This is a public declaration only to convince CLANG not to elide it. -extern "C" EncodedJSValue HOST_CALL_RETURN_VALUE_OPTION getHostCallReturnValueWithExecState(ExecState*) REFERENCED_FROM_ASM; +extern "C" EncodedJSValue HOST_CALL_RETURN_VALUE_OPTION getHostCallReturnValueWithExecState(ExecState*) REFERENCED_FROM_ASM WTF_INTERNAL; inline void initializeHostCallReturnValue() { diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp index ff5615f44..2aca35146 100644 --- a/Source/JavaScriptCore/jit/JIT.cpp +++ b/Source/JavaScriptCore/jit/JIT.cpp @@ -259,6 +259,7 @@ void JIT::privateCompileMainPass() DEFINE_OP(op_get_by_val) DEFINE_OP(op_get_argument_by_val) DEFINE_OP(op_get_by_pname) + DEFINE_OP(op_get_global_var_watchable) DEFINE_OP(op_get_global_var) DEFINE_OP(op_get_pnames) DEFINE_OP(op_get_scoped_var) @@ -324,6 +325,7 @@ void JIT::privateCompileMainPass() DEFINE_OP(op_put_by_val) DEFINE_OP(op_put_getter_setter) DEFINE_OP(op_put_global_var) + DEFINE_OP(op_put_global_var_check) DEFINE_OP(op_put_scoped_var) DEFINE_OP(op_resolve) DEFINE_OP(op_resolve_base) @@ -481,6 +483,7 @@ void JIT::privateCompileSlowCases() case op_put_by_id_transition_normal: DEFINE_SLOWCASE_OP(op_put_by_id) DEFINE_SLOWCASE_OP(op_put_by_val) + DEFINE_SLOWCASE_OP(op_put_global_var_check); DEFINE_SLOWCASE_OP(op_resolve_global) DEFINE_SLOWCASE_OP(op_resolve_global_dynamic) DEFINE_SLOWCASE_OP(op_rshift) @@ -715,11 +718,9 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck, JITCompilationEffo patchBuffer.link(iter->from, FunctionPtr(iter->to)); } - if (m_codeBlock->needsCallReturnIndices()) { - m_codeBlock->callReturnIndexVector().reserveCapacity(m_calls.size()); - for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) - m_codeBlock->callReturnIndexVector().append(CallReturnOffsetToBytecodeOffset(patchBuffer.returnAddressOffset(iter->from), iter->bytecodeOffset)); - } + m_codeBlock->callReturnIndexVector().reserveCapacity(m_calls.size()); + for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) + m_codeBlock->callReturnIndexVector().append(CallReturnOffsetToBytecodeOffset(patchBuffer.returnAddressOffset(iter->from), iter->bytecodeOffset)); m_codeBlock->setNumberOfStructureStubInfos(m_propertyAccessCompilationInfo.size()); for (unsigned i = 0; i < m_propertyAccessCompilationInfo.size(); ++i) @@ -760,7 +761,8 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck, JITCompilationEffo if (m_codeBlock->codeType() == FunctionCode && functionEntryArityCheck) *functionEntryArityCheck = patchBuffer.locationOf(arityCheck); - CodeRef result = patchBuffer.finalizeCode(); + CodeRef result = FINALIZE_CODE( + patchBuffer, ("Baseline JIT code for CodeBlock %p", m_codeBlock)); m_globalData->machineCodeBytesPerBytecodeWordForBaselineJIT.add( static_cast<double>(result.size()) / diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h index d1143105a..6491edbed 100644 --- a/Source/JavaScriptCore/jit/JIT.h +++ b/Source/JavaScriptCore/jit/JIT.h @@ -463,7 +463,7 @@ namespace JSC { bool isMapped(int virtualRegisterIndex); bool getMappedPayload(int virtualRegisterIndex, RegisterID& payload); bool getMappedTag(int virtualRegisterIndex, RegisterID& tag); - + void emitJumpSlowCaseIfNotJSCell(int virtualRegisterIndex); void emitJumpSlowCaseIfNotJSCell(int virtualRegisterIndex, RegisterID tag); @@ -599,6 +599,7 @@ namespace JSC { void emit_op_get_argument_by_val(Instruction*); void emit_op_get_by_pname(Instruction*); void emit_op_get_global_var(Instruction*); + void emit_op_get_global_var_watchable(Instruction* instruction) { emit_op_get_global_var(instruction); } void emit_op_get_scoped_var(Instruction*); void emit_op_init_lazy_reg(Instruction*); void emit_op_check_has_instance(Instruction*); @@ -662,6 +663,7 @@ namespace JSC { void emit_op_put_by_val(Instruction*); void emit_op_put_getter_setter(Instruction*); void emit_op_put_global_var(Instruction*); + void emit_op_put_global_var_check(Instruction*); void emit_op_put_scoped_var(Instruction*); void emit_op_resolve(Instruction*); void emit_op_resolve_base(Instruction*); @@ -739,6 +741,7 @@ namespace JSC { void emitSlow_op_pre_inc(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_put_by_id(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_put_by_val(Instruction*, Vector<SlowCaseEntry>::iterator&); + void emitSlow_op_put_global_var_check(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_resolve_global(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_resolve_global_dynamic(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_rshift(Instruction*, Vector<SlowCaseEntry>::iterator&); diff --git a/Source/JavaScriptCore/jit/JITCode.h b/Source/JavaScriptCore/jit/JITCode.h index c85e02e80..478fcc7bf 100644 --- a/Source/JavaScriptCore/jit/JITCode.h +++ b/Source/JavaScriptCore/jit/JITCode.h @@ -29,6 +29,7 @@ #if ENABLE(JIT) #include "CallFrame.h" #include "JSValue.h" +#include "Disassembler.h" #include "MacroAssemblerCodeRef.h" #include "Profiler.h" #endif @@ -105,6 +106,11 @@ namespace JSC { return reinterpret_cast<char*>(m_ref.code().executableAddress()) + offset; } + void* executableAddress() const + { + return executableAddressAtOffset(0); + } + void* dataAddressAtOffset(size_t offset) const { ASSERT(offset <= size()); // use <= instead of < because it is valid to ask for an address at the exclusive end of the code. @@ -124,7 +130,7 @@ namespace JSC { // Execute the code! inline JSValue execute(RegisterFile* registerFile, CallFrame* callFrame, JSGlobalData* globalData) { - JSValue result = JSValue::decode(ctiTrampoline(m_ref.code().executableAddress(), registerFile, callFrame, 0, Profiler::enabledProfilerReference(), globalData)); + JSValue result = JSValue::decode(ctiTrampoline(m_ref.code().executableAddress(), registerFile, callFrame, 0, 0, globalData)); return globalData->exception ? jsNull() : result; } @@ -138,6 +144,11 @@ namespace JSC { ASSERT(m_ref.code().executableAddress()); return m_ref.size(); } + + bool tryToDisassemble(const char* prefix) const + { + return m_ref.tryToDisassemble(prefix); + } ExecutableMemoryHandle* getExecutableMemory() { diff --git a/Source/JavaScriptCore/jit/JITOpcodes.cpp b/Source/JavaScriptCore/jit/JITOpcodes.cpp index aa2938cc2..ad7a56e12 100644 --- a/Source/JavaScriptCore/jit/JITOpcodes.cpp +++ b/Source/JavaScriptCore/jit/JITOpcodes.cpp @@ -211,7 +211,7 @@ PassRefPtr<ExecutableMemoryHandle> JIT::privateCompileCTIMachineTrampolines(JSGl patchBuffer.link(callCallNotJSFunction, FunctionPtr(cti_op_call_NotJSFunction)); patchBuffer.link(callConstructNotJSFunction, FunctionPtr(cti_op_construct_NotJSConstruct)); - CodeRef finalCode = patchBuffer.finalizeCode(); + CodeRef finalCode = FINALIZE_CODE(patchBuffer, ("JIT CTI machine trampolines")); RefPtr<ExecutableMemoryHandle> executableMemory = finalCode.executableMemory(); trampolines->ctiVirtualCallLink = patchBuffer.trampolineAt(virtualCallLinkBegin); @@ -1290,25 +1290,16 @@ void JIT::emitSlow_op_create_this(Instruction* currentInstruction, Vector<SlowCa void JIT::emit_op_profile_will_call(Instruction* currentInstruction) { - peek(regT1, OBJECT_OFFSETOF(JITStackFrame, enabledProfilerReference) / sizeof(void*)); - Jump noProfiler = branchTestPtr(Zero, Address(regT1)); - JITStubCall stubCall(this, cti_op_profile_will_call); stubCall.addArgument(currentInstruction[1].u.operand, regT1); stubCall.call(); - noProfiler.link(this); - } void JIT::emit_op_profile_did_call(Instruction* currentInstruction) { - peek(regT1, OBJECT_OFFSETOF(JITStackFrame, enabledProfilerReference) / sizeof(void*)); - Jump noProfiler = branchTestPtr(Zero, Address(regT1)); - JITStubCall stubCall(this, cti_op_profile_did_call); stubCall.addArgument(currentInstruction[1].u.operand, regT1); stubCall.call(); - noProfiler.link(this); } diff --git a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp index 12e47b2ee..57ef7ef2f 100644 --- a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp +++ b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp @@ -207,7 +207,7 @@ PassRefPtr<ExecutableMemoryHandle> JIT::privateCompileCTIMachineTrampolines(JSGl patchBuffer.link(callCallNotJSFunction, FunctionPtr(cti_op_call_NotJSFunction)); patchBuffer.link(callConstructNotJSFunction, FunctionPtr(cti_op_construct_NotJSConstruct)); - CodeRef finalCode = patchBuffer.finalizeCode(); + CodeRef finalCode = FINALIZE_CODE(patchBuffer, ("JIT CTI machine trampolines")); RefPtr<ExecutableMemoryHandle> executableMemory = finalCode.executableMemory(); trampolines->ctiVirtualCallLink = patchBuffer.trampolineAt(virtualCallLinkBegin); @@ -497,7 +497,7 @@ JIT::CodeRef JIT::privateCompileCTINativeCall(JSGlobalData* globalData, NativeFu LinkBuffer patchBuffer(*m_globalData, this, GLOBAL_THUNK_ID); patchBuffer.link(nativeCall, FunctionPtr(func)); - return patchBuffer.finalizeCode(); + return FINALIZE_CODE(patchBuffer, ("JIT CTI native call")); } void JIT::emit_op_mov(Instruction* currentInstruction) @@ -1590,24 +1590,16 @@ void JIT::emitSlow_op_convert_this(Instruction* currentInstruction, Vector<SlowC void JIT::emit_op_profile_will_call(Instruction* currentInstruction) { - peek(regT2, OBJECT_OFFSETOF(JITStackFrame, enabledProfilerReference) / sizeof(void*)); - Jump noProfiler = branchTestPtr(Zero, Address(regT2)); - JITStubCall stubCall(this, cti_op_profile_will_call); stubCall.addArgument(currentInstruction[1].u.operand); stubCall.call(); - noProfiler.link(this); } void JIT::emit_op_profile_did_call(Instruction* currentInstruction) { - peek(regT2, OBJECT_OFFSETOF(JITStackFrame, enabledProfilerReference) / sizeof(void*)); - Jump noProfiler = branchTestPtr(Zero, Address(regT2)); - JITStubCall stubCall(this, cti_op_profile_did_call); stubCall.addArgument(currentInstruction[1].u.operand); stubCall.call(); - noProfiler.link(this); } void JIT::emit_op_get_arguments_length(Instruction* currentInstruction) @@ -1672,7 +1664,7 @@ void JIT::emitSlow_op_get_argument_by_val(Instruction* currentInstruction, Vecto JITStubCall stubCall(this, cti_op_get_by_val); stubCall.addArgument(arguments); stubCall.addArgument(property); - stubCall.call(dst); + stubCall.callWithValueProfiling(dst); } } // namespace JSC diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp index 5d39735af..7478f9184 100644 --- a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp +++ b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp @@ -30,12 +30,13 @@ #include "CodeBlock.h" #include "GetterSetter.h" +#include "Interpreter.h" #include "JITInlineMethods.h" #include "JITStubCall.h" #include "JSArray.h" #include "JSFunction.h" #include "JSPropertyNameIterator.h" -#include "Interpreter.h" +#include "JSVariableObject.h" #include "LinkBuffer.h" #include "RepatchBuffer.h" #include "ResultType.h" @@ -87,7 +88,7 @@ JIT::CodeRef JIT::stringGetByValStubGenerator(JSGlobalData* globalData) jit.ret(); LinkBuffer patchBuffer(*globalData, &jit, GLOBAL_THUNK_ID); - return patchBuffer.finalizeCode(); + return FINALIZE_CODE(patchBuffer, ("String get_by_val stub")); } void JIT::emit_op_get_by_val(Instruction* currentInstruction) @@ -563,7 +564,10 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure patchBuffer.link(m_calls[0].from, FunctionPtr(cti_op_put_by_id_transition_realloc)); } - stubInfo->stubRoutine = patchBuffer.finalizeCode(); + stubInfo->stubRoutine = FINALIZE_CODE( + patchBuffer, + ("Baseline put_by_id transition for CodeBlock %p, return point %p", + m_codeBlock, returnAddress.value())); RepatchBuffer repatchBuffer(m_codeBlock); repatchBuffer.relinkCallerToTrampoline(returnAddress, CodeLocationLabel(stubInfo->stubRoutine.code())); } @@ -624,7 +628,11 @@ void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress) patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(stubInfo->patch.baseline.u.get.putResult)); // Track the stub we have created so that it will be deleted later. - stubInfo->stubRoutine = patchBuffer.finalizeCode(); + stubInfo->stubRoutine = FINALIZE_CODE( + patchBuffer, + ("Basline JIT get_by_id array length stub for CodeBlock %p, return point %p", + m_codeBlock, stubInfo->hotPathBegin.labelAtOffset( + stubInfo->patch.baseline.u.get.putResult).executableAddress())); // Finally patch the jump to slow case back in the hot path to jump here instead. CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(stubInfo->patch.baseline.u.get.structureCheck); @@ -687,7 +695,11 @@ void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str } } // Track the stub we have created so that it will be deleted later. - stubInfo->stubRoutine = patchBuffer.finalizeCode(); + stubInfo->stubRoutine = FINALIZE_CODE( + patchBuffer, + ("Baseline JIT get_by_id proto stub for CodeBlock %p, return point %p", + m_codeBlock, stubInfo->hotPathBegin.labelAtOffset( + stubInfo->patch.baseline.u.get.putResult).executableAddress())); // Finally patch the jump to slow case back in the hot path to jump here instead. CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(stubInfo->patch.baseline.u.get.structureCheck); @@ -744,7 +756,11 @@ void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Polymorphic // On success return back to the hot patch code, at a point it will perform the store to dest for us. patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(stubInfo->patch.baseline.u.get.putResult)); - MacroAssemblerCodeRef stubCode = patchBuffer.finalizeCode(); + MacroAssemblerCodeRef stubCode = FINALIZE_CODE( + patchBuffer, + ("Baseline JIT get_by_id list stub for CodeBlock %p, return point %p", + m_codeBlock, stubInfo->hotPathBegin.labelAtOffset( + stubInfo->patch.baseline.u.get.putResult).executableAddress())); polymorphicStructures->list[currentIndex].set(*m_globalData, m_codeBlock->ownerExecutable(), stubCode, structure, isDirect); @@ -810,7 +826,11 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi // On success return back to the hot patch code, at a point it will perform the store to dest for us. patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(stubInfo->patch.baseline.u.get.putResult)); - MacroAssemblerCodeRef stubCode = patchBuffer.finalizeCode(); + MacroAssemblerCodeRef stubCode = FINALIZE_CODE( + patchBuffer, + ("Baseline JIT get_by_id proto list stub for CodeBlock %p, return point %p", + m_codeBlock, stubInfo->hotPathBegin.labelAtOffset( + stubInfo->patch.baseline.u.get.putResult).executableAddress())); prototypeStructures->list[currentIndex].set(*m_globalData, m_codeBlock->ownerExecutable(), stubCode, structure, prototypeStructure, isDirect); // Finally patch the jump to slow case back in the hot path to jump here instead. @@ -879,7 +899,11 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi // On success return back to the hot patch code, at a point it will perform the store to dest for us. patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(stubInfo->patch.baseline.u.get.putResult)); - CodeRef stubRoutine = patchBuffer.finalizeCode(); + CodeRef stubRoutine = FINALIZE_CODE( + patchBuffer, + ("Baseline JIT get_by_id chain list stub for CodeBlock %p, return point %p", + m_codeBlock, stubInfo->hotPathBegin.labelAtOffset( + stubInfo->patch.baseline.u.get.putResult).executableAddress())); // Track the stub we have created so that it will be deleted later. prototypeStructures->list[currentIndex].set(callFrame->globalData(), m_codeBlock->ownerExecutable(), stubRoutine, structure, chain, isDirect); @@ -946,7 +970,11 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(stubInfo->patch.baseline.u.get.putResult)); // Track the stub we have created so that it will be deleted later. - CodeRef stubRoutine = patchBuffer.finalizeCode(); + CodeRef stubRoutine = FINALIZE_CODE( + patchBuffer, + ("Baseline JIT get_by_id chain stub for CodeBlock %p, return point %p", + m_codeBlock, stubInfo->hotPathBegin.labelAtOffset( + stubInfo->patch.baseline.u.get.putResult).executableAddress())); stubInfo->stubRoutine = stubRoutine; // Finally patch the jump to slow case back in the hot path to jump here instead. @@ -1010,9 +1038,7 @@ void JIT::emit_op_put_scoped_var(Instruction* currentInstruction) void JIT::emit_op_get_global_var(Instruction* currentInstruction) { - JSVariableObject* globalObject = m_codeBlock->globalObject(); - loadPtr(&globalObject->m_registers, regT0); - loadPtr(Address(regT0, currentInstruction[2].u.operand * sizeof(Register)), regT0); + loadPtr(currentInstruction[2].u.registerPointer, regT0); emitValueProfilingSite(); emitPutVirtualRegister(currentInstruction[1].u.operand); } @@ -1022,11 +1048,33 @@ void JIT::emit_op_put_global_var(Instruction* currentInstruction) JSGlobalObject* globalObject = m_codeBlock->globalObject(); emitGetVirtualRegister(currentInstruction[2].u.operand, regT0); + + storePtr(regT0, currentInstruction[1].u.registerPointer); + if (Heap::isWriteBarrierEnabled()) + emitWriteBarrier(globalObject, regT0, regT2, ShouldFilterImmediates, WriteBarrierForVariableAccess); +} - move(TrustedImmPtr(globalObject), regT1); - loadPtr(Address(regT1, JSVariableObject::offsetOfRegisters()), regT1); - storePtr(regT0, Address(regT1, currentInstruction[1].u.operand * sizeof(Register))); - emitWriteBarrier(globalObject, regT0, regT2, ShouldFilterImmediates, WriteBarrierForVariableAccess); +void JIT::emit_op_put_global_var_check(Instruction* currentInstruction) +{ + emitGetVirtualRegister(currentInstruction[2].u.operand, regT0); + + addSlowCase(branchTest8(NonZero, AbsoluteAddress(currentInstruction[3].u.predicatePointer))); + + JSGlobalObject* globalObject = m_codeBlock->globalObject(); + + storePtr(regT0, currentInstruction[1].u.registerPointer); + if (Heap::isWriteBarrierEnabled()) + emitWriteBarrier(globalObject, regT0, regT2, ShouldFilterImmediates, WriteBarrierForVariableAccess); +} + +void JIT::emitSlow_op_put_global_var_check(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + linkSlowCase(iter); + + JITStubCall stubCall(this, cti_op_put_global_var_check); + stubCall.addArgument(regT0); + stubCall.addArgument(TrustedImm32(currentInstruction[4].u.operand)); + stubCall.call(); } void JIT::resetPatchGetById(RepatchBuffer& repatchBuffer, StructureStubInfo* stubInfo) diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp index bd57484c4..a44c576c5 100644 --- a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp +++ b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp @@ -30,12 +30,13 @@ #include "JIT.h" #include "CodeBlock.h" +#include "Interpreter.h" #include "JITInlineMethods.h" #include "JITStubCall.h" #include "JSArray.h" #include "JSFunction.h" #include "JSPropertyNameIterator.h" -#include "Interpreter.h" +#include "JSVariableObject.h" #include "LinkBuffer.h" #include "RepatchBuffer.h" #include "ResultType.h" @@ -193,7 +194,7 @@ JIT::CodeRef JIT::stringGetByValStubGenerator(JSGlobalData* globalData) jit.ret(); LinkBuffer patchBuffer(*globalData, &jit, GLOBAL_THUNK_ID); - return patchBuffer.finalizeCode(); + return FINALIZE_CODE(patchBuffer, ("String get_by_val stub")); } void JIT::emit_op_get_by_val(Instruction* currentInstruction) @@ -544,7 +545,10 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure patchBuffer.link(m_calls[0].from, FunctionPtr(cti_op_put_by_id_transition_realloc)); } - stubInfo->stubRoutine = patchBuffer.finalizeCode(); + stubInfo->stubRoutine = FINALIZE_CODE( + patchBuffer, + ("Baseline put_by_id transition stub for CodeBlock %p, return point %p", + m_codeBlock, returnAddress.value())); RepatchBuffer repatchBuffer(m_codeBlock); repatchBuffer.relinkCallerToTrampoline(returnAddress, CodeLocationLabel(stubInfo->stubRoutine.code())); } @@ -610,7 +614,11 @@ void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress) patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(stubInfo->patch.baseline.u.get.putResult)); // Track the stub we have created so that it will be deleted later. - stubInfo->stubRoutine = patchBuffer.finalizeCode(); + stubInfo->stubRoutine = FINALIZE_CODE( + patchBuffer, + ("Baseline get_by_id array length stub for CodeBlock %p, return point %p", + m_codeBlock, stubInfo->hotPathBegin.labelAtOffset( + stubInfo->patch.baseline.u.get.putResult).executableAddress())); // Finally patch the jump to slow case back in the hot path to jump here instead. CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(stubInfo->patch.baseline.u.get.structureCheck); @@ -676,7 +684,11 @@ void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str } // Track the stub we have created so that it will be deleted later. - stubInfo->stubRoutine = patchBuffer.finalizeCode(); + stubInfo->stubRoutine = FINALIZE_CODE( + patchBuffer, + ("Baseline get_by_id proto stub for CodeBlock %p, return point %p", + m_codeBlock, stubInfo->hotPathBegin.labelAtOffset( + stubInfo->patch.baseline.u.get.putResult).executableAddress())); // Finally patch the jump to slow case back in the hot path to jump here instead. CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(stubInfo->patch.baseline.u.get.structureCheck); @@ -734,7 +746,11 @@ void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Polymorphic // On success return back to the hot patch code, at a point it will perform the store to dest for us. patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(stubInfo->patch.baseline.u.get.putResult)); - CodeRef stubRoutine = patchBuffer.finalizeCode(); + MacroAssemblerCodeRef stubRoutine = FINALIZE_CODE( + patchBuffer, + ("Baseline get_by_id self list stub for CodeBlock %p, return point %p", + m_codeBlock, stubInfo->hotPathBegin.labelAtOffset( + stubInfo->patch.baseline.u.get.putResult).executableAddress())); polymorphicStructures->list[currentIndex].set(*m_globalData, m_codeBlock->ownerExecutable(), stubRoutine, structure, isDirect); @@ -799,7 +815,11 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi // On success return back to the hot patch code, at a point it will perform the store to dest for us. patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(stubInfo->patch.baseline.u.get.putResult)); - CodeRef stubRoutine = patchBuffer.finalizeCode(); + MacroAssemblerCodeRef stubRoutine = FINALIZE_CODE( + patchBuffer, + ("Baseline get_by_id proto list stub for CodeBlock %p, return point %p", + m_codeBlock, stubInfo->hotPathBegin.labelAtOffset( + stubInfo->patch.baseline.u.get.putResult).executableAddress())); prototypeStructures->list[currentIndex].set(callFrame->globalData(), m_codeBlock->ownerExecutable(), stubRoutine, structure, prototypeStructure, isDirect); @@ -869,7 +889,11 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi // On success return back to the hot patch code, at a point it will perform the store to dest for us. patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(stubInfo->patch.baseline.u.get.putResult)); - CodeRef stubRoutine = patchBuffer.finalizeCode(); + MacroAssemblerCodeRef stubRoutine = FINALIZE_CODE( + patchBuffer, + ("Baseline get_by_id chain list stub for CodeBlock %p, return point %p", + m_codeBlock, stubInfo->hotPathBegin.labelAtOffset( + stubInfo->patch.baseline.u.get.putResult).executableAddress())); // Track the stub we have created so that it will be deleted later. prototypeStructures->list[currentIndex].set(callFrame->globalData(), m_codeBlock->ownerExecutable(), stubRoutine, structure, chain, isDirect); @@ -935,7 +959,11 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(stubInfo->patch.baseline.u.get.putResult)); // Track the stub we have created so that it will be deleted later. - CodeRef stubRoutine = patchBuffer.finalizeCode(); + MacroAssemblerCodeRef stubRoutine = FINALIZE_CODE( + patchBuffer, + ("Baseline get_by_id chain stub for CodeBlock %p, return point %p", + m_codeBlock, stubInfo->hotPathBegin.labelAtOffset( + stubInfo->patch.baseline.u.get.putResult).executableAddress())); stubInfo->stubRoutine = stubRoutine; // Finally patch the jump to slow case back in the hot path to jump here instead. @@ -1060,13 +1088,10 @@ void JIT::emit_op_put_scoped_var(Instruction* currentInstruction) void JIT::emit_op_get_global_var(Instruction* currentInstruction) { int dst = currentInstruction[1].u.operand; - JSGlobalObject* globalObject = m_codeBlock->globalObject(); - ASSERT(globalObject->isGlobalObject()); - int index = currentInstruction[2].u.operand; + WriteBarrier<Unknown>* registerPointer = currentInstruction[2].u.registerPointer; - loadPtr(&globalObject->m_registers, regT2); - - emitLoad(index, regT1, regT0, regT2); + load32(registerPointer->tagPointer(), regT1); + load32(registerPointer->payloadPointer(), regT0); emitValueProfilingSite(); emitStore(dst, regT1, regT0); map(m_bytecodeOffset + OPCODE_LENGTH(op_get_global_var), dst, regT1, regT0); @@ -1074,21 +1099,55 @@ void JIT::emit_op_get_global_var(Instruction* currentInstruction) void JIT::emit_op_put_global_var(Instruction* currentInstruction) { - int index = currentInstruction[1].u.operand; + WriteBarrier<Unknown>* registerPointer = currentInstruction[1].u.registerPointer; int value = currentInstruction[2].u.operand; JSGlobalObject* globalObject = m_codeBlock->globalObject(); emitLoad(value, regT1, regT0); - move(TrustedImmPtr(globalObject), regT2); - - emitWriteBarrier(globalObject, regT1, regT3, ShouldFilterImmediates, WriteBarrierForVariableAccess); + + if (Heap::isWriteBarrierEnabled()) { + move(TrustedImmPtr(globalObject), regT2); + + emitWriteBarrier(globalObject, regT1, regT3, ShouldFilterImmediates, WriteBarrierForVariableAccess); + } - loadPtr(Address(regT2, JSVariableObject::offsetOfRegisters()), regT2); - emitStore(index, regT1, regT0, regT2); + store32(regT1, registerPointer->tagPointer()); + store32(regT0, registerPointer->payloadPointer()); map(m_bytecodeOffset + OPCODE_LENGTH(op_put_global_var), value, regT1, regT0); } +void JIT::emit_op_put_global_var_check(Instruction* currentInstruction) +{ + WriteBarrier<Unknown>* registerPointer = currentInstruction[1].u.registerPointer; + int value = currentInstruction[2].u.operand; + + JSGlobalObject* globalObject = m_codeBlock->globalObject(); + + emitLoad(value, regT1, regT0); + + addSlowCase(branchTest8(NonZero, AbsoluteAddress(currentInstruction[3].u.predicatePointer))); + + if (Heap::isWriteBarrierEnabled()) { + move(TrustedImmPtr(globalObject), regT2); + emitWriteBarrier(globalObject, regT1, regT3, ShouldFilterImmediates, WriteBarrierForVariableAccess); + } + + store32(regT1, registerPointer->tagPointer()); + store32(regT0, registerPointer->payloadPointer()); + unmap(); +} + +void JIT::emitSlow_op_put_global_var_check(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + linkSlowCase(iter); + + JITStubCall stubCall(this, cti_op_put_global_var_check); + stubCall.addArgument(regT1, regT0); + stubCall.addArgument(TrustedImm32(currentInstruction[4].u.operand)); + stubCall.call(); +} + void JIT::resetPatchGetById(RepatchBuffer& repatchBuffer, StructureStubInfo* stubInfo) { repatchBuffer.relink(stubInfo->callReturnLocation, cti_op_get_by_id); diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp index e75f2825c..12f3ec344 100644 --- a/Source/JavaScriptCore/jit/JITStubs.cpp +++ b/Source/JavaScriptCore/jit/JITStubs.cpp @@ -112,7 +112,7 @@ asm ( HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "movl %esp, %ecx" "\n" - "call " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n" + "call " LOCAL_REFERENCE(cti_vm_throw) "\n" "int3" "\n" ); @@ -172,7 +172,7 @@ asm ( HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "movq %rsp, %rdi" "\n" - "call " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n" + "call " LOCAL_REFERENCE(cti_vm_throw) "\n" "int3" "\n" ); @@ -205,7 +205,7 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" #define REGISTER_FILE_OFFSET 0x60 #define CALLFRAME_OFFSET 0x64 #define EXCEPTION_OFFSET 0x64 -#define ENABLE_PROFILER_REFERENCE_OFFSET 0x68 +#define FIRST_STACK_ARGUMENT 0x68 #elif (COMPILER(GCC) || COMPILER(MSVC) || COMPILER(RVCT)) && CPU(ARM_TRADITIONAL) @@ -225,7 +225,7 @@ COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x50, JITStackFrame_code_ extern "C" { - __declspec(naked) EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, void* /*unused1*/, Profiler**, JSGlobalData*) + __declspec(naked) EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, void* /*unused1*/, void* /*unused2*/, JSGlobalData*) { __asm { push ebp; @@ -284,12 +284,11 @@ extern "C" { #define REGISTER_FILE_OFFSET 84 #define CALLFRAME_OFFSET 88 #define EXCEPTION_OFFSET 92 -#define ENABLE_PROFILER_REFERENCE_OFFSET 96 #define GLOBAL_DATA_OFFSET 100 #define STACK_LENGTH 104 #elif CPU(SH4) #define SYMBOL_STRING(name) #name -/* code (r4), RegisterFile* (r5), CallFrame* (r6), JSValue* exception (r7), Profiler**(sp), JSGlobalData (sp)*/ +/* code (r4), RegisterFile* (r5), CallFrame* (r6), void* unused1 (r7), void* unused2(sp), JSGlobalData (sp)*/ asm volatile ( ".text\n" @@ -417,7 +416,7 @@ asm ( HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "movq %rsp, %rdi" "\n" - "call " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n" + "call " LOCAL_REFERENCE(cti_vm_throw) "\n" "int3" "\n" ); @@ -465,9 +464,7 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" "sw $5," STRINGIZE_VALUE_OF(REGISTER_FILE_OFFSET) "($29) # store registerFile to current stack" "\n" "sw $6," STRINGIZE_VALUE_OF(CALLFRAME_OFFSET) "($29) # store callFrame to curent stack" "\n" "sw $7," STRINGIZE_VALUE_OF(EXCEPTION_OFFSET) "($29) # store exception to current stack" "\n" - "lw $8," STRINGIZE_VALUE_OF(STACK_LENGTH + 16) "($29) # load enableProfilerReference from previous stack" "\n" "lw $9," STRINGIZE_VALUE_OF(STACK_LENGTH + 20) "($29) # load globalData from previous stack" "\n" - "sw $8," STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET) "($29) # store enableProfilerReference to current stack" "\n" "jalr $25" "\n" "sw $9," STRINGIZE_VALUE_OF(GLOBAL_DATA_OFFSET) "($29) # store globalData to current stack" "\n" "lw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n" @@ -543,7 +540,7 @@ HIDE_SYMBOL(ctiTrampoline) "\n" ".thumb" "\n" ".thumb_func " THUMB_FUNC_PARAM(ctiTrampoline) "\n" SYMBOL_STRING(ctiTrampoline) ":" "\n" - "sub sp, sp, #" STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET) "\n" + "sub sp, sp, #" STRINGIZE_VALUE_OF(FIRST_STACK_ARGUMENT) "\n" "str lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "]" "\n" "str r4, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R4_OFFSET) "]" "\n" "str r5, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R5_OFFSET) "]" "\n" @@ -568,7 +565,7 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" "ldr r5, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R5_OFFSET) "]" "\n" "ldr r4, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R4_OFFSET) "]" "\n" "ldr lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "]" "\n" - "add sp, sp, #" STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET) "\n" + "add sp, sp, #" STRINGIZE_VALUE_OF(FIRST_STACK_ARGUMENT) "\n" "bx lr" "\n" ".align 2" "\n" ".globl " SYMBOL_STRING(ctiTrampolineEnd) "\n" @@ -587,7 +584,7 @@ HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" ".thumb_func " THUMB_FUNC_PARAM(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "mov r0, sp" "\n" - "bl " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n" + "bl " LOCAL_REFERENCE(cti_vm_throw) "\n" "ldr r11, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R11_OFFSET) "]" "\n" "ldr r10, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R10_OFFSET) "]" "\n" "ldr r9, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R9_OFFSET) "]" "\n" @@ -597,7 +594,7 @@ SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "ldr r5, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R5_OFFSET) "]" "\n" "ldr r4, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R4_OFFSET) "]" "\n" "ldr lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "]" "\n" - "add sp, sp, #" STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET) "\n" + "add sp, sp, #" STRINGIZE_VALUE_OF(FIRST_STACK_ARGUMENT) "\n" "bx lr" "\n" ); @@ -618,7 +615,7 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "ldr r5, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R5_OFFSET) "]" "\n" "ldr r4, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R4_OFFSET) "]" "\n" "ldr lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "]" "\n" - "add sp, sp, #" STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET) "\n" + "add sp, sp, #" STRINGIZE_VALUE_OF(FIRST_STACK_ARGUMENT) "\n" "bx lr" "\n" ); @@ -661,10 +658,10 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" #elif COMPILER(RVCT) && CPU(ARM_THUMB2) -__asm EncodedJSValue ctiTrampoline(void*, RegisterFile*, CallFrame*, JSValue*, Profiler**, JSGlobalData*) +__asm EncodedJSValue ctiTrampoline(void*, RegisterFile*, CallFrame*, void* /*unused1*/, void* /*unused2*/, JSGlobalData*) { PRESERVE8 - sub sp, sp, # ENABLE_PROFILER_REFERENCE_OFFSET + sub sp, sp, # FIRST_STACK_ARGUMENT str lr, [sp, # PRESERVED_RETURN_ADDRESS_OFFSET ] str r4, [sp, # PRESERVED_R4_OFFSET ] str r5, [sp, # PRESERVED_R5_OFFSET ] @@ -689,7 +686,7 @@ __asm EncodedJSValue ctiTrampoline(void*, RegisterFile*, CallFrame*, JSValue*, P ldr r5, [sp, # PRESERVED_R5_OFFSET ] ldr r4, [sp, # PRESERVED_R4_OFFSET ] ldr lr, [sp, # PRESERVED_RETURN_ADDRESS_OFFSET ] - add sp, sp, # ENABLE_PROFILER_REFERENCE_OFFSET + add sp, sp, # FIRST_STACK_ARGUMENT bx lr } @@ -708,7 +705,7 @@ __asm void ctiVMThrowTrampoline() ldr r5, [sp, # PRESERVED_R5_OFFSET ] ldr r4, [sp, # PRESERVED_R4_OFFSET ] ldr lr, [sp, # PRESERVED_RETURN_ADDRESS_OFFSET ] - add sp, sp, # ENABLE_PROFILER_REFERENCE_OFFSET + add sp, sp, # FIRST_STACK_ARGUMENT bx lr } @@ -725,13 +722,13 @@ __asm void ctiOpThrowNotCaught() ldr r5, [sp, # PRESERVED_R5_OFFSET ] ldr r4, [sp, # PRESERVED_R4_OFFSET ] ldr lr, [sp, # PRESERVED_RETURN_ADDRESS_OFFSET ] - add sp, sp, # ENABLE_PROFILER_REFERENCE_OFFSET + add sp, sp, # FIRST_STACK_ARGUMENT bx lr } #elif COMPILER(RVCT) && CPU(ARM_TRADITIONAL) -__asm EncodedJSValue ctiTrampoline(void*, RegisterFile*, CallFrame*, void* /*unused1*/, Profiler**, JSGlobalData*) +__asm EncodedJSValue ctiTrampoline(void*, RegisterFile*, CallFrame*, void* /*unused1*/, void* /*unused2*/, JSGlobalData*) { ARM stmdb sp!, {r1-r3} @@ -800,7 +797,7 @@ JITThunks::JITThunks(JSGlobalData* globalData) ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, registerFile) == REGISTER_FILE_OFFSET); ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, callFrame) == CALLFRAME_OFFSET); // The fifth argument is the first item already on the stack. - ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, enabledProfilerReference) == ENABLE_PROFILER_REFERENCE_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, unused1) == FIRST_STACK_ARGUMENT); ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == THUNK_RETURN_ADDRESS_OFFSET); @@ -820,7 +817,6 @@ JITThunks::JITThunks(JSGlobalData* globalData) ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, registerFile) == REGISTER_FILE_OFFSET); ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, callFrame) == CALLFRAME_OFFSET); ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, unused1) == EXCEPTION_OFFSET); - ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, enabledProfilerReference) == ENABLE_PROFILER_REFERENCE_OFFSET); ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, globalData) == GLOBAL_DATA_OFFSET); #endif @@ -870,6 +866,7 @@ NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* co normalizePrototypeChain(callFrame, baseCell); StructureChain* prototypeChain = structure->prototypeChain(callFrame); + ASSERT(structure->previousID()->transitionWatchpointSetHasBeenInvalidated()); stubInfo->initPutByIdTransition(callFrame->globalData(), codeBlock->ownerExecutable(), structure->previousID(), structure, prototypeChain, direct); JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress, direct); return; @@ -949,7 +946,7 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co offset = slotBaseObject->structure()->get(callFrame->globalData(), propertyName); } - stubInfo->initGetByIdProto(callFrame->globalData(), codeBlock->ownerExecutable(), structure, slotBaseObject->structure()); + stubInfo->initGetByIdProto(callFrame->globalData(), codeBlock->ownerExecutable(), structure, slotBaseObject->structure(), slot.cachedPropertyType() == PropertySlot::Value); ASSERT(!structure->isDictionary()); ASSERT(!slotBaseObject->structure()->isDictionary()); @@ -965,7 +962,7 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co } StructureChain* prototypeChain = structure->prototypeChain(callFrame); - stubInfo->initGetByIdChain(callFrame->globalData(), codeBlock->ownerExecutable(), structure, prototypeChain); + stubInfo->initGetByIdChain(callFrame->globalData(), codeBlock->ownerExecutable(), structure, prototypeChain, count, slot.cachedPropertyType() == PropertySlot::Value); JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, propertyName, slot, offset, returnAddress); } @@ -2355,16 +2352,16 @@ DEFINE_STUB_FUNCTION(void, op_profile_will_call) { STUB_INIT_STACK_FRAME(stackFrame); - ASSERT(*stackFrame.enabledProfilerReference); - (*stackFrame.enabledProfilerReference)->willExecute(stackFrame.callFrame, stackFrame.args[0].jsValue()); + if (Profiler* profiler = stackFrame.globalData->enabledProfiler()) + profiler->willExecute(stackFrame.callFrame, stackFrame.args[0].jsValue()); } DEFINE_STUB_FUNCTION(void, op_profile_did_call) { STUB_INIT_STACK_FRAME(stackFrame); - ASSERT(*stackFrame.enabledProfilerReference); - (*stackFrame.enabledProfilerReference)->didExecute(stackFrame.callFrame, stackFrame.args[0].jsValue()); + if (Profiler* profiler = stackFrame.globalData->enabledProfiler()) + profiler->didExecute(stackFrame.callFrame, stackFrame.args[0].jsValue()); } DEFINE_STUB_FUNCTION(JSObject*, op_new_array) @@ -2381,6 +2378,15 @@ DEFINE_STUB_FUNCTION(JSObject*, op_new_array_buffer) return constructArray(stackFrame.callFrame, stackFrame.callFrame->codeBlock()->constantBuffer(stackFrame.args[0].int32()), stackFrame.args[1].int32()); } +DEFINE_STUB_FUNCTION(void, op_put_global_var_check) +{ + STUB_INIT_STACK_FRAME(stackFrame); + + CallFrame* callFrame = stackFrame.callFrame; + CodeBlock* codeBlock = callFrame->codeBlock(); + symbolTablePut(codeBlock->globalObject(), callFrame, codeBlock->identifier(stackFrame.args[1].int32()), stackFrame.args[0].jsValue(), true); +} + DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve) { STUB_INIT_STACK_FRAME(stackFrame); diff --git a/Source/JavaScriptCore/jit/JITStubs.h b/Source/JavaScriptCore/jit/JITStubs.h index 664338fd3..251776075 100644 --- a/Source/JavaScriptCore/jit/JITStubs.h +++ b/Source/JavaScriptCore/jit/JITStubs.h @@ -104,7 +104,7 @@ namespace JSC { RegisterFile* registerFile; CallFrame* callFrame; void* unused1; - Profiler** enabledProfilerReference; + void* unused2; JSGlobalData* globalData; void* savedRBX; @@ -140,7 +140,7 @@ namespace JSC { RegisterFile* registerFile; CallFrame* callFrame; void* unused1; - Profiler** enabledProfilerReference; + void* unused2; JSGlobalData* globalData; // When JIT code makes a call, it pushes its return address just below the rest of the stack. @@ -171,7 +171,7 @@ namespace JSC { CallFrame* callFrame; // These arguments passed on the stack. - Profiler** enabledProfilerReference; + void* unused1; JSGlobalData* globalData; ReturnAddressPtr* returnAddressSlot() { return &thunkReturnAddress; } @@ -199,7 +199,7 @@ namespace JSC { void* unused1; // These arguments passed on the stack. - Profiler** enabledProfilerReference; + void* unused2; JSGlobalData* globalData; // When JIT code makes a call, it pushes its return address just below the rest of the stack. @@ -231,7 +231,7 @@ namespace JSC { void* unused1; // These arguments passed on the stack. - Profiler** enabledProfilerReference; + void* unused2; JSGlobalData* globalData; ReturnAddressPtr* returnAddressSlot() { return &thunkReturnAddress; } @@ -252,7 +252,7 @@ namespace JSC { RegisterFile* registerFile; CallFrame* callFrame; JSValue* exception; - Profiler** enabledProfilerReference; + void* unused1; JSGlobalData* globalData; ReturnAddressPtr* returnAddressSlot() { return &thunkReturnAddress; } @@ -282,7 +282,7 @@ namespace JSC { extern "C" void ctiVMThrowTrampoline(); extern "C" void ctiOpThrowNotCaught(); - extern "C" EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, void* /*unused1*/, Profiler**, JSGlobalData*); + extern "C" EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, void* /*unused1*/, void* /*unused2*/, JSGlobalData*); #if ENABLE(DFG_JIT) extern "C" void ctiTrampolineEnd(); @@ -341,129 +341,130 @@ namespace JSC { }; extern "C" { - EncodedJSValue JIT_STUB cti_op_add(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_bitand(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_bitor(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_bitxor(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_call_NotJSFunction(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_call_eval(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_construct_NotJSConstruct(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_create_this(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_convert_this(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_create_arguments(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_del_by_id(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_del_by_val(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_div(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_get_by_id(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_get_by_id_array_fail(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_get_by_id_custom_stub(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_get_by_id_generic(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_get_by_id_getter_stub(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_get_by_id_method_check(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_get_by_id_method_check_update(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_get_by_id_proto_fail(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_get_by_id_proto_list(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_get_by_id_proto_list_full(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_get_by_id_self_fail(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_get_by_id_string_fail(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_get_by_val(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_get_by_val_string(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_in(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_instanceof(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_is_boolean(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_is_function(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_is_number(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_is_object(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_is_string(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_is_undefined(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_less(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_lesseq(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_greater(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_greatereq(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_lshift(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_mod(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_mul(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_negate(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_not(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_nstricteq(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_post_dec(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_post_inc(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_pre_dec(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_pre_inc(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_resolve(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_resolve_base(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_resolve_base_strict_put(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_ensure_property_exists(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_resolve_global(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_resolve_global_dynamic(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_resolve_skip(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_resolve_with_base(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_resolve_with_this(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_rshift(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_strcat(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_stricteq(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_sub(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_to_jsnumber(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_to_primitive(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_typeof(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_urshift(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_to_object(STUB_ARGS_DECLARATION); - JSObject* JIT_STUB cti_op_new_array(STUB_ARGS_DECLARATION); - JSObject* JIT_STUB cti_op_new_array_buffer(STUB_ARGS_DECLARATION); - JSObject* JIT_STUB cti_op_new_func(STUB_ARGS_DECLARATION); - JSObject* JIT_STUB cti_op_new_func_exp(STUB_ARGS_DECLARATION); - JSObject* JIT_STUB cti_op_new_object(STUB_ARGS_DECLARATION); - JSObject* JIT_STUB cti_op_new_regexp(STUB_ARGS_DECLARATION); - JSObject* JIT_STUB cti_op_push_activation(STUB_ARGS_DECLARATION); - JSObject* JIT_STUB cti_op_push_new_scope(STUB_ARGS_DECLARATION); - JSObject* JIT_STUB cti_op_push_scope(STUB_ARGS_DECLARATION); - JSObject* JIT_STUB cti_op_put_by_id_transition_realloc(STUB_ARGS_DECLARATION); - JSPropertyNameIterator* JIT_STUB cti_op_get_pnames(STUB_ARGS_DECLARATION); - int JIT_STUB cti_op_eq(STUB_ARGS_DECLARATION); - int JIT_STUB cti_op_eq_strings(STUB_ARGS_DECLARATION); - int JIT_STUB cti_op_jless(STUB_ARGS_DECLARATION); - int JIT_STUB cti_op_jlesseq(STUB_ARGS_DECLARATION); - int JIT_STUB cti_op_jgreater(STUB_ARGS_DECLARATION); - int JIT_STUB cti_op_jgreatereq(STUB_ARGS_DECLARATION); - int JIT_STUB cti_op_jtrue(STUB_ARGS_DECLARATION); - void* JIT_STUB cti_op_load_varargs(STUB_ARGS_DECLARATION); - int JIT_STUB cti_timeout_check(STUB_ARGS_DECLARATION); - int JIT_STUB cti_has_property(STUB_ARGS_DECLARATION); - void JIT_STUB cti_op_check_has_instance(STUB_ARGS_DECLARATION); - void JIT_STUB cti_op_debug(STUB_ARGS_DECLARATION); - void JIT_STUB cti_op_end(STUB_ARGS_DECLARATION); - void JIT_STUB cti_op_jmp_scopes(STUB_ARGS_DECLARATION); - void JIT_STUB cti_op_pop_scope(STUB_ARGS_DECLARATION); - void JIT_STUB cti_op_profile_did_call(STUB_ARGS_DECLARATION); - void JIT_STUB cti_op_profile_will_call(STUB_ARGS_DECLARATION); - void JIT_STUB cti_op_put_by_id(STUB_ARGS_DECLARATION); - void JIT_STUB cti_op_put_by_id_fail(STUB_ARGS_DECLARATION); - void JIT_STUB cti_op_put_by_id_generic(STUB_ARGS_DECLARATION); - void JIT_STUB cti_op_put_by_id_direct(STUB_ARGS_DECLARATION); - void JIT_STUB cti_op_put_by_id_direct_fail(STUB_ARGS_DECLARATION); - void JIT_STUB cti_op_put_by_id_direct_generic(STUB_ARGS_DECLARATION); - void JIT_STUB cti_op_put_by_index(STUB_ARGS_DECLARATION); - void JIT_STUB cti_op_put_by_val(STUB_ARGS_DECLARATION); - void JIT_STUB cti_op_put_getter_setter(STUB_ARGS_DECLARATION); - void JIT_STUB cti_op_tear_off_activation(STUB_ARGS_DECLARATION); - void JIT_STUB cti_op_tear_off_arguments(STUB_ARGS_DECLARATION); - void JIT_STUB cti_op_throw_reference_error(STUB_ARGS_DECLARATION); + EncodedJSValue JIT_STUB cti_op_add(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_bitand(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_bitor(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_bitxor(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_call_NotJSFunction(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_call_eval(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_construct_NotJSConstruct(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_create_this(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_convert_this(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_create_arguments(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_del_by_id(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_del_by_val(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_div(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_get_by_id(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_get_by_id_array_fail(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_get_by_id_custom_stub(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_get_by_id_generic(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_get_by_id_getter_stub(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_get_by_id_method_check(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_get_by_id_method_check_update(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_get_by_id_proto_fail(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_get_by_id_proto_list(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_get_by_id_proto_list_full(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_get_by_id_self_fail(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_get_by_id_string_fail(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_get_by_val(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_get_by_val_string(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_in(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_instanceof(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_is_boolean(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_is_function(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_is_number(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_is_object(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_is_string(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_is_undefined(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_less(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_lesseq(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_greater(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_greatereq(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_lshift(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_mod(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_mul(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_negate(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_not(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_nstricteq(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_post_dec(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_post_inc(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_pre_dec(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_pre_inc(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_resolve(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_resolve_base(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_resolve_base_strict_put(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_ensure_property_exists(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_resolve_global(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_resolve_global_dynamic(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_resolve_skip(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_resolve_with_base(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_resolve_with_this(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_rshift(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_strcat(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_stricteq(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_sub(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_to_jsnumber(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_to_primitive(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_typeof(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_urshift(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_to_object(STUB_ARGS_DECLARATION) WTF_INTERNAL; + JSObject* JIT_STUB cti_op_new_array(STUB_ARGS_DECLARATION) WTF_INTERNAL; + JSObject* JIT_STUB cti_op_new_array_buffer(STUB_ARGS_DECLARATION) WTF_INTERNAL; + JSObject* JIT_STUB cti_op_new_func(STUB_ARGS_DECLARATION) WTF_INTERNAL; + JSObject* JIT_STUB cti_op_new_func_exp(STUB_ARGS_DECLARATION) WTF_INTERNAL; + JSObject* JIT_STUB cti_op_new_object(STUB_ARGS_DECLARATION) WTF_INTERNAL; + JSObject* JIT_STUB cti_op_new_regexp(STUB_ARGS_DECLARATION) WTF_INTERNAL; + JSObject* JIT_STUB cti_op_push_activation(STUB_ARGS_DECLARATION) WTF_INTERNAL; + JSObject* JIT_STUB cti_op_push_new_scope(STUB_ARGS_DECLARATION) WTF_INTERNAL; + JSObject* JIT_STUB cti_op_push_scope(STUB_ARGS_DECLARATION) WTF_INTERNAL; + JSObject* JIT_STUB cti_op_put_by_id_transition_realloc(STUB_ARGS_DECLARATION) WTF_INTERNAL; + JSPropertyNameIterator* JIT_STUB cti_op_get_pnames(STUB_ARGS_DECLARATION) WTF_INTERNAL; + int JIT_STUB cti_op_eq(STUB_ARGS_DECLARATION) WTF_INTERNAL; + int JIT_STUB cti_op_eq_strings(STUB_ARGS_DECLARATION) WTF_INTERNAL; + int JIT_STUB cti_op_jless(STUB_ARGS_DECLARATION) WTF_INTERNAL; + int JIT_STUB cti_op_jlesseq(STUB_ARGS_DECLARATION) WTF_INTERNAL; + int JIT_STUB cti_op_jgreater(STUB_ARGS_DECLARATION) WTF_INTERNAL; + int JIT_STUB cti_op_jgreatereq(STUB_ARGS_DECLARATION) WTF_INTERNAL; + int JIT_STUB cti_op_jtrue(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void* JIT_STUB cti_op_load_varargs(STUB_ARGS_DECLARATION) WTF_INTERNAL; + int JIT_STUB cti_timeout_check(STUB_ARGS_DECLARATION) WTF_INTERNAL; + int JIT_STUB cti_has_property(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void JIT_STUB cti_op_check_has_instance(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void JIT_STUB cti_op_debug(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void JIT_STUB cti_op_end(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void JIT_STUB cti_op_jmp_scopes(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void JIT_STUB cti_op_pop_scope(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void JIT_STUB cti_op_profile_did_call(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void JIT_STUB cti_op_profile_will_call(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void JIT_STUB cti_op_put_by_id(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void JIT_STUB cti_op_put_by_id_fail(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void JIT_STUB cti_op_put_by_id_generic(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void JIT_STUB cti_op_put_by_id_direct(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void JIT_STUB cti_op_put_by_id_direct_fail(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void JIT_STUB cti_op_put_by_id_direct_generic(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void JIT_STUB cti_op_put_by_index(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void JIT_STUB cti_op_put_by_val(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void JIT_STUB cti_op_put_getter_setter(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void JIT_STUB cti_op_put_global_var_check(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void JIT_STUB cti_op_tear_off_activation(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void JIT_STUB cti_op_tear_off_arguments(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void JIT_STUB cti_op_throw_reference_error(STUB_ARGS_DECLARATION) WTF_INTERNAL; #if ENABLE(DFG_JIT) - void JIT_STUB cti_optimize_from_loop(STUB_ARGS_DECLARATION); - void JIT_STUB cti_optimize_from_ret(STUB_ARGS_DECLARATION); + void JIT_STUB cti_optimize_from_loop(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void JIT_STUB cti_optimize_from_ret(STUB_ARGS_DECLARATION) WTF_INTERNAL; #endif - void* JIT_STUB cti_op_call_arityCheck(STUB_ARGS_DECLARATION); - void* JIT_STUB cti_op_construct_arityCheck(STUB_ARGS_DECLARATION); - void* JIT_STUB cti_op_call_jitCompile(STUB_ARGS_DECLARATION); - void* JIT_STUB cti_op_construct_jitCompile(STUB_ARGS_DECLARATION); - void* JIT_STUB cti_op_switch_char(STUB_ARGS_DECLARATION); - void* JIT_STUB cti_op_switch_imm(STUB_ARGS_DECLARATION); - void* JIT_STUB cti_op_switch_string(STUB_ARGS_DECLARATION); - void* JIT_STUB cti_op_throw(STUB_ARGS_DECLARATION); - void* JIT_STUB cti_register_file_check(STUB_ARGS_DECLARATION); - void* JIT_STUB cti_vm_lazyLinkCall(STUB_ARGS_DECLARATION); - void* JIT_STUB cti_vm_lazyLinkConstruct(STUB_ARGS_DECLARATION); - void* JIT_STUB cti_vm_throw(STUB_ARGS_DECLARATION) REFERENCED_FROM_ASM; + void* JIT_STUB cti_op_call_arityCheck(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void* JIT_STUB cti_op_construct_arityCheck(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void* JIT_STUB cti_op_call_jitCompile(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void* JIT_STUB cti_op_construct_jitCompile(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void* JIT_STUB cti_op_switch_char(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void* JIT_STUB cti_op_switch_imm(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void* JIT_STUB cti_op_switch_string(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void* JIT_STUB cti_op_throw(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void* JIT_STUB cti_register_file_check(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void* JIT_STUB cti_vm_lazyLinkCall(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void* JIT_STUB cti_vm_lazyLinkConstruct(STUB_ARGS_DECLARATION) WTF_INTERNAL; + void* JIT_STUB cti_vm_throw(STUB_ARGS_DECLARATION) REFERENCED_FROM_ASM WTF_INTERNAL; } // extern "C" #endif // ENABLE(JIT) diff --git a/Source/JavaScriptCore/jit/SpecializedThunkJIT.h b/Source/JavaScriptCore/jit/SpecializedThunkJIT.h index 74e94ea3c..c98e57d12 100644 --- a/Source/JavaScriptCore/jit/SpecializedThunkJIT.h +++ b/Source/JavaScriptCore/jit/SpecializedThunkJIT.h @@ -132,13 +132,13 @@ namespace JSC { ret(); } - MacroAssemblerCodeRef finalize(JSGlobalData& globalData, MacroAssemblerCodePtr fallback) + MacroAssemblerCodeRef finalize(JSGlobalData& globalData, MacroAssemblerCodePtr fallback, const char* thunkKind) { LinkBuffer patchBuffer(globalData, this, GLOBAL_THUNK_ID); patchBuffer.link(m_failures, CodeLocationLabel(fallback)); for (unsigned i = 0; i < m_calls.size(); i++) patchBuffer.link(m_calls[i].first, m_calls[i].second); - return patchBuffer.finalizeCode(); + return FINALIZE_CODE(patchBuffer, ("Specialized thunk for %s", thunkKind)); } // Assumes that the target function uses fpRegister0 as the first argument diff --git a/Source/JavaScriptCore/jit/ThunkGenerators.cpp b/Source/JavaScriptCore/jit/ThunkGenerators.cpp index e46ba809c..c440b5157 100644 --- a/Source/JavaScriptCore/jit/ThunkGenerators.cpp +++ b/Source/JavaScriptCore/jit/ThunkGenerators.cpp @@ -78,7 +78,7 @@ MacroAssemblerCodeRef charCodeAtThunkGenerator(JSGlobalData* globalData) SpecializedThunkJIT jit(1, globalData); stringCharLoad(jit); jit.returnInt32(SpecializedThunkJIT::regT0); - return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall()); + return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall(), "charCodeAt"); } MacroAssemblerCodeRef charAtThunkGenerator(JSGlobalData* globalData) @@ -87,7 +87,7 @@ MacroAssemblerCodeRef charAtThunkGenerator(JSGlobalData* globalData) stringCharLoad(jit); charToString(jit, globalData, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1); jit.returnJSCell(SpecializedThunkJIT::regT0); - return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall()); + return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall(), "charAt"); } MacroAssemblerCodeRef fromCharCodeThunkGenerator(JSGlobalData* globalData) @@ -97,7 +97,7 @@ MacroAssemblerCodeRef fromCharCodeThunkGenerator(JSGlobalData* globalData) jit.loadInt32Argument(0, SpecializedThunkJIT::regT0); charToString(jit, globalData, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1); jit.returnJSCell(SpecializedThunkJIT::regT0); - return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall()); + return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall(), "fromCharCode"); } MacroAssemblerCodeRef sqrtThunkGenerator(JSGlobalData* globalData) @@ -109,7 +109,7 @@ MacroAssemblerCodeRef sqrtThunkGenerator(JSGlobalData* globalData) jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0); jit.sqrtDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT0); jit.returnDouble(SpecializedThunkJIT::fpRegT0); - return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall()); + return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall(), "sqrt"); } @@ -135,7 +135,7 @@ double jsRound(double d) ".globl " SYMBOL_STRING(function##Thunk) "\n" \ HIDE_SYMBOL(function##Thunk) "\n" \ SYMBOL_STRING(function##Thunk) ":" "\n" \ - "call " SYMBOL_STRING_RELOCATION(function) "\n" \ + "call " GLOBAL_REFERENCE(function) "\n" \ "ret\n" \ );\ extern "C" { \ @@ -152,7 +152,7 @@ double jsRound(double d) SYMBOL_STRING(function##Thunk) ":" "\n" \ "subl $8, %esp\n" \ "movsd %xmm0, (%esp) \n" \ - "call " SYMBOL_STRING_RELOCATION(function) "\n" \ + "call " GLOBAL_REFERENCE(function) "\n" \ "fstpl (%esp) \n" \ "movsd (%esp), %xmm0 \n" \ "addl $8, %esp\n" \ @@ -175,6 +175,11 @@ defineUnaryDoubleOpWrapper(log); defineUnaryDoubleOpWrapper(floor); defineUnaryDoubleOpWrapper(ceil); +static const double oneConstant = 1.0; +static const double negativeHalfConstant = -0.5; +static const double zeroConstant = 0.0; +static const double halfConstant = 0.5; + MacroAssemblerCodeRef floorThunkGenerator(JSGlobalData* globalData) { SpecializedThunkJIT jit(1, globalData); @@ -185,13 +190,26 @@ MacroAssemblerCodeRef floorThunkGenerator(JSGlobalData* globalData) jit.returnInt32(SpecializedThunkJIT::regT0); nonIntJump.link(&jit); jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0); - jit.callDoubleToDouble(UnaryDoubleOpWrapper(floor)); + SpecializedThunkJIT::Jump intResult; SpecializedThunkJIT::JumpList doubleResult; + if (jit.supportsFloatingPointTruncate()) { + jit.loadDouble(&zeroConstant, SpecializedThunkJIT::fpRegT1); + doubleResult.append(jit.branchDouble(MacroAssembler::DoubleEqual, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1)); + SpecializedThunkJIT::JumpList slowPath; + // Handle the negative doubles in the slow path for now. + slowPath.append(jit.branchDouble(MacroAssembler::DoubleLessThanOrUnordered, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1)); + slowPath.append(jit.branchTruncateDoubleToInt32(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0)); + intResult = jit.jump(); + slowPath.link(&jit); + } + jit.callDoubleToDouble(UnaryDoubleOpWrapper(floor)); jit.branchConvertDoubleToInt32(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0, doubleResult, SpecializedThunkJIT::fpRegT1); + if (jit.supportsFloatingPointTruncate()) + intResult.link(&jit); jit.returnInt32(SpecializedThunkJIT::regT0); doubleResult.link(&jit); jit.returnDouble(SpecializedThunkJIT::fpRegT0); - return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall()); + return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall(), "floor"); } MacroAssemblerCodeRef ceilThunkGenerator(JSGlobalData* globalData) @@ -210,12 +228,9 @@ MacroAssemblerCodeRef ceilThunkGenerator(JSGlobalData* globalData) jit.returnInt32(SpecializedThunkJIT::regT0); doubleResult.link(&jit); jit.returnDouble(SpecializedThunkJIT::fpRegT0); - return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall()); + return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall(), "ceil"); } -static const double oneConstant = 1.0; -static const double negativeHalfConstant = -0.5; - MacroAssemblerCodeRef roundThunkGenerator(JSGlobalData* globalData) { SpecializedThunkJIT jit(1, globalData); @@ -226,13 +241,28 @@ MacroAssemblerCodeRef roundThunkGenerator(JSGlobalData* globalData) jit.returnInt32(SpecializedThunkJIT::regT0); nonIntJump.link(&jit); jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0); - jit.callDoubleToDouble(UnaryDoubleOpWrapper(jsRound)); + SpecializedThunkJIT::Jump intResult; SpecializedThunkJIT::JumpList doubleResult; + if (jit.supportsFloatingPointTruncate()) { + jit.loadDouble(&zeroConstant, SpecializedThunkJIT::fpRegT1); + doubleResult.append(jit.branchDouble(MacroAssembler::DoubleEqual, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1)); + SpecializedThunkJIT::JumpList slowPath; + // Handle the negative doubles in the slow path for now. + slowPath.append(jit.branchDouble(MacroAssembler::DoubleLessThanOrUnordered, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1)); + jit.loadDouble(&halfConstant, SpecializedThunkJIT::fpRegT1); + jit.addDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1); + slowPath.append(jit.branchTruncateDoubleToInt32(SpecializedThunkJIT::fpRegT1, SpecializedThunkJIT::regT0)); + intResult = jit.jump(); + slowPath.link(&jit); + } + jit.callDoubleToDouble(UnaryDoubleOpWrapper(jsRound)); jit.branchConvertDoubleToInt32(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0, doubleResult, SpecializedThunkJIT::fpRegT1); + if (jit.supportsFloatingPointTruncate()) + intResult.link(&jit); jit.returnInt32(SpecializedThunkJIT::regT0); doubleResult.link(&jit); jit.returnDouble(SpecializedThunkJIT::fpRegT0); - return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall()); + return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall(), "round"); } MacroAssemblerCodeRef expThunkGenerator(JSGlobalData* globalData) @@ -245,7 +275,7 @@ MacroAssemblerCodeRef expThunkGenerator(JSGlobalData* globalData) jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0); jit.callDoubleToDouble(UnaryDoubleOpWrapper(exp)); jit.returnDouble(SpecializedThunkJIT::fpRegT0); - return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall()); + return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall(), "exp"); } MacroAssemblerCodeRef logThunkGenerator(JSGlobalData* globalData) @@ -258,7 +288,7 @@ MacroAssemblerCodeRef logThunkGenerator(JSGlobalData* globalData) jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0); jit.callDoubleToDouble(UnaryDoubleOpWrapper(log)); jit.returnDouble(SpecializedThunkJIT::fpRegT0); - return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall()); + return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall(), "log"); } MacroAssemblerCodeRef absThunkGenerator(JSGlobalData* globalData) @@ -278,7 +308,7 @@ MacroAssemblerCodeRef absThunkGenerator(JSGlobalData* globalData) jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0); jit.absDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1); jit.returnDouble(SpecializedThunkJIT::fpRegT1); - return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall()); + return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall(), "abs"); } MacroAssemblerCodeRef powThunkGenerator(JSGlobalData* globalData) @@ -330,7 +360,7 @@ MacroAssemblerCodeRef powThunkGenerator(JSGlobalData* globalData) } else jit.appendFailure(nonIntExponent); - return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall()); + return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall(), "pow"); } } diff --git a/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h b/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h index 2539ee9b3..7720f5ec2 100644 --- a/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h +++ b/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h @@ -94,14 +94,14 @@ #if CPU(ARM_THUMB2) #define OFFLINE_ASM_GLOBAL_LABEL(label) \ ".globl " SYMBOL_STRING(label) "\n" \ - HIDE_SYMBOL(name) "\n" \ + HIDE_SYMBOL(label) "\n" \ ".thumb\n" \ ".thumb_func " THUMB_FUNC_PARAM(label) "\n" \ SYMBOL_STRING(label) ":\n" #else #define OFFLINE_ASM_GLOBAL_LABEL(label) \ ".globl " SYMBOL_STRING(label) "\n" \ - HIDE_SYMBOL(name) "\n" \ + HIDE_SYMBOL(label) "\n" \ SYMBOL_STRING(label) ":\n" #endif diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp index b13e84b53..ca3eb1eb0 100644 --- a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp +++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp @@ -475,8 +475,10 @@ LLINT_SLOW_PATH_DECL(slow_path_convert_this) LLINT_BEGIN(); JSValue v1 = LLINT_OP(1).jsValue(); ASSERT(v1.isPrimitive()); +#if ENABLE(VALUE_PROFILER) pc[OPCODE_LENGTH(op_convert_this) - 1].u.profile->m_buckets[0] = JSValue::encode(v1.structureOrUndefined()); +#endif LLINT_RETURN(v1.toThisObject(exec)); } @@ -621,64 +623,88 @@ LLINT_SLOW_PATH_DECL(slow_path_add) LLINT_RETURN(jsAddSlowCase(exec, v1, v2)); } +// The following arithmetic and bitwise operations need to be sure to run +// toNumber() on their operands in order. (A call to toNumber() is idempotent +// if an exception is already set on the ExecState.) + LLINT_SLOW_PATH_DECL(slow_path_mul) { LLINT_BEGIN(); - LLINT_RETURN(jsNumber(LLINT_OP_C(2).jsValue().toNumber(exec) * LLINT_OP_C(3).jsValue().toNumber(exec))); + double a = LLINT_OP_C(2).jsValue().toNumber(exec); + double b = LLINT_OP_C(3).jsValue().toNumber(exec); + LLINT_RETURN(jsNumber(a * b)); } LLINT_SLOW_PATH_DECL(slow_path_sub) { LLINT_BEGIN(); - LLINT_RETURN(jsNumber(LLINT_OP_C(2).jsValue().toNumber(exec) - LLINT_OP_C(3).jsValue().toNumber(exec))); + double a = LLINT_OP_C(2).jsValue().toNumber(exec); + double b = LLINT_OP_C(3).jsValue().toNumber(exec); + LLINT_RETURN(jsNumber(a - b)); } LLINT_SLOW_PATH_DECL(slow_path_div) { LLINT_BEGIN(); - LLINT_RETURN(jsNumber(LLINT_OP_C(2).jsValue().toNumber(exec) / LLINT_OP_C(3).jsValue().toNumber(exec))); + double a = LLINT_OP_C(2).jsValue().toNumber(exec); + double b = LLINT_OP_C(3).jsValue().toNumber(exec); + LLINT_RETURN(jsNumber(a / b)); } LLINT_SLOW_PATH_DECL(slow_path_mod) { LLINT_BEGIN(); - LLINT_RETURN(jsNumber(fmod(LLINT_OP_C(2).jsValue().toNumber(exec), LLINT_OP_C(3).jsValue().toNumber(exec)))); + double a = LLINT_OP_C(2).jsValue().toNumber(exec); + double b = LLINT_OP_C(3).jsValue().toNumber(exec); + LLINT_RETURN(jsNumber(fmod(a, b))); } LLINT_SLOW_PATH_DECL(slow_path_lshift) { LLINT_BEGIN(); - LLINT_RETURN(jsNumber(LLINT_OP_C(2).jsValue().toInt32(exec) << (LLINT_OP_C(3).jsValue().toUInt32(exec) & 31))); + int32_t a = LLINT_OP_C(2).jsValue().toInt32(exec); + uint32_t b = LLINT_OP_C(3).jsValue().toUInt32(exec); + LLINT_RETURN(jsNumber(a << (b & 31))); } LLINT_SLOW_PATH_DECL(slow_path_rshift) { LLINT_BEGIN(); - LLINT_RETURN(jsNumber(LLINT_OP_C(2).jsValue().toInt32(exec) >> (LLINT_OP_C(3).jsValue().toUInt32(exec) & 31))); + int32_t a = LLINT_OP_C(2).jsValue().toInt32(exec); + uint32_t b = LLINT_OP_C(3).jsValue().toUInt32(exec); + LLINT_RETURN(jsNumber(a >> (b & 31))); } LLINT_SLOW_PATH_DECL(slow_path_urshift) { LLINT_BEGIN(); - LLINT_RETURN(jsNumber(LLINT_OP_C(2).jsValue().toUInt32(exec) >> (LLINT_OP_C(3).jsValue().toUInt32(exec) & 31))); + uint32_t a = LLINT_OP_C(2).jsValue().toUInt32(exec); + uint32_t b = LLINT_OP_C(3).jsValue().toUInt32(exec); + LLINT_RETURN(jsNumber(a >> (b & 31))); } LLINT_SLOW_PATH_DECL(slow_path_bitand) { LLINT_BEGIN(); - LLINT_RETURN(jsNumber(LLINT_OP_C(2).jsValue().toInt32(exec) & LLINT_OP_C(3).jsValue().toInt32(exec))); + int32_t a = LLINT_OP_C(2).jsValue().toInt32(exec); + int32_t b = LLINT_OP_C(3).jsValue().toInt32(exec); + LLINT_RETURN(jsNumber(a & b)); } LLINT_SLOW_PATH_DECL(slow_path_bitor) { LLINT_BEGIN(); - LLINT_RETURN(jsNumber(LLINT_OP_C(2).jsValue().toInt32(exec) | LLINT_OP_C(3).jsValue().toInt32(exec))); + int32_t a = LLINT_OP_C(2).jsValue().toInt32(exec); + int32_t b = LLINT_OP_C(3).jsValue().toInt32(exec); + LLINT_RETURN(jsNumber(a | b)); } LLINT_SLOW_PATH_DECL(slow_path_bitxor) { LLINT_BEGIN(); - LLINT_RETURN(jsNumber(LLINT_OP_C(2).jsValue().toInt32(exec) ^ LLINT_OP_C(3).jsValue().toInt32(exec))); + int32_t a = LLINT_OP_C(2).jsValue().toInt32(exec); + int32_t b = LLINT_OP_C(3).jsValue().toInt32(exec); + LLINT_RETURN(jsNumber(a ^ b)); } LLINT_SLOW_PATH_DECL(slow_path_check_has_instance) @@ -832,6 +858,14 @@ LLINT_SLOW_PATH_DECL(slow_path_resolve_with_this) LLINT_END(); } +LLINT_SLOW_PATH_DECL(slow_path_put_global_var_check) +{ + LLINT_BEGIN(); + CodeBlock* codeBlock = exec->codeBlock(); + symbolTablePut(codeBlock->globalObject(), exec, codeBlock->identifier(pc[4].u.operand), LLINT_OP_C(2).jsValue(), true); + LLINT_END(); +} + LLINT_SLOW_PATH_DECL(slow_path_get_by_id) { LLINT_BEGIN(); @@ -902,6 +936,8 @@ LLINT_SLOW_PATH_DECL(slow_path_put_by_id) if (slot.type() == PutPropertySlot::NewProperty) { if (!structure->isDictionary() && structure->previousID()->propertyStorageCapacity() == structure->propertyStorageCapacity()) { + ASSERT(structure->previousID()->transitionWatchpointSetHasBeenInvalidated()); + // This is needed because some of the methods we call // below may GC. pc[0].u.opcode = bitwise_cast<void*>(&llint_op_put_by_id); @@ -987,7 +1023,7 @@ LLINT_SLOW_PATH_DECL(slow_path_get_argument_by_val) exec->uncheckedR(unmodifiedArgumentsRegister(pc[2].u.operand)) = arguments; } - LLINT_RETURN(getByVal(exec, arguments, LLINT_OP_C(3).jsValue())); + LLINT_RETURN_PROFILED(op_get_argument_by_val, getByVal(exec, arguments, LLINT_OP_C(3).jsValue())); } LLINT_SLOW_PATH_DECL(slow_path_get_by_pname) @@ -1546,14 +1582,16 @@ LLINT_SLOW_PATH_DECL(slow_path_debug) LLINT_SLOW_PATH_DECL(slow_path_profile_will_call) { LLINT_BEGIN(); - (*Profiler::enabledProfilerReference())->willExecute(exec, LLINT_OP(1).jsValue()); + if (Profiler* profiler = globalData.enabledProfiler()) + profiler->willExecute(exec, LLINT_OP(1).jsValue()); LLINT_END(); } LLINT_SLOW_PATH_DECL(slow_path_profile_did_call) { LLINT_BEGIN(); - (*Profiler::enabledProfilerReference())->didExecute(exec, LLINT_OP(1).jsValue()); + if (Profiler* profiler = globalData.enabledProfiler()) + profiler->didExecute(exec, LLINT_OP(1).jsValue()); LLINT_END(); } diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.h b/Source/JavaScriptCore/llint/LLIntSlowPaths.h index a91cf797e..2e069d073 100644 --- a/Source/JavaScriptCore/llint/LLIntSlowPaths.h +++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.h @@ -78,118 +78,122 @@ extern "C" SlowPathReturnType llint_trace_value(ExecState*, Instruction*, int fr #define LLINT_SLOW_PATH_DECL(name) \ extern "C" SlowPathReturnType llint_##name(ExecState* exec, Instruction* pc) -LLINT_SLOW_PATH_DECL(trace_prologue); -LLINT_SLOW_PATH_DECL(trace_prologue_function_for_call); -LLINT_SLOW_PATH_DECL(trace_prologue_function_for_construct); -LLINT_SLOW_PATH_DECL(trace_arityCheck_for_call); -LLINT_SLOW_PATH_DECL(trace_arityCheck_for_construct); -LLINT_SLOW_PATH_DECL(trace); -LLINT_SLOW_PATH_DECL(special_trace); -LLINT_SLOW_PATH_DECL(entry_osr); -LLINT_SLOW_PATH_DECL(entry_osr_function_for_call); -LLINT_SLOW_PATH_DECL(entry_osr_function_for_construct); -LLINT_SLOW_PATH_DECL(entry_osr_function_for_call_arityCheck); -LLINT_SLOW_PATH_DECL(entry_osr_function_for_construct_arityCheck); -LLINT_SLOW_PATH_DECL(loop_osr); -LLINT_SLOW_PATH_DECL(replace); -LLINT_SLOW_PATH_DECL(register_file_check); -LLINT_SLOW_PATH_DECL(slow_path_call_arityCheck); -LLINT_SLOW_PATH_DECL(slow_path_construct_arityCheck); -LLINT_SLOW_PATH_DECL(slow_path_create_activation); -LLINT_SLOW_PATH_DECL(slow_path_create_arguments); -LLINT_SLOW_PATH_DECL(slow_path_create_this); -LLINT_SLOW_PATH_DECL(slow_path_convert_this); -LLINT_SLOW_PATH_DECL(slow_path_new_object); -LLINT_SLOW_PATH_DECL(slow_path_new_array); -LLINT_SLOW_PATH_DECL(slow_path_new_array_buffer); -LLINT_SLOW_PATH_DECL(slow_path_new_regexp); -LLINT_SLOW_PATH_DECL(slow_path_not); -LLINT_SLOW_PATH_DECL(slow_path_eq); -LLINT_SLOW_PATH_DECL(slow_path_neq); -LLINT_SLOW_PATH_DECL(slow_path_stricteq); -LLINT_SLOW_PATH_DECL(slow_path_nstricteq); -LLINT_SLOW_PATH_DECL(slow_path_less); -LLINT_SLOW_PATH_DECL(slow_path_lesseq); -LLINT_SLOW_PATH_DECL(slow_path_greater); -LLINT_SLOW_PATH_DECL(slow_path_greatereq); -LLINT_SLOW_PATH_DECL(slow_path_pre_inc); -LLINT_SLOW_PATH_DECL(slow_path_pre_dec); -LLINT_SLOW_PATH_DECL(slow_path_post_inc); -LLINT_SLOW_PATH_DECL(slow_path_post_dec); -LLINT_SLOW_PATH_DECL(slow_path_to_jsnumber); -LLINT_SLOW_PATH_DECL(slow_path_negate); -LLINT_SLOW_PATH_DECL(slow_path_add); -LLINT_SLOW_PATH_DECL(slow_path_mul); -LLINT_SLOW_PATH_DECL(slow_path_sub); -LLINT_SLOW_PATH_DECL(slow_path_div); -LLINT_SLOW_PATH_DECL(slow_path_mod); -LLINT_SLOW_PATH_DECL(slow_path_lshift); -LLINT_SLOW_PATH_DECL(slow_path_rshift); -LLINT_SLOW_PATH_DECL(slow_path_urshift); -LLINT_SLOW_PATH_DECL(slow_path_bitand); -LLINT_SLOW_PATH_DECL(slow_path_bitor); -LLINT_SLOW_PATH_DECL(slow_path_bitxor); -LLINT_SLOW_PATH_DECL(slow_path_check_has_instance); -LLINT_SLOW_PATH_DECL(slow_path_instanceof); -LLINT_SLOW_PATH_DECL(slow_path_typeof); -LLINT_SLOW_PATH_DECL(slow_path_is_object); -LLINT_SLOW_PATH_DECL(slow_path_is_function); -LLINT_SLOW_PATH_DECL(slow_path_in); -LLINT_SLOW_PATH_DECL(slow_path_resolve); -LLINT_SLOW_PATH_DECL(slow_path_resolve_skip); -LLINT_SLOW_PATH_DECL(slow_path_resolve_global); -LLINT_SLOW_PATH_DECL(slow_path_resolve_global_dynamic); -LLINT_SLOW_PATH_DECL(slow_path_resolve_for_resolve_global_dynamic); -LLINT_SLOW_PATH_DECL(slow_path_resolve_base); -LLINT_SLOW_PATH_DECL(slow_path_ensure_property_exists); -LLINT_SLOW_PATH_DECL(slow_path_resolve_with_base); -LLINT_SLOW_PATH_DECL(slow_path_resolve_with_this); -LLINT_SLOW_PATH_DECL(slow_path_get_by_id); -LLINT_SLOW_PATH_DECL(slow_path_get_arguments_length); -LLINT_SLOW_PATH_DECL(slow_path_put_by_id); -LLINT_SLOW_PATH_DECL(slow_path_del_by_id); -LLINT_SLOW_PATH_DECL(slow_path_get_by_val); -LLINT_SLOW_PATH_DECL(slow_path_get_argument_by_val); -LLINT_SLOW_PATH_DECL(slow_path_get_by_pname); -LLINT_SLOW_PATH_DECL(slow_path_put_by_val); -LLINT_SLOW_PATH_DECL(slow_path_del_by_val); -LLINT_SLOW_PATH_DECL(slow_path_put_by_index); -LLINT_SLOW_PATH_DECL(slow_path_put_getter_setter); -LLINT_SLOW_PATH_DECL(slow_path_jmp_scopes); -LLINT_SLOW_PATH_DECL(slow_path_jtrue); -LLINT_SLOW_PATH_DECL(slow_path_jfalse); -LLINT_SLOW_PATH_DECL(slow_path_jless); -LLINT_SLOW_PATH_DECL(slow_path_jnless); -LLINT_SLOW_PATH_DECL(slow_path_jgreater); -LLINT_SLOW_PATH_DECL(slow_path_jngreater); -LLINT_SLOW_PATH_DECL(slow_path_jlesseq); -LLINT_SLOW_PATH_DECL(slow_path_jnlesseq); -LLINT_SLOW_PATH_DECL(slow_path_jgreatereq); -LLINT_SLOW_PATH_DECL(slow_path_jngreatereq); -LLINT_SLOW_PATH_DECL(slow_path_switch_imm); -LLINT_SLOW_PATH_DECL(slow_path_switch_char); -LLINT_SLOW_PATH_DECL(slow_path_switch_string); -LLINT_SLOW_PATH_DECL(slow_path_new_func); -LLINT_SLOW_PATH_DECL(slow_path_new_func_exp); -LLINT_SLOW_PATH_DECL(slow_path_call); -LLINT_SLOW_PATH_DECL(slow_path_construct); -LLINT_SLOW_PATH_DECL(slow_path_call_varargs); -LLINT_SLOW_PATH_DECL(slow_path_call_eval); -LLINT_SLOW_PATH_DECL(slow_path_tear_off_activation); -LLINT_SLOW_PATH_DECL(slow_path_tear_off_arguments); -LLINT_SLOW_PATH_DECL(slow_path_strcat); -LLINT_SLOW_PATH_DECL(slow_path_to_primitive); -LLINT_SLOW_PATH_DECL(slow_path_get_pnames); -LLINT_SLOW_PATH_DECL(slow_path_next_pname); -LLINT_SLOW_PATH_DECL(slow_path_push_scope); -LLINT_SLOW_PATH_DECL(slow_path_pop_scope); -LLINT_SLOW_PATH_DECL(slow_path_push_new_scope); -LLINT_SLOW_PATH_DECL(slow_path_throw); -LLINT_SLOW_PATH_DECL(slow_path_throw_reference_error); -LLINT_SLOW_PATH_DECL(slow_path_debug); -LLINT_SLOW_PATH_DECL(slow_path_profile_will_call); -LLINT_SLOW_PATH_DECL(slow_path_profile_did_call); -LLINT_SLOW_PATH_DECL(throw_from_native_call); +#define LLINT_SLOW_PATH_HIDDEN_DECL(name) \ + LLINT_SLOW_PATH_DECL(name) WTF_INTERNAL + +LLINT_SLOW_PATH_HIDDEN_DECL(trace_prologue); +LLINT_SLOW_PATH_HIDDEN_DECL(trace_prologue_function_for_call); +LLINT_SLOW_PATH_HIDDEN_DECL(trace_prologue_function_for_construct); +LLINT_SLOW_PATH_HIDDEN_DECL(trace_arityCheck_for_call); +LLINT_SLOW_PATH_HIDDEN_DECL(trace_arityCheck_for_construct); +LLINT_SLOW_PATH_HIDDEN_DECL(trace); +LLINT_SLOW_PATH_HIDDEN_DECL(special_trace); +LLINT_SLOW_PATH_HIDDEN_DECL(entry_osr); +LLINT_SLOW_PATH_HIDDEN_DECL(entry_osr_function_for_call); +LLINT_SLOW_PATH_HIDDEN_DECL(entry_osr_function_for_construct); +LLINT_SLOW_PATH_HIDDEN_DECL(entry_osr_function_for_call_arityCheck); +LLINT_SLOW_PATH_HIDDEN_DECL(entry_osr_function_for_construct_arityCheck); +LLINT_SLOW_PATH_HIDDEN_DECL(loop_osr); +LLINT_SLOW_PATH_HIDDEN_DECL(replace); +LLINT_SLOW_PATH_HIDDEN_DECL(register_file_check); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_call_arityCheck); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_construct_arityCheck); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_create_activation); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_create_arguments); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_create_this); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_convert_this); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_object); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_array); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_array_buffer); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_regexp); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_not); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_eq); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_neq); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_stricteq); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_nstricteq); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_less); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_lesseq); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_greater); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_greatereq); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_pre_inc); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_pre_dec); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_post_inc); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_post_dec); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_to_jsnumber); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_negate); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_add); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_mul); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_sub); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_div); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_mod); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_lshift); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_rshift); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_urshift); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_bitand); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_bitor); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_bitxor); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_check_has_instance); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_instanceof); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_typeof); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_is_object); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_is_function); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_in); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_skip); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_global); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_global_dynamic); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_for_resolve_global_dynamic); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_base); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_ensure_property_exists); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_with_base); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_with_this); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_put_global_var_check); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_by_id); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_arguments_length); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_put_by_id); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_del_by_id); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_by_val); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_argument_by_val); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_by_pname); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_put_by_val); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_del_by_val); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_put_by_index); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_put_getter_setter); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_jmp_scopes); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_jtrue); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_jfalse); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_jless); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_jnless); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_jgreater); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_jngreater); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_jlesseq); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_jnlesseq); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_jgreatereq); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_jngreatereq); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_switch_imm); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_switch_char); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_switch_string); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_func); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_func_exp); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_call); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_construct); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_call_varargs); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_call_eval); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_tear_off_activation); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_tear_off_arguments); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_strcat); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_to_primitive); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_pnames); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_next_pname); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_push_scope); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_pop_scope); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_push_new_scope); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_throw); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_throw_reference_error); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_debug); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_profile_will_call); +LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_profile_did_call); +LLINT_SLOW_PATH_HIDDEN_DECL(throw_from_native_call); } } // namespace JSC::LLInt diff --git a/Source/JavaScriptCore/llint/LLIntThunks.cpp b/Source/JavaScriptCore/llint/LLIntThunks.cpp index b4d026423..6a6a579a3 100644 --- a/Source/JavaScriptCore/llint/LLIntThunks.cpp +++ b/Source/JavaScriptCore/llint/LLIntThunks.cpp @@ -36,7 +36,7 @@ namespace JSC { namespace LLInt { -static MacroAssemblerCodeRef generateThunkWithJumpTo(JSGlobalData* globalData, void (*target)()) +static MacroAssemblerCodeRef generateThunkWithJumpTo(JSGlobalData* globalData, void (*target)(), const char *thunkKind) { JSInterfaceJIT jit; @@ -45,37 +45,37 @@ static MacroAssemblerCodeRef generateThunkWithJumpTo(JSGlobalData* globalData, v jit.jump(JSInterfaceJIT::regT0); LinkBuffer patchBuffer(*globalData, &jit, GLOBAL_THUNK_ID); - return patchBuffer.finalizeCode(); + return FINALIZE_CODE(patchBuffer, ("LLInt %s prologue thunk", thunkKind)); } MacroAssemblerCodeRef functionForCallEntryThunkGenerator(JSGlobalData* globalData) { - return generateThunkWithJumpTo(globalData, llint_function_for_call_prologue); + return generateThunkWithJumpTo(globalData, llint_function_for_call_prologue, "function for call"); } MacroAssemblerCodeRef functionForConstructEntryThunkGenerator(JSGlobalData* globalData) { - return generateThunkWithJumpTo(globalData, llint_function_for_construct_prologue); + return generateThunkWithJumpTo(globalData, llint_function_for_construct_prologue, "function for construct"); } MacroAssemblerCodeRef functionForCallArityCheckThunkGenerator(JSGlobalData* globalData) { - return generateThunkWithJumpTo(globalData, llint_function_for_call_arity_check); + return generateThunkWithJumpTo(globalData, llint_function_for_call_arity_check, "function for call with arity check"); } MacroAssemblerCodeRef functionForConstructArityCheckThunkGenerator(JSGlobalData* globalData) { - return generateThunkWithJumpTo(globalData, llint_function_for_construct_arity_check); + return generateThunkWithJumpTo(globalData, llint_function_for_construct_arity_check, "function for construct with arity check"); } MacroAssemblerCodeRef evalEntryThunkGenerator(JSGlobalData* globalData) { - return generateThunkWithJumpTo(globalData, llint_eval_prologue); + return generateThunkWithJumpTo(globalData, llint_eval_prologue, "eval"); } MacroAssemblerCodeRef programEntryThunkGenerator(JSGlobalData* globalData) { - return generateThunkWithJumpTo(globalData, llint_program_prologue); + return generateThunkWithJumpTo(globalData, llint_program_prologue, "program"); } } } // namespace JSC::LLInt diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm index bbfa859f2..e59ddeba4 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm @@ -103,7 +103,7 @@ end # Some common utilities. macro crash() - storei 0, 0xbbadbeef[] + storei t0, 0xbbadbeef[] move 0, t0 call t0 end @@ -727,19 +727,13 @@ _llint_op_throw_reference_error: _llint_op_profile_will_call: traceExecution() - loadp JITStackFrame::enabledProfilerReference[sp], t0 - btpz [t0], .opProfileWillCallDone callSlowPath(_llint_slow_path_profile_will_call) -.opProfileWillCallDone: dispatch(2) _llint_op_profile_did_call: traceExecution() - loadp JITStackFrame::enabledProfilerReference[sp], t0 - btpz [t0], .opProfileWillCallDone callSlowPath(_llint_slow_path_profile_did_call) -.opProfileDidCallDone: dispatch(2) diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm index 95b26d42f..d27fd8229 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm @@ -1039,36 +1039,54 @@ _llint_op_put_scoped_var: dispatch(4) -_llint_op_get_global_var: +macro getGlobalVar(size) traceExecution() - loadi 8[PC], t1 + loadp 8[PC], t0 loadi 4[PC], t3 - loadp CodeBlock[cfr], t0 - loadp CodeBlock::m_globalObject[t0], t0 - loadp JSGlobalObject::m_registers[t0], t0 - loadi TagOffset[t0, t1, 8], t2 - loadi PayloadOffset[t0, t1, 8], t1 + loadi TagOffset[t0], t2 + loadi PayloadOffset[t0], t1 storei t2, TagOffset[cfr, t3, 8] storei t1, PayloadOffset[cfr, t3, 8] - loadi 12[PC], t3 + loadi (size - 1) * 4[PC], t3 valueProfile(t2, t1, t3) - dispatch(4) + dispatch(size) +end + +_llint_op_get_global_var: + getGlobalVar(4) + + +_llint_op_get_global_var_watchable: + getGlobalVar(5) _llint_op_put_global_var: traceExecution() loadi 8[PC], t1 - loadp CodeBlock[cfr], t0 - loadp CodeBlock::m_globalObject[t0], t0 - loadp JSGlobalObject::m_registers[t0], t0 + loadi 4[PC], t0 loadConstantOrVariable(t1, t2, t3) - loadi 4[PC], t1 writeBarrier(t2, t3) - storei t2, TagOffset[t0, t1, 8] - storei t3, PayloadOffset[t0, t1, 8] + storei t2, TagOffset[t0] + storei t3, PayloadOffset[t0] dispatch(3) +_llint_op_put_global_var_check: + traceExecution() + loadp 12[PC], t2 + loadi 8[PC], t1 + loadi 4[PC], t0 + btbnz [t2], .opPutGlobalVarCheckSlow + loadConstantOrVariable(t1, t2, t3) + writeBarrier(t2, t3) + storei t2, TagOffset[t0] + storei t3, PayloadOffset[t0] + dispatch(5) +.opPutGlobalVarCheckSlow: + callSlowPath(_llint_slow_path_put_global_var_check) + dispatch(5) + + _llint_op_get_by_id: traceExecution() # We only do monomorphic get_by_id caching for now, and we do not modify the diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm index 5225bdda9..a153586f4 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm @@ -893,33 +893,50 @@ _llint_op_put_scoped_var: dispatch(4) -_llint_op_get_global_var: +macro getGlobalVar(size) traceExecution() - loadis 16[PB, PC, 8], t1 + loadp 16[PB, PC, 8], t0 loadis 8[PB, PC, 8], t3 - loadp CodeBlock[cfr], t0 - loadp CodeBlock::m_globalObject[t0], t0 - loadp JSGlobalObject::m_registers[t0], t0 - loadp [t0, t1, 8], t2 - storep t2, [cfr, t3, 8] - loadp 24[PB, PC, 8], t3 - valueProfile(t2, t3) - dispatch(4) + loadp [t0], t1 + storep t1, [cfr, t3, 8] + loadp (size - 1) * 8[PB, PC, 8], t0 + valueProfile(t1, t0) + dispatch(size) +end + +_llint_op_get_global_var: + getGlobalVar(4) + + +_llint_op_get_global_var_watchable: + getGlobalVar(5) _llint_op_put_global_var: traceExecution() loadis 16[PB, PC, 8], t1 - loadp CodeBlock[cfr], t0 - loadp CodeBlock::m_globalObject[t0], t0 - loadp JSGlobalObject::m_registers[t0], t0 + loadp 8[PB, PC, 8], t0 loadConstantOrVariable(t1, t2) - loadis 8[PB, PC, 8], t1 writeBarrier(t2) - storep t2, [t0, t1, 8] + storep t2, [t0] dispatch(3) +_llint_op_put_global_var_check: + traceExecution() + loadp 24[PB, PC, 8], t2 + loadis 16[PB, PC, 8], t1 + loadp 8[PB, PC, 8], t0 + btbnz [t2], .opPutGlobalVarCheckSlow + loadConstantOrVariable(t1, t2) + writeBarrier(t2) + storep t2, [t0] + dispatch(5) +.opPutGlobalVarCheckSlow: + callSlowPath(_llint_slow_path_put_global_var_check) + dispatch(5) + + _llint_op_get_by_id: traceExecution() # We only do monomorphic get_by_id caching for now, and we do not modify the diff --git a/Source/JavaScriptCore/offlineasm/asm.rb b/Source/JavaScriptCore/offlineasm/asm.rb index 12bade022..50f9bc886 100644 --- a/Source/JavaScriptCore/offlineasm/asm.rb +++ b/Source/JavaScriptCore/offlineasm/asm.rb @@ -97,7 +97,7 @@ class Assembler end def self.labelReference(labelName) - "\" SYMBOL_STRING(#{labelName}) \"" + "\" LOCAL_REFERENCE(#{labelName}) \"" end def self.localLabelReference(labelName) diff --git a/Source/JavaScriptCore/profiler/Profiler.cpp b/Source/JavaScriptCore/profiler/Profiler.cpp index 0ecd5b2c9..723393b5c 100644 --- a/Source/JavaScriptCore/profiler/Profiler.cpp +++ b/Source/JavaScriptCore/profiler/Profiler.cpp @@ -51,7 +51,6 @@ static unsigned ProfilesUID = 0; static CallIdentifier createCallIdentifierFromFunctionImp(ExecState*, JSObject*, const UString& defaultSourceURL, int defaultLineNumber); Profiler* Profiler::s_sharedProfiler = 0; -Profiler* Profiler::s_sharedEnabledProfilerReference = 0; Profiler* Profiler::profiler() { @@ -74,7 +73,7 @@ void Profiler::startProfiling(ExecState* exec, const UString& title) return; } - s_sharedEnabledProfilerReference = this; + exec->globalData().m_enabledProfiler = this; RefPtr<ProfileGenerator> profileGenerator = ProfileGenerator::create(exec, title, ++ProfilesUID); m_currentProfiles.append(profileGenerator); } @@ -90,7 +89,7 @@ PassRefPtr<Profile> Profiler::stopProfiling(ExecState* exec, const UString& titl m_currentProfiles.remove(i); if (!m_currentProfiles.size()) - s_sharedEnabledProfilerReference = 0; + exec->globalData().m_enabledProfiler = 0; return returnProfile; } @@ -107,7 +106,7 @@ void Profiler::stopProfiling(JSGlobalObject* origin) profileGenerator->stopProfiling(); m_currentProfiles.remove(i); if (!m_currentProfiles.size()) - s_sharedEnabledProfilerReference = 0; + origin->globalData().m_enabledProfiler = 0; } } } diff --git a/Source/JavaScriptCore/profiler/Profiler.h b/Source/JavaScriptCore/profiler/Profiler.h index 45f91af44..877065eca 100644 --- a/Source/JavaScriptCore/profiler/Profiler.h +++ b/Source/JavaScriptCore/profiler/Profiler.h @@ -48,11 +48,6 @@ namespace JSC { class Profiler { WTF_MAKE_FAST_ALLOCATED; public: - static Profiler** enabledProfilerReference() - { - return &s_sharedEnabledProfilerReference; - } - JS_EXPORT_PRIVATE static Profiler* profiler(); static CallIdentifier createCallIdentifier(ExecState* exec, JSValue, const UString& sourceURL, int lineNumber); @@ -72,7 +67,6 @@ namespace JSC { private: Vector<RefPtr<ProfileGenerator> > m_currentProfiles; static Profiler* s_sharedProfiler; - static Profiler* s_sharedEnabledProfilerReference; }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Completion.cpp b/Source/JavaScriptCore/runtime/Completion.cpp index ce620245b..311d660a0 100644 --- a/Source/JavaScriptCore/runtime/Completion.cpp +++ b/Source/JavaScriptCore/runtime/Completion.cpp @@ -55,6 +55,8 @@ JSValue evaluate(ExecState* exec, ScopeChainNode* scopeChain, const SourceCode& { JSLock lock(exec); ASSERT(exec->globalData().identifierTable == wtfThreadData().currentIdentifierTable()); + if (exec->globalData().isCollectorBusy()) + CRASH(); CodeProfiling profile(source); diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp index 0ada2cb0f..73b4b6c4f 100644 --- a/Source/JavaScriptCore/runtime/Executable.cpp +++ b/Source/JavaScriptCore/runtime/Executable.cpp @@ -47,7 +47,7 @@ void ExecutableBase::destroy(JSCell* cell) } #endif -inline void ExecutableBase::clearCode() +void ExecutableBase::clearCode() { #if ENABLE(JIT) m_jitCodeForCall.clear(); @@ -98,11 +98,6 @@ static void jettisonCodeBlock(JSGlobalData& globalData, OwnPtr<T>& codeBlock) } #endif -void NativeExecutable::finalize(JSCell* cell) -{ - jsCast<NativeExecutable*>(cell)->clearCode(); -} - const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(ScriptExecutable) }; #if ENABLE(JIT) @@ -146,8 +141,6 @@ FunctionExecutable::FunctionExecutable(JSGlobalData& globalData, const Identifie , m_name(name) , m_inferredName(inferredName.isNull() ? globalData.propertyNames->emptyIdentifier : inferredName) , m_symbolTable(0) - , m_next(0) - , m_prev(0) { } @@ -159,8 +152,6 @@ FunctionExecutable::FunctionExecutable(ExecState* exec, const Identifier& name, , m_name(name) , m_inferredName(inferredName.isNull() ? exec->globalData().propertyNames->emptyIdentifier : inferredName) , m_symbolTable(0) - , m_next(0) - , m_prev(0) { } @@ -292,17 +283,9 @@ void EvalExecutable::unlinkCalls() #endif } -void EvalExecutable::finalize(JSCell* cell) -{ - jsCast<EvalExecutable*>(cell)->clearCode(); -} - -inline void EvalExecutable::clearCode() +void EvalExecutable::clearCode() { - if (m_evalCodeBlock) { - m_evalCodeBlock->clearEvalCache(); - m_evalCodeBlock.clear(); - } + m_evalCodeBlock.clear(); Base::clearCode(); } @@ -424,17 +407,9 @@ void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) thisObject->m_programCodeBlock->visitAggregate(visitor); } -void ProgramExecutable::finalize(JSCell* cell) -{ - jsCast<ProgramExecutable*>(cell)->clearCode(); -} - -inline void ProgramExecutable::clearCode() +void ProgramExecutable::clearCode() { - if (m_programCodeBlock) { - m_programCodeBlock->clearEvalCache(); - m_programCodeBlock.clear(); - } + m_programCodeBlock.clear(); Base::clearCode(); } @@ -642,37 +617,17 @@ void FunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) thisObject->m_codeBlockForConstruct->visitAggregate(visitor); } -void FunctionExecutable::discardCode() +void FunctionExecutable::clearCodeIfNotCompiling() { -#if ENABLE(JIT) - // These first two checks are to handle the rare case where - // we are trying to evict code for a function during its - // codegen. - if (!m_jitCodeForCall && m_codeBlockForCall) - return; - if (!m_jitCodeForConstruct && m_codeBlockForConstruct) + if (isCompiling()) return; -#endif clearCode(); } -void FunctionExecutable::finalize(JSCell* cell) +void FunctionExecutable::clearCode() { - FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell); - Heap::heap(executable)->removeFunctionExecutable(executable); - executable->clearCode(); -} - -inline void FunctionExecutable::clearCode() -{ - if (m_codeBlockForCall) { - m_codeBlockForCall->clearEvalCache(); - m_codeBlockForCall.clear(); - } - if (m_codeBlockForConstruct) { - m_codeBlockForConstruct->clearEvalCache(); - m_codeBlockForConstruct.clear(); - } + m_codeBlockForCall.clear(); + m_codeBlockForConstruct.clear(); Base::clearCode(); } diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h index e999d3a08..e5f6de438 100644 --- a/Source/JavaScriptCore/runtime/Executable.h +++ b/Source/JavaScriptCore/runtime/Executable.h @@ -54,7 +54,8 @@ namespace JSC { return false; } - class ExecutableBase : public JSCell { + class ExecutableBase : public JSCell, public DoublyLinkedListNode<ExecutableBase> { + friend class WTF::DoublyLinkedListNode<ExecutableBase>; friend class JIT; protected: @@ -80,6 +81,11 @@ namespace JSC { static void destroy(JSCell*); #endif + bool isFunctionExecutable() + { + return structure()->typeInfo().type() == FunctionExecutableType; + } + bool isHostFunction() const { ASSERT((m_numParametersForCall == NUM_PARAMETERS_IS_HOST) == (m_numParametersForConstruct == NUM_PARAMETERS_IS_HOST)); @@ -88,6 +94,8 @@ namespace JSC { static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(globalData, globalObject, proto, TypeInfo(CompoundType, StructureFlags), &s_info); } + void clearCode(); + static JS_EXPORTDATA const ClassInfo s_info; protected: @@ -95,8 +103,10 @@ namespace JSC { int m_numParametersForCall; int m_numParametersForConstruct; -#if ENABLE(JIT) public: + static void clearCodeVirtual(ExecutableBase*); + +#if ENABLE(JIT) JITCode& generatedJITCodeForCall() { ASSERT(m_jitCodeForCall); @@ -166,14 +176,18 @@ namespace JSC { return intrinsic(); return NoIntrinsic; } +#endif protected: + ExecutableBase* m_prev; + ExecutableBase* m_next; + +#if ENABLE(JIT) JITCode m_jitCodeForCall; JITCode m_jitCodeForConstruct; MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck; MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck; #endif - void clearCode(); }; class NativeExecutable : public ExecutableBase { @@ -194,7 +208,6 @@ namespace JSC { executable = new (NotNull, allocateCell<NativeExecutable>(globalData.heap)) NativeExecutable(globalData, function, constructor); executable->finishCreation(globalData, JITCode::HostFunction(callThunk), JITCode::HostFunction(constructThunk), intrinsic); } - globalData.heap.addFinalizer(executable, &finalize); return executable; } #endif @@ -205,7 +218,6 @@ namespace JSC { ASSERT(!globalData.canUseJIT()); NativeExecutable* executable = new (NotNull, allocateCell<NativeExecutable>(globalData.heap)) NativeExecutable(globalData, function, constructor); executable->finishCreation(globalData); - globalData.heap.addFinalizer(executable, &finalize); return executable; } #endif @@ -246,8 +258,6 @@ namespace JSC { } #endif - static void finalize(JSCell*); - private: NativeExecutable(JSGlobalData& globalData, NativeFunction function, NativeFunction constructor) : ExecutableBase(globalData, globalData.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST) @@ -303,6 +313,8 @@ namespace JSC { void finishCreation(JSGlobalData& globalData) { Base::finishCreation(globalData); + globalData.heap.addCompiledCode(this); // Balanced by Heap::deleteUnmarkedCompiledCode(). + #if ENABLE(CODEBLOCK_SAMPLING) if (SamplingTool* sampler = globalData.interpreter->sampler()) sampler->notifyOfScope(globalData, this); @@ -358,7 +370,6 @@ namespace JSC { { EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, source, isInStrictContext); executable->finishCreation(exec->globalData()); - exec->globalData().heap.addFinalizer(executable, &finalize); return executable; } @@ -377,9 +388,7 @@ namespace JSC { void unlinkCalls(); - protected: void clearCode(); - static void finalize(JSCell*); private: static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags; @@ -400,7 +409,6 @@ namespace JSC { { ProgramExecutable* executable = new (NotNull, allocateCell<ProgramExecutable>(*exec->heap())) ProgramExecutable(exec, source); executable->finishCreation(exec->globalData()); - exec->globalData().heap.addFinalizer(executable, &finalize); return executable; } @@ -447,9 +455,7 @@ namespace JSC { void unlinkCalls(); - protected: void clearCode(); - static void finalize(JSCell*); private: static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags; @@ -461,10 +467,9 @@ namespace JSC { OwnPtr<ProgramCodeBlock> m_programCodeBlock; }; - class FunctionExecutable : public ScriptExecutable, public DoublyLinkedListNode<FunctionExecutable> { + class FunctionExecutable : public ScriptExecutable { friend class JIT; friend class LLIntOffsetsExtractor; - friend class WTF::DoublyLinkedListNode<FunctionExecutable>; public: typedef ScriptExecutable Base; @@ -472,8 +477,6 @@ namespace JSC { { FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(*exec->heap())) FunctionExecutable(exec, name, inferredName, source, forceUsesArguments, parameters, isInStrictContext); executable->finishCreation(exec->globalData(), name, firstLine, lastLine); - exec->globalData().heap.addFunctionExecutable(executable); - exec->globalData().heap.addFinalizer(executable, &finalize); return executable; } @@ -481,8 +484,6 @@ namespace JSC { { FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(globalData.heap)) FunctionExecutable(globalData, name, inferredName, source, forceUsesArguments, parameters, isInStrictContext); executable->finishCreation(globalData, name, firstLine, lastLine); - globalData.heap.addFunctionExecutable(executable); - globalData.heap.addFinalizer(executable, &finalize); return executable; } @@ -639,7 +640,7 @@ namespace JSC { UString paramString() const; SharedSymbolTable* symbolTable() const { return m_symbolTable; } - void discardCode(); + void clearCodeIfNotCompiling(); static void visitChildren(JSCell*, SlotVisitor&); static FunctionExecutable* fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception); static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) @@ -651,10 +652,9 @@ namespace JSC { void unlinkCalls(); - protected: void clearCode(); - static void finalize(JSCell*); + protected: void finishCreation(JSGlobalData& globalData, const Identifier& name, int firstLine, int lastLine) { Base::finishCreation(globalData); @@ -677,7 +677,18 @@ namespace JSC { ASSERT(kind == CodeForConstruct); return m_codeBlockForConstruct; } - + + bool isCompiling() + { +#if ENABLE(JIT) + if (!m_jitCodeForCall && m_codeBlockForCall) + return true; + if (!m_jitCodeForConstruct && m_codeBlockForConstruct) + return true; +#endif + return false; + } + static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags; unsigned m_numCapturedVariables : 31; bool m_forceUsesArguments : 1; @@ -689,8 +700,6 @@ namespace JSC { Identifier m_inferredName; WriteBarrier<JSString> m_nameValue; SharedSymbolTable* m_symbolTable; - FunctionExecutable* m_next; - FunctionExecutable* m_prev; }; inline FunctionExecutable* JSFunction::jsExecutable() const @@ -725,6 +734,20 @@ namespace JSC { return function->nativeFunction() == nativeFunction; } + inline void ExecutableBase::clearCodeVirtual(ExecutableBase* executable) + { + switch (executable->structure()->typeInfo().type()) { + case EvalExecutableType: + return jsCast<EvalExecutable*>(executable)->clearCode(); + case ProgramExecutableType: + return jsCast<ProgramExecutable*>(executable)->clearCode(); + case FunctionExecutableType: + return jsCast<FunctionExecutable*>(executable)->clearCode(); + default: + return jsCast<NativeExecutable*>(executable)->clearCode(); + } + } + inline void ScriptExecutable::unlinkCalls() { switch (structure()->typeInfo().type()) { diff --git a/Source/JavaScriptCore/runtime/GCActivityCallback.cpp b/Source/JavaScriptCore/runtime/GCActivityCallback.cpp index 6ec538f72..794d1545e 100644 --- a/Source/JavaScriptCore/runtime/GCActivityCallback.cpp +++ b/Source/JavaScriptCore/runtime/GCActivityCallback.cpp @@ -29,28 +29,108 @@ #include "config.h" #include "GCActivityCallback.h" +#include "APIShims.h" +#include "Heap.h" +#include "JSGlobalData.h" +#include "JSLock.h" +#include "JSObject.h" +#include "ScopeChain.h" +#include <wtf/RetainPtr.h> +#include <wtf/WTFThreadData.h> + namespace JSC { -struct DefaultGCActivityCallbackPlatformData { -}; +#if USE(CF) + +const double gcTimeSlicePerMB = 0.01; // Percentage of CPU time we will spend to reclaim 1 MB +const double maxGCTimeSlice = 0.05; // The maximum amount of CPU time we want to use for opportunistic timer-triggered collections. +const double timerSlop = 2.0; // Fudge factor to avoid performance cost of resetting timer. +const double pagingTimeOut = 0.1; // Time in seconds to allow opportunistic timer to iterate over all blocks to see if the Heap is paged out. +const CFTimeInterval hour = 60 * 60; -DefaultGCActivityCallback::DefaultGCActivityCallback(Heap*) +DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap) + : GCActivityCallback(heap->globalData(), CFRunLoopGetCurrent()) + , m_delay(s_decade) { } -DefaultGCActivityCallback::~DefaultGCActivityCallback() +DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap, CFRunLoopRef runLoop) + : GCActivityCallback(heap->globalData(), runLoop) + , m_delay(s_decade) { } -void DefaultGCActivityCallback::didAllocate(size_t) +void DefaultGCActivityCallback::doWork() +{ + Heap* heap = &m_globalData->heap; + if (!isEnabled()) + return; + + APIEntryShim shim(m_globalData); +#if !PLATFORM(IOS) + double startTime = WTF::monotonicallyIncreasingTime(); + if (heap->isPagedOut(startTime + pagingTimeOut)) { + heap->activityCallback()->cancel(); + heap->increaseLastGCLength(pagingTimeOut); + return; + } +#endif + heap->collectAllGarbage(); +} + +void DefaultGCActivityCallback::scheduleTimer(double newDelay) +{ + if (newDelay * timerSlop > m_delay) + return; + double delta = m_delay - newDelay; + m_delay = newDelay; + CFRunLoopTimerSetNextFireDate(m_timer.get(), CFRunLoopTimerGetNextFireDate(m_timer.get()) - delta); +} + +void DefaultGCActivityCallback::cancelTimer() +{ + m_delay = s_decade; + CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + s_decade); +} + +void DefaultGCActivityCallback::didAllocate(size_t bytes) { + // The first byte allocated in an allocation cycle will report 0 bytes to didAllocate. + // We pretend it's one byte so that we don't ignore this allocation entirely. + if (!bytes) + bytes = 1; + Heap* heap = static_cast<Heap*>(&m_globalData->heap); + double gcTimeSlice = std::min((static_cast<double>(bytes) / MB) * gcTimeSlicePerMB, maxGCTimeSlice); + double newDelay = heap->lastGCLength() / gcTimeSlice; + scheduleTimer(newDelay); } void DefaultGCActivityCallback::willCollect() { + cancelTimer(); +} + +void DefaultGCActivityCallback::cancel() +{ + cancelTimer(); +} + +#else + +DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap) + : GCActivityCallback(heap->globalData()) +{ +} + +void DefaultGCActivityCallback::doWork() +{ } -void DefaultGCActivityCallback::synchronize() +void DefaultGCActivityCallback::didAllocate(size_t) +{ +} + +void DefaultGCActivityCallback::willCollect() { } @@ -58,5 +138,7 @@ void DefaultGCActivityCallback::cancel() { } +#endif + } diff --git a/Source/JavaScriptCore/runtime/GCActivityCallback.h b/Source/JavaScriptCore/runtime/GCActivityCallback.h index 32077f2b0..18bbd31e0 100644 --- a/Source/JavaScriptCore/runtime/GCActivityCallback.h +++ b/Source/JavaScriptCore/runtime/GCActivityCallback.h @@ -29,6 +29,7 @@ #ifndef GCActivityCallback_h #define GCActivityCallback_h +#include "HeapTimer.h" #include <wtf/OwnPtr.h> #include <wtf/PassOwnPtr.h> @@ -40,47 +41,54 @@ namespace JSC { class Heap; -class GCActivityCallback { +class GCActivityCallback : public HeapTimer { public: - virtual ~GCActivityCallback() { } virtual void didAllocate(size_t) { } virtual void willCollect() { } - virtual void synchronize() { } virtual void cancel() { } bool isEnabled() const { return m_enabled; } void setEnabled(bool enabled) { m_enabled = enabled; } protected: - GCActivityCallback() - : m_enabled(true) +#if USE(CF) + GCActivityCallback(JSGlobalData* globalData, CFRunLoopRef runLoop) + : HeapTimer(globalData, runLoop) + , m_enabled(true) + { + } +# else + GCActivityCallback(JSGlobalData* globalData) + : HeapTimer(globalData) + , m_enabled(true) { } +#endif bool m_enabled; }; -struct DefaultGCActivityCallbackPlatformData; - class DefaultGCActivityCallback : public GCActivityCallback { public: static PassOwnPtr<DefaultGCActivityCallback> create(Heap*); DefaultGCActivityCallback(Heap*); - virtual ~DefaultGCActivityCallback(); virtual void didAllocate(size_t); virtual void willCollect(); - virtual void synchronize(); virtual void cancel(); + + virtual void doWork(); #if USE(CF) protected: DefaultGCActivityCallback(Heap*, CFRunLoopRef); - void commonConstructor(Heap*, CFRunLoopRef); -#endif - + + void cancelTimer(); + void scheduleTimer(double); + private: - OwnPtr<DefaultGCActivityCallbackPlatformData> d; + double m_delay; +#endif }; inline PassOwnPtr<DefaultGCActivityCallback> DefaultGCActivityCallback::create(Heap* heap) diff --git a/Source/JavaScriptCore/runtime/GCActivityCallbackBlackBerry.cpp b/Source/JavaScriptCore/runtime/GCActivityCallbackBlackBerry.cpp new file mode 100644 index 000000000..3b0b5a751 --- /dev/null +++ b/Source/JavaScriptCore/runtime/GCActivityCallbackBlackBerry.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2012 Research In Motion Limited. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "GCActivityCallback.h" + +#include "Heap.h" +#include <BlackBerryPlatformMemory.h> + +namespace JSC { + +DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap) + : GCActivityCallback(heap->globalData()) +{ +} + +DefaultGCActivityCallback::doWork() +{ +} + +void DefaultGCActivityCallback::didAllocate(size_t bytesAllocated) +{ + if (!BlackBerry::Platform::isMemoryLow()) + return; + + if (bytesAllocated < 1 * 1024 * 1024) + return; + + if (m_globalData->heap.isBusy() || !m_globalData->heap.isSafeToCollect()) + return; + + m_globalData->heap.collect(Heap::DoNotSweep); +} + +void DefaultGCActivityCallback::willCollect() +{ +} + +void DefaultGCActivityCallback::cancel() +{ +} + +} diff --git a/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp b/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp deleted file mode 100644 index d82403a6b..000000000 --- a/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2010 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "GCActivityCallback.h" - -#include "APIShims.h" -#include "Heap.h" -#include "JSGlobalData.h" -#include "JSLock.h" -#include "JSObject.h" -#include "ScopeChain.h" -#include <wtf/RetainPtr.h> -#include <wtf/WTFThreadData.h> - -#if !USE(CF) -#error "This file should only be used on CF platforms." -#endif - -namespace JSC { - -struct DefaultGCActivityCallbackPlatformData { - static void timerDidFire(CFRunLoopTimerRef, void *info); - - RetainPtr<CFRunLoopTimerRef> timer; - RetainPtr<CFRunLoopRef> runLoop; - CFRunLoopTimerContext context; - double delay; -}; - -const double gcTimeSlicePerMB = 0.01; // Percentage of CPU time we will spend to reclaim 1 MB -const double maxGCTimeSlice = 0.05; // The maximum amount of CPU time we want to use for opportunistic timer-triggered collections. -const double timerSlop = 2.0; // Fudge factor to avoid performance cost of resetting timer. -const double pagingTimeOut = 0.1; // Time in seconds to allow opportunistic timer to iterate over all blocks to see if the Heap is paged out. -const CFTimeInterval decade = 60 * 60 * 24 * 365 * 10; -const CFTimeInterval hour = 60 * 60; - -void DefaultGCActivityCallbackPlatformData::timerDidFire(CFRunLoopTimerRef, void *info) -{ - Heap* heap = static_cast<Heap*>(info); - if (!heap->activityCallback()->isEnabled()) - return; - - APIEntryShim shim(heap->globalData()); -#if !PLATFORM(IOS) - double startTime = WTF::monotonicallyIncreasingTime(); - if (heap->isPagedOut(startTime + pagingTimeOut)) { - heap->activityCallback()->cancel(); - heap->increaseLastGCLength(pagingTimeOut); - return; - } -#endif - heap->collectAllGarbage(); -} - -DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap) -{ - commonConstructor(heap, CFRunLoopGetCurrent()); -} - -DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap, CFRunLoopRef runLoop) -{ - commonConstructor(heap, runLoop); -} - -DefaultGCActivityCallback::~DefaultGCActivityCallback() -{ - CFRunLoopRemoveTimer(d->runLoop.get(), d->timer.get(), kCFRunLoopCommonModes); - CFRunLoopTimerInvalidate(d->timer.get()); -} - -void DefaultGCActivityCallback::commonConstructor(Heap* heap, CFRunLoopRef runLoop) -{ - d = adoptPtr(new DefaultGCActivityCallbackPlatformData); - - memset(&d->context, 0, sizeof(CFRunLoopTimerContext)); - d->context.info = heap; - d->runLoop = runLoop; - d->timer.adoptCF(CFRunLoopTimerCreate(0, decade, decade, 0, 0, DefaultGCActivityCallbackPlatformData::timerDidFire, &d->context)); - d->delay = decade; - CFRunLoopAddTimer(d->runLoop.get(), d->timer.get(), kCFRunLoopCommonModes); -} - -static void scheduleTimer(DefaultGCActivityCallbackPlatformData* d, double newDelay) -{ - if (newDelay * timerSlop > d->delay) - return; - double delta = d->delay - newDelay; - d->delay = newDelay; - CFRunLoopTimerSetNextFireDate(d->timer.get(), CFRunLoopTimerGetNextFireDate(d->timer.get()) - delta); -} - -static void cancelTimer(DefaultGCActivityCallbackPlatformData* d) -{ - d->delay = decade; - CFRunLoopTimerSetNextFireDate(d->timer.get(), CFAbsoluteTimeGetCurrent() + decade); -} - -void DefaultGCActivityCallback::didAllocate(size_t bytes) -{ - // The first byte allocated in an allocation cycle will report 0 bytes to didAllocate. - // We pretend it's one byte so that we don't ignore this allocation entirely. - if (!bytes) - bytes = 1; - Heap* heap = static_cast<Heap*>(d->context.info); - double gcTimeSlice = std::min((static_cast<double>(bytes) / MB) * gcTimeSlicePerMB, maxGCTimeSlice); - double newDelay = heap->lastGCLength() / gcTimeSlice; - scheduleTimer(d.get(), newDelay); -} - -void DefaultGCActivityCallback::willCollect() -{ - cancelTimer(d.get()); -} - -void DefaultGCActivityCallback::synchronize() -{ - if (CFRunLoopGetCurrent() == d->runLoop.get()) - return; - CFRunLoopRemoveTimer(d->runLoop.get(), d->timer.get(), kCFRunLoopCommonModes); - d->runLoop = CFRunLoopGetCurrent(); - CFRunLoopAddTimer(d->runLoop.get(), d->timer.get(), kCFRunLoopCommonModes); -} - -void DefaultGCActivityCallback::cancel() -{ - cancelTimer(d.get()); -} - -} diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp index 9e7aaba51..96cc44780 100644 --- a/Source/JavaScriptCore/runtime/JSArray.cpp +++ b/Source/JavaScriptCore/runtime/JSArray.cpp @@ -1371,6 +1371,8 @@ void JSArray::visitChildren(JSCell* cell, SlotVisitor& visitor) JSNonFinalObject::visitChildren(thisObject, visitor); if (thisObject->m_storage) { + MARK_LOG_MESSAGE1("[%u]: ", thisObject->length()); + ArrayStorage* storage = thisObject->m_storage; void* baseStorage = storage->m_allocBase; diff --git a/Source/JavaScriptCore/runtime/JSCell.cpp b/Source/JavaScriptCore/runtime/JSCell.cpp index 06c1f7c4d..61e8549ee 100644 --- a/Source/JavaScriptCore/runtime/JSCell.cpp +++ b/Source/JavaScriptCore/runtime/JSCell.cpp @@ -184,6 +184,11 @@ UString JSCell::className(const JSObject*) return UString(); } +const char* JSCell::className() +{ + return classInfo()->className; +} + void JSCell::getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode) { ASSERT_NOT_REACHED(); diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h index 0233f0fec..cdd409706 100644 --- a/Source/JavaScriptCore/runtime/JSCell.h +++ b/Source/JavaScriptCore/runtime/JSCell.h @@ -84,6 +84,8 @@ namespace JSC { void setStructure(JSGlobalData&, Structure*); void clearStructure() { m_structure.clear(); } + const char* className(); + // Extracting the value. JS_EXPORT_PRIVATE bool getString(ExecState* exec, UString&) const; JS_EXPORT_PRIVATE UString getString(ExecState* exec) const; // null string if not a string @@ -197,6 +199,8 @@ namespace JSC { inline void JSCell::visitChildren(JSCell* cell, SlotVisitor& visitor) { + MARK_LOG_PARENT(visitor, cell); + visitor.append(&cell->m_structure); } diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.cpp b/Source/JavaScriptCore/runtime/JSGlobalData.cpp index a13eb79c5..1fb90df40 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalData.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalData.cpp @@ -54,6 +54,7 @@ #include "RegExpObject.h" #include "StrictEvalActivation.h" #include "StrongInlines.h" +#include <wtf/RetainPtr.h> #include <wtf/Threading.h> #include <wtf/WTFThreadData.h> @@ -100,13 +101,10 @@ static bool enableAssembler(ExecutableAllocator& executableAllocator) return false; #if USE(CF) - CFStringRef canUseJITKey = CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman); - CFBooleanRef canUseJIT = (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication); - if (canUseJIT) { - return kCFBooleanTrue == canUseJIT; - CFRelease(canUseJIT); - } - CFRelease(canUseJITKey); + RetainPtr<CFStringRef> canUseJITKey(AdoptCF, CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman)); + RetainPtr<CFBooleanRef> canUseJIT(AdoptCF, (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey.get(), kCFPreferencesCurrentApplication)); + if (canUseJIT) + return kCFBooleanTrue == canUseJIT.get(); #endif #if USE(CF) || OS(UNIX) @@ -159,6 +157,7 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread , dynamicGlobalObject(0) , cachedUTCOffset(std::numeric_limits<double>::quiet_NaN()) , maxReentryDepth(threadStackType == ThreadStackTypeSmall ? MaxSmallThreadReentryDepth : MaxLargeThreadReentryDepth) + , m_enabledProfiler(0) , m_regExpCache(new RegExpCache(this)) #if ENABLE(REGEXP_TRACING) , m_rtTraceList(new RTTraceList()) @@ -418,7 +417,7 @@ struct StackPreservingRecompiler : public MarkedBlock::VoidFunctor { FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell); if (currentlyExecutingFunctions.contains(executable)) return; - executable->discardCode(); + executable->clearCodeIfNotCompiling(); } }; diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.h b/Source/JavaScriptCore/runtime/JSGlobalData.h index c39a01920..f8833104a 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalData.h +++ b/Source/JavaScriptCore/runtime/JSGlobalData.h @@ -70,6 +70,7 @@ namespace JSC { class LLIntOffsetsExtractor; class NativeExecutable; class ParserArena; + class Profiler; class RegExpCache; class Stringifier; class Structure; @@ -255,6 +256,11 @@ namespace JSC { return m_inDefineOwnProperty; } + Profiler* enabledProfiler() + { + return m_enabledProfiler; + } + #if ENABLE(ASSEMBLER) ExecutableAllocator executableAllocator; #endif @@ -346,6 +352,7 @@ namespace JSC { int maxReentryDepth; + Profiler* m_enabledProfiler; RegExpCache* m_regExpCache; BumpPointerAllocator m_regExpAllocator; diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp index 86186b7e1..7b6109599 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -79,7 +79,7 @@ namespace JSC { -const ClassInfo JSGlobalObject::s_info = { "GlobalObject", &JSVariableObject::s_info, 0, ExecState::globalObjectTable, CREATE_METHOD_TABLE(JSGlobalObject) }; +const ClassInfo JSGlobalObject::s_info = { "GlobalObject", &JSSegmentedVariableObject::s_info, 0, ExecState::globalObjectTable, CREATE_METHOD_TABLE(JSGlobalObject) }; const GlobalObjectMethodTable JSGlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptExperimentsEnabled }; @@ -119,10 +119,8 @@ JSGlobalObject::~JSGlobalObject() if (m_debugger) m_debugger->detach(this); - Profiler** profiler = Profiler::enabledProfilerReference(); - if (UNLIKELY(*profiler != 0)) { - (*profiler)->stopProfiling(this); - } + if (Profiler* profiler = globalData().enabledProfiler()) + profiler->stopProfiling(this); } void JSGlobalObject::destroy(JSCell* cell) @@ -150,9 +148,9 @@ void JSGlobalObject::put(JSCell* cell, ExecState* exec, PropertyName propertyNam JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(cell); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject)); - if (thisObject->symbolTablePut(exec, propertyName, value, slot.isStrictMode())) + if (symbolTablePut(thisObject, exec, propertyName, value, slot.isStrictMode())) return; - JSVariableObject::put(thisObject, exec, propertyName, value, slot); + JSSegmentedVariableObject::put(thisObject, exec, propertyName, value, slot); } void JSGlobalObject::putDirectVirtual(JSObject* object, ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes) @@ -160,12 +158,12 @@ void JSGlobalObject::putDirectVirtual(JSObject* object, ExecState* exec, Propert JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(object); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject)); - if (thisObject->symbolTablePutWithAttributes(exec->globalData(), propertyName, value, attributes)) + if (symbolTablePutWithAttributes(thisObject, exec->globalData(), propertyName, value, attributes)) return; JSValue valueBefore = thisObject->getDirect(exec->globalData(), propertyName); PutPropertySlot slot; - JSVariableObject::put(thisObject, exec, propertyName, value, slot); + JSSegmentedVariableObject::put(thisObject, exec, propertyName, value, slot); if (!valueBefore) { JSValue valueAfter = thisObject->getDirect(exec->globalData(), propertyName); if (valueAfter) @@ -178,7 +176,7 @@ bool JSGlobalObject::defineOwnProperty(JSObject* object, ExecState* exec, Proper JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(object); PropertySlot slot; // silently ignore attempts to add accessors aliasing vars. - if (descriptor.isAccessorDescriptor() && thisObject->symbolTableGet(propertyName, slot)) + if (descriptor.isAccessorDescriptor() && symbolTableGet(thisObject, propertyName, slot)) return false; return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow); } @@ -347,7 +345,7 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor) ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); - JSVariableObject::visitChildren(thisObject, visitor); + JSSegmentedVariableObject::visitChildren(thisObject, visitor); visitIfNeeded(visitor, &thisObject->m_globalScopeChain); visitIfNeeded(visitor, &thisObject->m_methodCallDummy); @@ -395,17 +393,6 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor) visitIfNeeded(visitor, &thisObject->m_regExpStructure); visitIfNeeded(visitor, &thisObject->m_stringObjectStructure); visitIfNeeded(visitor, &thisObject->m_internalFunctionStructure); - - if (thisObject->m_registerArray) { - // Outside the execution of global code, when our variables are torn off, - // we can mark the torn-off array. - visitor.appendValues(thisObject->m_registerArray.get(), thisObject->m_registerArraySize); - } else if (thisObject->m_registers) { - // During execution of global code, when our variables are in the register file, - // the symbol table tells us how many variables there are, and registers - // points to where they end, and the registers used for execution begin. - visitor.appendValues(thisObject->m_registers - thisObject->symbolTable().size(), thisObject->symbolTable().size()); - } } ExecState* JSGlobalObject::globalExec() @@ -413,26 +400,9 @@ ExecState* JSGlobalObject::globalExec() return CallFrame::create(m_globalCallFrame + RegisterFile::CallFrameHeaderSize); } -void JSGlobalObject::resizeRegisters(size_t newSize) -{ - // Previous duplicate symbols may have created spare capacity in m_registerArray. - if (newSize <= m_registerArraySize) - return; - - size_t oldSize = m_registerArraySize; - OwnArrayPtr<WriteBarrier<Unknown> > registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[newSize]); - for (size_t i = 0; i < oldSize; ++i) - registerArray[i].set(globalData(), this, m_registerArray[i].get()); - for (size_t i = oldSize; i < newSize; ++i) - registerArray[i].setUndefined(); - - WriteBarrier<Unknown>* registers = registerArray.get(); - setRegisters(registers, registerArray.release(), newSize); -} - void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count) { - resizeRegisters(symbolTable().size() + count); + addRegisters(count); for (int i = 0; i < count; ++i) { GlobalPropertyInfo& global = globals[i]; @@ -448,17 +418,17 @@ void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count) bool JSGlobalObject::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(cell); - if (getStaticFunctionSlot<JSVariableObject>(exec, ExecState::globalObjectTable(exec), thisObject, propertyName, slot)) + if (getStaticFunctionSlot<JSSegmentedVariableObject>(exec, ExecState::globalObjectTable(exec), thisObject, propertyName, slot)) return true; - return thisObject->symbolTableGet(propertyName, slot); + return symbolTableGet(thisObject, propertyName, slot); } bool JSGlobalObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor) { JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(object); - if (getStaticFunctionDescriptor<JSVariableObject>(exec, ExecState::globalObjectTable(exec), thisObject, propertyName, descriptor)) + if (getStaticFunctionDescriptor<JSSegmentedVariableObject>(exec, ExecState::globalObjectTable(exec), thisObject, propertyName, descriptor)) return true; - return thisObject->symbolTableGet(propertyName, descriptor); + return symbolTableGet(thisObject, propertyName, descriptor); } void JSGlobalObject::clearRareData(JSCell* cell) @@ -473,7 +443,7 @@ DynamicGlobalObjectScope::DynamicGlobalObjectScope(JSGlobalData& globalData, JSG if (!m_dynamicGlobalObjectSlot) { #if ENABLE(ASSEMBLER) if (ExecutableAllocator::underMemoryPressure()) - globalData.heap.discardAllCompiledCode(); + globalData.heap.deleteAllCompiledCode(); #endif m_dynamicGlobalObjectSlot = dynamicGlobalObject; diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h index 1e75b7267..2396142b1 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.h +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h @@ -25,7 +25,7 @@ #include "JSArray.h" #include "JSGlobalData.h" #include "JSGlobalThis.h" -#include "JSVariableObject.h" +#include "JSSegmentedVariableObject.h" #include "JSWeakObjectMapRefInternal.h" #include "NumberPrototype.h" #include "StringPrototype.h" @@ -74,7 +74,7 @@ namespace JSC { JavaScriptExperimentsEnabledFunctionPtr javaScriptExperimentsEnabled; }; - class JSGlobalObject : public JSVariableObject { + class JSGlobalObject : public JSSegmentedVariableObject { private: typedef HashSet<RefPtr<OpaqueJSWeakObjectMap> > WeakMapSet; @@ -90,7 +90,6 @@ namespace JSC { protected: - size_t m_registerArraySize; Register m_globalCallFrame[RegisterFile::CallFrameHeaderSize]; WriteBarrier<ScopeChainNode> m_globalScopeChain; @@ -164,7 +163,7 @@ namespace JSC { } public: - typedef JSVariableObject Base; + typedef JSSegmentedVariableObject Base; static JSGlobalObject* create(JSGlobalData& globalData, Structure* structure) { @@ -177,8 +176,7 @@ namespace JSC { protected: explicit JSGlobalObject(JSGlobalData& globalData, Structure* structure, const GlobalObjectMethodTable* globalObjectMethodTable = 0) - : JSVariableObject(globalData, structure, &m_symbolTable, 0) - , m_registerArraySize(0) + : JSSegmentedVariableObject(globalData, structure, &m_symbolTable) , m_globalScopeChain() , m_weakRandom(static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0))) , m_evalEnabled(true) @@ -308,8 +306,6 @@ namespace JSC { void setEvalEnabled(bool enabled) { m_evalEnabled = enabled; } bool evalEnabled() { return m_evalEnabled; } - void resizeRegisters(size_t newSize); - void resetPrototype(JSGlobalData&, JSValue prototype); JSGlobalData& globalData() const { return *Heap::heap(this)->globalData(); } @@ -334,7 +330,7 @@ namespace JSC { double weakRandomNumber() { return m_weakRandom.get(); } protected: - static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags; + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSSegmentedVariableObject::StructureFlags; struct GlobalPropertyInfo { GlobalPropertyInfo(const Identifier& i, JSValue v, unsigned a) @@ -359,7 +355,6 @@ namespace JSC { void createThrowTypeError(ExecState*); - void setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray, size_t count); JS_EXPORT_PRIVATE static void clearRareData(JSCell*); }; @@ -371,19 +366,13 @@ namespace JSC { return jsCast<JSGlobalObject*>(asObject(value)); } - inline void JSGlobalObject::setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray, size_t count) - { - JSVariableObject::setRegisters(registers, registerArray); - m_registerArraySize = count; - } - inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, PropertyName propertyName) { PropertySlot slot; - if (JSVariableObject::getOwnPropertySlot(this, exec, propertyName, slot)) + if (JSSegmentedVariableObject::getOwnPropertySlot(this, exec, propertyName, slot)) return true; bool slotIsWriteable; - return symbolTableGet(propertyName, slot, slotIsWriteable); + return symbolTableGet(this, propertyName, slot, slotIsWriteable); } inline bool JSGlobalObject::symbolTableHasProperty(PropertyName propertyName) @@ -392,13 +381,18 @@ namespace JSC { return !entry.isNull(); } - inline JSValue Structure::prototypeForLookup(ExecState* exec) const + inline JSValue Structure::prototypeForLookup(JSGlobalObject* globalObject) const { if (isObject()) return m_prototype.get(); ASSERT(typeInfo().type() == StringType); - return exec->lexicalGlobalObject()->stringPrototype(); + return globalObject->stringPrototype(); + } + + inline JSValue Structure::prototypeForLookup(ExecState* exec) const + { + return prototypeForLookup(exec->lexicalGlobalObject()); } inline StructureChain* Structure::prototypeChain(ExecState* exec) const diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp index 8d9e4a96b..aa71b8a7b 100644 --- a/Source/JavaScriptCore/runtime/JSObject.cpp +++ b/Source/JavaScriptCore/runtime/JSObject.cpp @@ -56,7 +56,7 @@ const ClassInfo JSObject::s_info = { "Object", 0, 0, 0, CREATE_METHOD_TABLE(JSOb const ClassInfo JSFinalObject::s_info = { "Object", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSFinalObject) }; -static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode) +static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode, bool didReify) { // Add properties from the static hashtables of properties for (; classInfo; classInfo = classInfo->parentClass) { @@ -69,7 +69,7 @@ static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* class int hashSizeMask = table->compactSize - 1; const HashEntry* entry = table->table; for (int i = 0; i <= hashSizeMask; ++i, ++entry) { - if (entry->key() && (!(entry->attributes() & DontEnum) || (mode == IncludeDontEnumProperties))) + if (entry->key() && (!(entry->attributes() & DontEnum) || (mode == IncludeDontEnumProperties)) && !((entry->attributes() & Function) && didReify)) propertyNames.add(entry->key()); } } @@ -417,9 +417,8 @@ void JSObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameA void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { + getClassPropertyNames(exec, object->classInfo(), propertyNames, mode, object->staticFunctionsReified()); object->structure()->getPropertyNamesFromStructure(exec->globalData(), propertyNames, mode); - if (!object->staticFunctionsReified()) - getClassPropertyNames(exec, object->classInfo(), propertyNames, mode); } double JSObject::toNumber(ExecState* exec) const @@ -505,22 +504,25 @@ void JSObject::reifyStaticFunctionsForDelete(ExecState* exec) structure()->setStaticFunctionsReified(); } -void JSObject::removeDirect(JSGlobalData& globalData, PropertyName propertyName) +bool JSObject::removeDirect(JSGlobalData& globalData, PropertyName propertyName) { if (structure()->get(globalData, propertyName) == WTF::notFound) - return; + return false; size_t offset; if (structure()->isUncacheableDictionary()) { offset = structure()->removePropertyWithoutTransition(globalData, propertyName); - if (offset != WTF::notFound) - putUndefinedAtDirectOffset(offset); - return; + if (offset == WTF::notFound) + return false; + putUndefinedAtDirectOffset(offset); + return true; } setStructure(globalData, Structure::removePropertyTransition(globalData, structure(), propertyName, offset)); - if (offset != WTF::notFound) - putUndefinedAtDirectOffset(offset); + if (offset == WTF::notFound) + return false; + putUndefinedAtDirectOffset(offset); + return true; } NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, WriteBarrierBase<Unknown>* location) diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h index 67aa1516c..ac8601deb 100644 --- a/Source/JavaScriptCore/runtime/JSObject.h +++ b/Source/JavaScriptCore/runtime/JSObject.h @@ -176,7 +176,7 @@ namespace JSC { void transitionTo(JSGlobalData&, Structure*); - void removeDirect(JSGlobalData&, PropertyName); + bool removeDirect(JSGlobalData&, PropertyName); // Return true if anything is removed. bool hasCustomProperties() { return structure()->didTransition(); } bool hasGetterSetterProperties() { return structure()->hasGetterSetterProperties(); } diff --git a/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp b/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp new file mode 100644 index 000000000..c65d2b1b9 --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSSegmentedVariableObject.h" + +namespace JSC { + +int JSSegmentedVariableObject::findRegisterIndex(void* registerAddress) +{ + for (int i = m_registers.size(); i--;) { + if (&m_registers[i] != registerAddress) + continue; + return i; + } + CRASH(); + return -1; +} + +int JSSegmentedVariableObject::addRegisters(int numberOfRegistersToAdd) +{ + ASSERT(numberOfRegistersToAdd >= 0); + + size_t oldSize = m_registers.size(); + m_registers.grow(oldSize + numberOfRegistersToAdd); + + for (size_t i = numberOfRegistersToAdd; i--;) + m_registers[oldSize + i].setWithoutWriteBarrier(jsUndefined()); + + return static_cast<int>(oldSize); +} + +void JSSegmentedVariableObject::visitChildren(JSCell* cell, SlotVisitor& slotVisitor) +{ + JSSegmentedVariableObject* thisObject = jsCast<JSSegmentedVariableObject*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + JSSymbolTableObject::visitChildren(thisObject, slotVisitor); + + for (unsigned i = thisObject->m_registers.size(); i--;) + slotVisitor.append(&thisObject->m_registers[i]); +} + +} // namespace JSC + diff --git a/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h b/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h new file mode 100644 index 000000000..f1fe0483d --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSSegmentedVariableObject_h +#define JSSegmentedVariableObject_h + +#include "JSObject.h" +#include "JSSymbolTableObject.h" +#include "Register.h" +#include "SymbolTable.h" +#include <wtf/OwnArrayPtr.h> +#include <wtf/SegmentedVector.h> +#include <wtf/UnusedParam.h> + +namespace JSC { + +class LLIntOffsetsExtractor; +class Register; + +// This is a mostly drop-in replacement for JSVariableObject, except that it preserves +// the invariant that after a variable is created, its address in memory will not change +// so long as the JSSegmentedVariableObject is alive. This allows optimizations based +// on getting the address of the variable and remembering it. As well, unlike a +// JSVariableObject, this will manage the memory for the registers itself and neither +// requires nor allows for the subclasses to manage that memory. Finally, +// JSSegmentedVariableObject has its own GC tracing functionality, since it knows the +// exact dimensions of the variables array at all times. + +class JSSegmentedVariableObject : public JSSymbolTableObject { + friend class JIT; + friend class LLIntOffsetsExtractor; + +public: + typedef JSSymbolTableObject Base; + + WriteBarrier<Unknown>& registerAt(int index) { return m_registers[index]; } + + // This is a slow method call, which searches the register bank to find the index + // given a pointer. It will CRASH() if it does not find the register. Only use this + // in debug code (like bytecode dumping). + JS_EXPORT_PRIVATE int findRegisterIndex(void*); + + WriteBarrier<Unknown>* assertRegisterIsInThisObject(WriteBarrier<Unknown>* registerPointer) + { +#if !ASSERT_DISABLED + findRegisterIndex(registerPointer); +#endif + return registerPointer; + } + + // Adds numberOfRegistersToAdd registers, initializes them to Undefined, and returns + // the index of the first one added. + JS_EXPORT_PRIVATE int addRegisters(int numberOfRegistersToAdd); + + JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); + +protected: + static const unsigned StructureFlags = OverridesVisitChildren | JSSymbolTableObject::StructureFlags; + + JSSegmentedVariableObject(JSGlobalData& globalData, Structure* structure, SymbolTable* symbolTable) + : JSSymbolTableObject(globalData, structure, symbolTable) + { + } + + void finishCreation(JSGlobalData& globalData) + { + Base::finishCreation(globalData); + } + + SegmentedVector<WriteBarrier<Unknown>, 16> m_registers; +}; + +} // namespace JSC + +#endif // JSSegmentedVariableObject_h + diff --git a/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp b/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp index e5e65673c..14187f422 100644 --- a/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp +++ b/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp @@ -66,13 +66,13 @@ void JSStaticScopeObject::put(JSCell* cell, ExecState* exec, PropertyName proper // a pointer compare. PropertySlot slot; bool isWritable = true; - thisObject->symbolTableGet(propertyName, slot, isWritable); + symbolTableGet(thisObject, propertyName, slot, isWritable); if (!isWritable) { throwError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError)); return; } } - if (thisObject->symbolTablePut(exec, propertyName, value, slot.isStrictMode())) + if (symbolTablePut(thisObject, exec, propertyName, value, slot.isStrictMode())) return; ASSERT_NOT_REACHED(); @@ -81,7 +81,7 @@ void JSStaticScopeObject::put(JSCell* cell, ExecState* exec, PropertyName proper void JSStaticScopeObject::putDirectVirtual(JSObject* object, ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes) { JSStaticScopeObject* thisObject = jsCast<JSStaticScopeObject*>(object); - if (thisObject->symbolTablePutWithAttributes(exec->globalData(), propertyName, value, attributes)) + if (symbolTablePutWithAttributes(thisObject, exec->globalData(), propertyName, value, attributes)) return; ASSERT_NOT_REACHED(); @@ -89,7 +89,7 @@ void JSStaticScopeObject::putDirectVirtual(JSObject* object, ExecState* exec, Pr bool JSStaticScopeObject::getOwnPropertySlot(JSCell* cell, ExecState*, PropertyName propertyName, PropertySlot& slot) { - return jsCast<JSStaticScopeObject*>(cell)->symbolTableGet(propertyName, slot); + return symbolTableGet(jsCast<JSStaticScopeObject*>(cell), propertyName, slot); } } diff --git a/Source/JavaScriptCore/runtime/JSString.cpp b/Source/JavaScriptCore/runtime/JSString.cpp index 180c64b8b..4eb2a5297 100644 --- a/Source/JavaScriptCore/runtime/JSString.cpp +++ b/Source/JavaScriptCore/runtime/JSString.cpp @@ -56,6 +56,19 @@ void JSString::visitChildren(JSCell* cell, SlotVisitor& visitor) JSString* thisObject = jsCast<JSString*>(cell); Base::visitChildren(thisObject, visitor); + MARK_LOG_MESSAGE1("[%u]: ", thisObject->length()); + +#if ENABLE(OBJECT_MARK_LOGGING) + if (!thisObject->isRope()) { + WTF::StringImpl* ourImpl = thisObject->m_value.impl(); + if (ourImpl->is8Bit()) + MARK_LOG_MESSAGE1("[8 %p]", ourImpl->characters8()); + else + MARK_LOG_MESSAGE1("[16 %p]", ourImpl->characters16()); + } else + MARK_LOG_MESSAGE0("[rope]: "); +#endif + if (thisObject->isRope()) static_cast<JSRopeString*>(thisObject)->visitFibers(visitor); } diff --git a/Source/JavaScriptCore/runtime/JSString.h b/Source/JavaScriptCore/runtime/JSString.h index 111853c39..4fb157c8b 100644 --- a/Source/JavaScriptCore/runtime/JSString.h +++ b/Source/JavaScriptCore/runtime/JSString.h @@ -67,6 +67,7 @@ namespace JSC { friend class JSGlobalData; friend class SpecializedThunkJIT; friend class JSRopeString; + friend class SlotVisitor; friend struct ThunkHelpers; typedef JSCell Base; diff --git a/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp b/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp new file mode 100644 index 000000000..927ad25cf --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSSymbolTableObject.h" + +#include "JSActivation.h" +#include "JSGlobalObject.h" +#include "JSStaticScopeObject.h" +#include "PropertyNameArray.h" + +namespace JSC { + +void JSSymbolTableObject::destroy(JSCell* cell) +{ + static_cast<JSSymbolTableObject*>(cell)->JSSymbolTableObject::~JSSymbolTableObject(); +} + +bool JSSymbolTableObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) +{ + JSSymbolTableObject* thisObject = jsCast<JSSymbolTableObject*>(cell); + if (thisObject->symbolTable().contains(propertyName.publicName())) + return false; + + return JSObject::deleteProperty(thisObject, exec, propertyName); +} + +void JSSymbolTableObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) +{ + JSSymbolTableObject* thisObject = jsCast<JSSymbolTableObject*>(object); + SymbolTable::const_iterator end = thisObject->symbolTable().end(); + for (SymbolTable::const_iterator it = thisObject->symbolTable().begin(); it != end; ++it) { + if (!(it->second.getAttributes() & DontEnum) || (mode == IncludeDontEnumProperties)) + propertyNames.add(Identifier(exec, it->first.get())); + } + + JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode); +} + +void JSSymbolTableObject::putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned) +{ + ASSERT_NOT_REACHED(); +} + +bool JSSymbolTableObject::isDynamicScope(bool& requiresDynamicChecks) const +{ + switch (structure()->typeInfo().type()) { + case GlobalObjectType: + return static_cast<const JSGlobalObject*>(this)->isDynamicScope(requiresDynamicChecks); + case ActivationObjectType: + return static_cast<const JSActivation*>(this)->isDynamicScope(requiresDynamicChecks); + case StaticScopeObjectType: + return static_cast<const JSStaticScopeObject*>(this)->isDynamicScope(requiresDynamicChecks); + default: + ASSERT_NOT_REACHED(); + break; + } + + return false; +} + +} // namespace JSC + diff --git a/Source/JavaScriptCore/runtime/JSSymbolTableObject.h b/Source/JavaScriptCore/runtime/JSSymbolTableObject.h new file mode 100644 index 000000000..2bbe21d06 --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSSymbolTableObject.h @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSSymbolTableObject_h +#define JSSymbolTableObject_h + +#include "JSObject.h" +#include "PropertyDescriptor.h" +#include "SymbolTable.h" + +namespace JSC { + +class JSSymbolTableObject : public JSNonFinalObject { +public: + typedef JSNonFinalObject Base; + + SymbolTable& symbolTable() const { return *m_symbolTable; } + + JS_EXPORT_PRIVATE static void destroy(JSCell*); + + static NO_RETURN_DUE_TO_ASSERT void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes); + + JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName); + JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + + bool isDynamicScope(bool& requiresDynamicChecks) const; + +protected: + static const unsigned StructureFlags = OverridesGetPropertyNames | JSNonFinalObject::StructureFlags; + + JSSymbolTableObject(JSGlobalData& globalData, Structure* structure, SymbolTable* symbolTable) + : JSNonFinalObject(globalData, structure) + , m_symbolTable(symbolTable) + { + } + + void finishCreation(JSGlobalData& globalData) + { + Base::finishCreation(globalData); + ASSERT(m_symbolTable); + } + + SymbolTable* m_symbolTable; +}; + +template<typename SymbolTableObjectType> +inline bool symbolTableGet( + SymbolTableObjectType* object, PropertyName propertyName, PropertySlot& slot) +{ + SymbolTable& symbolTable = object->symbolTable(); + SymbolTable::iterator iter = symbolTable.find(propertyName.publicName()); + if (iter == symbolTable.end()) + return false; + SymbolTableEntry::Fast entry = iter->second; + ASSERT(!entry.isNull()); + slot.setValue(object->registerAt(entry.getIndex()).get()); + return true; +} + +template<typename SymbolTableObjectType> +inline bool symbolTableGet( + SymbolTableObjectType* object, PropertyName propertyName, PropertyDescriptor& descriptor) +{ + SymbolTable& symbolTable = object->symbolTable(); + SymbolTable::iterator iter = symbolTable.find(propertyName.publicName()); + if (iter == symbolTable.end()) + return false; + SymbolTableEntry::Fast entry = iter->second; + ASSERT(!entry.isNull()); + descriptor.setDescriptor( + object->registerAt(entry.getIndex()).get(), entry.getAttributes() | DontDelete); + return true; +} + +template<typename SymbolTableObjectType> +inline bool symbolTableGet( + SymbolTableObjectType* object, PropertyName propertyName, PropertySlot& slot, + bool& slotIsWriteable) +{ + SymbolTable& symbolTable = object->symbolTable(); + SymbolTable::iterator iter = symbolTable.find(propertyName.publicName()); + if (iter == symbolTable.end()) + return false; + SymbolTableEntry::Fast entry = iter->second; + ASSERT(!entry.isNull()); + slot.setValue(object->registerAt(entry.getIndex()).get()); + slotIsWriteable = !entry.isReadOnly(); + return true; +} + +template<typename SymbolTableObjectType> +inline bool symbolTablePut( + SymbolTableObjectType* object, ExecState* exec, PropertyName propertyName, JSValue value, + bool shouldThrow) +{ + JSGlobalData& globalData = exec->globalData(); + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object)); + + SymbolTable& symbolTable = object->symbolTable(); + SymbolTable::iterator iter = symbolTable.find(propertyName.publicName()); + if (iter == symbolTable.end()) + return false; + bool wasFat; + SymbolTableEntry::Fast fastEntry = iter->second.getFast(wasFat); + ASSERT(!fastEntry.isNull()); + if (fastEntry.isReadOnly()) { + if (shouldThrow) + throwTypeError(exec, StrictModeReadonlyPropertyWriteError); + return true; + } + if (UNLIKELY(wasFat)) + iter->second.notifyWrite(); + object->registerAt(fastEntry.getIndex()).set(globalData, object, value); + return true; +} + +template<typename SymbolTableObjectType> +inline bool symbolTablePutWithAttributes( + SymbolTableObjectType* object, JSGlobalData& globalData, PropertyName propertyName, + JSValue value, unsigned attributes) +{ + ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object)); + + SymbolTable::iterator iter = object->symbolTable().find(propertyName.publicName()); + if (iter == object->symbolTable().end()) + return false; + SymbolTableEntry& entry = iter->second; + ASSERT(!entry.isNull()); + entry.notifyWrite(); + entry.setAttributes(attributes); + object->registerAt(entry.getIndex()).set(globalData, object, value); + return true; +} + +} // namespace JSC + +#endif // JSSymbolTableObject_h + diff --git a/Source/JavaScriptCore/runtime/JSVariableObject.cpp b/Source/JavaScriptCore/runtime/JSVariableObject.cpp index 9dcbead34..7210c9b90 100644 --- a/Source/JavaScriptCore/runtime/JSVariableObject.cpp +++ b/Source/JavaScriptCore/runtime/JSVariableObject.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 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 @@ -29,12 +29,6 @@ #include "config.h" #include "JSVariableObject.h" -#include "JSActivation.h" -#include "JSGlobalObject.h" -#include "JSStaticScopeObject.h" -#include "PropertyNameArray.h" -#include "PropertyDescriptor.h" - namespace JSC { void JSVariableObject::destroy(JSCell* cell) @@ -42,57 +36,4 @@ void JSVariableObject::destroy(JSCell* cell) static_cast<JSVariableObject*>(cell)->JSVariableObject::~JSVariableObject(); } -bool JSVariableObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) -{ - JSVariableObject* thisObject = jsCast<JSVariableObject*>(cell); - if (thisObject->symbolTable().contains(propertyName.publicName())) - return false; - - return JSObject::deleteProperty(thisObject, exec, propertyName); -} - -void JSVariableObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) -{ - JSVariableObject* thisObject = jsCast<JSVariableObject*>(object); - SymbolTable::const_iterator end = thisObject->symbolTable().end(); - for (SymbolTable::const_iterator it = thisObject->symbolTable().begin(); it != end; ++it) { - if (!(it->second.getAttributes() & DontEnum) || (mode == IncludeDontEnumProperties)) - propertyNames.add(Identifier(exec, it->first.get())); - } - - JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode); -} - -bool JSVariableObject::symbolTableGet(PropertyName propertyName, PropertyDescriptor& descriptor) -{ - SymbolTableEntry entry = symbolTable().inlineGet(propertyName.publicName()); - if (!entry.isNull()) { - descriptor.setDescriptor(registerAt(entry.getIndex()).get(), entry.getAttributes() | DontDelete); - return true; - } - return false; -} - -void JSVariableObject::putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned) -{ - ASSERT_NOT_REACHED(); -} - -bool JSVariableObject::isDynamicScope(bool& requiresDynamicChecks) const -{ - switch (structure()->typeInfo().type()) { - case GlobalObjectType: - return static_cast<const JSGlobalObject*>(this)->isDynamicScope(requiresDynamicChecks); - case ActivationObjectType: - return static_cast<const JSActivation*>(this)->isDynamicScope(requiresDynamicChecks); - case StaticScopeObjectType: - return static_cast<const JSStaticScopeObject*>(this)->isDynamicScope(requiresDynamicChecks); - default: - ASSERT_NOT_REACHED(); - break; - } - - return false; -} - } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSVariableObject.h b/Source/JavaScriptCore/runtime/JSVariableObject.h index ea2798457..46fe72684 100644 --- a/Source/JavaScriptCore/runtime/JSVariableObject.h +++ b/Source/JavaScriptCore/runtime/JSVariableObject.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 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,6 +30,7 @@ #define JSVariableObject_h #include "JSObject.h" +#include "JSSymbolTableObject.h" #include "Register.h" #include "SymbolTable.h" #include <wtf/UnusedParam.h> @@ -41,40 +42,25 @@ namespace JSC { class LLIntOffsetsExtractor; class Register; - class JSVariableObject : public JSNonFinalObject { + class JSVariableObject : public JSSymbolTableObject { friend class JIT; friend class LLIntOffsetsExtractor; public: - typedef JSNonFinalObject Base; - - SymbolTable& symbolTable() const { return *m_symbolTable; } - - JS_EXPORT_PRIVATE static void destroy(JSCell*); - - static NO_RETURN_DUE_TO_ASSERT void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes); - - JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName); - JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - - bool isDynamicScope(bool& requiresDynamicChecks) const; + typedef JSSymbolTableObject Base; WriteBarrier<Unknown>& registerAt(int index) const { return m_registers[index]; } WriteBarrier<Unknown>* const * addressOfRegisters() const { return &m_registers; } static size_t offsetOfRegisters() { return OBJECT_OFFSETOF(JSVariableObject, m_registers); } - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(globalData, globalObject, prototype, TypeInfo(VariableObjectType, StructureFlags), &s_info); - } - + JS_EXPORT_PRIVATE static void destroy(JSCell*); + protected: - static const unsigned StructureFlags = OverridesGetPropertyNames | JSNonFinalObject::StructureFlags; + static const unsigned StructureFlags = JSSymbolTableObject::StructureFlags; JSVariableObject(JSGlobalData& globalData, Structure* structure, SymbolTable* symbolTable, Register* registers) - : JSNonFinalObject(globalData, structure) - , m_symbolTable(symbolTable) + : JSSymbolTableObject(globalData, structure, symbolTable) , m_registers(reinterpret_cast<WriteBarrier<Unknown>*>(registers)) { } @@ -82,76 +68,16 @@ namespace JSC { void finishCreation(JSGlobalData& globalData) { Base::finishCreation(globalData); - ASSERT(m_symbolTable); COMPILE_ASSERT(sizeof(WriteBarrier<Unknown>) == sizeof(Register), Register_should_be_same_size_as_WriteBarrier); } PassOwnArrayPtr<WriteBarrier<Unknown> > copyRegisterArray(JSGlobalData&, WriteBarrier<Unknown>* src, size_t count, size_t callframeStarts); void setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray); - bool symbolTableGet(PropertyName, PropertySlot&); - JS_EXPORT_PRIVATE bool symbolTableGet(PropertyName, PropertyDescriptor&); - bool symbolTableGet(PropertyName, PropertySlot&, bool& slotIsWriteable); - bool symbolTablePut(ExecState*, PropertyName, JSValue, bool shouldThrow); - bool symbolTablePutWithAttributes(JSGlobalData&, PropertyName, JSValue, unsigned attributes); - - SymbolTable* m_symbolTable; // Maps name -> offset from "r" in register file. WriteBarrier<Unknown>* m_registers; // "r" in the register file. OwnArrayPtr<WriteBarrier<Unknown> > m_registerArray; // Independent copy of registers, used when a variable object copies its registers out of the register file. }; - inline bool JSVariableObject::symbolTableGet(PropertyName propertyName, PropertySlot& slot) - { - SymbolTableEntry entry = symbolTable().inlineGet(propertyName.publicName()); - if (!entry.isNull()) { - slot.setValue(registerAt(entry.getIndex()).get()); - return true; - } - return false; - } - - inline bool JSVariableObject::symbolTableGet(PropertyName propertyName, PropertySlot& slot, bool& slotIsWriteable) - { - SymbolTableEntry entry = symbolTable().inlineGet(propertyName.publicName()); - if (!entry.isNull()) { - slot.setValue(registerAt(entry.getIndex()).get()); - slotIsWriteable = !entry.isReadOnly(); - return true; - } - return false; - } - - inline bool JSVariableObject::symbolTablePut(ExecState* exec, PropertyName propertyName, JSValue value, bool shouldThrow) - { - JSGlobalData& globalData = exec->globalData(); - ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); - - SymbolTableEntry entry = symbolTable().inlineGet(propertyName.publicName()); - if (entry.isNull()) - return false; - if (entry.isReadOnly()) { - if (shouldThrow) - throwTypeError(exec, StrictModeReadonlyPropertyWriteError); - return true; - } - registerAt(entry.getIndex()).set(globalData, this, value); - return true; - } - - inline bool JSVariableObject::symbolTablePutWithAttributes(JSGlobalData& globalData, PropertyName propertyName, JSValue value, unsigned attributes) - { - ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); - - SymbolTable::iterator iter = symbolTable().find(propertyName.publicName()); - if (iter == symbolTable().end()) - return false; - SymbolTableEntry& entry = iter->second; - ASSERT(!entry.isNull()); - entry.setAttributes(attributes); - registerAt(entry.getIndex()).set(globalData, this, value); - return true; - } - inline PassOwnArrayPtr<WriteBarrier<Unknown> > JSVariableObject::copyRegisterArray(JSGlobalData& globalData, WriteBarrier<Unknown>* src, size_t count, size_t callframeStarts) { OwnArrayPtr<WriteBarrier<Unknown> > registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[count]); diff --git a/Source/JavaScriptCore/runtime/Lookup.h b/Source/JavaScriptCore/runtime/Lookup.h index a75b521cd..ccb08128d 100644 --- a/Source/JavaScriptCore/runtime/Lookup.h +++ b/Source/JavaScriptCore/runtime/Lookup.h @@ -114,6 +114,13 @@ namespace JSC { const HashTableValue* values; // Fixed values generated by script. mutable const HashEntry* table; // Table allocated at runtime. + ALWAYS_INLINE HashTable copy() const + { + // Don't copy dynamic table since it's thread specific. + HashTable result = { compactSize, compactHashSizeMask, values, 0 }; + return result; + } + ALWAYS_INLINE void initializeIfNeeded(JSGlobalData* globalData) const { if (!table) diff --git a/Source/JavaScriptCore/runtime/MathObject.cpp b/Source/JavaScriptCore/runtime/MathObject.cpp index 9d83290a5..2a550a38b 100644 --- a/Source/JavaScriptCore/runtime/MathObject.cpp +++ b/Source/JavaScriptCore/runtime/MathObject.cpp @@ -202,6 +202,43 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncMin(ExecState* exec) return JSValue::encode(jsNumber(result)); } +#if PLATFORM(IOS) && CPU(ARM_THUMB2) + +static double fdlibmPow(double x, double y); + +static ALWAYS_INLINE bool isDenormal(double x) +{ + static const uint64_t signbit = 0x8000000000000000ULL; + static const uint64_t minNormal = 0x0001000000000000ULL; + return (bitwise_cast<uint64_t>(x) & ~signbit) - 1 < minNormal - 1; +} + +static ALWAYS_INLINE bool isEdgeCase(double x) +{ + static const uint64_t signbit = 0x8000000000000000ULL; + static const uint64_t infinity = 0x7fffffffffffffffULL; + return (bitwise_cast<uint64_t>(x) & ~signbit) - 1 >= infinity - 1; +} + +static ALWAYS_INLINE double mathPow(double x, double y) +{ + if (!isDenormal(x) && !isDenormal(y)) { + double libmResult = pow(x,y); + if (libmResult || isEdgeCase(x) || isEdgeCase(y)) + return libmResult; + } + return fdlibmPow(x,y); +} + +#else + +ALWAYS_INLINE double mathPow(double x, double y) +{ + return pow(x, y); +} + +#endif + EncodedJSValue JSC_HOST_CALL mathProtoFuncPow(ExecState* exec) { // ECMA 15.8.2.1.13 @@ -213,7 +250,7 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncPow(ExecState* exec) return JSValue::encode(jsNaN()); if (isinf(arg2) && fabs(arg) == 1) return JSValue::encode(jsNaN()); - return JSValue::encode(jsNumber(pow(arg, arg2))); + return JSValue::encode(jsNumber(mathPow(arg, arg2))); } EncodedJSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState* exec) @@ -243,4 +280,353 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncTan(ExecState* exec) return JSValue::encode(jsDoubleNumber(tan(exec->argument(0).toNumber(exec)))); } +#if PLATFORM(IOS) && CPU(ARM_THUMB2) + +// The following code is taken from netlib.org: +// http://www.netlib.org/fdlibm/fdlibm.h +// http://www.netlib.org/fdlibm/e_pow.c +// http://www.netlib.org/fdlibm/s_scalbn.c +// +// And was originally distributed under the following license: + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* __ieee754_pow(x,y) return x**y + * + * n + * Method: Let x = 2 * (1+f) + * 1. Compute and return log2(x) in two pieces: + * log2(x) = w1 + w2, + * where w1 has 53-24 = 29 bit trailing zeros. + * 2. Perform y*log2(x) = n+y' by simulating muti-precision + * arithmetic, where |y'|<=0.5. + * 3. Return x**y = 2**n*exp(y'*log2) + * + * Special cases: + * 1. (anything) ** 0 is 1 + * 2. (anything) ** 1 is itself + * 3. (anything) ** NAN is NAN + * 4. NAN ** (anything except 0) is NAN + * 5. +-(|x| > 1) ** +INF is +INF + * 6. +-(|x| > 1) ** -INF is +0 + * 7. +-(|x| < 1) ** +INF is +0 + * 8. +-(|x| < 1) ** -INF is +INF + * 9. +-1 ** +-INF is NAN + * 10. +0 ** (+anything except 0, NAN) is +0 + * 11. -0 ** (+anything except 0, NAN, odd integer) is +0 + * 12. +0 ** (-anything except 0, NAN) is +INF + * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF + * 14. -0 ** (odd integer) = -( +0 ** (odd integer) ) + * 15. +INF ** (+anything except 0,NAN) is +INF + * 16. +INF ** (-anything except 0,NAN) is +0 + * 17. -INF ** (anything) = -0 ** (-anything) + * 18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) + * 19. (-anything except 0 and inf) ** (non-integer) is NAN + * + * Accuracy: + * pow(x,y) returns x**y nearly rounded. In particular + * pow(integer,integer) + * always returns the correct integer provided it is + * representable. + * + * Constants : + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#define __HI(x) *(1+(int*)&x) +#define __LO(x) *(int*)&x + +static const double +bp[] = {1.0, 1.5,}, +dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */ +dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */ +zero = 0.0, +one = 1.0, +two = 2.0, +two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */ +huge = 1.0e300, +tiny = 1.0e-300, + /* for scalbn */ +two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */ +twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */ + /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ +L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */ +L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */ +L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */ +L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */ +L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */ +L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */ +P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ +P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ +P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ +P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ +P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */ +lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */ +lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */ +lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */ +ovt = 8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */ +cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */ +cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */ +cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/ +ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */ +ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/ +ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/ + +inline double fdlibmScalbn (double x, int n) +{ + int k,hx,lx; + hx = __HI(x); + lx = __LO(x); + k = (hx&0x7ff00000)>>20; /* extract exponent */ + if (k==0) { /* 0 or subnormal x */ + if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */ + x *= two54; + hx = __HI(x); + k = ((hx&0x7ff00000)>>20) - 54; + if (n< -50000) return tiny*x; /*underflow*/ + } + if (k==0x7ff) return x+x; /* NaN or Inf */ + k = k+n; + if (k > 0x7fe) return huge*copysign(huge,x); /* overflow */ + if (k > 0) /* normal result */ + {__HI(x) = (hx&0x800fffff)|(k<<20); return x;} + if (k <= -54) { + if (n > 50000) /* in case integer overflow in n+k */ + return huge*copysign(huge,x); /*overflow*/ + else return tiny*copysign(tiny,x); /*underflow*/ + } + k += 54; /* subnormal result */ + __HI(x) = (hx&0x800fffff)|(k<<20); + return x*twom54; +} + +double fdlibmPow(double x, double y) +{ + double z,ax,z_h,z_l,p_h,p_l; + double y1,t1,t2,r,s,t,u,v,w; + int i0,i1,i,j,k,yisint,n; + int hx,hy,ix,iy; + unsigned lx,ly; + + i0 = ((*(int*)&one)>>29)^1; i1=1-i0; + hx = __HI(x); lx = __LO(x); + hy = __HI(y); ly = __LO(y); + ix = hx&0x7fffffff; iy = hy&0x7fffffff; + + /* y==zero: x**0 = 1 */ + if((iy|ly)==0) return one; + + /* +-NaN return x+y */ + if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) || + iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0))) + return x+y; + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if(hx<0) { + if(iy>=0x43400000) yisint = 2; /* even integer y */ + else if(iy>=0x3ff00000) { + k = (iy>>20)-0x3ff; /* exponent */ + if(k>20) { + j = ly>>(52-k); + if(static_cast<unsigned>(j<<(52-k))==ly) yisint = 2-(j&1); + } else if(ly==0) { + j = iy>>(20-k); + if((j<<(20-k))==iy) yisint = 2-(j&1); + } + } + } + + /* special value of y */ + if(ly==0) { + if (iy==0x7ff00000) { /* y is +-inf */ + if(((ix-0x3ff00000)|lx)==0) + return y - y; /* inf**+-1 is NaN */ + else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */ + return (hy>=0)? y: zero; + else /* (|x|<1)**-,+inf = inf,0 */ + return (hy<0)?-y: zero; + } + if(iy==0x3ff00000) { /* y is +-1 */ + if(hy<0) return one/x; else return x; + } + if(hy==0x40000000) return x*x; /* y is 2 */ + if(hy==0x3fe00000) { /* y is 0.5 */ + if(hx>=0) /* x >= +0 */ + return sqrt(x); + } + } + + ax = fabs(x); + /* special value of x */ + if(lx==0) { + if(ix==0x7ff00000||ix==0||ix==0x3ff00000){ + z = ax; /*x is +-0,+-inf,+-1*/ + if(hy<0) z = one/z; /* z = (1/|x|) */ + if(hx<0) { + if(((ix-0x3ff00000)|yisint)==0) { + z = (z-z)/(z-z); /* (-1)**non-int is NaN */ + } else if(yisint==1) + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + return z; + } + } + + n = (hx>>31)+1; + + /* (x<0)**(non-int) is NaN */ + if((n|yisint)==0) return (x-x)/(x-x); + + s = one; /* s (sign of result -ve**odd) = -1 else = 1 */ + if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */ + + /* |y| is huge */ + if(iy>0x41e00000) { /* if |y| > 2**31 */ + if(iy>0x43f00000){ /* if |y| > 2**64, must o/uflow */ + if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny; + if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny; + } + /* over/underflow if x is not close to one */ + if(ix<0x3fefffff) return (hy<0)? s*huge*huge:s*tiny*tiny; + if(ix>0x3ff00000) return (hy>0)? s*huge*huge:s*tiny*tiny; + /* now |1-x| is tiny <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax-one; /* t has 20 trailing zeros */ + w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25)); + u = ivln2_h*t; /* ivln2_h has 21 sig. bits */ + v = t*ivln2_l-w*ivln2; + t1 = u+v; + __LO(t1) = 0; + t2 = v-(t1-u); + } else { + double ss,s2,s_h,s_l,t_h,t_l; + n = 0; + /* take care subnormal number */ + if(ix<0x00100000) + {ax *= two53; n -= 53; ix = __HI(ax); } + n += ((ix)>>20)-0x3ff; + j = ix&0x000fffff; + /* determine interval */ + ix = j|0x3ff00000; /* normalize ix */ + if(j<=0x3988E) k=0; /* |x|<sqrt(3/2) */ + else if(j<0xBB67A) k=1; /* |x|<sqrt(3) */ + else {k=0;n+=1;ix -= 0x00100000;} + __HI(ax) = ix; + + /* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */ + u = ax-bp[k]; /* bp[0]=1.0, bp[1]=1.5 */ + v = one/(ax+bp[k]); + ss = u*v; + s_h = ss; + __LO(s_h) = 0; + /* t_h=ax+bp[k] High */ + t_h = zero; + __HI(t_h)=((ix>>1)|0x20000000)+0x00080000+(k<<18); + t_l = ax - (t_h-bp[k]); + s_l = v*((u-s_h*t_h)-s_h*t_l); + /* compute log(ax) */ + s2 = ss*ss; + r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6))))); + r += s_l*(s_h+ss); + s2 = s_h*s_h; + t_h = 3.0+s2+r; + __LO(t_h) = 0; + t_l = r-((t_h-3.0)-s2); + /* u+v = ss*(1+...) */ + u = s_h*t_h; + v = s_l*t_h+t_l*ss; + /* 2/(3log2)*(ss+...) */ + p_h = u+v; + __LO(p_h) = 0; + p_l = v-(p_h-u); + z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = cp_l*p_h+p_l*cp+dp_l[k]; + /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = (double)n; + t1 = (((z_h+z_l)+dp_h[k])+t); + __LO(t1) = 0; + t2 = z_l-(((t1-t)-dp_h[k])-z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + y1 = y; + __LO(y1) = 0; + p_l = (y-y1)*t1+y*t2; + p_h = y1*t1; + z = p_l+p_h; + j = __HI(z); + i = __LO(z); + if (j>=0x40900000) { /* z >= 1024 */ + if(((j-0x40900000)|i)!=0) /* if z > 1024 */ + return s*huge*huge; /* overflow */ + else { + if(p_l+ovt>z-p_h) return s*huge*huge; /* overflow */ + } + } else if((j&0x7fffffff)>=0x4090cc00 ) { /* z <= -1075 */ + if(((j-0xc090cc00)|i)!=0) /* z < -1075 */ + return s*tiny*tiny; /* underflow */ + else { + if(p_l<=z-p_h) return s*tiny*tiny; /* underflow */ + } + } + /* + * compute 2**(p_h+p_l) + */ + i = j&0x7fffffff; + k = (i>>20)-0x3ff; + n = 0; + if(i>0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */ + n = j+(0x00100000>>(k+1)); + k = ((n&0x7fffffff)>>20)-0x3ff; /* new k for n */ + t = zero; + __HI(t) = (n&~(0x000fffff>>k)); + n = ((n&0x000fffff)|0x00100000)>>(20-k); + if(j<0) n = -n; + p_h -= t; + } + t = p_l+p_h; + __LO(t) = 0; + u = t*lg2_h; + v = (p_l-(t-p_h))*lg2+t*lg2_l; + z = u+v; + w = v-(z-u); + t = z*z; + t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + r = (z*t1)/(t1-two)-(w+z*w); + z = one-(r-z); + j = __HI(z); + j += (n<<20); + if((j>>20)<=0) z = fdlibmScalbn(z,n); /* subnormal output */ + else __HI(z) += (n<<20); + return s*z; +} + +#endif + } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Options.cpp b/Source/JavaScriptCore/runtime/Options.cpp index 8f5a05067..ec228f82a 100644 --- a/Source/JavaScriptCore/runtime/Options.cpp +++ b/Source/JavaScriptCore/runtime/Options.cpp @@ -47,6 +47,8 @@ namespace JSC { namespace Options { bool useJIT; +bool showDisassembly; + unsigned maximumOptimizationCandidateInstructionCount; unsigned maximumFunctionForCallInlineCandidateInstructionCount; @@ -89,9 +91,6 @@ double doubleVoteRatioForDoubleFormat; unsigned minimumNumberOfScansBetweenRebalance; unsigned gcMarkStackSegmentSize; -unsigned minimumNumberOfCellsToKeep; -unsigned maximumNumberOfSharedSegments; -unsigned sharedStackWakeupThreshold; unsigned numberOfGCMarkers; unsigned opaqueRootMergeThreshold; @@ -145,10 +144,28 @@ void setHeuristic(T& variable, const char* name, U value) #define SET(variable, value) variable = value #endif +static unsigned computeNumberOfGCMarkers(int maxNumberOfGCMarkers) +{ + int cpusToUse = 1; + +#if ENABLE(PARALLEL_GC) + cpusToUse = std::min(WTF::numberOfProcessorCores(), maxNumberOfGCMarkers); + + // Be paranoid, it is the OS we're dealing with, after all. + ASSERT(cpusToUse >= 1); + if (cpusToUse < 1) + cpusToUse = 1; +#endif + + return cpusToUse; +} + void initializeOptions() { SET(useJIT, true); + SET(showDisassembly, false); + SET(maximumOptimizationCandidateInstructionCount, 10000); SET(maximumFunctionForCallInlineCandidateInstructionCount, 180); @@ -188,25 +205,10 @@ void initializeOptions() SET(doubleVoteRatioForDoubleFormat, 2); - SET(minimumNumberOfScansBetweenRebalance, 10000); + SET(minimumNumberOfScansBetweenRebalance, 100); SET(gcMarkStackSegmentSize, pageSize()); - SET(minimumNumberOfCellsToKeep, 10); - SET(maximumNumberOfSharedSegments, 3); - SET(sharedStackWakeupThreshold, 1); SET(opaqueRootMergeThreshold, 1000); - - int cpusToUse = 1; -#if ENABLE(PARALLEL_GC) - cpusToUse = WTF::numberOfProcessorCores(); -#endif - // We don't scale so well beyond 4. - if (cpusToUse > 4) - cpusToUse = 4; - // Be paranoid, it is the OS we're dealing with, after all. - if (cpusToUse < 1) - cpusToUse = 1; - - SET(numberOfGCMarkers, cpusToUse); + SET(numberOfGCMarkers, computeNumberOfGCMarkers(7)); // We don't scale so well beyond 7. ASSERT(thresholdForOptimizeAfterLongWarmUp >= thresholdForOptimizeAfterWarmUp); ASSERT(thresholdForOptimizeAfterWarmUp >= thresholdForOptimizeSoon); diff --git a/Source/JavaScriptCore/runtime/Options.h b/Source/JavaScriptCore/runtime/Options.h index d1ad2ca87..e5cc99590 100644 --- a/Source/JavaScriptCore/runtime/Options.h +++ b/Source/JavaScriptCore/runtime/Options.h @@ -32,6 +32,8 @@ namespace JSC { namespace Options { extern bool useJIT; +extern bool showDisassembly; + extern unsigned maximumOptimizationCandidateInstructionCount; extern unsigned maximumFunctionForCallInlineCandidateInstructionCount; @@ -75,9 +77,6 @@ extern double doubleVoteRatioForDoubleFormat; extern unsigned minimumNumberOfScansBetweenRebalance; extern unsigned gcMarkStackSegmentSize; -extern unsigned minimumNumberOfCellsToKeep; -extern unsigned maximumNumberOfSharedSegments; -extern unsigned sharedStackWakeupThreshold; JS_EXPORTDATA extern unsigned numberOfGCMarkers; JS_EXPORTDATA extern unsigned opaqueRootMergeThreshold; diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp index dc4239799..569126147 100644 --- a/Source/JavaScriptCore/runtime/Structure.cpp +++ b/Source/JavaScriptCore/runtime/Structure.cpp @@ -155,6 +155,7 @@ Structure::Structure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSV , m_globalObject(globalData, this, globalObject, WriteBarrier<JSGlobalObject>::MayBeNull) , m_prototype(globalData, this, prototype) , m_classInfo(classInfo) + , m_transitionWatchpointSet(InitializedWatching) , m_propertyStorageCapacity(typeInfo.isFinalObject() ? JSFinalObject_inlineStorageCapacity : JSNonFinalObject_inlineStorageCapacity) , m_offset(noOffset) , m_dictionaryKind(NoneDictionaryKind) @@ -177,6 +178,7 @@ Structure::Structure(JSGlobalData& globalData) , m_typeInfo(CompoundType, OverridesVisitChildren) , m_prototype(globalData, this, jsNull()) , m_classInfo(&s_info) + , m_transitionWatchpointSet(InitializedWatching) , m_propertyStorageCapacity(0) , m_offset(noOffset) , m_dictionaryKind(NoneDictionaryKind) @@ -197,6 +199,7 @@ Structure::Structure(JSGlobalData& globalData, const Structure* previous) , m_typeInfo(previous->typeInfo()) , m_prototype(globalData, this, previous->storedPrototype()) , m_classInfo(previous->m_classInfo) + , m_transitionWatchpointSet(InitializedWatching) , m_propertyStorageCapacity(previous->m_propertyStorageCapacity) , m_offset(noOffset) , m_dictionaryKind(previous->m_dictionaryKind) @@ -210,6 +213,7 @@ Structure::Structure(JSGlobalData& globalData, const Structure* previous) , m_didTransition(true) , m_staticFunctionReified(previous->m_staticFunctionReified) { + previous->notifyTransitionFromThisStructure(); if (previous->m_globalObject) m_globalObject.set(globalData, this, previous->m_globalObject.get()); } diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h index f67c4e7f7..448a81c27 100644 --- a/Source/JavaScriptCore/runtime/Structure.h +++ b/Source/JavaScriptCore/runtime/Structure.h @@ -37,6 +37,7 @@ #include "StructureTransitionTable.h" #include "JSTypeInfo.h" #include "UString.h" +#include "Watchpoint.h" #include "Weak.h" #include <wtf/PassOwnPtr.h> #include <wtf/PassRefPtr.h> @@ -127,6 +128,8 @@ namespace JSC { JSValue storedPrototype() const { return m_prototype.get(); } JSValue prototypeForLookup(ExecState*) const; + JSValue prototypeForLookup(JSGlobalObject*) const; + JSValue prototypeForLookup(CodeBlock*) const; StructureChain* prototypeChain(ExecState*) const; static void visitChildren(JSCell*, SlotVisitor&); @@ -208,6 +211,27 @@ namespace JSC { return structure; } + bool transitionWatchpointSetHasBeenInvalidated() const + { + return m_transitionWatchpointSet.hasBeenInvalidated(); + } + + bool transitionWatchpointSetIsStillValid() const + { + return m_transitionWatchpointSet.isStillValid(); + } + + void addTransitionWatchpoint(Watchpoint* watchpoint) const + { + ASSERT(transitionWatchpointSetIsStillValid()); + m_transitionWatchpointSet.add(watchpoint); + } + + void notifyTransitionFromThisStructure() const + { + m_transitionWatchpointSet.notifyWrite(); + } + static JS_EXPORTDATA const ClassInfo s_info; private: @@ -291,9 +315,11 @@ namespace JSC { OwnPtr<PropertyTable> m_propertyTable; - uint32_t m_propertyStorageCapacity; - WriteBarrier<JSString> m_objectToStringValue; + + mutable InlineWatchpointSet m_transitionWatchpointSet; + + uint32_t m_propertyStorageCapacity; // m_offset does not account for anonymous slots int m_offset; @@ -363,6 +389,9 @@ namespace JSC { { ASSERT(structure->typeInfo().overridesVisitChildren() == this->structure()->typeInfo().overridesVisitChildren()); ASSERT(structure->classInfo() == m_structure->classInfo()); + ASSERT(!m_structure + || m_structure->transitionWatchpointSetHasBeenInvalidated() + || m_structure.get() == structure); m_structure.set(globalData, this, structure); } @@ -382,10 +411,13 @@ namespace JSC { #if ENABLE(GC_VALIDATION) validate(cell); #endif - m_visitCount++; if (Heap::testAndSetMarked(cell) || !cell->structure()) return; + + m_visitCount++; + MARK_LOG_CHILD(*this, cell); + // Should never attempt to mark something that is zapped. ASSERT(!cell->isZapped()); diff --git a/Source/JavaScriptCore/runtime/SymbolTable.cpp b/Source/JavaScriptCore/runtime/SymbolTable.cpp new file mode 100644 index 000000000..2a9d71629 --- /dev/null +++ b/Source/JavaScriptCore/runtime/SymbolTable.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "SymbolTable.h" + +namespace JSC { + +SymbolTableEntry& SymbolTableEntry::copySlow(const SymbolTableEntry& other) +{ + ASSERT(other.isFat()); + FatEntry* newFatEntry = new FatEntry(*other.fatEntry()); + freeFatEntry(); + m_bits = bitwise_cast<intptr_t>(newFatEntry) | FatFlag; + return *this; +} + +void SymbolTableEntry::freeFatEntrySlow() +{ + ASSERT(isFat()); + delete fatEntry(); +} + +bool SymbolTableEntry::couldBeWatched() +{ + if (!isFat()) + return false; + WatchpointSet* watchpoints = fatEntry()->m_watchpoints.get(); + if (!watchpoints) + return false; + return watchpoints->isStillValid(); +} + +void SymbolTableEntry::attemptToWatch() +{ + FatEntry* entry = inflate(); + if (!entry->m_watchpoints) + entry->m_watchpoints = adoptRef(new WatchpointSet(InitializedWatching)); +} + +bool* SymbolTableEntry::addressOfIsWatched() +{ + ASSERT(couldBeWatched()); + return fatEntry()->m_watchpoints->addressOfIsWatched(); +} + +void SymbolTableEntry::addWatchpoint(Watchpoint* watchpoint) +{ + ASSERT(couldBeWatched()); + fatEntry()->m_watchpoints->add(watchpoint); +} + +void SymbolTableEntry::notifyWriteSlow() +{ + WatchpointSet* watchpoints = fatEntry()->m_watchpoints.get(); + if (!watchpoints) + return; + watchpoints->notifyWrite(); +} + +SymbolTableEntry::FatEntry* SymbolTableEntry::inflateSlow() +{ + FatEntry* entry = new FatEntry(m_bits); + m_bits = bitwise_cast<intptr_t>(entry) | FatFlag; + return entry; +} + +} // namespace JSC + diff --git a/Source/JavaScriptCore/runtime/SymbolTable.h b/Source/JavaScriptCore/runtime/SymbolTable.h index f540a12c7..9ddc32c8c 100644 --- a/Source/JavaScriptCore/runtime/SymbolTable.h +++ b/Source/JavaScriptCore/runtime/SymbolTable.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 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 @@ -31,53 +31,163 @@ #include "JSObject.h" #include "UString.h" +#include "Watchpoint.h" #include <wtf/AlwaysInline.h> #include <wtf/HashTraits.h> namespace JSC { + class Watchpoint; + class WatchpointSet; + static ALWAYS_INLINE int missingSymbolMarker() { return std::numeric_limits<int>::max(); } // The bit twiddling in this class assumes that every register index is a // reasonably small positive or negative number, and therefore has its high // four bits all set or all unset. + // In addition to implementing semantics-mandated variable attributes and + // implementation-mandated variable indexing, this class also implements + // watchpoints to be used for JIT optimizations. Because watchpoints are + // meant to be relatively rare, this class optimizes heavily for the case + // that they are not being used. To that end, this class uses the thin-fat + // idiom: either it is thin, in which case it contains an in-place encoded + // word that consists of attributes, the index, and a bit saying that it is + // thin; or it is fat, in which case it contains a pointer to a malloc'd + // data structure and a bit saying that it is fat. The malloc'd data + // structure will be malloced a second time upon copy, to preserve the + // property that in-place edits to SymbolTableEntry do not manifest in any + // copies. However, the malloc'd FatEntry data structure contains a ref- + // counted pointer to a shared WatchpointSet. Thus, in-place edits of the + // WatchpointSet will manifest in all copies. Here's a picture: + // + // SymbolTableEntry --> FatEntry --> WatchpointSet + // + // If you make a copy of a SymbolTableEntry, you will have: + // + // original: SymbolTableEntry --> FatEntry --> WatchpointSet + // copy: SymbolTableEntry --> FatEntry -----^ + struct SymbolTableEntry { + // Use the SymbolTableEntry::Fast class, either via implicit cast or by calling + // getFast(), when you (1) only care about isNull(), getIndex(), and isReadOnly(), + // and (2) you are in a hot path where you need to minimize the number of times + // that you branch on isFat() when getting the bits(). + class Fast { + public: + Fast() + : m_bits(0) + { + } + + ALWAYS_INLINE Fast(const SymbolTableEntry& entry) + : m_bits(entry.bits()) + { + } + + bool isNull() const + { + return !m_bits; + } + + int getIndex() const + { + return static_cast<int>(m_bits >> FlagBits); + } + + bool isReadOnly() const + { + return m_bits & ReadOnlyFlag; + } + + unsigned getAttributes() const + { + unsigned attributes = 0; + if (m_bits & ReadOnlyFlag) + attributes |= ReadOnly; + if (m_bits & DontEnumFlag) + attributes |= DontEnum; + return attributes; + } + + bool isFat() const + { + return m_bits & FatFlag; + } + + private: + friend struct SymbolTableEntry; + intptr_t m_bits; + }; + SymbolTableEntry() : m_bits(0) { } SymbolTableEntry(int index) + : m_bits(0) { ASSERT(isValidIndex(index)); pack(index, false, false); } SymbolTableEntry(int index, unsigned attributes) + : m_bits(0) { ASSERT(isValidIndex(index)); pack(index, attributes & ReadOnly, attributes & DontEnum); } + ~SymbolTableEntry() + { + freeFatEntry(); + } + + SymbolTableEntry(const SymbolTableEntry& other) + : m_bits(0) + { + *this = other; + } + + SymbolTableEntry& operator=(const SymbolTableEntry& other) + { + if (UNLIKELY(other.isFat())) + return copySlow(other); + freeFatEntry(); + m_bits = other.m_bits; + return *this; + } + bool isNull() const { - return !m_bits; + return !bits(); } int getIndex() const { - return m_bits >> FlagBits; + return static_cast<int>(bits() >> FlagBits); } - + + ALWAYS_INLINE Fast getFast() const + { + return Fast(*this); + } + + ALWAYS_INLINE Fast getFast(bool& wasFat) const + { + Fast result; + wasFat = isFat(); + if (wasFat) + result.m_bits = fatEntry()->m_bits; + else + result.m_bits = m_bits; + return result; + } + unsigned getAttributes() const { - unsigned attributes = 0; - if (m_bits & ReadOnlyFlag) - attributes |= ReadOnly; - if (m_bits & DontEnumFlag) - attributes |= DontEnum; - return attributes; + return getFast().getAttributes(); } void setAttributes(unsigned attributes) @@ -87,30 +197,125 @@ namespace JSC { bool isReadOnly() const { - return m_bits & ReadOnlyFlag; + return bits() & ReadOnlyFlag; } - + + bool couldBeWatched(); + + // Notify an opportunity to create a watchpoint for a variable. This is + // idempotent and fail-silent. It is idempotent in the sense that if + // a watchpoint set had already been created, then another one will not + // be created. Hence two calls to this method have the same effect as + // one call. It is also fail-silent, in the sense that if a watchpoint + // set had been created and had already been invalidated, then this will + // just return. This means that couldBeWatched() may return false even + // immediately after a call to attemptToWatch(). + void attemptToWatch(); + + bool* addressOfIsWatched(); + + void addWatchpoint(Watchpoint*); + + WatchpointSet* watchpointSet() + { + return fatEntry()->m_watchpoints.get(); + } + + ALWAYS_INLINE void notifyWrite() + { + if (LIKELY(!isFat())) + return; + notifyWriteSlow(); + } + private: - static const unsigned ReadOnlyFlag = 0x1; - static const unsigned DontEnumFlag = 0x2; - static const unsigned NotNullFlag = 0x4; - static const unsigned FlagBits = 3; + static const intptr_t FatFlag = 0x1; + static const intptr_t ReadOnlyFlag = 0x2; + static const intptr_t DontEnumFlag = 0x4; + static const intptr_t NotNullFlag = 0x8; + static const intptr_t FlagBits = 4; + + class FatEntry { + WTF_MAKE_FAST_ALLOCATED; + public: + FatEntry(intptr_t bits) + : m_bits(bits | FatFlag) + { + } + + intptr_t m_bits; // always has FatFlag set and exactly matches what the bits would have been if this wasn't fat. + + RefPtr<WatchpointSet> m_watchpoints; + }; + + SymbolTableEntry& copySlow(const SymbolTableEntry&); + JS_EXPORT_PRIVATE void notifyWriteSlow(); + + bool isFat() const + { + return m_bits & FatFlag; + } + + const FatEntry* fatEntry() const + { + ASSERT(isFat()); + return bitwise_cast<const FatEntry*>(m_bits & ~FatFlag); + } + + FatEntry* fatEntry() + { + ASSERT(isFat()); + return bitwise_cast<FatEntry*>(m_bits & ~FatFlag); + } + + FatEntry* inflate() + { + if (LIKELY(isFat())) + return fatEntry(); + return inflateSlow(); + } + + FatEntry* inflateSlow(); + + ALWAYS_INLINE intptr_t bits() const + { + if (isFat()) + return fatEntry()->m_bits; + return m_bits; + } + + ALWAYS_INLINE intptr_t& bits() + { + if (isFat()) + return fatEntry()->m_bits; + return m_bits; + } + + void freeFatEntry() + { + if (LIKELY(!isFat())) + return; + freeFatEntrySlow(); + } + + void freeFatEntrySlow(); void pack(int index, bool readOnly, bool dontEnum) { - m_bits = (index << FlagBits) | NotNullFlag; + intptr_t& bitsRef = bits(); + bitsRef = (static_cast<intptr_t>(index) << FlagBits) | NotNullFlag; if (readOnly) - m_bits |= ReadOnlyFlag; + bitsRef |= ReadOnlyFlag; if (dontEnum) - m_bits |= DontEnumFlag; + bitsRef |= DontEnumFlag; } bool isValidIndex(int index) { - return ((index << FlagBits) >> FlagBits) == index; + return ((static_cast<intptr_t>(index) << FlagBits) >> FlagBits) == static_cast<intptr_t>(index); } - int m_bits; + intptr_t m_bits; }; struct SymbolTableIndexHashTraits : HashTraits<SymbolTableEntry> { diff --git a/Source/JavaScriptCore/runtime/WriteBarrier.h b/Source/JavaScriptCore/runtime/WriteBarrier.h index 05f3bc5bb..9784a921e 100644 --- a/Source/JavaScriptCore/runtime/WriteBarrier.h +++ b/Source/JavaScriptCore/runtime/WriteBarrier.h @@ -177,6 +177,9 @@ public: return u.slot; } + int32_t* tagPointer() { return &bitwise_cast<EncodedValueDescriptor*>(&m_value)->asBits.tag; } + int32_t* payloadPointer() { return &bitwise_cast<EncodedValueDescriptor*>(&m_value)->asBits.payload; } + typedef JSValue (WriteBarrierBase::*UnspecifiedBoolType); operator UnspecifiedBoolType*() const { return get() ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; } bool operator!() const { return !get(); } diff --git a/Source/JavaScriptCore/shell/CMakeLists.txt b/Source/JavaScriptCore/shell/CMakeLists.txt index 85ad89a88..561d779dd 100644 --- a/Source/JavaScriptCore/shell/CMakeLists.txt +++ b/Source/JavaScriptCore/shell/CMakeLists.txt @@ -19,10 +19,6 @@ IF (JSC_LINK_FLAGS) ADD_TARGET_PROPERTIES(${JSC_EXECUTABLE_NAME} LINK_FLAGS "${JSC_LINK_FLAGS}") ENDIF () -IF ("${PORT}" STREQUAL "Efl") - SET_TARGET_PROPERTIES(${JSC_EXECUTABLE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") -ENDIF () - IF (SHOULD_INSTALL_JS_SHELL) INSTALL(TARGETS ${JSC_EXECUTABLE_NAME} DESTINATION bin) ENDIF () diff --git a/Source/JavaScriptCore/yarr/YarrJIT.cpp b/Source/JavaScriptCore/yarr/YarrJIT.cpp index 60519ebd8..eb9861fed 100644 --- a/Source/JavaScriptCore/yarr/YarrJIT.cpp +++ b/Source/JavaScriptCore/yarr/YarrJIT.cpp @@ -2611,14 +2611,14 @@ public: if (compileMode == MatchOnly) { if (m_charSize == Char8) - jitObject.set8BitCodeMatchOnly(linkBuffer.finalizeCode()); + jitObject.set8BitCodeMatchOnly(FINALIZE_CODE(linkBuffer, ("Match-only 8-bit regular expression"))); else - jitObject.set16BitCodeMatchOnly(linkBuffer.finalizeCode()); + jitObject.set16BitCodeMatchOnly(FINALIZE_CODE(linkBuffer, ("Match-only 16-bit regular expression"))); } else { if (m_charSize == Char8) - jitObject.set8BitCode(linkBuffer.finalizeCode()); + jitObject.set8BitCode(FINALIZE_CODE(linkBuffer, ("8-bit regular expression"))); else - jitObject.set16BitCode(linkBuffer.finalizeCode()); + jitObject.set16BitCode(FINALIZE_CODE(linkBuffer, ("16-bit regular expression"))); } jitObject.setFallBack(m_shouldFallBack); } |