diff options
Diffstat (limited to 'Source/JavaScriptCore')
72 files changed, 1983 insertions, 484 deletions
diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt index 412be293f..4b030ca40 100644 --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt @@ -56,6 +56,7 @@ SET(JavaScriptCore_SOURCES bytecode/PutByIdStatus.cpp bytecode/ResolveGlobalStatus.cpp bytecode/SamplingTool.cpp + bytecode/StructureStubClearingWatchpoint.cpp bytecode/StructureStubInfo.cpp bytecode/Watchpoint.cpp @@ -143,6 +144,7 @@ SET(JavaScriptCore_SOURCES jit/JITPropertyAccess.cpp jit/JITStubRoutine.cpp jit/JITStubs.cpp + jit/JumpReplacementWatchpoint.cpp jit/ThunkGenerators.cpp parser/Lexer.cpp diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog index f0e93b012..2697bbb8f 100644 --- a/Source/JavaScriptCore/ChangeLog +++ b/Source/JavaScriptCore/ChangeLog @@ -1,20 +1,479 @@ -2012-06-13 Patrick Gansterer <paroga@webkit.org> +2012-07-13 Mark Lam <mark.lam@apple.com> - [WIN] Remove dependency on pthread from MachineStackMarker - https://bugs.webkit.org/show_bug.cgi?id=68429 + OfflineASM Pretty printing and commenting enhancements. + https://bugs.webkit.org/show_bug.cgi?id=91281 - Reviewed by NOBODY (OOPS!). + Reviewed by Filip Pizlo. - Implement pthread TLS functionality with native windows functions. + Added some minor pretty printing in the OfflineASM. + Also added infrastruture for adding multiple types of comments and + annotations with the ability to enable/disable them in the generated + output as desired. - * heap/MachineStackMarker.cpp: Use the new functions instead of pthread directly. - * heap/MachineStackMarker.h: - * wtf/ThreadSpecific.h: - (WTF::ThreadSpecificKeyCreate): Added wrapper around pthread_key_create. - (WTF::ThreadSpecificKeyDelete): Added wrapper around pthread_key_delete. - (WTF::ThreadSpecificSet): Added wrapper around pthread_setspecific. - (WTF::ThreadSpecificGet): Added wrapper around pthread_getspecific. - * wtf/ThreadSpecificWin.cpp: + * GNUmakefile.list.am: add new file config.rb. + * llint/LLIntOfflineAsmConfig.h: + Added OFFLINE_ASM_BEGIN, OFFLINE_ASM_END, and OFFLINE_ASM_LOCAL_LABEL macros. + This will allow us to redefine these for other backends later. + * llint/LowLevelInterpreter32_64.asm: + Add a small example of instruction annotations for now. + * llint/LowLevelInterpreter64.asm: + Add a small example of instruction annotations for now. + * offlineasm/armv7.rb: Added handling of annotations. + * offlineasm/asm.rb: + Added machinery to dump the new comments and annotations. + Also added some indentations to make the output a little prettier. + * offlineasm/ast.rb: Added annotation field in class Instruction. + * offlineasm/backends.rb: + * offlineasm/config.rb: Added. + Currently only contains commenting options. This file is meant to be + a centralized place for build config values much like config.h for + JavaScriptCore. + * offlineasm/generate_offset_extractor.rb: + * offlineasm/instructions.rb: + * offlineasm/offsets.rb: + * offlineasm/opt.rb: + * offlineasm/parser.rb: Parse and record annotations. + * offlineasm/registers.rb: + * offlineasm/self_hash.rb: + * offlineasm/settings.rb: + * offlineasm/transform.rb: + * offlineasm/x86.rb: Added handling of annotations. + +2012-07-13 Filip Pizlo <fpizlo@apple.com> + + ASSERTION FAILED: use.useKind() != DoubleUse + https://bugs.webkit.org/show_bug.cgi?id=91082 + + Reviewed by Geoffrey Garen. + + The implementation of Branch() was unwisely relying on register allocation state + to decide what speculations to perform. That's never correct. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + +2012-07-13 Sheriff Bot <webkit.review.bot@gmail.com> + + Unreviewed, rolling out r122640. + http://trac.webkit.org/changeset/122640 + https://bugs.webkit.org/show_bug.cgi?id=91298 + + LLInt apparently does not expect to mark these (Requested by + olliej on #webkit). + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::visitStructures): + (JSC::CodeBlock::stronglyVisitStrongReferences): + +2012-07-13 Oliver Hunt <oliver@apple.com> + + LLInt fails to mark structures stored in the bytecode + https://bugs.webkit.org/show_bug.cgi?id=91296 + + Reviewed by Geoffrey Garen. + + LLInt stores structures in the bytecode, so we need to visit the appropriate + instructions as we would if we were running in the classic interpreter. + This requires adding additional checks for the LLInt specific opcodes, and + the lint specific variants of operand ordering. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::visitStructures): + (JSC::CodeBlock::stronglyVisitStrongReferences): + +2012-07-13 Yong Li <yoli@rim.com> + + [BlackBerry] Implement GCActivityCallback with platform timer + https://bugs.webkit.org/show_bug.cgi?id=90175 + + Reviewed by Rob Buis. + + Implement GCActivityCallback and HeapTimer for BlackBerry port. + + * heap/HeapTimer.cpp: + (JSC): + (JSC::HeapTimer::HeapTimer): + (JSC::HeapTimer::~HeapTimer): + (JSC::HeapTimer::timerDidFire): + (JSC::HeapTimer::synchronize): + (JSC::HeapTimer::invalidate): + (JSC::HeapTimer::didStartVMShutdown): + * heap/HeapTimer.h: + (HeapTimer): + * runtime/GCActivityCallbackBlackBerry.cpp: + (JSC): + (JSC::DefaultGCActivityCallback::doWork): + (JSC::DefaultGCActivityCallback::didAllocate): + (JSC::DefaultGCActivityCallback::willCollect): + (JSC::DefaultGCActivityCallback::cancel): + +2012-07-13 Patrick Gansterer <paroga@webkit.org> + + [WIN] Fix compilation of DFGRepatch.cpp + https://bugs.webkit.org/show_bug.cgi?id=91241 + + Reviewed by Geoffrey Garen. + + Use intptr_t instead of uintptr_t when calling CodeLocationCommon::dataLabelPtrAtOffset(int) + to fix MSVC "unary minus operator applied to unsigned type, result still unsigned" warning. + + * dfg/DFGRepatch.cpp: + (JSC::DFG::dfgResetGetByID): + (JSC::DFG::dfgResetPutByID): + +2012-07-13 Patrick Gansterer <paroga@webkit.org> + + Fix ARM_TRADITIONAL JIT for COMPILER(MSVC) and COMPILER(RVCT) after r121885 + https://bugs.webkit.org/show_bug.cgi?id=91238 + + Reviewed by Zoltan Herczeg. + + r121885 changed the assembler instruction only for COMPILER(GCC). + Use the same instructions for the other compilers too. + + * jit/JITStubs.cpp: + (JSC::ctiTrampoline): + (JSC::ctiTrampolineEnd): + (JSC::ctiVMThrowTrampoline): + +2012-07-12 Filip Pizlo <fpizlo@apple.com> + + DFG property access stubs should use structure transition watchpoints + https://bugs.webkit.org/show_bug.cgi?id=91135 + + Reviewed by Geoffrey Garen. + + This adds a Watchpoint subclass that will clear a structure stub (i.e. + a property access stub) when fired. The DFG stub generation code now + uses this optimization. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * Target.pri: + * bytecode/CodeBlock.cpp: + (JSC): + (JSC::CodeBlock::finalizeUnconditionally): + (JSC::CodeBlock::resetStub): + (JSC::CodeBlock::resetStubInternal): + * bytecode/CodeBlock.h: + (JSC): + (CodeBlock): + * bytecode/StructureStubClearingWatchpoint.cpp: Added. + (JSC): + (JSC::StructureStubClearingWatchpoint::~StructureStubClearingWatchpoint): + (JSC::StructureStubClearingWatchpoint::push): + (JSC::StructureStubClearingWatchpoint::fireInternal): + (JSC::WatchpointsOnStructureStubInfo::~WatchpointsOnStructureStubInfo): + (JSC::WatchpointsOnStructureStubInfo::addWatchpoint): + (JSC::WatchpointsOnStructureStubInfo::ensureReferenceAndAddWatchpoint): + * bytecode/StructureStubClearingWatchpoint.h: Added. + (JSC): + (StructureStubClearingWatchpoint): + (JSC::StructureStubClearingWatchpoint::StructureStubClearingWatchpoint): + (WatchpointsOnStructureStubInfo): + (JSC::WatchpointsOnStructureStubInfo::WatchpointsOnStructureStubInfo): + (JSC::WatchpointsOnStructureStubInfo::codeBlock): + (JSC::WatchpointsOnStructureStubInfo::stubInfo): + * bytecode/StructureStubInfo.h: + (JSC::StructureStubInfo::reset): + (JSC::StructureStubInfo::addWatchpoint): + (StructureStubInfo): + * dfg/DFGRepatch.cpp: + (JSC::DFG::addStructureTransitionCheck): + (DFG): + (JSC::DFG::generateProtoChainAccessStub): + (JSC::DFG::emitPutTransitionStub): + * jit/JumpReplacementWatchpoint.h: + +2012-07-12 Filip Pizlo <fpizlo@apple.com> + + DFG CFA may get overzealous in loops that have code that must exit + https://bugs.webkit.org/show_bug.cgi?id=91188 + + Reviewed by Gavin Barraclough. + + Ensure that if the CFA assumes that an operation must exit, then it will always exit + no matter what happens after. That's necessary to preserve soundness. + + Remove a broken fixup done by the DFG simplifier, where it was trying to say that the + variable-at-head was the first access in the second block in the merge, if the first + block did not read the variable. That's totally wrong, if the first block was in fact + doing a phantom read. I removed that fixup and instead hardened the rest of the + compiler. + + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::endBasicBlock): + * dfg/DFGBasicBlock.h: + (JSC::DFG::BasicBlock::BasicBlock): + (BasicBlock): + * dfg/DFGCFAPhase.cpp: + (JSC::DFG::CFAPhase::performBlockCFA): + * dfg/DFGCFGSimplificationPhase.cpp: + (JSC::DFG::CFGSimplificationPhase::mergeBlocks): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::ConstantFoldingPhase): + (JSC::DFG::ConstantFoldingPhase::run): + (ConstantFoldingPhase): + (JSC::DFG::ConstantFoldingPhase::foldConstants): + (JSC::DFG::ConstantFoldingPhase::paintUnreachableCode): + * dfg/DFGVariableEventStream.cpp: + (JSC::DFG::VariableEventStream::reconstruct): + +2012-07-12 Allan Sandfeld Jensen <allan.jensen@nokia.com> + + [Qt] Implement MemoryUsageSupport + https://bugs.webkit.org/show_bug.cgi?id=91094 + + Reviewed by Adam Barth. + + Compile in MemoryStatistics so we can make use of the interface. + + * Target.pri: + +2012-07-12 Csaba Osztrogonác <ossy@webkit.org> + + Remove dead code after r122392. + https://bugs.webkit.org/show_bug.cgi?id=91049 + + Reviewed by Filip Pizlo. + + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + +2012-07-11 Adenilson Cavalcanti <cavalcantii@gmail.com> + + Build fix + remove dead code + https://bugs.webkit.org/show_bug.cgi?id=91039 + + Reviewed by Filip Pizlo. + + An unused variable was breaking compilation (thanks to warnings being treated as errors). + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + +2012-07-11 Mark Rowe <mrowe@apple.com> + + <http://webkit.org/b/91024> Build against the latest SDK when targeting older OS X versions. + + Reviewed by Dan Bernstein. + + The deployment target is already set to the version that we're targeting, and it's that setting + which determines which functionality from the SDK is available to us. + + * Configurations/Base.xcconfig: + +2012-07-11 Filip Pizlo <fpizlo@apple.com> + + DFG should have fast virtual calls + https://bugs.webkit.org/show_bug.cgi?id=90924 + + Reviewed by Gavin Barraclough. + + Implements virtual call support in the style of the old JIT, with the + caveat that we still use the same slow path for both InternalFunction + calls and JSFunction calls. Also rationalized the way that our + CodeOrigin indices tie into exception checks (previously it was a + strange one-to-one mapping with fairly limited assertions; now it's a + one-to-many mapping for CodeOrigins to exception checks, respectively). + I also took the opportunity to clean up + CallLinkInfo::callReturnLocation, which previously was either a Call or + a NearCall. Now it's just a NearCall. As well, exceptions during slow + path call resolution are now handled by returning an exception throwing + thunk rather than returning null. And finally, I made a few things + public that were previously private-with-lots-of-friends, because I + truly despise the thought of listing each thunk generating function as + a friend of JSValue and friends. + + * bytecode/CallLinkInfo.cpp: + (JSC::CallLinkInfo::unlink): + * bytecode/CallLinkInfo.h: + (CallLinkInfo): + * bytecode/CodeOrigin.h: + (JSC::CodeOrigin::CodeOrigin): + (JSC::CodeOrigin::isSet): + * dfg/DFGAssemblyHelpers.h: + (JSC::DFG::AssemblyHelpers::AssemblyHelpers): + * dfg/DFGCCallHelpers.h: + (JSC::DFG::CCallHelpers::CCallHelpers): + * dfg/DFGGPRInfo.h: + (GPRInfo): + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::link): + (JSC::DFG::JITCompiler::compileFunction): + * dfg/DFGJITCompiler.h: + (JSC::DFG::CallBeginToken::CallBeginToken): + (JSC::DFG::CallBeginToken::~CallBeginToken): + (CallBeginToken): + (JSC::DFG::CallBeginToken::set): + (JSC::DFG::CallBeginToken::registerWithExceptionCheck): + (JSC::DFG::CallBeginToken::codeOrigin): + (JSC::DFG::CallExceptionRecord::CallExceptionRecord): + (CallExceptionRecord): + (JSC::DFG::JITCompiler::currentCodeOriginIndex): + (JITCompiler): + (JSC::DFG::JITCompiler::beginCall): + (JSC::DFG::JITCompiler::notifyCall): + (JSC::DFG::JITCompiler::prepareForExceptionCheck): + (JSC::DFG::JITCompiler::addExceptionCheck): + (JSC::DFG::JITCompiler::addFastExceptionCheck): + * dfg/DFGOperations.cpp: + * dfg/DFGRepatch.cpp: + (JSC::DFG::dfgLinkFor): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::appendCallWithExceptionCheck): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + * dfg/DFGThunks.cpp: + (JSC::DFG::emitPointerValidation): + (DFG): + (JSC::DFG::throwExceptionFromCallSlowPathGenerator): + (JSC::DFG::slowPathFor): + (JSC::DFG::linkForThunkGenerator): + (JSC::DFG::linkCallThunkGenerator): + (JSC::DFG::linkConstructThunkGenerator): + (JSC::DFG::virtualForThunkGenerator): + (JSC::DFG::virtualCallThunkGenerator): + (JSC::DFG::virtualConstructThunkGenerator): + * dfg/DFGThunks.h: + (DFG): + * jit/JIT.cpp: + (JSC::JIT::privateCompile): + (JSC::JIT::linkFor): + * runtime/Executable.h: + (ExecutableBase): + (JSC::ExecutableBase::offsetOfJITCodeFor): + (JSC::ExecutableBase::offsetOfNumParametersFor): + * runtime/JSValue.h: + (JSValue): + +2012-07-11 Filip Pizlo <fpizlo@apple.com> + + Accidentally used the wrong license (3-clause instead of 2-clause) in some + files I just committed. + + Rubber stamped by Oliver Hunt. + + * bytecode/Watchpoint.cpp: + * bytecode/Watchpoint.h: + * jit/JumpReplacementWatchpoint.cpp: + * jit/JumpReplacementWatchpoint.h: + +2012-07-11 Filip Pizlo <fpizlo@apple.com> + + Watchpoints and jump replacement should be decoupled + https://bugs.webkit.org/show_bug.cgi?id=91016 + + Reviewed by Oliver Hunt. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * Target.pri: + * assembler/AbstractMacroAssembler.h: + (JSC): + (Label): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::appendWatchpoint): + (JSC::CodeBlock::watchpoint): + (DFGData): + * bytecode/Watchpoint.cpp: + (JSC): + * bytecode/Watchpoint.h: + (JSC::Watchpoint::Watchpoint): + (Watchpoint): + (JSC::Watchpoint::fire): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::speculationWatchpoint): + * jit/JumpReplacementWatchpoint.cpp: Added. + (JSC): + (JSC::JumpReplacementWatchpoint::correctLabels): + (JSC::JumpReplacementWatchpoint::fireInternal): + * jit/JumpReplacementWatchpoint.h: Added. + (JSC): + (JumpReplacementWatchpoint): + (JSC::JumpReplacementWatchpoint::JumpReplacementWatchpoint): + (JSC::JumpReplacementWatchpoint::setDestination): + +2012-07-11 Kevin Ollivier <kevino@theolliviers.com> + + [wx] Unreviewed build fix. Don't try to build udis86_itab.c since it's included by + another file. + + * wscript: + +2012-07-11 Chao-ying Fu <fu@mips.com> + + Add MIPS convertibleLoadPtr and other functions + https://bugs.webkit.org/show_bug.cgi?id=90714 + + Reviewed by Oliver Hunt. + + * assembler/MIPSAssembler.h: + (JSC::MIPSAssembler::labelIgnoringWatchpoints): + (MIPSAssembler): + (JSC::MIPSAssembler::replaceWithLoad): + (JSC::MIPSAssembler::replaceWithAddressComputation): + * assembler/MacroAssemblerMIPS.h: + (JSC::MacroAssemblerMIPS::convertibleLoadPtr): + (MacroAssemblerMIPS): + +2012-07-11 Anders Carlsson <andersca@apple.com> + + Add -Wtautological-compare and -Wsign-compare warning flags + https://bugs.webkit.org/show_bug.cgi?id=90994 + + Reviewed by Mark Rowe. + + * Configurations/Base.xcconfig: + +2012-07-11 Benjamin Poulain <bpoulain@apple.com> + + Simplify the copying of JSC ARMv7's LinkRecord + https://bugs.webkit.org/show_bug.cgi?id=90930 + + Reviewed by Filip Pizlo. + + The class LinkRecord is used by value everywhere in ARMv7Assembler. The compiler uses + memmove() to move the objects. + + The problem is memmove() is overkill for this object, moving the value can be done with + 3 load-store. This patch adds an operator= to the class doing more efficient copying. + This reduces the link time by 19%. + + * assembler/ARMv7Assembler.h: + (JSC::ARMv7Assembler::LinkRecord::LinkRecord): + (JSC::ARMv7Assembler::LinkRecord::operator=): + (JSC::ARMv7Assembler::LinkRecord::from): + (JSC::ARMv7Assembler::LinkRecord::setFrom): + (JSC::ARMv7Assembler::LinkRecord::to): + (JSC::ARMv7Assembler::LinkRecord::type): + (JSC::ARMv7Assembler::LinkRecord::linkType): + (JSC::ARMv7Assembler::LinkRecord::setLinkType): + (JSC::ARMv7Assembler::LinkRecord::condition): + +2012-07-11 Andy Wingo <wingo@igalia.com> + + jsc: Parse options before creating global data + https://bugs.webkit.org/show_bug.cgi?id=90975 + + Reviewed by Filip Pizlo. + + This patch moves the options parsing in "jsc" before the creation + of the JSGlobalData, so that --useJIT=no has a chance to take + effect. + + * jsc.cpp: + (CommandLine::parseArguments): Refactor to be a class, and take + argc and argv as constructor arguments. + (jscmain): Move arg parsing before JSGlobalData creation. 2012-07-10 Filip Pizlo <fpizlo@apple.com> diff --git a/Source/JavaScriptCore/Configurations/Base.xcconfig b/Source/JavaScriptCore/Configurations/Base.xcconfig index 96e9a356f..47c8f7382 100644 --- a/Source/JavaScriptCore/Configurations/Base.xcconfig +++ b/Source/JavaScriptCore/Configurations/Base.xcconfig @@ -24,7 +24,7 @@ #include "CompilerVersion.xcconfig" COMPILER_SPECIFIC_WARNING_CFLAGS = $(COMPILER_SPECIFIC_WARNING_CFLAGS_$(TARGET_GCC_VERSION)); -COMPILER_SPECIFIC_WARNING_CFLAGS_LLVM_COMPILER = -Wglobal-constructors -Wexit-time-destructors; +COMPILER_SPECIFIC_WARNING_CFLAGS_LLVM_COMPILER = -Wexit-time-destructors -Wglobal-constructors -Wtautological-compare; CLANG_WARN_CXX0X_EXTENSIONS = NO; DEBUG_INFORMATION_FORMAT = dwarf-with-dsym; @@ -54,6 +54,7 @@ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; +GCC_WARN_SIGN_COMPARE = YES; LINKER_DISPLAYS_MANGLED_NAMES = YES; PREBINDING = NO; VALID_ARCHS = $(VALID_ARCHS_$(REAL_PLATFORM_NAME)); @@ -126,18 +127,15 @@ DEAD_CODE_STRIPPING = $(DEAD_CODE_STRIPPING_$(CURRENT_VARIANT)); SECTORDER_FLAGS = -Wl,-order_file,JavaScriptCore.order; -// If the target Mac OS X version does not match the current Mac OS X version then we'll want to build using the target version's SDK. -SDKROOT = $(SDKROOT_$(MAC_OS_X_VERSION_MAJOR)_$(TARGET_MAC_OS_X_VERSION_MAJOR)); -SDKROOT_1060_1050 = macosx10.5; -SDKROOT_1070_1050 = macosx10.5; -SDKROOT_1080_1050 = macosx10.5; -SDKROOT_1090_1050 = macosx10.5; -SDKROOT_1070_1060 = macosx10.6; -SDKROOT_1080_1060 = macosx10.6; -SDKROOT_1090_1060 = macosx10.6; -SDKROOT_1080_1070 = macosx10.7; -SDKROOT_1090_1070 = macosx10.7; -SDKROOT_1090_1080 = macosx10.8; +TARGETING_SAME_OS_X_VERSION = $(TARGETING_SAME_OS_X_VERSION_$(MAC_OS_X_VERSION_MAJOR)_$(TARGET_MAC_OS_X_VERSION_MAJOR)); +TARGETING_SAME_OS_X_VERSION_1060_1060 = YES; +TARGETING_SAME_OS_X_VERSION_1070_1070 = YES; +TARGETING_SAME_OS_X_VERSION_1080_1080 = YES; +TARGETING_SAME_OS_X_VERSION_1090_1090 = YES; + +// Don't build against an SDK unless we're targeting an older OS version. +SDKROOT = $(SDKROOT_TARGETING_SAME_OS_X_VERSION_$(TARGETING_SAME_OS_X_VERSION)); +SDKROOT_TARGETING_SAME_OS_X_VERSION_ = macosx; // HAVE_DTRACE is disabled on Leopard due to <rdar://problem/5628149> diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am index 7e6056e97..751d5657a 100644 --- a/Source/JavaScriptCore/GNUmakefile.list.am +++ b/Source/JavaScriptCore/GNUmakefile.list.am @@ -134,6 +134,8 @@ javascriptcore_sources += \ Source/JavaScriptCore/bytecode/StructureSet.h \ Source/JavaScriptCore/bytecode/StructureStubInfo.cpp \ Source/JavaScriptCore/bytecode/StructureStubInfo.h \ + Source/JavaScriptCore/bytecode/StructureStubClearingWatchpoint.cpp \ + Source/JavaScriptCore/bytecode/StructureStubClearingWatchpoint.h \ Source/JavaScriptCore/bytecode/ValueProfile.h \ Source/JavaScriptCore/bytecode/ValueRecovery.h \ Source/JavaScriptCore/bytecode/VirtualRegister.h \ @@ -383,6 +385,8 @@ javascriptcore_sources += \ Source/JavaScriptCore/jit/JITStubs.h \ Source/JavaScriptCore/jit/JITWriteBarrier.h \ Source/JavaScriptCore/jit/JSInterfaceJIT.h \ + Source/JavaScriptCore/jit/JumpReplacementWatchpoint.cpp \ + Source/JavaScriptCore/jit/JumpReplacementWatchpoint.h \ Source/JavaScriptCore/jit/SpecializedThunkJIT.h \ Source/JavaScriptCore/jit/ThunkGenerators.cpp \ Source/JavaScriptCore/jit/ThunkGenerators.h \ @@ -680,6 +684,7 @@ offlineasm_nosources += \ Source/JavaScriptCore/offlineasm/asm.rb \ Source/JavaScriptCore/offlineasm/ast.rb \ Source/JavaScriptCore/offlineasm/backends.rb \ + Source/JavaScriptCore/offlineasm/config.rb \ Source/JavaScriptCore/offlineasm/generate_offset_extractor.rb \ Source/JavaScriptCore/offlineasm/instructions.rb \ Source/JavaScriptCore/offlineasm/offsets.rb \ diff --git a/Source/JavaScriptCore/JavaScriptCore.pri b/Source/JavaScriptCore/JavaScriptCore.pri index f6580c51f..380bbaf1b 100644 --- a/Source/JavaScriptCore/JavaScriptCore.pri +++ b/Source/JavaScriptCore/JavaScriptCore.pri @@ -34,6 +34,12 @@ INCLUDEPATH += \ win32-* { LIBS += -lwinmm + + win32-g++* { + LIBS += -lpthreadGC2 + } else:win32-msvc* { + LIBS += -lpthreadVC2 + } } wince* { diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def index c50013ac1..dfa38aafb 100755 --- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def +++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def @@ -72,6 +72,9 @@ EXPORTS ?append@StringBuilder@WTF@@QAEXPB_WI@Z ?ascii@UString@JSC@@QBE?AVCString@WTF@@XZ ?attach@Debugger@JSC@@QAEXPAVJSGlobalObject@2@@Z + ?base64Decode@WTF@@YA_NABVString@1@AAV?$Vector@D$0A@@1@W4Base64DecodePolicy@1@@Z + ?base64Encode@WTF@@YA?AVString@1@PBDIW4Base64EncodePolicy@1@@Z + ?base64Encode@WTF@@YAXPBDIAAV?$Vector@D$0A@@1@W4Base64EncodePolicy@1@@Z ?broadcast@ThreadCondition@WTF@@QAEXXZ ?bufferLengthForStringDecimal@DecimalNumber@WTF@@QBEIXZ ?bufferLengthForStringExponential@DecimalNumber@WTF@@QBEIXZ diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj index 92749eb75..2efa84059 100644 --- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj +++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj @@ -1682,6 +1682,14 @@ > </File> <File + RelativePath="..\..\bytecode\StructureStubClearingWatchpoint.cpp" + > + </File> + <File + RelativePath="..\..\bytecode\StructureStubClearingWatchpoint.h" + > + </File> + <File RelativePath="..\..\bytecode\StructureStubInfo.cpp" > </File> @@ -1942,6 +1950,14 @@ > </File> <File + RelativePath="..\..\jit\JumpReplacementWatchpoint.cpp" + > + </File> + <File + RelativePath="..\..\jit\JumpReplacementWatchpoint.h" + > + </File> + <File RelativePath="..\..\jit\JSInterfaceJIT.h" > </File> diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj index 188c1ffe7..f9548f184 100644 --- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj +++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj @@ -146,6 +146,10 @@ 0F766D2F15A8DCE0008F363E /* GCAwareJITStubRoutine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F766D2D15A8DCDD008F363E /* GCAwareJITStubRoutine.cpp */; }; 0F766D3015A8DCE2008F363E /* GCAwareJITStubRoutine.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F766D2E15A8DCDD008F363E /* GCAwareJITStubRoutine.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F766D3115AA8112008F363E /* JITStubRoutine.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F766D1C15A5028D008F363E /* JITStubRoutine.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F766D3415AE2538008F363E /* JumpReplacementWatchpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F766D3215AE2535008F363E /* JumpReplacementWatchpoint.cpp */; }; + 0F766D3515AE253B008F363E /* JumpReplacementWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F766D3315AE2535008F363E /* JumpReplacementWatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F766D3815AE4A1C008F363E /* StructureStubClearingWatchpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F766D3615AE4A1A008F363E /* StructureStubClearingWatchpoint.cpp */; }; + 0F766D3915AE4A1F008F363E /* StructureStubClearingWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F766D3715AE4A1A008F363E /* StructureStubClearingWatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F7700921402FF3C0078EB39 /* SamplingCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F7700911402FF280078EB39 /* SamplingCounter.cpp */; }; 0F7B294A14C3CD29007C3DB1 /* DFGCCallHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F7B294814C3CD23007C3DB1 /* DFGCCallHelpers.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F7B294B14C3CD2F007C3DB1 /* DFGCapabilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82E1F14172C2F00179C94 /* DFGCapabilities.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -887,6 +891,10 @@ 0F766D2A15A8CC34008F363E /* JITStubRoutineSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITStubRoutineSet.h; sourceTree = "<group>"; }; 0F766D2D15A8DCDD008F363E /* GCAwareJITStubRoutine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GCAwareJITStubRoutine.cpp; sourceTree = "<group>"; }; 0F766D2E15A8DCDD008F363E /* GCAwareJITStubRoutine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCAwareJITStubRoutine.h; sourceTree = "<group>"; }; + 0F766D3215AE2535008F363E /* JumpReplacementWatchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JumpReplacementWatchpoint.cpp; sourceTree = "<group>"; }; + 0F766D3315AE2535008F363E /* JumpReplacementWatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JumpReplacementWatchpoint.h; sourceTree = "<group>"; }; + 0F766D3615AE4A1A008F363E /* StructureStubClearingWatchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StructureStubClearingWatchpoint.cpp; sourceTree = "<group>"; }; + 0F766D3715AE4A1A008F363E /* StructureStubClearingWatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructureStubClearingWatchpoint.h; sourceTree = "<group>"; }; 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>"; }; @@ -1731,6 +1739,8 @@ 14A6581A0F4E36F4000150FD /* JITStubs.h */, A76F54A213B28AAB00EF2BCE /* JITWriteBarrier.h */, A76C51741182748D00715B05 /* JSInterfaceJIT.h */, + 0F766D3215AE2535008F363E /* JumpReplacementWatchpoint.cpp */, + 0F766D3315AE2535008F363E /* JumpReplacementWatchpoint.h */, A7386551118697B400540279 /* SpecializedThunkJIT.h */, A7386552118697B400540279 /* ThunkGenerators.cpp */, A7386553118697B400540279 /* ThunkGenerators.h */, @@ -2433,6 +2443,8 @@ 0FD82E4F141DAEA100179C94 /* SpeculatedType.h */, 1429D8830ED21C3D00B89619 /* SamplingTool.cpp */, 1429D8840ED21C3D00B89619 /* SamplingTool.h */, + 0F766D3615AE4A1A008F363E /* StructureStubClearingWatchpoint.cpp */, + 0F766D3715AE4A1A008F363E /* StructureStubClearingWatchpoint.h */, BCCF0D0B0EF0B8A500413C8F /* StructureStubInfo.cpp */, BCCF0D070EF0AAB900413C8F /* StructureStubInfo.h */, 0F963B3613FC6FDE0002D9B2 /* ValueProfile.h */, @@ -2836,6 +2848,8 @@ 0F766D2C15A8CC3A008F363E /* JITStubRoutineSet.h in Headers */, 0F766D3015A8DCE2008F363E /* GCAwareJITStubRoutine.h in Headers */, 0F766D3115AA8112008F363E /* JITStubRoutine.h in Headers */, + 0F766D3515AE253B008F363E /* JumpReplacementWatchpoint.h in Headers */, + 0F766D3915AE4A1F008F363E /* StructureStubClearingWatchpoint.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3431,6 +3445,8 @@ 0F766D2815A8CC1E008F363E /* JITStubRoutine.cpp in Sources */, 0F766D2B15A8CC38008F363E /* JITStubRoutineSet.cpp in Sources */, 0F766D2F15A8DCE0008F363E /* GCAwareJITStubRoutine.cpp in Sources */, + 0F766D3415AE2538008F363E /* JumpReplacementWatchpoint.cpp in Sources */, + 0F766D3815AE4A1C008F363E /* StructureStubClearingWatchpoint.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Source/JavaScriptCore/Target.pri b/Source/JavaScriptCore/Target.pri index b019e417e..035656f0c 100644 --- a/Source/JavaScriptCore/Target.pri +++ b/Source/JavaScriptCore/Target.pri @@ -67,6 +67,7 @@ SOURCES += \ bytecode/ResolveGlobalStatus.cpp \ bytecode/SamplingTool.cpp \ bytecode/SpeculatedType.cpp \ + bytecode/StructureStubClearingWatchpoint.cpp \ bytecode/StructureStubInfo.cpp \ bytecode/Watchpoint.cpp \ bytecompiler/BytecodeGenerator.cpp \ @@ -151,6 +152,7 @@ SOURCES += \ jit/JITPropertyAccess32_64.cpp \ jit/JITStubRoutine.cpp \ jit/JITStubs.cpp \ + jit/JumpReplacementWatchpoint.cpp \ jit/ThunkGenerators.cpp \ parser/Lexer.cpp \ parser/Nodes.cpp \ @@ -217,6 +219,7 @@ SOURCES += \ runtime/LiteralParser.cpp \ runtime/Lookup.cpp \ runtime/MathObject.cpp \ + runtime/MemoryStatistics.cpp \ runtime/NameConstructor.cpp \ runtime/NameInstance.cpp \ runtime/NamePrototype.cpp \ diff --git a/Source/JavaScriptCore/assembler/ARMv7Assembler.h b/Source/JavaScriptCore/assembler/ARMv7Assembler.h index eef0ba8a7..96c4f096c 100644 --- a/Source/JavaScriptCore/assembler/ARMv7Assembler.h +++ b/Source/JavaScriptCore/assembler/ARMv7Assembler.h @@ -462,28 +462,42 @@ public: class LinkRecord { public: LinkRecord(intptr_t from, intptr_t to, JumpType type, Condition condition) - : m_from(from) - , m_to(to) - , m_type(type) - , m_linkType(LinkInvalid) - , m_condition(condition) { + data.realTypes.m_from = from; + data.realTypes.m_to = to; + data.realTypes.m_type = type; + data.realTypes.m_linkType = LinkInvalid; + data.realTypes.m_condition = condition; } - intptr_t from() const { return m_from; } - void setFrom(intptr_t from) { m_from = from; } - intptr_t to() const { return m_to; } - JumpType type() const { return m_type; } - JumpLinkType linkType() const { return m_linkType; } - void setLinkType(JumpLinkType linkType) { ASSERT(m_linkType == LinkInvalid); m_linkType = linkType; } - Condition condition() const { return m_condition; } + void operator=(const LinkRecord& other) + { + data.copyTypes.content[0] = other.data.copyTypes.content[0]; + data.copyTypes.content[1] = other.data.copyTypes.content[1]; + data.copyTypes.content[2] = other.data.copyTypes.content[2]; + } + intptr_t from() const { return data.realTypes.m_from; } + void setFrom(intptr_t from) { data.realTypes.m_from = from; } + intptr_t to() const { return data.realTypes.m_to; } + JumpType type() const { return data.realTypes.m_type; } + JumpLinkType linkType() const { return data.realTypes.m_linkType; } + void setLinkType(JumpLinkType linkType) { ASSERT(data.realTypes.m_linkType == LinkInvalid); data.realTypes.m_linkType = linkType; } + Condition condition() const { return data.realTypes.m_condition; } private: - intptr_t m_from : 31; - intptr_t m_to : 31; - JumpType m_type : 8; - JumpLinkType m_linkType : 8; - Condition m_condition : 16; + union { + struct RealTypes { + intptr_t m_from : 31; + intptr_t m_to : 31; + JumpType m_type : 8; + JumpLinkType m_linkType : 8; + Condition m_condition : 16; + } realTypes; + struct CopyTypes { + uint32_t content[3]; + } copyTypes; + COMPILE_ASSERT(sizeof(RealTypes) == sizeof(CopyTypes), LinkRecordCopyStructSizeEqualsRealStruct); + } data; }; - + ARMv7Assembler() : m_indexOfLastWatchpoint(INT_MIN) , m_indexOfTailOfLastWatchpoint(INT_MIN) diff --git a/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h b/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h index a24f7573a..ef1808ffb 100644 --- a/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h +++ b/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h @@ -46,6 +46,7 @@ namespace JSC { +class JumpReplacementWatchpoint; class LinkBuffer; class RepatchBuffer; class Watchpoint; @@ -277,6 +278,7 @@ public: friend class AbstractMacroAssembler; friend class DFG::CorrectableJumpPoint; friend class Jump; + friend class JumpReplacementWatchpoint; friend class MacroAssemblerCodeRef; friend class LinkBuffer; friend class Watchpoint; diff --git a/Source/JavaScriptCore/assembler/MIPSAssembler.h b/Source/JavaScriptCore/assembler/MIPSAssembler.h index 7212a182c..65307d950 100644 --- a/Source/JavaScriptCore/assembler/MIPSAssembler.h +++ b/Source/JavaScriptCore/assembler/MIPSAssembler.h @@ -616,6 +616,11 @@ public: // General helpers + AssemblerLabel labelIgnoringWatchpoints() + { + return m_buffer.label(); + } + AssemblerLabel label() { return m_buffer.label(); @@ -809,6 +814,28 @@ public: #endif } + static void replaceWithLoad(void* instructionStart) + { + MIPSWord* insn = reinterpret_cast<MIPSWord*>(instructionStart); + ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui + insn++; + ASSERT((*insn & 0xfc0007ff) == 0x00000021); // addu + insn++; + *insn = 0x8c000000 | ((*insn) & 0x3ffffff); // lw + cacheFlush(insn, 4); + } + + static void replaceWithAddressComputation(void* instructionStart) + { + MIPSWord* insn = reinterpret_cast<MIPSWord*>(instructionStart); + ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui + insn++; + ASSERT((*insn & 0xfc0007ff) == 0x00000021); // addu + insn++; + *insn = 0x24000000 | ((*insn) & 0x3ffffff); // addiu + cacheFlush(insn, 4); + } + private: /* Update each jump in the buffer of newBase. */ void relocateJumps(void* oldBase, void* newBase) diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h b/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h index 5adcf9b4e..bc280acec 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h @@ -496,6 +496,20 @@ public: ASSERT_NOT_REACHED(); } + ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest) + { + ConvertibleLoadLabel result(this); + /* + lui addrTemp, (offset + 0x8000) >> 16 + addu addrTemp, addrTemp, base + lw dest, (offset & 0xffff)(addrTemp) + */ + m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); + m_assembler.addu(addrTempRegister, addrTempRegister, address.base); + m_assembler.lw(dest, addrTempRegister, address.offset); + return result; + } + // Memory access operations: // // Loads are of the form load(address, destination) and stores of the form diff --git a/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp b/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp index 4c108ecf1..4933a494c 100644 --- a/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp +++ b/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp @@ -27,6 +27,7 @@ #include "CallLinkInfo.h" #include "DFGOperations.h" +#include "DFGThunks.h" #include "RepatchBuffer.h" #if ENABLE(JIT) @@ -38,12 +39,12 @@ void CallLinkInfo::unlink(JSGlobalData& globalData, RepatchBuffer& repatchBuffer if (isDFG) { #if ENABLE(DFG_JIT) - repatchBuffer.relink(CodeLocationCall(callReturnLocation), callType == Construct ? DFG::operationLinkConstruct : DFG::operationLinkCall); + repatchBuffer.relink(callReturnLocation, (callType == Construct ? globalData.getCTIStub(DFG::linkConstructThunkGenerator) : globalData.getCTIStub(DFG::linkCallThunkGenerator)).code()); #else ASSERT_NOT_REACHED(); #endif } else - repatchBuffer.relink(CodeLocationNearCall(callReturnLocation), callType == Construct ? globalData.jitStubs->ctiVirtualConstructLink() : globalData.jitStubs->ctiVirtualCallLink()); + repatchBuffer.relink(callReturnLocation, callType == Construct ? globalData.jitStubs->ctiVirtualConstructLink() : globalData.jitStubs->ctiVirtualCallLink()); hasSeenShouldRepatch = false; callee.clear(); diff --git a/Source/JavaScriptCore/bytecode/CallLinkInfo.h b/Source/JavaScriptCore/bytecode/CallLinkInfo.h index 44d50a971..4a78e5d02 100644 --- a/Source/JavaScriptCore/bytecode/CallLinkInfo.h +++ b/Source/JavaScriptCore/bytecode/CallLinkInfo.h @@ -65,7 +65,7 @@ struct CallLinkInfo : public BasicRawSentinelNode<CallLinkInfo> { remove(); } - CodeLocationLabel callReturnLocation; // it's a near call in the old JIT, or a normal call in DFG + CodeLocationNearCall callReturnLocation; CodeLocationDataLabelPtr hotPathBegin; CodeLocationNearCall hotPathOther; JITWriteBarrier<JSFunction> callee; diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp index 48d0fe728..d417a5fbd 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp @@ -2026,16 +2026,16 @@ void CodeBlock::visitWeakReferences(SlotVisitor& visitor) performTracingFixpointIteration(visitor); } -void CodeBlock::finalizeUnconditionally() -{ #if ENABLE(JIT) #if ENABLE(JIT_VERBOSE_OSR) - static const bool verboseUnlinking = true; +static const bool verboseUnlinking = true; #else - static const bool verboseUnlinking = false; +static const bool verboseUnlinking = false; #endif #endif // ENABLE(JIT) +void CodeBlock::finalizeUnconditionally() +{ #if ENABLE(LLINT) Interpreter* interpreter = m_globalData->interpreter; // interpreter->classicEnabled() returns true if the old C++ interpreter is enabled. If that's enabled @@ -2141,28 +2141,10 @@ void CodeBlock::finalizeUnconditionally() for (size_t size = m_structureStubInfos.size(), i = 0; i < size; ++i) { StructureStubInfo& stubInfo = m_structureStubInfos[i]; - AccessType accessType = static_cast<AccessType>(stubInfo.accessType); - if (stubInfo.visitWeakReferences()) continue; - if (verboseUnlinking) - dataLog("Clearing structure cache (kind %d) in %p.\n", stubInfo.accessType, this); - - if (isGetByIdAccess(accessType)) { - if (getJITCode().jitType() == JITCode::DFGJIT) - DFG::dfgResetGetByID(repatchBuffer, stubInfo); - else - JIT::resetPatchGetById(repatchBuffer, &stubInfo); - } else { - ASSERT(isPutByIdAccess(accessType)); - if (getJITCode().jitType() == JITCode::DFGJIT) - DFG::dfgResetPutByID(repatchBuffer, stubInfo); - else - JIT::resetPatchPutById(repatchBuffer, &stubInfo); - } - - stubInfo.reset(); + resetStubInternal(repatchBuffer, stubInfo); } for (size_t size = m_methodCallLinkInfos.size(), i = 0; i < size; ++i) { @@ -2198,6 +2180,40 @@ void CodeBlock::finalizeUnconditionally() #endif } +#if ENABLE(JIT) +void CodeBlock::resetStub(StructureStubInfo& stubInfo) +{ + if (stubInfo.accessType == access_unset) + return; + + RepatchBuffer repatchBuffer(this); + resetStubInternal(repatchBuffer, stubInfo); +} + +void CodeBlock::resetStubInternal(RepatchBuffer& repatchBuffer, StructureStubInfo& stubInfo) +{ + AccessType accessType = static_cast<AccessType>(stubInfo.accessType); + + if (verboseUnlinking) + dataLog("Clearing structure cache (kind %d) in %p.\n", stubInfo.accessType, this); + + if (isGetByIdAccess(accessType)) { + if (getJITCode().jitType() == JITCode::DFGJIT) + DFG::dfgResetGetByID(repatchBuffer, stubInfo); + else + JIT::resetPatchGetById(repatchBuffer, &stubInfo); + } else { + ASSERT(isPutByIdAccess(accessType)); + if (getJITCode().jitType() == JITCode::DFGJIT) + DFG::dfgResetPutByID(repatchBuffer, stubInfo); + else + JIT::resetPatchPutById(repatchBuffer, &stubInfo); + } + + stubInfo.reset(); +} +#endif + void CodeBlock::stronglyVisitStrongReferences(SlotVisitor& visitor) { visitor.append(&m_globalObject); diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h index ed072f832..56ede595a 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.h +++ b/Source/JavaScriptCore/bytecode/CodeBlock.h @@ -55,6 +55,7 @@ #include "JITCode.h" #include "JITWriteBarrier.h" #include "JSGlobalObject.h" +#include "JumpReplacementWatchpoint.h" #include "JumpTable.h" #include "LLIntCallLinkInfo.h" #include "LazyOperandValueProfile.h" @@ -103,6 +104,7 @@ namespace JSC { class DFGCodeBlocks; class ExecState; class LLIntOffsetsExtractor; + class RepatchBuffer; inline int unmodifiedArgumentsRegister(int argumentsRegister) { return argumentsRegister - 1; } @@ -204,6 +206,8 @@ namespace JSC { { return *(binarySearch<StructureStubInfo, unsigned, getStructureStubInfoBytecodeIndex>(m_structureStubInfos.begin(), m_structureStubInfos.size(), bytecodeIndex)); } + + void resetStub(StructureStubInfo&); CallLinkInfo& getCallLinkInfo(ReturnAddressPtr returnAddress) { @@ -328,7 +332,7 @@ namespace JSC { return result; } - unsigned appendWatchpoint(const Watchpoint& watchpoint) + unsigned appendWatchpoint(const JumpReplacementWatchpoint& watchpoint) { createDFGDataIfNecessary(); unsigned result = m_dfgData->watchpoints.size(); @@ -367,7 +371,7 @@ namespace JSC { return m_dfgData->speculationRecovery[index]; } - Watchpoint& watchpoint(unsigned index) + JumpReplacementWatchpoint& watchpoint(unsigned index) { return m_dfgData->watchpoints[index]; } @@ -1232,6 +1236,10 @@ namespace JSC { if (!m_rareData) m_rareData = adoptPtr(new RareData); } + +#if ENABLE(JIT) + void resetStubInternal(RepatchBuffer&, StructureStubInfo&); +#endif int m_numParameters; @@ -1299,7 +1307,7 @@ namespace JSC { Vector<DFG::OSREntryData> osrEntry; SegmentedVector<DFG::OSRExit, 8> osrExit; Vector<DFG::SpeculationRecovery> speculationRecovery; - SegmentedVector<Watchpoint, 1, 0> watchpoints; + SegmentedVector<JumpReplacementWatchpoint, 1, 0> watchpoints; Vector<WeakReferenceTransition> transitions; Vector<WriteBarrier<JSCell> > weakReferences; DFG::VariableEventStream variableEventStream; diff --git a/Source/JavaScriptCore/bytecode/CodeOrigin.h b/Source/JavaScriptCore/bytecode/CodeOrigin.h index 034e48f3f..c9c0f7005 100644 --- a/Source/JavaScriptCore/bytecode/CodeOrigin.h +++ b/Source/JavaScriptCore/bytecode/CodeOrigin.h @@ -39,6 +39,8 @@ class ExecutableBase; class JSFunction; struct CodeOrigin { + static const unsigned maximumBytecodeIndex = (1u << 29) - 1; + // Bytecode offset that you'd use to re-execute this instruction. unsigned bytecodeIndex : 29; // Bytecode offset corresponding to the opcode that gives the result (needed to handle @@ -48,7 +50,7 @@ struct CodeOrigin { InlineCallFrame* inlineCallFrame; CodeOrigin() - : bytecodeIndex(std::numeric_limits<uint32_t>::max()) + : bytecodeIndex(maximumBytecodeIndex) , valueProfileOffset(0) , inlineCallFrame(0) { @@ -59,11 +61,11 @@ struct CodeOrigin { , valueProfileOffset(valueProfileOffset) , inlineCallFrame(inlineCallFrame) { - ASSERT(bytecodeIndex < (1u << 29)); + ASSERT(bytecodeIndex <= maximumBytecodeIndex); ASSERT(valueProfileOffset < (1u << 3)); } - bool isSet() const { return bytecodeIndex != std::numeric_limits<uint32_t>::max(); } + bool isSet() const { return bytecodeIndex != maximumBytecodeIndex; } unsigned bytecodeIndexForValueProfile() const { diff --git a/Source/JavaScriptCore/bytecode/StructureStubClearingWatchpoint.cpp b/Source/JavaScriptCore/bytecode/StructureStubClearingWatchpoint.cpp new file mode 100644 index 000000000..5cfb3d1e8 --- /dev/null +++ b/Source/JavaScriptCore/bytecode/StructureStubClearingWatchpoint.cpp @@ -0,0 +1,80 @@ +/* + * 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 "StructureStubClearingWatchpoint.h" + +#if ENABLE(JIT) + +#include "CodeBlock.h" +#include "StructureStubInfo.h" + +namespace JSC { + +StructureStubClearingWatchpoint::~StructureStubClearingWatchpoint() { } + +StructureStubClearingWatchpoint* StructureStubClearingWatchpoint::push( + WatchpointsOnStructureStubInfo& holder, + OwnPtr<StructureStubClearingWatchpoint>& head) +{ + head = adoptPtr(new StructureStubClearingWatchpoint(holder, head.release())); + return head.get(); +} + +void StructureStubClearingWatchpoint::fireInternal() +{ + // This will implicitly cause my own demise: stub reset removes all watchpoints. + // That works, because deleting a watchpoint removes it from the set's list, and + // the set's list traversal for firing is robust against the set changing. + m_holder.codeBlock()->resetStub(*m_holder.stubInfo()); +} + +WatchpointsOnStructureStubInfo::~WatchpointsOnStructureStubInfo() +{ +} + +StructureStubClearingWatchpoint* WatchpointsOnStructureStubInfo::addWatchpoint() +{ + return StructureStubClearingWatchpoint::push(*this, m_head); +} + +StructureStubClearingWatchpoint* WatchpointsOnStructureStubInfo::ensureReferenceAndAddWatchpoint( + RefPtr<WatchpointsOnStructureStubInfo>& holderRef, CodeBlock* codeBlock, + StructureStubInfo* stubInfo) +{ + if (!holderRef) + holderRef = adoptRef(new WatchpointsOnStructureStubInfo(codeBlock, stubInfo)); + else { + ASSERT(holderRef->m_codeBlock == codeBlock); + ASSERT(holderRef->m_stubInfo == stubInfo); + } + + return holderRef->addWatchpoint(); +} + +} // namespace JSC + +#endif // ENABLE(JIT) + diff --git a/Source/JavaScriptCore/bytecode/StructureStubClearingWatchpoint.h b/Source/JavaScriptCore/bytecode/StructureStubClearingWatchpoint.h new file mode 100644 index 000000000..827e816ee --- /dev/null +++ b/Source/JavaScriptCore/bytecode/StructureStubClearingWatchpoint.h @@ -0,0 +1,109 @@ +/* + * 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 StructureStubClearingWatchpoint_h +#define StructureStubClearingWatchpoint_h + +#include "Watchpoint.h" +#include <wtf/Platform.h> + +#if ENABLE(JIT) + +#include <wtf/FastAllocBase.h> +#include <wtf/Noncopyable.h> +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace JSC { + +class CodeBlock; +class WatchpointsOnStructureStubInfo; +struct StructureStubInfo; + +class StructureStubClearingWatchpoint : public Watchpoint { + WTF_MAKE_NONCOPYABLE(StructureStubClearingWatchpoint); + WTF_MAKE_FAST_ALLOCATED; +public: + StructureStubClearingWatchpoint( + WatchpointsOnStructureStubInfo& holder) + : m_holder(holder) + { + } + + StructureStubClearingWatchpoint( + WatchpointsOnStructureStubInfo& holder, + PassOwnPtr<StructureStubClearingWatchpoint> next) + : m_holder(holder) + , m_next(next) + { + } + + virtual ~StructureStubClearingWatchpoint(); + + static StructureStubClearingWatchpoint* push( + WatchpointsOnStructureStubInfo& holder, + OwnPtr<StructureStubClearingWatchpoint>& head); + +protected: + void fireInternal(); + +private: + WatchpointsOnStructureStubInfo& m_holder; + OwnPtr<StructureStubClearingWatchpoint> m_next; +}; + +class WatchpointsOnStructureStubInfo : public RefCounted<WatchpointsOnStructureStubInfo> { +public: + WatchpointsOnStructureStubInfo(CodeBlock* codeBlock, StructureStubInfo* stubInfo) + : m_codeBlock(codeBlock) + , m_stubInfo(stubInfo) + { + } + + ~WatchpointsOnStructureStubInfo(); + + StructureStubClearingWatchpoint* addWatchpoint(); + + static StructureStubClearingWatchpoint* ensureReferenceAndAddWatchpoint( + RefPtr<WatchpointsOnStructureStubInfo>& holderRef, + CodeBlock*, StructureStubInfo*); + + CodeBlock* codeBlock() const { return m_codeBlock; } + StructureStubInfo* stubInfo() const { return m_stubInfo; } + +private: + CodeBlock* m_codeBlock; + StructureStubInfo* m_stubInfo; + OwnPtr<StructureStubClearingWatchpoint> m_head; +}; + +} // namespace JSC + +#endif // ENABLE(JIT) + +#endif // StructureStubClearingWatchpoint_h + diff --git a/Source/JavaScriptCore/bytecode/StructureStubInfo.h b/Source/JavaScriptCore/bytecode/StructureStubInfo.h index 807966cf3..737ea88c2 100644 --- a/Source/JavaScriptCore/bytecode/StructureStubInfo.h +++ b/Source/JavaScriptCore/bytecode/StructureStubInfo.h @@ -36,6 +36,8 @@ #include "MacroAssembler.h" #include "Opcode.h" #include "Structure.h" +#include "StructureStubClearingWatchpoint.h" +#include <wtf/OwnPtr.h> namespace JSC { @@ -170,6 +172,7 @@ namespace JSC { deref(); accessType = access_unset; stubRoutine.clear(); + watchpoints.clear(); } void deref(); @@ -186,6 +189,12 @@ namespace JSC { seen = true; } + StructureStubClearingWatchpoint* addWatchpoint(CodeBlock* codeBlock) + { + return WatchpointsOnStructureStubInfo::ensureReferenceAndAddWatchpoint( + watchpoints, codeBlock, this); + } + unsigned bytecodeIndex; int8_t accessType; @@ -290,6 +299,7 @@ namespace JSC { RefPtr<JITStubRoutine> stubRoutine; CodeLocationCall callReturnLocation; CodeLocationLabel hotPathBegin; + RefPtr<WatchpointsOnStructureStubInfo> watchpoints; }; inline void* getStructureStubInfoReturnLocation(StructureStubInfo* structureStubInfo) diff --git a/Source/JavaScriptCore/bytecode/Watchpoint.cpp b/Source/JavaScriptCore/bytecode/Watchpoint.cpp index 1dd633f52..6f80dfa5e 100644 --- a/Source/JavaScriptCore/bytecode/Watchpoint.cpp +++ b/Source/JavaScriptCore/bytecode/Watchpoint.cpp @@ -4,26 +4,23 @@ * 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. * - * 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. + * 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" @@ -39,30 +36,6 @@ Watchpoint::~Watchpoint() 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) diff --git a/Source/JavaScriptCore/bytecode/Watchpoint.h b/Source/JavaScriptCore/bytecode/Watchpoint.h index 0055bf607..8e0526c0f 100644 --- a/Source/JavaScriptCore/bytecode/Watchpoint.h +++ b/Source/JavaScriptCore/bytecode/Watchpoint.h @@ -4,33 +4,28 @@ * 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. * - * 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. + * 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 Watchpoint_h #define Watchpoint_h -#include "CodeLocation.h" -#include "MacroAssembler.h" #include <wtf/RefCounted.h> #include <wtf/SentinelLinkedList.h> @@ -39,33 +34,15 @@ 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(); + virtual ~Watchpoint(); + + void fire() { fireInternal(); } -private: - uintptr_t m_source; - uintptr_t m_destination; +protected: + virtual void fireInternal() = 0; }; enum InitialWatchpointSetMode { InitializedWatching, InitializedBlind }; diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp index 4cd31f2a8..95f44c092 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp +++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp @@ -52,6 +52,10 @@ void AbstractState::beginBasicBlock(BasicBlock* basicBlock) ASSERT(basicBlock->variablesAtTail.numberOfLocals() == basicBlock->valuesAtTail.numberOfLocals()); ASSERT(basicBlock->variablesAtHead.numberOfLocals() == basicBlock->variablesAtTail.numberOfLocals()); + // This is usually a no-op, but it is possible that the graph has grown since the + // abstract state was last used. + m_nodes.resize(m_graph.size()); + for (size_t i = 0; i < basicBlock->size(); i++) m_nodes[basicBlock->at(i)].clear(); @@ -164,6 +168,7 @@ bool AbstractState::endBasicBlock(MergeMode mergeMode, BranchDirection* branchDi BasicBlock* block = m_block; // Save the block for successor merging. block->cfaFoundConstants = m_foundConstants; + block->cfaDidFinish = m_isValid; if (!m_isValid) { reset(); diff --git a/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h b/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h index 4bea292f3..57f758c9c 100644 --- a/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h +++ b/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h @@ -46,12 +46,13 @@ public: AssemblyHelpers(JSGlobalData* globalData, CodeBlock* codeBlock) : m_globalData(globalData) , m_codeBlock(codeBlock) - , m_baselineCodeBlock(codeBlock->baselineVersion()) + , m_baselineCodeBlock(codeBlock ? codeBlock->baselineVersion() : 0) { - ASSERT(m_codeBlock); - ASSERT(m_baselineCodeBlock); - ASSERT(!m_baselineCodeBlock->alternative()); - ASSERT(m_baselineCodeBlock->getJITType() == JITCode::BaselineJIT); + if (m_codeBlock) { + ASSERT(m_baselineCodeBlock); + ASSERT(!m_baselineCodeBlock->alternative()); + ASSERT(m_baselineCodeBlock->getJITType() == JITCode::BaselineJIT); + } } CodeBlock* codeBlock() { return m_codeBlock; } diff --git a/Source/JavaScriptCore/dfg/DFGBasicBlock.h b/Source/JavaScriptCore/dfg/DFGBasicBlock.h index 9128f0882..441e2e75e 100644 --- a/Source/JavaScriptCore/dfg/DFGBasicBlock.h +++ b/Source/JavaScriptCore/dfg/DFGBasicBlock.h @@ -45,6 +45,7 @@ struct BasicBlock : Vector<NodeIndex, 8> { , cfaHasVisited(false) , cfaShouldRevisit(false) , cfaFoundConstants(false) + , cfaDidFinish(true) #if !ASSERT_DISABLED , isLinked(false) #endif @@ -103,6 +104,7 @@ struct BasicBlock : Vector<NodeIndex, 8> { bool cfaHasVisited; bool cfaShouldRevisit; bool cfaFoundConstants; + bool cfaDidFinish; #if !ASSERT_DISABLED bool isLinked; #endif diff --git a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h index 9c1718bdb..5985b251e 100644 --- a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h +++ b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h @@ -37,7 +37,7 @@ namespace JSC { namespace DFG { class CCallHelpers : public AssemblyHelpers { public: - CCallHelpers(JSGlobalData* globalData, CodeBlock* codeBlock) + CCallHelpers(JSGlobalData* globalData, CodeBlock* codeBlock = 0) : AssemblyHelpers(globalData, codeBlock) { } diff --git a/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp index c52349645..24ea0b36f 100644 --- a/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp @@ -95,8 +95,12 @@ private: m_state.dump(WTF::dataFile()); dataLog("\n"); #endif - if (!m_state.execute(i)) + if (!m_state.execute(i)) { +#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) + dataLog(" Expect OSR exit.\n"); +#endif break; + } } #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLog(" tail regs: "); diff --git a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp index c234e6e4e..dc1632dc4 100644 --- a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp @@ -643,18 +643,6 @@ 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; } diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp index d3029b39a..a8eb9ee5c 100644 --- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp @@ -40,6 +40,7 @@ class ConstantFoldingPhase : public Phase { public: ConstantFoldingPhase(Graph& graph) : Phase(graph, "constant folding") + , m_state(graph) { } @@ -47,114 +48,192 @@ public: { bool changed = false; - AbstractState state(m_graph); - InsertionSet<NodeIndex> insertionSet; - for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) { BasicBlock* block = m_graph.m_blocks[blockIndex].get(); if (!block) continue; - if (!block->cfaFoundConstants) - continue; + if (!block->cfaDidFinish) + changed |= paintUnreachableCode(blockIndex); + if (block->cfaFoundConstants) + changed |= foldConstants(blockIndex); + } + + return changed; + } + +private: + bool foldConstants(BlockIndex blockIndex) + { #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) - dataLog("Constant folding considering Block #%u.\n", blockIndex); + dataLog("Constant folding considering Block #%u.\n", blockIndex); #endif - state.beginBasicBlock(block); - for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { - if (!state.isValid()) - break; - NodeIndex nodeIndex = block->at(indexInBlock); - Node& node = m_graph[nodeIndex]; + BasicBlock* block = m_graph.m_blocks[blockIndex].get(); + bool changed = false; + m_state.beginBasicBlock(block); + for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { + NodeIndex nodeIndex = block->at(indexInBlock); + Node& node = m_graph[nodeIndex]; - bool eliminated = false; + if (!m_state.isValid()) + break; + + 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; + switch (node.op()) { + case CheckArgumentsNotCreated: { + if (!isEmptySpeculation( + m_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; - } + default: + break; + } - if (eliminated) { - changed = true; - continue; - } + if (eliminated) { + changed = true; + continue; + } - state.execute(indexInBlock); - if (!node.shouldGenerate() - || state.didClobber() - || node.hasConstant()) - continue; - JSValue value = state.forNode(nodeIndex).value(); - if (!value) - continue; + m_state.execute(indexInBlock); + if (!node.shouldGenerate() + || m_state.didClobber() + || node.hasConstant()) + continue; + JSValue value = m_state.forNode(nodeIndex).value(); + if (!value) + continue; - Node phantom(Phantom, node.codeOrigin); + Node phantom(Phantom, node.codeOrigin); - if (node.op() == GetLocal) { - NodeIndex previousLocalAccess = NoNode; - 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(); - block->variablesAtHead.operand(node.local()) = previousLocalAccess; - } else { - ASSERT(indexInBlock > 0); - // Must search for the previous access to this local. - for (BlockIndex subIndexInBlock = indexInBlock; subIndexInBlock--;) { - NodeIndex subNodeIndex = block->at(subIndexInBlock); - Node& subNode = m_graph[subNodeIndex]; - if (!subNode.shouldGenerate()) - continue; - if (!subNode.hasVariableAccessData()) + if (node.op() == GetLocal) { + NodeIndex previousLocalAccess = NoNode; + 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(); + block->variablesAtHead.operand(node.local()) = previousLocalAccess; + } else { + ASSERT(indexInBlock > 0); + // Must search for the previous access to this local. + for (BlockIndex subIndexInBlock = indexInBlock; subIndexInBlock--;) { + NodeIndex subNodeIndex = block->at(subIndexInBlock); + Node& subNode = m_graph[subNodeIndex]; + if (!subNode.shouldGenerate()) + continue; + if (!subNode.hasVariableAccessData()) + continue; + if (subNode.local() != node.local()) + continue; + // The two must have been unified. + ASSERT(subNode.variableAccessData() == node.variableAccessData()); + previousLocalAccess = subNodeIndex; + break; + } + if (previousLocalAccess == NoNode) { + // The previous access must have been a Phi. + for (BlockIndex phiIndexInBlock = block->phis.size(); phiIndexInBlock--;) { + NodeIndex phiNodeIndex = block->phis[phiIndexInBlock]; + Node& phiNode = m_graph[phiNodeIndex]; + if (!phiNode.shouldGenerate()) continue; - if (subNode.local() != node.local()) + if (phiNode.local() != node.local()) continue; // The two must have been unified. - ASSERT(subNode.variableAccessData() == node.variableAccessData()); - previousLocalAccess = subNodeIndex; + ASSERT(phiNode.variableAccessData() == node.variableAccessData()); + previousLocalAccess = phiNodeIndex; break; } ASSERT(previousLocalAccess != NoNode); } + } - NodeIndex tailNodeIndex = block->variablesAtTail.operand(node.local()); - if (tailNodeIndex == nodeIndex) - block->variablesAtTail.operand(node.local()) = previousLocalAccess; - else { - ASSERT(m_graph[tailNodeIndex].op() == Flush - || m_graph[tailNodeIndex].op() == SetLocal); - } + ASSERT(previousLocalAccess != NoNode); + + NodeIndex tailNodeIndex = block->variablesAtTail.operand(node.local()); + if (tailNodeIndex == nodeIndex) + block->variablesAtTail.operand(node.local()) = previousLocalAccess; + else { + ASSERT(m_graph[tailNodeIndex].op() == Flush + || m_graph[tailNodeIndex].op() == SetLocal); } + } - phantom.children = node.children; - phantom.ref(); + phantom.children = node.children; + phantom.ref(); + + m_graph.convertToConstant(nodeIndex, value); + NodeIndex phantomNodeIndex = m_graph.size(); + m_graph.append(phantom); + m_insertionSet.append(indexInBlock, phantomNodeIndex); - m_graph.convertToConstant(nodeIndex, value); - NodeIndex phantomNodeIndex = m_graph.size(); - m_graph.append(phantom); - insertionSet.append(indexInBlock, phantomNodeIndex); + changed = true; + } + m_state.reset(); + m_insertionSet.execute(*block); + + return changed; + } + + // This is necessary because the CFA may reach conclusions about constants based on its + // assumption that certain code must exit, but then those constants may lead future + // reexecutions of the CFA to believe that the same code will now no longer exit. Thus + // to ensure soundness, we must paint unreachable code as such, by inserting an + // unconditional ForceOSRExit wherever we find that a node would have always exited. + // This will only happen in cases where we are making static speculations, or we're + // making totally wrong speculations due to imprecision on the prediction propagator. + bool paintUnreachableCode(BlockIndex blockIndex) + { + bool changed = false; + +#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) + dataLog("Painting unreachable code in Block #%u.\n", blockIndex); +#endif + BasicBlock* block = m_graph.m_blocks[blockIndex].get(); + m_state.beginBasicBlock(block); + + for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { + m_state.execute(indexInBlock); + if (m_state.isValid()) + continue; + + NodeIndex nodeIndex = block->at(indexInBlock); + Node& node = m_graph[nodeIndex]; + switch (node.op()) { + case Return: + case Throw: + case ThrowReferenceError: + case ForceOSRExit: + // Do nothing. These nodes will already do the right thing. + break; + default: + Node forceOSRExit(ForceOSRExit, node.codeOrigin); + forceOSRExit.ref(); + NodeIndex forceOSRExitIndex = m_graph.size(); + m_graph.append(forceOSRExit); + m_insertionSet.append(indexInBlock, forceOSRExitIndex); changed = true; + break; } - insertionSet.execute(*block); - state.reset(); + break; } + m_state.reset(); + m_insertionSet.execute(*block); return changed; } + + AbstractState m_state; + InsertionSet<NodeIndex> m_insertionSet; }; bool performConstantFolding(Graph& graph) diff --git a/Source/JavaScriptCore/dfg/DFGGPRInfo.h b/Source/JavaScriptCore/dfg/DFGGPRInfo.h index 89faef94b..23f1697a6 100644 --- a/Source/JavaScriptCore/dfg/DFGGPRInfo.h +++ b/Source/JavaScriptCore/dfg/DFGGPRInfo.h @@ -273,6 +273,7 @@ public: static const GPRReg argumentGPR1 = X86Registers::edx; // regT1 static const GPRReg nonArgGPR0 = X86Registers::eax; // regT0 static const GPRReg nonArgGPR1 = X86Registers::ebx; // regT3 + static const GPRReg nonArgGPR2 = X86Registers::esi; // regT4 static const GPRReg returnValueGPR = X86Registers::eax; // regT0 static const GPRReg returnValueGPR2 = X86Registers::edx; // regT1 static const GPRReg nonPreservedNonReturnGPR = X86Registers::ecx; @@ -344,6 +345,7 @@ public: static const GPRReg argumentGPR5 = X86Registers::r9; // regT7 static const GPRReg nonArgGPR0 = X86Registers::eax; // regT0 static const GPRReg nonArgGPR1 = X86Registers::ebx; // regT3 + static const GPRReg nonArgGPR2 = X86Registers::r10; // regT8 static const GPRReg returnValueGPR = X86Registers::eax; // regT0 static const GPRReg returnValueGPR2 = X86Registers::edx; // regT1 static const GPRReg nonPreservedNonReturnGPR = X86Registers::esi; @@ -416,6 +418,7 @@ public: static const GPRReg argumentGPR3 = ARMRegisters::r3; // FIXME! static const GPRReg nonArgGPR0 = ARMRegisters::r4; // regT3 static const GPRReg nonArgGPR1 = ARMRegisters::r8; // regT4 + static const GPRReg nonArgGPR2 = ARMRegisters::r9; // regT5 static const GPRReg returnValueGPR = ARMRegisters::r0; // regT0 static const GPRReg returnValueGPR2 = ARMRegisters::r1; // regT1 static const GPRReg nonPreservedNonReturnGPR = ARMRegisters::r2; diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp index 497fc346f..2ebee13c1 100644 --- a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp +++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp @@ -153,7 +153,6 @@ void JITCompiler::link(LinkBuffer& linkBuffer) unsigned returnAddressOffset = linkBuffer.returnAddressOffset(m_exceptionChecks[i].m_call); codeOrigins[i].codeOrigin = record.m_codeOrigin; codeOrigins[i].callReturnOffset = returnAddressOffset; - record.m_token.assertCodeOriginIndex(i); } m_codeBlock->setNumberOfStructureStubInfos(m_propertyAccesses.size()); @@ -189,7 +188,8 @@ void JITCompiler::link(LinkBuffer& linkBuffer) CallLinkInfo& info = m_codeBlock->callLinkInfo(i); info.callType = m_jsCalls[i].m_callType; info.isDFG = true; - info.callReturnLocation = CodeLocationLabel(linkBuffer.locationOf(m_jsCalls[i].m_slowCall)); + linkBuffer.link(m_jsCalls[i].m_slowCall, FunctionPtr((m_globalData->getCTIStub(info.callType == CallLinkInfo::Construct ? linkConstructThunkGenerator : linkCallThunkGenerator)).code().executableAddress())); + info.callReturnLocation = linkBuffer.locationOfNearCall(m_jsCalls[i].m_slowCall); info.hotPathBegin = linkBuffer.locationOf(m_jsCalls[i].m_targetToCheck); info.hotPathOther = linkBuffer.locationOfNearCall(m_jsCalls[i].m_fastCall); } @@ -280,7 +280,8 @@ bool JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWi move(stackPointerRegister, GPRInfo::argumentGPR0); poke(GPRInfo::callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*)); - CallBeginToken token = beginCall(); + CallBeginToken token; + beginCall(CodeOrigin(0), token); Call callRegisterFileCheck = call(); notifyCall(callRegisterFileCheck, CodeOrigin(0), token); jump(fromRegisterFileCheck); @@ -297,7 +298,7 @@ bool JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWi branch32(AboveOrEqual, GPRInfo::regT1, TrustedImm32(m_codeBlock->numParameters())).linkTo(fromArityCheck, this); move(stackPointerRegister, GPRInfo::argumentGPR0); poke(GPRInfo::callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*)); - token = beginCall(); + beginCall(CodeOrigin(0), token); Call callArityCheck = call(); notifyCall(callArityCheck, CodeOrigin(0), token); move(GPRInfo::regT0, GPRInfo::callFrameRegister); diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.h b/Source/JavaScriptCore/dfg/DFGJITCompiler.h index 24dbbdcd0..d6374b790 100644 --- a/Source/JavaScriptCore/dfg/DFGJITCompiler.h +++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.h @@ -76,28 +76,58 @@ class CallBeginToken { public: CallBeginToken() #if !ASSERT_DISABLED - : m_codeOriginIndex(UINT_MAX) + : m_registered(false) + , m_exceptionCheckIndex(std::numeric_limits<unsigned>::max()) #endif { } - explicit CallBeginToken(unsigned codeOriginIndex) + ~CallBeginToken() + { + ASSERT(m_registered || !m_codeOrigin.isSet()); + ASSERT(m_codeOrigin.isSet() == (m_exceptionCheckIndex != std::numeric_limits<unsigned>::max())); + } + + void set(CodeOrigin codeOrigin, unsigned index) + { #if !ASSERT_DISABLED - : m_codeOriginIndex(codeOriginIndex) + ASSERT(m_registered || !m_codeOrigin.isSet()); + ASSERT(m_codeOrigin.isSet() == (m_exceptionCheckIndex != std::numeric_limits<unsigned>::max())); + m_codeOrigin = codeOrigin; + m_registered = false; + m_exceptionCheckIndex = index; +#else + UNUSED_PARAM(codeOrigin); + UNUSED_PARAM(index); #endif - { - UNUSED_PARAM(codeOriginIndex); } - void assertCodeOriginIndex(unsigned codeOriginIndex) const + void registerWithExceptionCheck(CodeOrigin codeOrigin, unsigned index) { - ASSERT_UNUSED(codeOriginIndex, codeOriginIndex < UINT_MAX); - ASSERT_UNUSED(codeOriginIndex, codeOriginIndex == m_codeOriginIndex); +#if !ASSERT_DISABLED + ASSERT(m_codeOrigin == codeOrigin); + if (m_registered) + return; + ASSERT(m_exceptionCheckIndex == index); + m_registered = true; +#else + UNUSED_PARAM(codeOrigin); + UNUSED_PARAM(index); +#endif } +#if !ASSERT_DISABLED + const CodeOrigin& codeOrigin() const + { + return m_codeOrigin; + } +#endif + private: #if !ASSERT_DISABLED - unsigned m_codeOriginIndex; + CodeOrigin m_codeOrigin; + bool m_registered; + unsigned m_exceptionCheckIndex; #endif }; @@ -107,25 +137,22 @@ private: // Calls that might throw an exception also record the Jump taken on exception // (unset if not present) and code origin used to recover handler/source info. struct CallExceptionRecord { - CallExceptionRecord(MacroAssembler::Call call, CodeOrigin codeOrigin, CallBeginToken token) + CallExceptionRecord(MacroAssembler::Call call, CodeOrigin codeOrigin) : m_call(call) , m_codeOrigin(codeOrigin) - , m_token(token) { } - CallExceptionRecord(MacroAssembler::Call call, MacroAssembler::Jump exceptionCheck, CodeOrigin codeOrigin, CallBeginToken token) + CallExceptionRecord(MacroAssembler::Call call, MacroAssembler::Jump exceptionCheck, CodeOrigin codeOrigin) : m_call(call) , m_exceptionCheck(exceptionCheck) , m_codeOrigin(codeOrigin) - , m_token(token) { } MacroAssembler::Call m_call; MacroAssembler::Jump m_exceptionCheck; CodeOrigin m_codeOrigin; - CallBeginToken m_token; }; struct PropertyAccessRecord { @@ -257,19 +284,27 @@ public: m_disassembler->setEndOfCode(labelIgnoringWatchpoints()); } + unsigned currentCodeOriginIndex() const + { + return m_currentCodeOriginIndex; + } + // Get a token for beginning a call, and set the current code origin index in - // the call frame. - CallBeginToken beginCall() + // the call frame. For each beginCall() there must be at least one exception + // check, and all of the exception checks must have the same CodeOrigin as the + // beginCall(). + void beginCall(CodeOrigin codeOrigin, CallBeginToken& token) { - unsigned codeOriginIndex = m_currentCodeOriginIndex++; - store32(TrustedImm32(codeOriginIndex), tagFor(static_cast<VirtualRegister>(RegisterFile::ArgumentCount))); - return CallBeginToken(codeOriginIndex); + unsigned index = m_exceptionChecks.size(); + store32(TrustedImm32(index), tagFor(static_cast<VirtualRegister>(RegisterFile::ArgumentCount))); + token.set(codeOrigin, index); } // Notify the JIT of a call that does not require linking. - void notifyCall(Call functionCall, CodeOrigin codeOrigin, CallBeginToken token) + void notifyCall(Call functionCall, CodeOrigin codeOrigin, CallBeginToken& token) { - m_exceptionChecks.append(CallExceptionRecord(functionCall, codeOrigin, token)); + token.registerWithExceptionCheck(codeOrigin, m_exceptionChecks.size()); + m_exceptionChecks.append(CallExceptionRecord(functionCall, codeOrigin)); } // Add a call out from JIT code, without an exception check. @@ -279,20 +314,27 @@ public: m_calls.append(CallLinkRecord(functionCall, function)); return functionCall; } + + void prepareForExceptionCheck() + { + move(TrustedImm32(m_exceptionChecks.size()), GPRInfo::nonPreservedNonReturnGPR); + } // Add a call out from JIT code, with an exception check. - void addExceptionCheck(Call functionCall, CodeOrigin codeOrigin, CallBeginToken token) + void addExceptionCheck(Call functionCall, CodeOrigin codeOrigin, CallBeginToken& token) { - move(TrustedImm32(m_exceptionChecks.size()), GPRInfo::nonPreservedNonReturnGPR); - m_exceptionChecks.append(CallExceptionRecord(functionCall, emitExceptionCheck(), codeOrigin, token)); + prepareForExceptionCheck(); + token.registerWithExceptionCheck(codeOrigin, m_exceptionChecks.size()); + m_exceptionChecks.append(CallExceptionRecord(functionCall, emitExceptionCheck(), codeOrigin)); } // Add a call out from JIT code, with a fast exception check that tests if the return value is zero. - void addFastExceptionCheck(Call functionCall, CodeOrigin codeOrigin, CallBeginToken token) + void addFastExceptionCheck(Call functionCall, CodeOrigin codeOrigin, CallBeginToken& token) { - move(TrustedImm32(m_exceptionChecks.size()), GPRInfo::nonPreservedNonReturnGPR); + prepareForExceptionCheck(); Jump exceptionCheck = branchTestPtr(Zero, GPRInfo::returnValueGPR); - m_exceptionChecks.append(CallExceptionRecord(functionCall, exceptionCheck, codeOrigin, token)); + token.registerWithExceptionCheck(codeOrigin, m_exceptionChecks.size()); + m_exceptionChecks.append(CallExceptionRecord(functionCall, exceptionCheck, codeOrigin)); } // Helper methods to get predictions diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp index 5d6575a6f..bbe55d351 100644 --- a/Source/JavaScriptCore/dfg/DFGOperations.cpp +++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp @@ -30,6 +30,7 @@ #include "CodeBlock.h" #include "DFGOSRExit.h" #include "DFGRepatch.h" +#include "DFGThunks.h" #include "HostCallReturnValue.h" #include "GetterSetter.h" #include "Interpreter.h" @@ -849,7 +850,6 @@ static void* handleHostCall(ExecState* execCallee, JSValue callee, CodeSpecializ execCallee->setScopeChain(exec->scopeChain()); execCallee->setCodeBlock(0); - execCallee->clearReturnPC(); if (kind == CodeForCall) { CallData callData; @@ -862,14 +862,14 @@ static void* handleHostCall(ExecState* execCallee, JSValue callee, CodeSpecializ execCallee->setCallee(asObject(callee)); globalData->hostCallReturnValue = JSValue::decode(callData.native.function(execCallee)); if (globalData->exception) - return 0; + return globalData->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); return reinterpret_cast<void*>(getHostCallReturnValue); } ASSERT(callType == CallTypeNone); exec->globalData().exception = createNotAFunctionError(exec, callee); - return 0; + return globalData->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); } ASSERT(kind == CodeForConstruct); @@ -884,17 +884,17 @@ static void* handleHostCall(ExecState* execCallee, JSValue callee, CodeSpecializ execCallee->setCallee(asObject(callee)); globalData->hostCallReturnValue = JSValue::decode(constructData.native.function(execCallee)); if (globalData->exception) - return 0; + return globalData->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); return reinterpret_cast<void*>(getHostCallReturnValue); } ASSERT(constructType == ConstructTypeNone); exec->globalData().exception = createNotAConstructorError(exec, callee); - return 0; + return globalData->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); } -inline void* linkFor(ExecState* execCallee, ReturnAddressPtr returnAddress, CodeSpecializationKind kind) +inline void* linkFor(ExecState* execCallee, CodeSpecializationKind kind) { ExecState* exec = execCallee->callerFrame(); JSGlobalData* globalData = &exec->globalData(); @@ -918,7 +918,7 @@ inline void* linkFor(ExecState* execCallee, ReturnAddressPtr returnAddress, Code JSObject* error = functionExecutable->compileFor(execCallee, callee->scope(), kind); if (error) { globalData->exception = createStackOverflowError(exec); - return 0; + return globalData->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); } codeBlock = &functionExecutable->generatedBytecodeFor(kind); if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters())) @@ -926,7 +926,7 @@ inline void* linkFor(ExecState* execCallee, ReturnAddressPtr returnAddress, Code else codePtr = functionExecutable->generatedJITCodeFor(kind).addressForCall(); } - CallLinkInfo& callLinkInfo = exec->codeBlock()->getCallLinkInfo(returnAddress); + CallLinkInfo& callLinkInfo = exec->codeBlock()->getCallLinkInfo(execCallee->returnPC()); if (!callLinkInfo.seenOnce()) callLinkInfo.setSeen(); else @@ -934,16 +934,14 @@ inline void* linkFor(ExecState* execCallee, ReturnAddressPtr returnAddress, Code return codePtr.executableAddress(); } -P_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(operationLinkCall); -void* DFG_OPERATION operationLinkCallWithReturnAddress(ExecState* execCallee, ReturnAddressPtr returnAddress) +void* DFG_OPERATION operationLinkCall(ExecState* execCallee) { - return linkFor(execCallee, returnAddress, CodeForCall); + return linkFor(execCallee, CodeForCall); } -P_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(operationLinkConstruct); -void* DFG_OPERATION operationLinkConstructWithReturnAddress(ExecState* execCallee, ReturnAddressPtr returnAddress) +void* DFG_OPERATION operationLinkConstruct(ExecState* execCallee) { - return linkFor(execCallee, returnAddress, CodeForConstruct); + return linkFor(execCallee, CodeForConstruct); } inline void* virtualFor(ExecState* execCallee, CodeSpecializationKind kind) @@ -965,7 +963,7 @@ inline void* virtualFor(ExecState* execCallee, CodeSpecializationKind kind) JSObject* error = functionExecutable->compileFor(execCallee, function->scope(), kind); if (error) { exec->globalData().exception = error; - return 0; + return globalData->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); } } return executable->generatedJITCodeWithArityCheckFor(kind).executableAddress(); diff --git a/Source/JavaScriptCore/dfg/DFGRepatch.cpp b/Source/JavaScriptCore/dfg/DFGRepatch.cpp index 752316f9c..e25c6aa27 100644 --- a/Source/JavaScriptCore/dfg/DFGRepatch.cpp +++ b/Source/JavaScriptCore/dfg/DFGRepatch.cpp @@ -30,6 +30,7 @@ #include "DFGCCallHelpers.h" #include "DFGSpeculativeJIT.h" +#include "DFGThunks.h" #include "GCAwareJITStubRoutine.h" #include "LinkBuffer.h" #include "Operations.h" @@ -70,6 +71,48 @@ static void dfgRepatchByIdSelfAccess(CodeBlock* codeBlock, StructureStubInfo& st #endif } +static void addStructureTransitionCheck( + JSCell* object, Structure* structure, CodeBlock* codeBlock, StructureStubInfo& stubInfo, + MacroAssembler& jit, MacroAssembler::JumpList& failureCases, GPRReg scratchGPR) +{ + if (object->structure() == structure && structure->transitionWatchpointSetIsStillValid()) { + structure->addTransitionWatchpoint(stubInfo.addWatchpoint(codeBlock)); +#if DFG_ENABLE(JIT_ASSERT) + // If we execute this code, the object must have the structure we expect. Assert + // this in debug modes. + jit.move(MacroAssembler::TrustedImmPtr(object), scratchGPR); + MacroAssembler::Jump ok = jit.branchPtr( + MacroAssembler::Equal, + MacroAssembler::Address(scratchGPR, JSCell::structureOffset()), + MacroAssembler::TrustedImmPtr(structure)); + jit.breakpoint(); + ok.link(&jit); +#endif + return; + } + + jit.move(MacroAssembler::TrustedImmPtr(object), scratchGPR); + failureCases.append( + jit.branchPtr( + MacroAssembler::NotEqual, + MacroAssembler::Address(scratchGPR, JSCell::structureOffset()), + MacroAssembler::TrustedImmPtr(structure))); +} + +static void addStructureTransitionCheck( + JSValue prototype, CodeBlock* codeBlock, StructureStubInfo& stubInfo, + MacroAssembler& jit, MacroAssembler::JumpList& failureCases, GPRReg scratchGPR) +{ + if (prototype.isNull()) + return; + + ASSERT(prototype.isCell()); + + addStructureTransitionCheck( + prototype.asCell(), prototype.asCell()->structure(), codeBlock, stubInfo, jit, + failureCases, scratchGPR); +} + static void emitRestoreScratch(MacroAssembler& stubJit, bool needToRestoreScratch, GPRReg scratchGPR, MacroAssembler::Jump& success, MacroAssembler::Jump& fail, MacroAssembler::JumpList failureCases) { if (needToRestoreScratch) { @@ -136,8 +179,9 @@ static void generateProtoChainAccessStub(ExecState* exec, StructureStubInfo& stu JSObject* protoObject = 0; for (unsigned i = 0; i < count; ++i, ++it) { protoObject = asObject(currStructure->prototypeForLookup(exec)); - stubJit.move(MacroAssembler::TrustedImmPtr(protoObject), scratchGPR); - failureCases.append(stubJit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(scratchGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(protoObject->structure()))); + addStructureTransitionCheck( + protoObject, protoObject->structure(), exec->codeBlock(), stubInfo, stubJit, + failureCases, scratchGPR); currStructure = it->get(); } @@ -568,17 +612,6 @@ static V_DFGOperation_EJCI appropriateListBuildingPutByIdFunction(const PutPrope return operationPutByIdNonStrictBuildList; } -static void testPrototype(MacroAssembler &stubJit, GPRReg scratchGPR, JSValue prototype, MacroAssembler::JumpList& failureCases) -{ - if (prototype.isNull()) - return; - - ASSERT(prototype.isCell()); - - stubJit.move(MacroAssembler::TrustedImmPtr(prototype.asCell()), scratchGPR); - failureCases.append(stubJit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(scratchGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(prototype.asCell()->structure()))); -} - static void emitPutReplaceStub( ExecState* exec, JSValue, @@ -707,12 +740,17 @@ static void emitPutTransitionStub( ASSERT(oldStructure->transitionWatchpointSetHasBeenInvalidated()); failureCases.append(stubJit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(oldStructure))); - - testPrototype(stubJit, scratchGPR, oldStructure->storedPrototype(), failureCases); + + addStructureTransitionCheck( + oldStructure->storedPrototype(), exec->codeBlock(), stubInfo, stubJit, failureCases, + scratchGPR); if (putKind == NotDirect) { - for (WriteBarrier<Structure>* it = prototypeChain->head(); *it; ++it) - testPrototype(stubJit, scratchGPR, (*it)->storedPrototype(), failureCases); + for (WriteBarrier<Structure>* it = prototypeChain->head(); *it; ++it) { + addStructureTransitionCheck( + (*it)->storedPrototype(), exec->codeBlock(), stubInfo, stubJit, failureCases, + scratchGPR); + } } #if ENABLE(GGC) || ENABLE(WRITE_BARRIER_PROFILING) @@ -916,6 +954,7 @@ void dfgBuildPutByIdList(ExecState* exec, JSValue baseValue, const Identifier& p void dfgLinkFor(ExecState* exec, CallLinkInfo& callLinkInfo, CodeBlock* calleeCodeBlock, JSFunction* callee, MacroAssemblerCodePtr codePtr, CodeSpecializationKind kind) { CodeBlock* callerCodeBlock = exec->callerFrame()->codeBlock(); + JSGlobalData* globalData = callerCodeBlock->globalData(); RepatchBuffer repatchBuffer(callerCodeBlock); @@ -928,17 +967,17 @@ void dfgLinkFor(ExecState* exec, CallLinkInfo& callLinkInfo, CodeBlock* calleeCo calleeCodeBlock->linkIncomingCall(&callLinkInfo); if (kind == CodeForCall) { - repatchBuffer.relink(CodeLocationCall(callLinkInfo.callReturnLocation), operationVirtualCall); + repatchBuffer.relink(callLinkInfo.callReturnLocation, globalData->getCTIStub(virtualCallThunkGenerator).code()); return; } ASSERT(kind == CodeForConstruct); - repatchBuffer.relink(CodeLocationCall(callLinkInfo.callReturnLocation), operationVirtualConstruct); + repatchBuffer.relink(callLinkInfo.callReturnLocation, globalData->getCTIStub(virtualConstructThunkGenerator).code()); } void dfgResetGetByID(RepatchBuffer& repatchBuffer, StructureStubInfo& stubInfo) { repatchBuffer.relink(stubInfo.callReturnLocation, operationGetByIdOptimize); - repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelPtrAtOffset(-(uintptr_t)stubInfo.patch.dfg.deltaCheckImmToCall), reinterpret_cast<void*>(-1)); + repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelPtrAtOffset(-(intptr_t)stubInfo.patch.dfg.deltaCheckImmToCall), reinterpret_cast<void*>(-1)); #if USE(JSVALUE64) repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelCompactAtOffset(stubInfo.patch.dfg.deltaCallToLoadOrStore), 0); #else @@ -963,7 +1002,7 @@ void dfgResetPutByID(RepatchBuffer& repatchBuffer, StructureStubInfo& stubInfo) optimizedFunction = operationPutByIdDirectNonStrictOptimize; } repatchBuffer.relink(stubInfo.callReturnLocation, optimizedFunction); - repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelPtrAtOffset(-(uintptr_t)stubInfo.patch.dfg.deltaCheckImmToCall), reinterpret_cast<void*>(-1)); + repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelPtrAtOffset(-(intptr_t)stubInfo.patch.dfg.deltaCheckImmToCall), reinterpret_cast<void*>(-1)); #if USE(JSVALUE64) repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabel32AtOffset(stubInfo.patch.dfg.deltaCallToLoadOrStore), 0); #else diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h index 57bc84a12..28d8033cb 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h @@ -1738,7 +1738,8 @@ public: { prepareForExternalCall(); CodeOrigin codeOrigin = at(m_compileIndex).codeOrigin; - CallBeginToken token = m_jit.beginCall(); + CallBeginToken token; + m_jit.beginCall(codeOrigin, token); JITCompiler::Call call = m_jit.appendCall(function); m_jit.addExceptionCheck(call, codeOrigin, token); return call; @@ -2165,7 +2166,7 @@ public: // 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) + JumpReplacementWatchpoint* speculationWatchpoint(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex) { if (!m_compileOkay) return 0; @@ -2176,13 +2177,13 @@ public: m_jit.graph().methodOfGettingAValueProfileFor(nodeIndex), JITCompiler::Jump(), this, m_stream->size()))); exit.m_watchpointIndex = m_jit.codeBlock()->appendWatchpoint( - Watchpoint(m_jit.watchpointLabel())); + JumpReplacementWatchpoint(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() + JumpReplacementWatchpoint* speculationWatchpoint() { return speculationWatchpoint(UncountableWatchpoint, JSValueSource(), NoNode); } diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp index bbbf3c40c..ec2377389 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp @@ -956,14 +956,9 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeStrictEq(Node& node, bool invert) void SpeculativeJIT::emitCall(Node& node) { - P_DFGOperation_E slowCallFunction; - if (node.op() == Call) - slowCallFunction = operationLinkCall; - else { + if (node.op() != Call) ASSERT(node.op() == Construct); - slowCallFunction = operationLinkConstruct; - } // For constructors, the this argument is not passed but we have to make space // for it. @@ -1007,16 +1002,18 @@ void SpeculativeJIT::emitCall(Node& node) JITCompiler::DataLabelPtr targetToCheck; JITCompiler::JumpList slowPath; + CallBeginToken token; + m_jit.beginCall(node.codeOrigin, token); + + m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister); + slowPath.append(m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleePayloadGPR, targetToCheck)); slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, calleeTagGPR, TrustedImm32(JSValue::CellTag))); m_jit.loadPtr(MacroAssembler::Address(calleePayloadGPR, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), resultPayloadGPR); - m_jit.storePtr(resultPayloadGPR, callFramePayloadSlot(RegisterFile::ScopeChain)); - m_jit.store32(MacroAssembler::TrustedImm32(JSValue::CellTag), callFrameTagSlot(RegisterFile::ScopeChain)); - - m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister); + m_jit.storePtr(resultPayloadGPR, MacroAssembler::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ScopeChain + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload))); + m_jit.store32(MacroAssembler::TrustedImm32(JSValue::CellTag), MacroAssembler::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ScopeChain + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag))); CodeOrigin codeOrigin = at(m_compileIndex).codeOrigin; - CallBeginToken token = m_jit.beginCall(); JITCompiler::Call fastCall = m_jit.nearCall(); m_jit.notifyCall(fastCall, codeOrigin, token); @@ -1024,15 +1021,20 @@ void SpeculativeJIT::emitCall(Node& node) slowPath.link(&m_jit); - m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); - m_jit.poke(GPRInfo::argumentGPR0); - token = m_jit.beginCall(); - JITCompiler::Call slowCall = m_jit.appendCall(slowCallFunction); - m_jit.addFastExceptionCheck(slowCall, codeOrigin, token); - m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister); - token = m_jit.beginCall(); - JITCompiler::Call theCall = m_jit.call(GPRInfo::returnValueGPR); - m_jit.notifyCall(theCall, codeOrigin, token); + if (calleeTagGPR == GPRInfo::nonArgGPR0) { + if (calleePayloadGPR == GPRInfo::nonArgGPR1) + m_jit.swap(GPRInfo::nonArgGPR1, GPRInfo::nonArgGPR0); + else { + m_jit.move(calleeTagGPR, GPRInfo::nonArgGPR1); + m_jit.move(calleePayloadGPR, GPRInfo::nonArgGPR0); + } + } else { + m_jit.move(calleePayloadGPR, GPRInfo::nonArgGPR0); + m_jit.move(calleeTagGPR, GPRInfo::nonArgGPR1); + } + m_jit.prepareForExceptionCheck(); + JITCompiler::Call slowCall = m_jit.nearCall(); + m_jit.notifyCall(slowCall, codeOrigin, token); done.link(&m_jit); @@ -2863,7 +2865,7 @@ void SpeculativeJIT::compile(Node& node) } case Branch: - if (isStrictInt32(node.child1().index()) || at(node.child1()).shouldSpeculateInteger()) { + if (at(node.child1()).shouldSpeculateInteger()) { SpeculateIntegerOperand op(this, node.child1()); BlockIndex taken = node.takenBlockIndex(); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp index 27eb28fa7..b5058e35a 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp @@ -953,14 +953,8 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeStrictEq(Node& node, bool invert) void SpeculativeJIT::emitCall(Node& node) { - P_DFGOperation_E slowCallFunction; - - if (node.op() == Call) - slowCallFunction = operationLinkCall; - else { + if (node.op() != Call) ASSERT(node.op() == Construct); - slowCallFunction = operationLinkConstruct; - } // For constructors, the this argument is not passed but we have to make space // for it. @@ -998,14 +992,16 @@ void SpeculativeJIT::emitCall(Node& node) JITCompiler::DataLabelPtr targetToCheck; JITCompiler::Jump slowPath; + CallBeginToken token; + m_jit.beginCall(node.codeOrigin, token); + + m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister); + slowPath = m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleeGPR, targetToCheck, MacroAssembler::TrustedImmPtr(JSValue::encode(JSValue()))); m_jit.loadPtr(MacroAssembler::Address(calleeGPR, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), resultGPR); - m_jit.storePtr(resultGPR, callFrameSlot(RegisterFile::ScopeChain)); + m_jit.storePtr(resultGPR, MacroAssembler::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ScopeChain)); - m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister); - CodeOrigin codeOrigin = at(m_compileIndex).codeOrigin; - CallBeginToken token = m_jit.beginCall(); JITCompiler::Call fastCall = m_jit.nearCall(); m_jit.notifyCall(fastCall, codeOrigin, token); @@ -1013,14 +1009,10 @@ void SpeculativeJIT::emitCall(Node& node) slowPath.link(&m_jit); - m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); - token = m_jit.beginCall(); - JITCompiler::Call slowCall = m_jit.appendCall(slowCallFunction); - m_jit.addFastExceptionCheck(slowCall, codeOrigin, token); - m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister); - token = m_jit.beginCall(); - JITCompiler::Call theCall = m_jit.call(GPRInfo::returnValueGPR); - m_jit.notifyCall(theCall, codeOrigin, token); + m_jit.move(calleeGPR, GPRInfo::nonArgGPR0); + m_jit.prepareForExceptionCheck(); + JITCompiler::Call slowCall = m_jit.nearCall(); + m_jit.notifyCall(slowCall, codeOrigin, token); done.link(&m_jit); @@ -2947,7 +2939,7 @@ void SpeculativeJIT::compile(Node& node) } case Branch: - if (isStrictInt32(node.child1().index()) || at(node.child1()).shouldSpeculateInteger()) { + if (at(node.child1()).shouldSpeculateInteger()) { SpeculateIntegerOperand op(this, node.child1()); BlockIndex taken = node.takenBlockIndex(); diff --git a/Source/JavaScriptCore/dfg/DFGThunks.cpp b/Source/JavaScriptCore/dfg/DFGThunks.cpp index 08ca6eaa1..b056de79c 100644 --- a/Source/JavaScriptCore/dfg/DFGThunks.cpp +++ b/Source/JavaScriptCore/dfg/DFGThunks.cpp @@ -28,6 +28,7 @@ #if ENABLE(DFG_JIT) +#include "DFGCCallHelpers.h" #include "DFGFPRInfo.h" #include "DFGGPRInfo.h" #include "DFGOSRExitCompiler.h" @@ -82,6 +83,217 @@ MacroAssemblerCodeRef osrExitGenerationThunkGenerator(JSGlobalData* globalData) return FINALIZE_CODE(patchBuffer, ("DFG OSR exit generation thunk")); } +inline void emitPointerValidation(CCallHelpers& jit, GPRReg pointerGPR) +{ +#if !ASSERT_DISABLED + CCallHelpers::Jump isNonZero = jit.branchTestPtr(CCallHelpers::NonZero, pointerGPR); + jit.breakpoint(); + isNonZero.link(&jit); + jit.push(pointerGPR); + jit.load8(pointerGPR, pointerGPR); + jit.pop(pointerGPR); +#else + UNUSED_PARAM(jit); + UNUSED_PARAM(pointerGPR); +#endif +} + +MacroAssemblerCodeRef throwExceptionFromCallSlowPathGenerator(JSGlobalData* globalData) +{ + CCallHelpers jit(globalData); + + // We will jump to here if the JIT code thinks it's making a call, but the + // linking helper (C++ code) decided to throw an exception instead. We will + // have saved the callReturnIndex in the first arguments of JITStackFrame. + // Note that the return address will be on the stack at this point, so we + // need to remove it and drop it on the floor, since we don't care about it. + // Finally note that the call frame register points at the callee frame, so + // we need to pop it. + jit.preserveReturnAddressAfterCall(GPRInfo::nonPreservedNonReturnGPR); + jit.loadPtr( + CCallHelpers::Address( + GPRInfo::callFrameRegister, + static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::CallerFrame), + GPRInfo::callFrameRegister); + jit.peek(GPRInfo::nonPreservedNonReturnGPR, JITSTACKFRAME_ARGS_INDEX); + jit.setupArgumentsWithExecState(GPRInfo::nonPreservedNonReturnGPR); + jit.move(CCallHelpers::TrustedImmPtr(bitwise_cast<void*>(lookupExceptionHandler)), GPRInfo::nonArgGPR0); + emitPointerValidation(jit, GPRInfo::nonArgGPR0); + jit.call(GPRInfo::nonArgGPR0); + emitPointerValidation(jit, GPRInfo::returnValueGPR2); + jit.jump(GPRInfo::returnValueGPR2); + + LinkBuffer patchBuffer(*globalData, &jit, GLOBAL_THUNK_ID); + return FINALIZE_CODE(patchBuffer, ("DFG throw exception from call slow path thunk")); +} + +static void slowPathFor( + CCallHelpers& jit, JSGlobalData* globalData, P_DFGOperation_E slowPathFunction) +{ + jit.preserveReturnAddressAfterCall(GPRInfo::nonArgGPR2); + emitPointerValidation(jit, GPRInfo::nonArgGPR2); + jit.storePtr( + GPRInfo::nonArgGPR2, + CCallHelpers::Address( + GPRInfo::callFrameRegister, + static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ReturnPC)); + jit.storePtr(GPRInfo::callFrameRegister, &globalData->topCallFrame); + jit.poke(GPRInfo::nonPreservedNonReturnGPR, JITSTACKFRAME_ARGS_INDEX); + jit.setupArgumentsExecState(); + jit.move(CCallHelpers::TrustedImmPtr(bitwise_cast<void*>(slowPathFunction)), GPRInfo::nonArgGPR0); + emitPointerValidation(jit, GPRInfo::nonArgGPR0); + jit.call(GPRInfo::nonArgGPR0); + + // This slow call will return the address of one of the following: + // 1) Exception throwing thunk. + // 2) Host call return value returner thingy. + // 3) The function to call. + jit.loadPtr( + CCallHelpers::Address( + GPRInfo::callFrameRegister, + static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ReturnPC), + GPRInfo::nonPreservedNonReturnGPR); + jit.storePtr( + CCallHelpers::TrustedImmPtr(0), + CCallHelpers::Address( + GPRInfo::callFrameRegister, + static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ReturnPC)); + emitPointerValidation(jit, GPRInfo::nonPreservedNonReturnGPR); + jit.restoreReturnAddressBeforeReturn(GPRInfo::nonPreservedNonReturnGPR); + emitPointerValidation(jit, GPRInfo::returnValueGPR); + jit.jump(GPRInfo::returnValueGPR); +} + +static MacroAssemblerCodeRef linkForThunkGenerator( + JSGlobalData* globalData, CodeSpecializationKind kind) +{ + // The return address is on the stack or in the link register. We will hence + // save the return address to the call frame while we make a C++ function call + // to perform linking and lazy compilation if necessary. We expect the callee + // to be in nonArgGPR0/nonArgGPR1 (payload/tag), the call frame to have already + // been adjusted, nonPreservedNonReturnGPR holds the exception handler index, + // and all other registers to be available for use. We use JITStackFrame::args + // to save important information across calls. + + CCallHelpers jit(globalData); + + slowPathFor(jit, globalData, kind == CodeForCall ? operationLinkCall : operationLinkConstruct); + + LinkBuffer patchBuffer(*globalData, &jit, GLOBAL_THUNK_ID); + return FINALIZE_CODE( + patchBuffer, + ("DFG link %s slow path thunk", kind == CodeForCall ? "call" : "construct")); +} + +MacroAssemblerCodeRef linkCallThunkGenerator(JSGlobalData* globalData) +{ + return linkForThunkGenerator(globalData, CodeForCall); +} + +MacroAssemblerCodeRef linkConstructThunkGenerator(JSGlobalData* globalData) +{ + return linkForThunkGenerator(globalData, CodeForConstruct); +} + +static MacroAssemblerCodeRef virtualForThunkGenerator( + JSGlobalData* globalData, CodeSpecializationKind kind) +{ + // The return address is on the stack, or in the link register. We will hence + // jump to the callee, or save the return address to the call frame while we + // make a C++ function call to the appropriate DFG operation. + + CCallHelpers jit(globalData); + + CCallHelpers::JumpList slowCase; + + // FIXME: we should have a story for eliminating these checks. In many cases, + // the DFG knows that the value is definitely a cell, or definitely a function. + +#if USE(JSVALUE64) + slowCase.append( + jit.branchTestPtr( + CCallHelpers::NonZero, GPRInfo::nonArgGPR0, GPRInfo::tagMaskRegister)); +#else + slowCase.append( + jit.branch32( + CCallHelpers::NotEqual, GPRInfo::nonArgGPR1, + CCallHelpers::TrustedImm32(JSValue::CellTag))); +#endif + slowCase.append( + jit.branchPtr( + CCallHelpers::NotEqual, + CCallHelpers::Address(GPRInfo::nonArgGPR0, JSCell::classInfoOffset()), + CCallHelpers::TrustedImmPtr(&JSFunction::s_info))); + + // Now we know we have a JSFunction. + + jit.loadPtr( + CCallHelpers::Address(GPRInfo::nonArgGPR0, JSFunction::offsetOfExecutable()), + GPRInfo::nonArgGPR2); + slowCase.append( + jit.branch32( + CCallHelpers::LessThan, + CCallHelpers::Address( + GPRInfo::nonArgGPR2, ExecutableBase::offsetOfNumParametersFor(kind)), + CCallHelpers::TrustedImm32(0))); + + // Now we know that we have a CodeBlock, and we're committed to making a fast + // call. + + jit.loadPtr( + CCallHelpers::Address(GPRInfo::nonArgGPR0, JSFunction::offsetOfScopeChain()), + GPRInfo::nonArgGPR1); +#if USE(JSVALUE64) + jit.storePtr( + GPRInfo::nonArgGPR1, + CCallHelpers::Address( + GPRInfo::callFrameRegister, + static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ScopeChain)); +#else + jit.storePtr( + GPRInfo::nonArgGPR1, + CCallHelpers::Address( + GPRInfo::callFrameRegister, + static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ScopeChain + + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload))); + jit.store32( + CCallHelpers::TrustedImm32(JSValue::CellTag), + CCallHelpers::Address( + GPRInfo::callFrameRegister, + static_cast<ptrdiff_t>(sizeof(Register)) * RegisterFile::ScopeChain + + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag))); +#endif + + jit.loadPtr( + CCallHelpers::Address(GPRInfo::nonArgGPR2, ExecutableBase::offsetOfJITCodeWithArityCheckFor(kind)), + GPRInfo::regT0); + + // Make a tail call. This will return back to DFG code. + emitPointerValidation(jit, GPRInfo::regT0); + jit.jump(GPRInfo::regT0); + + slowCase.link(&jit); + + // Here we don't know anything, so revert to the full slow path. + + slowPathFor(jit, globalData, kind == CodeForCall ? operationVirtualCall : operationVirtualConstruct); + + LinkBuffer patchBuffer(*globalData, &jit, GLOBAL_THUNK_ID); + return FINALIZE_CODE( + patchBuffer, + ("DFG virtual %s slow path thunk", kind == CodeForCall ? "call" : "construct")); +} + +MacroAssemblerCodeRef virtualCallThunkGenerator(JSGlobalData* globalData) +{ + return virtualForThunkGenerator(globalData, CodeForCall); +} + +MacroAssemblerCodeRef virtualConstructThunkGenerator(JSGlobalData* globalData) +{ + return virtualForThunkGenerator(globalData, CodeForConstruct); +} + } } // namespace JSC::DFG #endif // ENABLE(DFG_JIT) diff --git a/Source/JavaScriptCore/dfg/DFGThunks.h b/Source/JavaScriptCore/dfg/DFGThunks.h index 3db62442a..11a06d107 100644 --- a/Source/JavaScriptCore/dfg/DFGThunks.h +++ b/Source/JavaScriptCore/dfg/DFGThunks.h @@ -40,6 +40,14 @@ namespace DFG { MacroAssemblerCodeRef osrExitGenerationThunkGenerator(JSGlobalData*); +MacroAssemblerCodeRef throwExceptionFromCallSlowPathGenerator(JSGlobalData*); + +MacroAssemblerCodeRef linkCallThunkGenerator(JSGlobalData*); +MacroAssemblerCodeRef linkConstructThunkGenerator(JSGlobalData*); + +MacroAssemblerCodeRef virtualCallThunkGenerator(JSGlobalData*); +MacroAssemblerCodeRef virtualConstructThunkGenerator(JSGlobalData*); + } } // namespace JSC::DFG #endif // ENABLE(DFG_JIT) diff --git a/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp b/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp index 5d548a755..a1152bc2b 100644 --- a/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp +++ b/Source/JavaScriptCore/dfg/DFGVariableEventStream.cpp @@ -102,6 +102,10 @@ void VariableEventStream::reconstruct( while (at(startIndex).kind() != Reset) startIndex--; +#if DFG_ENABLE(DEBUG_VERBOSE) + dataLog("Computing OSR exit recoveries starting at seq#%u.\n", startIndex); +#endif + // Step 2: Create a mock-up of the DFG's state and execute the events. Operands<ValueSource> operandSources(codeBlock->numParameters(), numVariables); Vector<MinifiedGenerationInfo, 32> generationInfos(graph.originalGraphSize()); diff --git a/Source/JavaScriptCore/heap/HeapTimer.cpp b/Source/JavaScriptCore/heap/HeapTimer.cpp index ae66f9e26..fa979781e 100644 --- a/Source/JavaScriptCore/heap/HeapTimer.cpp +++ b/Source/JavaScriptCore/heap/HeapTimer.cpp @@ -98,8 +98,38 @@ void HeapTimer::timerDidFire(CFRunLoopTimerRef, void* info) agent->m_shutdownMutex.unlock(); } +#elif PLATFORM(BLACKBERRY) + +HeapTimer::HeapTimer(JSGlobalData* globalData) + : m_globalData(globalData) + , m_timer(this, &HeapTimer::timerDidFire) +{ +} + +HeapTimer::~HeapTimer() +{ +} + +void HeapTimer::timerDidFire() +{ + doWork(); +} + +void HeapTimer::synchronize() +{ +} + +void HeapTimer::invalidate() +{ +} + +void HeapTimer::didStartVMShutdown() +{ + delete this; +} + #else - + HeapTimer::HeapTimer(JSGlobalData* globalData) : m_globalData(globalData) { diff --git a/Source/JavaScriptCore/heap/HeapTimer.h b/Source/JavaScriptCore/heap/HeapTimer.h index 9255e0648..88715098a 100644 --- a/Source/JavaScriptCore/heap/HeapTimer.h +++ b/Source/JavaScriptCore/heap/HeapTimer.h @@ -31,6 +31,8 @@ #if USE(CF) #include <CoreFoundation/CoreFoundation.h> +#elif PLATFORM(BLACKBERRY) +#include <BlackBerryPlatformTimer.h> #endif namespace JSC { @@ -63,6 +65,10 @@ protected: CFRunLoopTimerContext m_context; Mutex m_shutdownMutex; +#elif PLATFORM(BLACKBERRY) + void timerDidFire(); + + BlackBerry::Platform::Timer<HeapTimer> m_timer; #endif private: diff --git a/Source/JavaScriptCore/heap/MachineStackMarker.cpp b/Source/JavaScriptCore/heap/MachineStackMarker.cpp index 8e0c57b6a..7eb57479b 100644 --- a/Source/JavaScriptCore/heap/MachineStackMarker.cpp +++ b/Source/JavaScriptCore/heap/MachineStackMarker.cpp @@ -141,8 +141,10 @@ MachineThreads::MachineThreads(Heap* heap) MachineThreads::~MachineThreads() { - if (m_threadSpecific) - ThreadSpecificKeyDelete(m_threadSpecific); + if (m_threadSpecific) { + int error = pthread_key_delete(m_threadSpecific); + ASSERT_UNUSED(error, !error); + } MutexLocker registeredThreadsLock(m_registeredThreadsMutex); for (Thread* t = m_registeredThreads; t;) { @@ -179,17 +181,19 @@ void MachineThreads::makeUsableFromMultipleThreads() if (m_threadSpecific) return; - ThreadSpecificKeyCreate(&m_threadSpecific, removeThread); + int error = pthread_key_create(&m_threadSpecific, removeThread); + if (error) + CRASH(); } void MachineThreads::addCurrentThread() { ASSERT(!m_heap->globalData()->exclusiveThread || m_heap->globalData()->exclusiveThread == currentThread()); - if (!m_threadSpecific || ThreadSpecificGet(m_threadSpecific)) + if (!m_threadSpecific || pthread_getspecific(m_threadSpecific)) return; - ThreadSpecificSet(m_threadSpecific, this); + pthread_setspecific(m_threadSpecific, this); Thread* thread = new Thread(getCurrentPlatformThread(), wtfThreadData().stack().origin()); MutexLocker lock(m_registeredThreadsMutex); diff --git a/Source/JavaScriptCore/heap/MachineStackMarker.h b/Source/JavaScriptCore/heap/MachineStackMarker.h index 3d4aa22d4..5c7705fcf 100644 --- a/Source/JavaScriptCore/heap/MachineStackMarker.h +++ b/Source/JavaScriptCore/heap/MachineStackMarker.h @@ -22,8 +22,8 @@ #ifndef MachineThreads_h #define MachineThreads_h +#include <pthread.h> #include <wtf/Noncopyable.h> -#include <wtf/ThreadSpecific.h> #include <wtf/ThreadingPrimitives.h> namespace JSC { @@ -55,7 +55,7 @@ namespace JSC { Heap* m_heap; Mutex m_registeredThreadsMutex; Thread* m_registeredThreads; - WTF::ThreadSpecificKey m_threadSpecific; + pthread_key_t m_threadSpecific; }; } // namespace JSC diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp index 285355f1b..52a7158e6 100644 --- a/Source/JavaScriptCore/jit/JIT.cpp +++ b/Source/JavaScriptCore/jit/JIT.cpp @@ -739,7 +739,7 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck, JITCompilationEffo CallLinkInfo& info = m_codeBlock->callLinkInfo(i); info.callType = m_callStructureStubCompilationInfo[i].callType; info.bytecodeIndex = m_callStructureStubCompilationInfo[i].bytecodeIndex; - info.callReturnLocation = CodeLocationLabel(patchBuffer.locationOfNearCall(m_callStructureStubCompilationInfo[i].callReturnLocation)); + info.callReturnLocation = patchBuffer.locationOfNearCall(m_callStructureStubCompilationInfo[i].callReturnLocation); info.hotPathBegin = patchBuffer.locationOf(m_callStructureStubCompilationInfo[i].hotPathBegin); info.hotPathOther = patchBuffer.locationOfNearCall(m_callStructureStubCompilationInfo[i].hotPathOther); } @@ -802,12 +802,12 @@ void JIT::linkFor(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* cal // Patch the slow patch so we do not continue to try to link. if (kind == CodeForCall) { - repatchBuffer.relink(CodeLocationNearCall(callLinkInfo->callReturnLocation), globalData->jitStubs->ctiVirtualCall()); + repatchBuffer.relink(callLinkInfo->callReturnLocation, globalData->jitStubs->ctiVirtualCall()); return; } ASSERT(kind == CodeForConstruct); - repatchBuffer.relink(CodeLocationNearCall(callLinkInfo->callReturnLocation), globalData->jitStubs->ctiVirtualConstruct()); + repatchBuffer.relink(callLinkInfo->callReturnLocation, globalData->jitStubs->ctiVirtualConstruct()); } } // namespace JSC diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp index 2273f0f38..bfc4709bc 100644 --- a/Source/JavaScriptCore/jit/JITStubs.cpp +++ b/Source/JavaScriptCore/jit/JITStubs.cpp @@ -740,17 +740,20 @@ __asm EncodedJSValue ctiTrampoline(void*, RegisterFile*, CallFrame*, void* /*unu { ARM stmdb sp!, {r1-r3} - stmdb sp!, {r4-r8, lr} + stmdb sp!, {r4-r6, r8-r11, lr} sub sp, sp, # PRESERVEDR4_OFFSET - mov r4, r2 - mov r5, #512 + mov r5, r2 + mov r6, #512 mov lr, pc bx r0 add sp, sp, # PRESERVEDR4_OFFSET - ldmia sp!, {r4-r8, lr} + ldmia sp!, {r4-r6, r8-r11, lr} add sp, sp, #12 bx lr } +__asm void ctiTrampolineEnd() +{ +} __asm void ctiVMThrowTrampoline() { @@ -759,7 +762,7 @@ __asm void ctiVMThrowTrampoline() mov r0, sp bl cti_vm_throw add sp, sp, # PRESERVEDR4_OFFSET - ldmia sp!, {r4-r8, lr} + ldmia sp!, {r4-r6, r8-r11, lr} add sp, sp, #12 bx lr } @@ -1212,31 +1215,32 @@ RVCT() MSVC_BEGIN( AREA Trampoline, CODE) MSVC_BEGIN() MSVC_BEGIN( EXPORT ctiTrampoline) +MSVC_BEGIN( EXPORT ctiTrampolineEnd) MSVC_BEGIN( EXPORT ctiVMThrowTrampoline) MSVC_BEGIN( EXPORT ctiOpThrowNotCaught) MSVC_BEGIN() MSVC_BEGIN(ctiTrampoline PROC) MSVC_BEGIN( stmdb sp!, {r1-r3}) -MSVC_BEGIN( stmdb sp!, {r4-r8, lr}) +MSVC_BEGIN( stmdb sp!, {r4-r6, r8-r11, lr}) MSVC_BEGIN( sub sp, sp, #68 ; sync with PRESERVEDR4_OFFSET) -MSVC_BEGIN( mov r4, r2) -MSVC_BEGIN( mov r5, #512) +MSVC_BEGIN( mov r5, r2) +MSVC_BEGIN( mov r6, #512) MSVC_BEGIN( ; r0 contains the code) MSVC_BEGIN( mov lr, pc) MSVC_BEGIN( bx r0) MSVC_BEGIN( add sp, sp, #68 ; sync with PRESERVEDR4_OFFSET) -MSVC_BEGIN( ldmia sp!, {r4-r8, lr}) +MSVC_BEGIN( ldmia sp!, {r4-r6, r8-r11, lr}) MSVC_BEGIN( add sp, sp, #12) MSVC_BEGIN( bx lr) +MSVC_BEGIN(ctiTrampolineEnd) MSVC_BEGIN(ctiTrampoline ENDP) MSVC_BEGIN() MSVC_BEGIN(ctiVMThrowTrampoline PROC) MSVC_BEGIN( mov r0, sp) -MSVC_BEGIN( mov lr, pc) MSVC_BEGIN( bl cti_vm_throw) MSVC_BEGIN(ctiOpThrowNotCaught) MSVC_BEGIN( add sp, sp, #68 ; sync with PRESERVEDR4_OFFSET) -MSVC_BEGIN( ldmia sp!, {r4-r8, lr}) +MSVC_BEGIN( ldmia sp!, {r4-r6, r8-r11, lr}) MSVC_BEGIN( add sp, sp, #12) MSVC_BEGIN( bx lr) MSVC_BEGIN(ctiVMThrowTrampoline ENDP) diff --git a/Source/JavaScriptCore/jit/JumpReplacementWatchpoint.cpp b/Source/JavaScriptCore/jit/JumpReplacementWatchpoint.cpp new file mode 100644 index 000000000..725108dd5 --- /dev/null +++ b/Source/JavaScriptCore/jit/JumpReplacementWatchpoint.cpp @@ -0,0 +1,56 @@ +/* + * 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 "JumpReplacementWatchpoint.h" + +#if ENABLE(JIT) + +#include "LinkBuffer.h" + +namespace JSC { + +void JumpReplacementWatchpoint::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()); +} + +void JumpReplacementWatchpoint::fireInternal() +{ + MacroAssembler::replaceWithJump( + CodeLocationLabel(bitwise_cast<void*>(m_source)), + CodeLocationLabel(bitwise_cast<void*>(m_destination))); + if (isOnList()) + remove(); +} + +} // namespace JSC + +#endif // ENABLE(JIT) + diff --git a/Source/JavaScriptCore/jit/JumpReplacementWatchpoint.h b/Source/JavaScriptCore/jit/JumpReplacementWatchpoint.h new file mode 100644 index 000000000..b4f35c724 --- /dev/null +++ b/Source/JavaScriptCore/jit/JumpReplacementWatchpoint.h @@ -0,0 +1,73 @@ +/* + * 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 JumpReplacementWatchpoint_h +#define JumpReplacementWatchpoint_h + +#include "Watchpoint.h" +#include <wtf/Platform.h> + +#if ENABLE(JIT) + +#include "CodeLocation.h" +#include "MacroAssembler.h" + +namespace JSC { + +class JumpReplacementWatchpoint : public Watchpoint { +public: + JumpReplacementWatchpoint() + : m_source(std::numeric_limits<uintptr_t>::max()) + , m_destination(std::numeric_limits<uintptr_t>::max()) + { + } + + JumpReplacementWatchpoint(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&); + +protected: + void fireInternal(); + +private: + uintptr_t m_source; + uintptr_t m_destination; +}; + +} // namespace JSC + +#endif // ENABLE(JIT) + +#endif // JumpReplacementWatchpoint_h + diff --git a/Source/JavaScriptCore/jsc.cpp b/Source/JavaScriptCore/jsc.cpp index 43337e4ee..5f3dbdb99 100644 --- a/Source/JavaScriptCore/jsc.cpp +++ b/Source/JavaScriptCore/jsc.cpp @@ -113,19 +113,23 @@ struct Script { } }; -struct CommandLine { - CommandLine() - : interactive(false) - , dump(false) - , exitCode(false) +class CommandLine { +public: + CommandLine(int argc, char** argv) + : m_interactive(false) + , m_dump(false) + , m_exitCode(false) { + parseArguments(argc, argv); } - bool interactive; - bool dump; - bool exitCode; - Vector<Script> scripts; - Vector<UString> arguments; + bool m_interactive; + bool m_dump; + bool m_exitCode; + Vector<Script> m_scripts; + Vector<UString> m_arguments; + + void parseArguments(int, char**); }; static const char interactivePrompt[] = "> "; @@ -623,7 +627,7 @@ static NO_RETURN void printUsageStatement(bool help = false) exit(help ? EXIT_SUCCESS : EXIT_FAILURE); } -static void parseArguments(int argc, char** argv, CommandLine& options) +void CommandLine::parseArguments(int argc, char** argv) { int i = 1; bool needToDumpOptions = false; @@ -634,21 +638,21 @@ static void parseArguments(int argc, char** argv, CommandLine& options) if (!strcmp(arg, "-f")) { if (++i == argc) printUsageStatement(); - options.scripts.append(Script(true, argv[i])); + m_scripts.append(Script(true, argv[i])); continue; } if (!strcmp(arg, "-e")) { if (++i == argc) printUsageStatement(); - options.scripts.append(Script(false, argv[i])); + m_scripts.append(Script(false, argv[i])); continue; } if (!strcmp(arg, "-i")) { - options.interactive = true; + m_interactive = true; continue; } if (!strcmp(arg, "-d")) { - options.dump = true; + m_dump = true; continue; } if (!strcmp(arg, "-s")) { @@ -661,7 +665,7 @@ static void parseArguments(int argc, char** argv, CommandLine& options) continue; } if (!strcmp(arg, "-x")) { - options.exitCode = true; + m_exitCode = true; continue; } if (!strcmp(arg, "--")) { @@ -690,14 +694,14 @@ static void parseArguments(int argc, char** argv, CommandLine& options) // This arg is not recognized by the VM nor by jsc. Pass it on to the // script. - options.scripts.append(Script(true, argv[i])); + m_scripts.append(Script(true, argv[i])); } - if (options.scripts.isEmpty()) - options.interactive = true; + if (m_scripts.isEmpty()) + m_interactive = true; for (; i < argc; ++i) - options.arguments.append(argv[i]); + m_arguments.append(argv[i]); if (needToDumpOptions) JSC::Options::dumpAllOptions(stderr); @@ -707,21 +711,21 @@ static void parseArguments(int argc, char** argv, CommandLine& options) int jscmain(int argc, char** argv) { + // Note that the options parsing can affect JSGlobalData creation, and thus + // comes first. + CommandLine options(argc, argv); RefPtr<JSGlobalData> globalData = JSGlobalData::create(ThreadStackTypeLarge, LargeHeap); JSLockHolder lock(globalData.get()); int result; - CommandLine options; - parseArguments(argc, argv, options); - - GlobalObject* globalObject = GlobalObject::create(*globalData, GlobalObject::createStructure(*globalData, jsNull()), options.arguments); - bool success = runWithScripts(globalObject, options.scripts, options.dump); - if (options.interactive && success) + GlobalObject* globalObject = GlobalObject::create(*globalData, GlobalObject::createStructure(*globalData, jsNull()), options.m_arguments); + bool success = runWithScripts(globalObject, options.m_scripts, options.m_dump); + if (options.m_interactive && success) runInteractive(globalObject); result = success ? 0 : 3; - if (options.exitCode) + if (options.m_exitCode) printf("jsc exiting %d\n", result); return result; diff --git a/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h b/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h index 7720f5ec2..9a1539576 100644 --- a/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h +++ b/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h @@ -91,6 +91,10 @@ #define OFFLINE_ASM_VALUE_PROFILER 0 #endif +// These are for building an interpreter from generated assembly code: +#define OFFLINE_ASM_BEGIN asm ( +#define OFFLINE_ASM_END ); + #if CPU(ARM_THUMB2) #define OFFLINE_ASM_GLOBAL_LABEL(label) \ ".globl " SYMBOL_STRING(label) "\n" \ @@ -105,4 +109,6 @@ SYMBOL_STRING(label) ":\n" #endif +#define OFFLINE_ASM_LOCAL_LABEL(label) LOCAL_LABEL_STRING(label) ":\n" + #endif // LLIntOfflineAsmConfig_h diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm index 9d6304de7..513b742ee 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm @@ -301,8 +301,8 @@ end _llint_op_enter: traceExecution() - loadp CodeBlock[cfr], t2 - loadi CodeBlock::m_numVars[t2], t2 + loadp CodeBlock[cfr], t2 // t2<CodeBlock> = cfr.CodeBlock + loadi CodeBlock::m_numVars[t2], t2 // t2<size_t> = t2<CodeBlock>.m_numVars btiz t2, .opEnterDone move UndefinedTag, t0 move 0, t1 diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm index a7a2ce88f..b976421f0 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm @@ -182,8 +182,8 @@ end _llint_op_enter: traceExecution() - loadp CodeBlock[cfr], t2 - loadi CodeBlock::m_numVars[t2], t2 + loadp CodeBlock[cfr], t2 // t2<CodeBlock> = cfr.CodeBlock + loadi CodeBlock::m_numVars[t2], t2 // t2<size_t> = t2<CodeBlock>.m_numVars btiz t2, .opEnterDone move ValueUndefined, t0 .opEnterLoop: diff --git a/Source/JavaScriptCore/offlineasm/armv7.rb b/Source/JavaScriptCore/offlineasm/armv7.rb index 69df51a45..18538120b 100644 --- a/Source/JavaScriptCore/offlineasm/armv7.rb +++ b/Source/JavaScriptCore/offlineasm/armv7.rb @@ -21,6 +21,7 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # THE POSSIBILITY OF SUCH DAMAGE. +require "config" require "ast" require "opt" @@ -147,6 +148,7 @@ def armV7LowerBranchOps(list) list.each { | node | if node.is_a? Instruction + annotation = node.annotation case node.opcode when /^b(addi|subi|ori|addp)/ op = $1 @@ -161,17 +163,17 @@ def armV7LowerBranchOps(list) op = "oris" end - newList << Instruction.new(node.codeOrigin, op, node.operands[0..-2]) + newList << Instruction.new(node.codeOrigin, op, node.operands[0..-2], annotation) newList << Instruction.new(node.codeOrigin, branch, [node.operands[-1]]) when "bmulio" tmp1 = Tmp.new(node.codeOrigin, :gpr) tmp2 = Tmp.new(node.codeOrigin, :gpr) - newList << Instruction.new(node.codeOrigin, "smulli", [node.operands[0], node.operands[1], node.operands[1], tmp1]) + newList << Instruction.new(node.codeOrigin, "smulli", [node.operands[0], node.operands[1], node.operands[1], tmp1], annotation) newList << Instruction.new(node.codeOrigin, "rshifti", [node.operands[-2], Immediate.new(node.codeOrigin, 31), tmp2]) newList << Instruction.new(node.codeOrigin, "bineq", [tmp1, tmp2, node.operands[-1]]) when /^bmuli/ condition = $~.post_match - newList << Instruction.new(node.codeOrigin, "muli", node.operands[0..-2]) + newList << Instruction.new(node.codeOrigin, "muli", node.operands[0..-2], annotation) newList << Instruction.new(node.codeOrigin, "bti" + condition, [node.operands[-2], node.operands[-1]]) else newList << node @@ -210,9 +212,9 @@ def armV7LowerShiftOps(list) case node.opcode when "lshifti", "rshifti", "urshifti", "lshiftp", "rshiftp", "urshiftp" if node.operands.size == 2 - newList << Instruction.new(node.codeOrigin, node.opcode, [armV7SanitizeShift(node.operands[0], newList), node.operands[1]]) + newList << Instruction.new(node.codeOrigin, node.opcode, [armV7SanitizeShift(node.operands[0], newList), node.operands[1]], node.annotation) else - newList << Instruction.new(node.codeOrigin, node.opcode, [node.operands[0], armV7SanitizeShift(node.operands[1], newList), node.operands[2]]) + newList << Instruction.new(node.codeOrigin, node.opcode, [node.operands[0], armV7SanitizeShift(node.operands[1], newList), node.operands[2]], node.annotation) raise "Wrong number of operands for shift at #{node.codeOriginString}" unless node.operands.size == 3 end else @@ -321,9 +323,9 @@ def armV7LowerMalformedAddressesDouble(list) if node.is_a? Instruction case node.opcode when "loadd" - newList << Instruction.new(node.codeOrigin, "loadd", [node.operands[0].armV7DoubleAddress(newList), node.operands[1]]) + newList << Instruction.new(node.codeOrigin, "loadd", [node.operands[0].armV7DoubleAddress(newList), node.operands[1]], node.annotation) when "stored" - newList << Instruction.new(node.codeOrigin, "stored", [node.operands[0], node.operands[1].armV7DoubleAddress(newList)]) + newList << Instruction.new(node.codeOrigin, "stored", [node.operands[0], node.operands[1].armV7DoubleAddress(newList)], node.annotation) else newList << node end @@ -364,7 +366,7 @@ def armV7LowerMisplacedImmediates(list) newOperands << operand end } - newList << Instruction.new(node.codeOrigin, node.opcode, newOperands) + newList << Instruction.new(node.codeOrigin, node.opcode, newOperands, node.annotation) else newList << node end @@ -431,6 +433,7 @@ def armV7LowerMalformedImmediates(list) list.each { | node | if node.is_a? Instruction + annotation = node.annotation case node.opcode when "move" newList << node @@ -445,14 +448,15 @@ def armV7LowerMalformedImmediates(list) newOpcode = "add" + node.opcode[-1..-1] end newList << Instruction.new(node.codeOrigin, newOpcode, - [Immediate.new(-node.operands[0].value)] + node.operands[1..-1]) + [Immediate.new(-node.operands[0].value)] + node.operands[1..-1], + annotation) else newList << node.armV7LowerMalformedImmediatesRecurse(newList) end when "muli", "mulp" if node.operands[0].is_a? Immediate tmp = Tmp.new(codeOrigin, :gpr) - newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp]) + newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp], annotation) newList << Instruction.new(node.codeOrigin, "muli", [tmp] + node.operands[1..-1]) else newList << node.armV7LowerMalformedImmediatesRecurse(newList) @@ -514,30 +518,36 @@ def armV7LowerMisplacedAddresses(list) | node | if node.is_a? Instruction postInstructions = [] + annotation = node.annotation case node.opcode when "addi", "addp", "addis", "andi", "andp", "lshifti", "lshiftp", "muli", "mulp", "negi", "negp", "noti", "ori", "oris", "orp", "rshifti", "urshifti", "rshiftp", "urshiftp", "subi", "subp", "subis", "xori", "xorp", /^bi/, /^bp/, /^bti/, /^btp/, /^ci/, /^cp/, /^ti/ newList << Instruction.new(node.codeOrigin, node.opcode, - armV7AsRegisters(newList, postInstructions, node.operands, "i")) + armV7AsRegisters(newList, postInstructions, node.operands, "i"), + annotation) when "bbeq", "bbneq", "bba", "bbaeq", "bbb", "bbbeq", "btbo", "btbz", "btbnz", "tbz", "tbnz", "tbo", "cbeq", "cbneq", "cba", "cbaeq", "cbb", "cbbeq" newList << Instruction.new(node.codeOrigin, node.opcode, - armV7AsRegisters(newList, postInstructions, node.operands, "b")) + armV7AsRegisters(newList, postInstructions, node.operands, "b"), + annotation) when "bbgt", "bbgteq", "bblt", "bblteq", "btbs", "tbs", "cbgt", "cbgteq", "cblt", "cblteq" newList << Instruction.new(node.codeOrigin, node.opcode, - armV7AsRegisters(newList, postInstructions, node.operands, "bs")) + armV7AsRegisters(newList, postInstructions, node.operands, "bs"), + annotation) when "addd", "divd", "subd", "muld", "sqrtd", /^bd/ newList << Instruction.new(node.codeOrigin, node.opcode, - armV7AsRegisters(newList, postInstructions, node.operands, "d")) + armV7AsRegisters(newList, postInstructions, node.operands, "d"), + annotation) when "jmp", "call" newList << Instruction.new(node.codeOrigin, node.opcode, - [armV7AsRegister(newList, postInstructions, node.operands[0], "p", false)]) + [armV7AsRegister(newList, postInstructions, node.operands[0], "p", false)], + annotation) else newList << node end @@ -565,6 +575,7 @@ def armV7LowerRegisterReuse(list) list.each { | node | if node.is_a? Instruction + annotation = node.annotation case node.opcode when "cieq", "cineq", "cia", "ciaeq", "cib", "cibeq", "cigt", "cigteq", "cilt", "cilteq", "cpeq", "cpneq", "cpa", "cpaeq", "cpb", "cpbeq", "cpgt", "cpgteq", "cplt", "cplteq", @@ -573,7 +584,7 @@ def armV7LowerRegisterReuse(list) if node.operands.size == 2 if node.operands[0] == node.operands[1] tmp = Tmp.new(node.codeOrigin, :gpr) - newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp]) + newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp], annotation) newList << Instruction.new(node.codeOrigin, node.opcode, [tmp, node.operands[1]]) else newList << node @@ -582,11 +593,11 @@ def armV7LowerRegisterReuse(list) raise "Wrong number of arguments at #{node.codeOriginString}" unless node.operands.size == 3 if node.operands[0] == node.operands[2] tmp = Tmp.new(node.codeOrigin, :gpr) - newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp]) + newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp], annotation) newList << Instruction.new(node.codeOrigin, node.opcode, [tmp, node.operands[1], node.operands[2]]) elsif node.operands[1] == node.operands[2] tmp = Tmp.new(node.codeOrigin, :gpr) - newList << Instruction.new(node.codeOrigin, "move", [node.operands[1], tmp]) + newList << Instruction.new(node.codeOrigin, "move", [node.operands[1], tmp], annotation) newList << Instruction.new(node.codeOrigin, node.opcode, [node.operands[0], tmp, node.operands[2]]) else newList << node @@ -732,7 +743,9 @@ end class Instruction def lowerARMv7 - $asm.comment codeOriginString + $asm.codeOrigin codeOriginString + $asm.annotation annotation + case opcode when "addi", "addp", "addis" if opcode == "addis" diff --git a/Source/JavaScriptCore/offlineasm/asm.rb b/Source/JavaScriptCore/offlineasm/asm.rb index 50f9bc886..0cf6320af 100644 --- a/Source/JavaScriptCore/offlineasm/asm.rb +++ b/Source/JavaScriptCore/offlineasm/asm.rb @@ -25,6 +25,7 @@ $: << File.dirname(__FILE__) +require "config" require "backends" require "digest/sha1" require "offsets" @@ -39,16 +40,21 @@ class Assembler @state = :cpp @commentState = :none @comment = nil + @internalComment = nil + @annotation = nil + @codeOrigin = nil + @numLocalLabels = 0 + @numGlobalLabels = 0 end def enterAsm - @outp.puts "asm (" + @outp.puts "OFFLINE_ASM_BEGIN" @state = :asm end def leaveAsm putsLastComment - @outp.puts ");" + @outp.puts "OFFLINE_ASM_END" @state = :cpp end @@ -58,17 +64,35 @@ class Assembler leaveAsm end + # Concatenates all the various components of the comment to dump. def lastComment - if @comment - result = "// #{@comment}" - else - result = "" + result = "" + result = " #{@comment} ." if @comment + result += " #{@annotation} ." if @annotation and $enableTrailingInstrAnnotations + result += " #{@internalComment} ." if @internalComment + result += " #{@codeOrigin} ." if @codeOrigin and $enableCodeOriginComments + if result != "" + result = " //" + result end + + # Reset all the components that we've just sent to be dumped. @commentState = :none @comment = nil + @internalComment = nil + @annotation = nil + @codeOrigin = nil result end + # Dumps the current instruction annotation in interlaced mode if appropriate. + def putInterlacedAnnotation() + raise unless @state == :asm + if $enableInterlacedInstrAnnotations + @outp.puts(" // #{@annotation}") if @annotation + @annotation = nil + end + end + def putsLastComment comment = lastComment unless comment.empty? @@ -78,7 +102,8 @@ class Assembler def puts(*line) raise unless @state == :asm - @outp.puts("\"\\t" + line.join('') + "\\n\" #{lastComment}") + putInterlacedAnnotation + @outp.puts(" \"\\t" + line.join('') + "\\n\"#{lastComment}") end def print(line) @@ -88,12 +113,18 @@ class Assembler def putsLabel(labelName) raise unless @state == :asm - @outp.puts("OFFLINE_ASM_GLOBAL_LABEL(#{labelName}) #{lastComment}") + @numGlobalLabels += 1 + @outp.puts("\n") + @internalComment = $enableLabelCountComments ? "Global Label #{@numGlobalLabels}" : nil + @outp.puts("OFFLINE_ASM_GLOBAL_LABEL(#{labelName})#{lastComment}") end def putsLocalLabel(labelName) raise unless @state == :asm - @outp.puts("LOCAL_LABEL_STRING(#{labelName}) \":\\n\" #{lastComment}") + @numLocalLabels += 1 + @outp.puts("\n") + @internalComment = $enableLabelCountComments ? "Local Label #{@numLocalLabels}" : nil + @outp.puts("OFFLINE_ASM_LOCAL_LABEL(#{labelName})#{lastComment}") end def self.labelReference(labelName) @@ -104,22 +135,31 @@ class Assembler "\" LOCAL_LABEL_STRING(#{labelName}) \"" end - def comment(text) + def codeOrigin(text) case @commentState when :none - @comment = text + @codeOrigin = text @commentState = :one when :one - @outp.puts "// #{@comment}" - @outp.puts "// #{text}" - @comment = nil + if $enableCodeOriginComments + @outp.puts " // #{@codeOrigin}" + @outp.puts " // #{text}" + end + @codeOrigin = nil @commentState = :many when :many - @outp.puts "// #{text}" + @outp.puts "// #{text}" if $enableCodeOriginComments else raise end end + + def comment(text) + @comment = text + end + def annotation(text) + @annotation = text + end end asmFile = ARGV.shift diff --git a/Source/JavaScriptCore/offlineasm/ast.rb b/Source/JavaScriptCore/offlineasm/ast.rb index e555b5d98..86ad6bcb2 100644 --- a/Source/JavaScriptCore/offlineasm/ast.rb +++ b/Source/JavaScriptCore/offlineasm/ast.rb @@ -21,6 +21,8 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # THE POSSIBILITY OF SUCH DAMAGE. +require "config" + # # Base utility types for the AST. # @@ -784,12 +786,13 @@ class AbsoluteAddress < NoChildren end class Instruction < Node - attr_reader :opcode, :operands + attr_reader :opcode, :operands, :annotation - def initialize(codeOrigin, opcode, operands) + def initialize(codeOrigin, opcode, operands, annotation=nil) super(codeOrigin) @opcode = opcode @operands = operands + @annotation = annotation end def children @@ -797,7 +800,7 @@ class Instruction < Node end def mapChildren(&proc) - Instruction.new(codeOrigin, @opcode, @operands.map(&proc)) + Instruction.new(codeOrigin, @opcode, @operands.map(&proc), @annotation) end def dump diff --git a/Source/JavaScriptCore/offlineasm/backends.rb b/Source/JavaScriptCore/offlineasm/backends.rb index db7a1e218..e33a2a083 100644 --- a/Source/JavaScriptCore/offlineasm/backends.rb +++ b/Source/JavaScriptCore/offlineasm/backends.rb @@ -21,6 +21,7 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # THE POSSIBILITY OF SUCH DAMAGE. +require "config" require "armv7" require "ast" require "x86" diff --git a/Source/JavaScriptCore/offlineasm/config.rb b/Source/JavaScriptCore/offlineasm/config.rb new file mode 100644 index 000000000..ce1898170 --- /dev/null +++ b/Source/JavaScriptCore/offlineasm/config.rb @@ -0,0 +1,76 @@ +# 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. 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 INC. 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. + + +# Turns on dumping of the count of labels. +# For example, the output will look like this: +# +# ... +# OFFLINE_ASM_LOCAL_LABEL(_offlineasm_4_functionArityCheck__continue) // Local Label 24 . +# ... +# OFFLINE_ASM_GLOBAL_LABEL(llint_op_enter) // Global Label 8 . +# ... +# +$enableLabelCountComments = false + +# Turns on dumping of source file and line numbers in the output file. +# For example, the output will look like this: +# +# ... +# "\tmovq -8(%r13), %rcx\n" // JavaScriptCore/llint/LowLevelInterpreter64.asm:185 +# "\tmovl 52(%rcx), %ecx\n" // JavaScriptCore/llint/LowLevelInterpreter64.asm:186 +# ... +# +$enableCodeOriginComments = true + +# Turns on recording and dumping of annotations in the generated output file. +# An annotations can be specified for each instruction in the source asm files. +# +# $enableInterlacedInstrAnnotations will interlace the annotation between +# instructions. For example, the output will look like this: +# +# ... +# // @ t2<CodeBlock> = cfr.CodeBlock +# "\tmovq -8(%r13), %rcx\n" +# // @ t2<size_t> = t2<CodeBlock>.m_numVars +# "\tmovl 52(%rcx), %ecx\n" +# ... +# +# $enableTrailingInstrAnnotations will insert the annotation in the trailing +# comment after your instructions. For example, the output will look like this: +# +# ... +# "\tmovq -8(%r13), %rcx\n" // @ t2<CodeBlock> = cfr.CodeBlock +# "\tmovl 52(%rcx), %ecx\n" // @ t2<size_t> = t2<CodeBlock>.m_numVars +# ... +# +# If both $enableInterlacedInstrAnnotations and $enableTrailingInstrAnnotations +# are enabled, interlaced annotations will take precedence, and any available +# annotations will only be dumped in the interlaced format. +# +$enableInterlacedInstrAnnotations = false +$enableTrailingInstrAnnotations = false + + +# Sanity check for annotation configs. +$enableInstrAnnotations = ($enableInterlacedInstrAnnotations or $enableTrailingInstrAnnotations) diff --git a/Source/JavaScriptCore/offlineasm/generate_offset_extractor.rb b/Source/JavaScriptCore/offlineasm/generate_offset_extractor.rb index b2a8c2c83..fefbb1290 100644 --- a/Source/JavaScriptCore/offlineasm/generate_offset_extractor.rb +++ b/Source/JavaScriptCore/offlineasm/generate_offset_extractor.rb @@ -25,6 +25,7 @@ $: << File.dirname(__FILE__) +require "config" require "backends" require "digest/sha1" require "offsets" diff --git a/Source/JavaScriptCore/offlineasm/instructions.rb b/Source/JavaScriptCore/offlineasm/instructions.rb index 67cec6d96..aa1a32393 100644 --- a/Source/JavaScriptCore/offlineasm/instructions.rb +++ b/Source/JavaScriptCore/offlineasm/instructions.rb @@ -21,6 +21,8 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # THE POSSIBILITY OF SUCH DAMAGE. +require "config" + # Interesting invariant, which we take advantage of: branching instructions # always begin with "b", and no non-branching instructions begin with "b". # Terminal instructions are "jmp" and "ret". diff --git a/Source/JavaScriptCore/offlineasm/offsets.rb b/Source/JavaScriptCore/offlineasm/offsets.rb index 4f2734f86..8a064a216 100644 --- a/Source/JavaScriptCore/offlineasm/offsets.rb +++ b/Source/JavaScriptCore/offlineasm/offsets.rb @@ -21,6 +21,7 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # THE POSSIBILITY OF SUCH DAMAGE. +require "config" require "ast" def to32Bit(value) diff --git a/Source/JavaScriptCore/offlineasm/opt.rb b/Source/JavaScriptCore/offlineasm/opt.rb index 3170d3ae1..c721758f7 100644 --- a/Source/JavaScriptCore/offlineasm/opt.rb +++ b/Source/JavaScriptCore/offlineasm/opt.rb @@ -21,6 +21,7 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # THE POSSIBILITY OF SUCH DAMAGE. +require "config" require "ast" # diff --git a/Source/JavaScriptCore/offlineasm/parser.rb b/Source/JavaScriptCore/offlineasm/parser.rb index 11863c724..8696a61a9 100644 --- a/Source/JavaScriptCore/offlineasm/parser.rb +++ b/Source/JavaScriptCore/offlineasm/parser.rb @@ -21,6 +21,7 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # THE POSSIBILITY OF SUCH DAMAGE. +require "config" require "ast" require "instructions" require "pathname" @@ -81,11 +82,20 @@ def lex(str, fileName) fileName = Pathname.new(fileName) result = [] lineNumber = 1 + annotation = nil while not str.empty? case str when /\A\#([^\n]*)/ # comment, ignore + when /\A\/\/([^\n]*)/ + # annotation + annotation = $1 when /\A\n/ + # We've found a '\n'. Emit the last comment recorded if appropriate: + if $enableInstrAnnotations and annotation + result << Token.new(CodeOrigin.new(fileName, lineNumber), "@" + annotation) + annotation = nil + end result << Token.new(CodeOrigin.new(fileName, lineNumber), $&) lineNumber += 1 when /\A[a-zA-Z]([a-zA-Z0-9_]*)/ @@ -136,6 +146,10 @@ def isIdentifier(token) token =~ /\A[a-zA-Z]([a-zA-Z0-9_]*)\Z/ and not isKeyword(token) end +def isAnnotation(token) + token =~ /\A\@([^\n]*)/ +end + def isLabel(token) token =~ /\A_([a-zA-Z0-9_]*)\Z/ end @@ -535,6 +549,10 @@ class Parser # Zero operand instruction, and it's the last one. list << Instruction.new(codeOrigin, name, []) break + elsif isAnnotation @tokens[@idx] + annotation = @tokens[@idx].string + list << Instruction.new(codeOrigin, name, [], annotation) + @idx += 2 # Consume the newline as well. elsif @tokens[@idx] == "\n" # Zero operand instruction. list << Instruction.new(codeOrigin, name, []) @@ -543,6 +561,7 @@ class Parser # It's definitely an instruction, and it has at least one operand. operands = [] endOfSequence = false + annotation = nil loop { operands << parseOperand("while inside of instruction #{name}") if (not final and @idx == @tokens.size) or (final and @tokens[@idx] =~ final) @@ -552,6 +571,10 @@ class Parser elsif @tokens[@idx] == "," # Has another operand. @idx += 1 + elsif isAnnotation @tokens[@idx] + annotation = @tokens[@idx].string + @idx += 2 # Consume the newline as well. + break elsif @tokens[@idx] == "\n" # The end of the instruction. @idx += 1 @@ -560,7 +583,7 @@ class Parser parseError("Expected a comma, newline, or #{final} after #{operands.last.dump}") end } - list << Instruction.new(codeOrigin, name, operands) + list << Instruction.new(codeOrigin, name, operands, annotation) if endOfSequence break end diff --git a/Source/JavaScriptCore/offlineasm/registers.rb b/Source/JavaScriptCore/offlineasm/registers.rb index 2c5a4ebf6..f062ae6a5 100644 --- a/Source/JavaScriptCore/offlineasm/registers.rb +++ b/Source/JavaScriptCore/offlineasm/registers.rb @@ -21,6 +21,8 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # THE POSSIBILITY OF SUCH DAMAGE. +require "config" + GPRS = [ "t0", diff --git a/Source/JavaScriptCore/offlineasm/self_hash.rb b/Source/JavaScriptCore/offlineasm/self_hash.rb index 2c300fccc..b91057391 100644 --- a/Source/JavaScriptCore/offlineasm/self_hash.rb +++ b/Source/JavaScriptCore/offlineasm/self_hash.rb @@ -21,6 +21,7 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # THE POSSIBILITY OF SUCH DAMAGE. +require "config" require "digest/sha1" require "pathname" diff --git a/Source/JavaScriptCore/offlineasm/settings.rb b/Source/JavaScriptCore/offlineasm/settings.rb index b7daa7492..601934f99 100644 --- a/Source/JavaScriptCore/offlineasm/settings.rb +++ b/Source/JavaScriptCore/offlineasm/settings.rb @@ -21,6 +21,7 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # THE POSSIBILITY OF SUCH DAMAGE. +require "config" require "ast" require "backends" require "parser" diff --git a/Source/JavaScriptCore/offlineasm/transform.rb b/Source/JavaScriptCore/offlineasm/transform.rb index 86c72be67..a47ea0ad6 100644 --- a/Source/JavaScriptCore/offlineasm/transform.rb +++ b/Source/JavaScriptCore/offlineasm/transform.rb @@ -21,6 +21,7 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # THE POSSIBILITY OF SUCH DAMAGE. +require "config" require "ast" # diff --git a/Source/JavaScriptCore/offlineasm/x86.rb b/Source/JavaScriptCore/offlineasm/x86.rb index 383526b25..470318a09 100644 --- a/Source/JavaScriptCore/offlineasm/x86.rb +++ b/Source/JavaScriptCore/offlineasm/x86.rb @@ -21,6 +21,8 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # THE POSSIBILITY OF SUCH DAMAGE. +require "config" + def isX64 case $activeBackend when "X86" @@ -353,7 +355,7 @@ class Sequence operand end } - newNode = Instruction.new(node.codeOrigin, node.opcode, newOperands) + newNode = Instruction.new(node.codeOrigin, node.opcode, newOperands, node.annotation) end else unless node.is_a? Label or @@ -622,7 +624,9 @@ class Instruction end def lowerX86Common - $asm.comment codeOriginString + $asm.codeOrigin codeOriginString + $asm.annotation annotation + case opcode when "addi" handleX86Add(:int) diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h index e5f6de438..2f6c6a253 100644 --- a/Source/JavaScriptCore/runtime/Executable.h +++ b/Source/JavaScriptCore/runtime/Executable.h @@ -176,6 +176,30 @@ namespace JSC { return intrinsic(); return NoIntrinsic; } + + static ptrdiff_t offsetOfJITCodeFor(CodeSpecializationKind kind) + { + if (kind == CodeForCall) + return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForCall); + ASSERT(kind == CodeForConstruct); + return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstruct); + } + + static ptrdiff_t offsetOfJITCodeWithArityCheckFor(CodeSpecializationKind kind) + { + if (kind == CodeForCall) + return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForCallWithArityCheck); + ASSERT(kind == CodeForConstruct); + return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstructWithArityCheck); + } + + static ptrdiff_t offsetOfNumParametersFor(CodeSpecializationKind kind) + { + if (kind == CodeForCall) + return OBJECT_OFFSETOF(ExecutableBase, m_numParametersForCall); + ASSERT(kind == CodeForConstruct); + return OBJECT_OFFSETOF(ExecutableBase, m_numParametersForConstruct); + } #endif protected: diff --git a/Source/JavaScriptCore/runtime/GCActivityCallbackBlackBerry.cpp b/Source/JavaScriptCore/runtime/GCActivityCallbackBlackBerry.cpp index 3b0b5a751..d9f96fa1e 100644 --- a/Source/JavaScriptCore/runtime/GCActivityCallbackBlackBerry.cpp +++ b/Source/JavaScriptCore/runtime/GCActivityCallbackBlackBerry.cpp @@ -20,39 +20,40 @@ #include "GCActivityCallback.h" #include "Heap.h" +#include "JSGlobalData.h" #include <BlackBerryPlatformMemory.h> namespace JSC { +static const size_t bytesWorthGC = 4 * 1024 * 1024; + DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap) : GCActivityCallback(heap->globalData()) { } -DefaultGCActivityCallback::doWork() +void DefaultGCActivityCallback::doWork() { + m_globalData->heap.collect(Heap::DoNotSweep); } void DefaultGCActivityCallback::didAllocate(size_t bytesAllocated) { - if (!BlackBerry::Platform::isMemoryLow()) - return; - - if (bytesAllocated < 1 * 1024 * 1024) + if (bytesAllocated < bytesWorthGC || m_timer.started()) return; - if (m_globalData->heap.isBusy() || !m_globalData->heap.isSafeToCollect()) - return; - - m_globalData->heap.collect(Heap::DoNotSweep); + // Try using ~5% CPU time. + m_timer.start(m_globalData->heap.lastGCLength() * 20); } void DefaultGCActivityCallback::willCollect() { + cancel(); } void DefaultGCActivityCallback::cancel() { + m_timer.stop(); } } diff --git a/Source/JavaScriptCore/runtime/JSValue.h b/Source/JavaScriptCore/runtime/JSValue.h index f74bfad90..6f98bd6f7 100644 --- a/Source/JavaScriptCore/runtime/JSValue.h +++ b/Source/JavaScriptCore/runtime/JSValue.h @@ -124,6 +124,18 @@ namespace JSC { friend class LLInt::Data; public: +#if USE(JSVALUE32_64) + enum { Int32Tag = 0xffffffff }; + enum { BooleanTag = 0xfffffffe }; + enum { NullTag = 0xfffffffd }; + enum { UndefinedTag = 0xfffffffc }; + enum { CellTag = 0xfffffffb }; + enum { EmptyValueTag = 0xfffffffa }; + enum { DeletedValueTag = 0xfffffff9 }; + + enum { LowestTag = DeletedValueTag }; +#endif + static EncodedJSValue encode(JSValue); static JSValue decode(EncodedJSValue); @@ -278,16 +290,6 @@ namespace JSC { * cell, integer and bool values the lower 32 bits (the 'payload') contain the pointer * integer or boolean value; in the case of all other tags the payload is 0. */ - enum { Int32Tag = 0xffffffff }; - enum { BooleanTag = 0xfffffffe }; - enum { NullTag = 0xfffffffd }; - enum { UndefinedTag = 0xfffffffc }; - enum { CellTag = 0xfffffffb }; - enum { EmptyValueTag = 0xfffffffa }; - enum { DeletedValueTag = 0xfffffff9 }; - - enum { LowestTag = DeletedValueTag }; - uint32_t tag() const; int32_t payload() const; #elif USE(JSVALUE64) diff --git a/Source/JavaScriptCore/wscript b/Source/JavaScriptCore/wscript index 4afb4d26a..2270455c8 100644 --- a/Source/JavaScriptCore/wscript +++ b/Source/JavaScriptCore/wscript @@ -33,7 +33,7 @@ def build(bld): import Options - jscore_excludes = ['jsc.cpp', 'ExecutableAllocatorPosix.cpp', 'LLIntOffsetsExtractor.cpp'] + jscore_excludes = ['jsc.cpp', 'ExecutableAllocatorPosix.cpp', 'LLIntOffsetsExtractor.cpp', 'udis86_itab.c'] jscore_exclude_patterns = get_port_excludes(Options.options.port) jscore_exclude_patterns.append('*None.cpp') @@ -46,9 +46,6 @@ def build(bld): else: jscore_excludes.append('JSStringRefBSTR.cpp') - if sys.platform.startswith('darwin'): - jscore_excludes.append('GCActivityCallback.cpp') # this is an empty impl. - bld.env.LIBDIR = output_dir full_dirs = get_dirs_for_features(jscore_dir, features=[Options.options.port.lower()], dirs=jscore_dirs) abs_dirs = [] |