diff options
author | Ben Murdoch <benm@google.com> | 2010-05-11 18:35:50 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2010-05-14 10:23:05 +0100 |
commit | 21939df44de1705786c545cd1bf519d47250322d (patch) | |
tree | ef56c310f5c0cdc379c2abb2e212308a3281ce20 /JavaScriptCore | |
parent | 4ff1d8891d520763f17675827154340c7c740f90 (diff) | |
download | external_webkit-21939df44de1705786c545cd1bf519d47250322d.zip external_webkit-21939df44de1705786c545cd1bf519d47250322d.tar.gz external_webkit-21939df44de1705786c545cd1bf519d47250322d.tar.bz2 |
Merge Webkit at r58956: Initial merge by Git.
Change-Id: I1d9fb60ea2c3f2ddc04c17a871acdb39353be228
Diffstat (limited to 'JavaScriptCore')
123 files changed, 6248 insertions, 2031 deletions
diff --git a/JavaScriptCore/API/APIShims.h b/JavaScriptCore/API/APIShims.h index 3d42ca2..892068d 100644 --- a/JavaScriptCore/API/APIShims.h +++ b/JavaScriptCore/API/APIShims.h @@ -66,7 +66,7 @@ public: // JSPropertyNameAccumulator only has a globalData. APIEntryShim(JSGlobalData* globalData, bool registerThread = true) : APIEntryShimWithoutLock(globalData, registerThread) - , m_lock(globalData->isSharedInstance ? LockForReal : SilenceAssertionsOnly) + , m_lock(globalData->isSharedInstance() ? LockForReal : SilenceAssertionsOnly) { } diff --git a/JavaScriptCore/API/JSBase.cpp b/JavaScriptCore/API/JSBase.cpp index ebfeafa..c5f1b15 100644 --- a/JavaScriptCore/API/JSBase.cpp +++ b/JavaScriptCore/API/JSBase.cpp @@ -38,6 +38,7 @@ #include <runtime/JSGlobalObject.h> #include <runtime/JSLock.h> #include <runtime/JSObject.h> +#include <wtf/text/StringHash.h> using namespace JSC; diff --git a/JavaScriptCore/API/JSCallbackObject.cpp b/JavaScriptCore/API/JSCallbackObject.cpp index 2fde0f8..b36c194 100644 --- a/JavaScriptCore/API/JSCallbackObject.cpp +++ b/JavaScriptCore/API/JSCallbackObject.cpp @@ -28,6 +28,7 @@ #include "JSCallbackObject.h" #include "Collector.h" +#include <wtf/text/StringHash.h> namespace JSC { diff --git a/JavaScriptCore/API/JSContextRef.cpp b/JavaScriptCore/API/JSContextRef.cpp index 06f9274..b97ceda 100644 --- a/JavaScriptCore/API/JSContextRef.cpp +++ b/JavaScriptCore/API/JSContextRef.cpp @@ -46,7 +46,7 @@ using namespace JSC; JSContextGroupRef JSContextGroupCreate() { initializeThreading(); - return toRef(JSGlobalData::createNonDefault(ThreadStackTypeSmall).releaseRef()); + return toRef(JSGlobalData::createContextGroup(ThreadStackTypeSmall).releaseRef()); } JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group) @@ -84,7 +84,7 @@ JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClass initializeThreading(); JSLock lock(LockForReal); - RefPtr<JSGlobalData> globalData = group ? PassRefPtr<JSGlobalData>(toJS(group)) : JSGlobalData::createNonDefault(ThreadStackTypeSmall); + RefPtr<JSGlobalData> globalData = group ? PassRefPtr<JSGlobalData>(toJS(group)) : JSGlobalData::createContextGroup(ThreadStackTypeSmall); APIEntryShim entryShim(globalData.get(), false); diff --git a/JavaScriptCore/API/JSStringRef.h b/JavaScriptCore/API/JSStringRef.h index 92135b1..51871b1 100644 --- a/JavaScriptCore/API/JSStringRef.h +++ b/JavaScriptCore/API/JSStringRef.h @@ -38,7 +38,7 @@ extern "C" { #endif #if !defined(WIN32) && !defined(_WIN32) && !defined(__WINSCW__) \ - && !(defined(__CC_ARM) || defined(__ARMCC__)) /* RVCT */ + && !((defined(__CC_ARM) || defined(__ARMCC__)) && defined(__SYMBIAN32__)) /* RVCT */ /*! @typedef JSChar @abstract A Unicode character. diff --git a/JavaScriptCore/API/JSWeakObjectMapRefPrivate.cpp b/JavaScriptCore/API/JSWeakObjectMapRefPrivate.cpp index e377ea0..7e6bb63 100644 --- a/JavaScriptCore/API/JSWeakObjectMapRefPrivate.cpp +++ b/JavaScriptCore/API/JSWeakObjectMapRefPrivate.cpp @@ -33,6 +33,7 @@ #include "JSWeakObjectMapRefInternal.h" #include <wtf/HashMap.h> #include <wtf/RefCounted.h> +#include <wtf/text/StringHash.h> using namespace WTF; using namespace JSC; diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog index 11f02e3..eb2f97d 100644 --- a/JavaScriptCore/ChangeLog +++ b/JavaScriptCore/ChangeLog @@ -1,3 +1,1513 @@ +2010-05-06 Fumitoshi Ukai <ukai@chromium.org> + + Reviewed by Alexey Proskuryakov. + + JavaScriptCore/wtf/RandomNumber.h should provide using WTF::* + https://bugs.webkit.org/show_bug.cgi?id=38719 + + * wtf/RandomNumber.h: + Add using directives. + +2010-05-06 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Kenneth Rohde Christiansen. + + [Qt] Enable YARR_JIT for X86 Mac for QtWebKit + https://bugs.webkit.org/show_bug.cgi?id=38668 + + * wtf/Platform.h: + +2010-05-06 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Geoff Garen. + + Bug 38714 - Add result caching for Math.sin + + Math.sin is frequently called with the same operand, caching the result should + improve performance. CachedTranscendentalFunction adds a generic mechanism to + cache results for pure functions with the signature "double func(double)", and + where NaN maps to NaN. + + CachedTranscendentalFunction uses a very simple hash function designed to be + fast to execute since we cannot cache the result, and trivial to JIT generate, + should we wish to do so. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * runtime/CachedTranscendentalFunction.h: Added. + (JSC::CachedTranscendentalFunction::CachedTranscendentalFunction): + (JSC::CachedTranscendentalFunction::~CachedTranscendentalFunction): + (JSC::CachedTranscendentalFunction::operator()): + (JSC::CachedTranscendentalFunction::initialize): + (JSC::CachedTranscendentalFunction::hash): + * runtime/JSGlobalData.h: + * runtime/MathObject.cpp: + (JSC::mathProtoFuncSin): + * wtf/Platform.h: + +2010-05-06 Geoffrey Garen <ggaren@apple.com> + + Windows build fix. + + * bytecode/SamplingTool.cpp: + (JSC::SamplingFlags::sample): Use a cast, so Windows will be happy when + this code is enabled. + * wtf/Platform.h: Reverted last change to this file, which seems to have + been accidental. + +2010-05-06 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Oliver Hunt. + + Add compile switch to make debugger keyword plant breakpoint instructions. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitDebugHook): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_debug): + * wtf/Platform.h: + +2010-05-06 Oliver Hunt <oliver@apple.com> + + Build fix + + Fix ARM builds + + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::load16): + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::load16): + +2010-05-06 Oliver Hunt <oliver@apple.com> + + Reviewed by Geoffrey Garen. + + Improve performance of single character string compares + https://bugs.webkit.org/show_bug.cgi?id=38659 + + Add logic to the jit to identify comparisons to single character string literals + and then just perform the comparison inline, rather than ignoring the evidence + and attempting to perform an integer comparison. + + Multiple changes required -- add jnlesseq opcode, add helper function to identify + single character string constants, add a helper to load single character strings. + Then add the 32_64 and normal codepaths to the JIT. + + * assembler/MacroAssemblerX86Common.h: + (JSC::MacroAssemblerX86Common::load16): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + * bytecode/Opcode.h: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitJumpIfTrue): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + (JSC::JIT::privateCompileSlowCases): + * jit/JIT.h: + * jit/JITArithmetic.cpp: + (JSC::JIT::emit_op_jnless): + (JSC::JIT::emitSlow_op_jnless): + (JSC::JIT::emit_op_jless): + (JSC::JIT::emitSlow_op_jless): + (JSC::JIT::emit_op_jlesseq): + (JSC::JIT::emit_op_jnlesseq): + (JSC::JIT::emitSlow_op_jlesseq): + (JSC::JIT::emitSlow_op_jnlesseq): + * jit/JITArithmetic32_64.cpp: + (JSC::JIT::emit_op_jnless): + (JSC::JIT::emitSlow_op_jnless): + (JSC::JIT::emit_op_jless): + (JSC::JIT::emitSlow_op_jless): + (JSC::JIT::emit_op_jlesseq): + (JSC::JIT::emit_op_jnlesseq): + (JSC::JIT::emitSlow_op_jlesseq): + (JSC::JIT::emitSlow_op_jnlesseq): + (JSC::JIT::emitBinaryDoubleOp): + * jit/JITInlineMethods.h: + (JSC::JIT::emitLoadCharacterString): + (JSC::JIT::isOperandConstantImmediateChar): + * jit/JSInterfaceJIT.h: + (JSC::ThunkHelpers::stringImplDataOffset): + (JSC::ThunkHelpers::jsStringLengthOffset): + (JSC::ThunkHelpers::jsStringValueOffset): + Moved from ThunkGenerators to make it possible to share. + * jit/ThunkGenerators.cpp: + +2010-05-06 Martin Robinson <mrobinson@webkit.org> + + Reviewed by Gustavo Noronha Silva. + + [GTK] Enable DOM clipboard and drag-and-drop access + https://bugs.webkit.org/show_bug.cgi?id=30623 + + Convert dragging portion of drag-and-drop to use DataObjectGtk. + + * wtf/gobject/GRefPtr.h: Add forward declarations for GObject functions. + +2010-05-06 Steve Block <steveblock@google.com> + + Reviewed by Eric Seidel. + + MAC_JAVA_BRIDGE should be renamed JAVA_BRIDGE + https://bugs.webkit.org/show_bug.cgi?id=38544 + + * wtf/Platform.h: + +2010-05-06 Adam Barth <abarth@webkit.org> + + Reviewed by Maciej Stachowiak. + + [WTFURL] Add a class to represent the segments of a URL + https://bugs.webkit.org/show_bug.cgi?id=38566 + + When paired with a string, this class represents a parsed URL. + + * wtf/url/src/URLSegments.cpp: Added. + (WTF::URLSegments::length): + (WTF::URLSegments::charactersBefore): + * wtf/url/src/URLSegments.h: Added. + (WTF::URLSegments::): + (WTF::URLSegments::URLSegments): + * wtf/url/wtfurl.gyp: + +2010-05-05 Tony Gentilcore <tonyg@chromium.org> + + Reviewed by Adam Barth. + + Adding comment with link to RefPtr documentation. + https://bugs.webkit.org/show_bug.cgi?id=38601 + + * wtf/RefPtr.h: + +2010-05-05 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Darin Adler. + + Bug 38604 - workers-gc2 crashing on Qt + + This appears to be due to a couple of issues. + (1) When the atomic string table is deleted it does not clear the 'inTable' bit + on AtomicStrings - it implicitly assumes that all AtomicStrings have already + been deleted at this point (otherwise they will crash in their destructor when + they try to remove themselves from the atomic string table). + (2) We don't fix the ordering in which WTF::WTFThreadData and + WebCore::ThreadGlobalData are destructed. + + We should make sure that ThreadGlobalData is cleaned up before worker threads + terminate and WTF::WTFThreadData is destroyed, and we should clear the inTable + bit of members on atomic string table destruction. + + WTF changes (fix issue 1, above) - ensure inTable property is cleared when the + atomic string table is destroyed (also, rename InTable to IsAtomic, to make it + clear which table we are refering to!) + + * wtf/text/AtomicString.cpp: + (WebCore::AtomicStringTable::destroy): + (WebCore::CStringTranslator::translate): + (WebCore::UCharBufferTranslator::translate): + (WebCore::HashAndCharactersTranslator::translate): + (WebCore::AtomicString::add): + * wtf/text/StringImpl.cpp: + (WebCore::StringImpl::~StringImpl): + * wtf/text/StringImpl.h: + (WebCore::StringImpl::isAtomic): + (WebCore::StringImpl::setIsAtomic): + * wtf/text/StringImplBase.h: + +2010-05-05 Oliver Hunt <oliver@apple.com> + + Reviewed by Geoffrey Garen. + + Make Array.join specialised for actual arrays + https://bugs.webkit.org/show_bug.cgi?id=38592 + + Bring Array.join in line with the other array methods by specialising for + this === an array. + + * runtime/ArrayPrototype.cpp: + (JSC::arrayProtoFuncJoin): + +2010-05-04 Yongjun Zhang <yongjun_zhang@apple.com> + + Reviewed by Darin Adler. + + WebKit crashes at DebuggerCallFrame::functionName() if m_callFrame is the top global callframe. + https://bugs.webkit.org/show_bug.cgi?id=38535 + + Don't call asFunction if callee is not a FunctionType to prevent assertion failure + in JSCell::isObject(). + + * debugger/DebuggerCallFrame.cpp: + (JSC::DebuggerCallFrame::functionName): + (JSC::DebuggerCallFrame::calculatedFunctionName): + +2010-05-04 Steve Falkenburg <sfalken@apple.com> + + Remove redundant exports to fix Windows build warnings. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + +2010-05-04 Jedrzej Nowacki <jedrzej.nowacki@nokia.com> + + Reviewed by Holger Freyther. + + Fix a memory leak inside the QScriptValue. + + QSciptValuePrivate::toString should release all temporary variables. + + [Qt] QScriptValue::toString have a memory leak. + https://bugs.webkit.org/show_bug.cgi?id=38112 + + * qt/api/qscriptvalue_p.h: + (QScriptValuePrivate::toString): + +2010-05-04 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk> + + Reviewed by Darin Adler. + + Does not work on SPARC because of alignment issues + https://bugs.webkit.org/show_bug.cgi?id=38455 + + Use AllocAlignmentInteger instead of void* on pageheap_memory to + avoid crashing at runtime in some architectures. Investigated by + Mike Hommey <mh@glandium.org>, change suggested by Darin Adler. + + * wtf/FastMalloc.cpp: + +2010-05-04 Adam Barth <abarth@webkit.org> + + Reviewed by Maciej Stachowiak. + + Add first WTFURL file + https://bugs.webkit.org/show_bug.cgi?id=38470 + + This class represents a component of a URL, such as the scheme or path. + Essentially, the class is an index into a string buffer. + + * wtf/url: Added. + - There was some discussion about where to put the URL library. + There are a number of reasonable options, but putting the library + in the WTF directory seems like a reasonable alternative. This + location will make more sense once WTF is moved out of + JavaScriptCore and into a top-level directory. + * wtf/url/src: Added. + - I've added this extra directory to the usual structure because we + eventually want a "public" folder that defines the public + interface to this library that clients outside of svn.webkit.org + can rely upon, much like the various subfolders of the WebKit + directory often define a public API. + * wtf/url/src/URLComponent.h: Added. + - I've added this somewhat trivial class to get the ball rolling. + (WTF::URLComponent::URLComponent): + (WTF::URLComponent::isValid): + (WTF::URLComponent::isNonempty): + (WTF::URLComponent::reset): + (WTF::URLComponent::operator==): + (WTF::URLComponent::begin): + (WTF::URLComponent::setBegin): + (WTF::URLComponent::length): + (WTF::URLComponent::setLength): + (WTF::URLComponent::end): + * wtf/url/wtfurl.gyp: Added. + - WTFURL will be an independently buildable library, hence the + beginnings of a wtfurl.gyp file. + +2010-05-03 Stephanie Lewis <slewis@apple.com> + + Reviewed by Geoff Garen. + + https://bugs.webkit.org/show_bug.cgi?id=38368 + <rdar://problem/7834433> REGRESSSION: 1.5% PLT regression due to 56028 + (return memory quicker). + Instead of returning everything but the smallest spans spread out + the spans kept over several size lists. + + * wtf/FastMalloc.cpp: + (WTF::TCMalloc_PageHeap::scavenge): + +2010-05-03 James Robinson <jamesr@chromium.org> + + Reviewed by Eric Seidel. + + Clean up a few compiler warnings + https://bugs.webkit.org/show_bug.cgi?id=38073 + + * wtf/text/StringImpl.cpp: + (WebCore::StringImpl::ascii): + +2010-05-03 Gavin Barraclough <barraclough@apple.com> + + Reviewed by NOBODY (reverting previous commit). + + Rolling out r58114 - this introduced memory leaks of + AtomicStrings then workers terminated. + + * GNUmakefile.am: + * JavaScriptCore.gypi: + * JavaScriptCore.vcproj/WTF/WTF.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * jit/ThunkGenerators.cpp: + (JSC::ThunkHelpers::stringImplDataOffset): + * runtime/Identifier.cpp: + (JSC::IdentifierTable::~IdentifierTable): + (JSC::IdentifierTable::add): + (JSC::IdentifierCStringTranslator::hash): + (JSC::IdentifierCStringTranslator::equal): + (JSC::IdentifierCStringTranslator::translate): + (JSC::Identifier::add): + (JSC::IdentifierUCharBufferTranslator::hash): + (JSC::IdentifierUCharBufferTranslator::equal): + (JSC::IdentifierUCharBufferTranslator::translate): + (JSC::Identifier::addSlowCase): + * runtime/Identifier.h: + * runtime/JSGlobalData.cpp: + (JSC::JSGlobalData::JSGlobalData): + (JSC::JSGlobalData::~JSGlobalData): + * runtime/JSGlobalData.h: + * wtf/WTFThreadData.cpp: + (WTF::WTFThreadData::WTFThreadData): + (WTF::WTFThreadData::~WTFThreadData): + * wtf/WTFThreadData.h: + (JSC::IdentifierTable::remove): + (JSC::IdentifierTable::literalTable): + (WTF::WTFThreadData::atomicStringTable): + * wtf/text/AtomicString.cpp: + (WebCore::AtomicStringTable::create): + (WebCore::AtomicStringTable::table): + (WebCore::AtomicStringTable::destroy): + (WebCore::stringTable): + (WebCore::CStringTranslator::hash): + (WebCore::CStringTranslator::equal): + (WebCore::CStringTranslator::translate): + (WebCore::operator==): + (WebCore::AtomicString::add): + (WebCore::equal): + (WebCore::UCharBufferTranslator::hash): + (WebCore::UCharBufferTranslator::equal): + (WebCore::UCharBufferTranslator::translate): + (WebCore::HashAndCharactersTranslator::hash): + (WebCore::HashAndCharactersTranslator::equal): + (WebCore::HashAndCharactersTranslator::translate): + (WebCore::AtomicString::find): + (WebCore::AtomicString::remove): + * wtf/text/AtomicStringTable.h: Removed. + * wtf/text/StringImpl.cpp: + (WebCore::StringImpl::~StringImpl): + * wtf/text/StringImpl.h: + (WebCore::StringImpl::inTable): + (WebCore::StringImpl::setInTable): + (WebCore::equal): + * wtf/text/StringImplBase.h: + (WTF::StringImplBase::StringImplBase): + +2010-05-03 Kevin Watters <kevinwatters@gmail.com> + + Reviewed by Kevin Ollivier. + + [wx] Implement scheduleDispatchFunctionsOnMainThread for wx port. + https://bugs.webkit.org/show_bug.cgi?id=38480 + + * wtf/wx/MainThreadWx.cpp: + (wxCallAfter::wxCallAfter): + (wxCallAfter::OnCallback): + (WTF::scheduleDispatchFunctionsOnMainThread): + +2010-05-03 Kevin Watters <kevinwatters@gmail.com> + + Reviewed by Kevin Ollivier. + + [wx] Build and use Mac's ComplexTextController to support complex text in wx. + https://bugs.webkit.org/show_bug.cgi?id=38482 + + * wtf/Platform.h: + +2010-05-03 Oliver Hunt <oliver@apple.com> + + Reviewed by Maciej Stachowiak. + + Interpreter crashes due to incorrect refcounting of cached structures. + https://bugs.webkit.org/show_bug.cgi?id=38491 + rdar://problem/7926160 + + Make sure we ref/deref structures used for cached custom property getters + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::derefStructures): + (JSC::CodeBlock::refStructures): + +2010-05-02 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Eric Seidel. + + [Qt] Enable JIT for QtWebKit on Symbian + https://bugs.webkit.org/show_bug.cgi?id=38339 + + JIT on Symbian has been stable for quite some time, it + is time to turn it on by default. + + * wtf/Platform.h: + +2010-04-29 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + Add codegen support for unsigned right shift + https://bugs.webkit.org/show_bug.cgi?id=38375 + + Expose unsigned right shift in the macro assembler, and make use of it + from the jit. Currently if the result is outside the range 0..2^31-1 + we simply fall back to the slow case, even in JSVALUE64 and JSVALUE32_64 + where technically we could still return an immediate value. + + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::urshift32): + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::urshift32): + * assembler/MacroAssemblerX86Common.h: + (JSC::MacroAssemblerX86Common::urshift32): + * assembler/X86Assembler.h: + (JSC::X86Assembler::): + (JSC::X86Assembler::shrl_i8r): + (JSC::X86Assembler::shrl_CLr): + Add unsigned right shift to the x86 assembler + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + (JSC::JIT::privateCompileSlowCases): + op_rshift no longer simply get thrown to a stub function + * jit/JIT.h: + * jit/JITArithmetic.cpp: + (JSC::JIT::emit_op_urshift): + (JSC::JIT::emitSlow_op_urshift): + JSVALUE32 and JSVALUE64 implementation. Only supports + double lhs in JSVALUE64. + * jit/JITArithmetic32_64.cpp: + (JSC::JIT::emit_op_rshift): + (JSC::JIT::emitSlow_op_rshift): + (JSC::JIT::emit_op_urshift): + (JSC::JIT::emitSlow_op_urshift): + Refactor right shift code to have shared implementation between signed + and unsigned versions. + +2010-04-29 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + Handle double on righthand side of a right shift + https://bugs.webkit.org/show_bug.cgi?id=38363 + + In 64-bit we support right shift of a double, and there's no + reason not to in 32-bit either. This is a 1.1% sunspider + improvement in 32bit. + + Given high performance javascript code frequently makes + use of bit operators to perform double->int conversion i'll + follow this patch up with similar patches for bitwise 'and' + and 'or'. + + * jit/JITArithmetic32_64.cpp: + (JSC::JIT::emit_op_rshift): + (JSC::JIT::emitSlow_op_rshift): + +2010-04-29 Oliver Hunt <oliver@apple.com> + + Reviewed by Geoff Garen. + + Hoist JSVALUE32_64 arithmetic implementations into a separate file. + + * GNUmakefile.am: + * JavaScriptCore.gypi: + * JavaScriptCore.pro: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * jit/JITArithmetic.cpp: + (JSC::JIT::emitSlow_op_jnless): + (JSC::JIT::emitSlow_op_jless): + (JSC::JIT::emitSlow_op_jnlesseq): + (JSC::JIT::emit_op_mod): + (JSC::JIT::compileBinaryArithOpSlowCase): + (JSC::JIT::emit_op_div): + (JSC::JIT::compileBinaryArithOp): + * jit/JITArithmetic32_64.cpp: Added. + (JSC::JIT::emit_op_negate): + (JSC::JIT::emitSlow_op_negate): + (JSC::JIT::emit_op_jnless): + (JSC::JIT::emitSlow_op_jnless): + (JSC::JIT::emit_op_jless): + (JSC::JIT::emitSlow_op_jless): + (JSC::JIT::emit_op_jnlesseq): + (JSC::JIT::emitSlow_op_jnlesseq): + (JSC::JIT::emit_op_lshift): + (JSC::JIT::emitSlow_op_lshift): + (JSC::JIT::emit_op_rshift): + (JSC::JIT::emitSlow_op_rshift): + (JSC::JIT::emit_op_bitand): + (JSC::JIT::emitSlow_op_bitand): + (JSC::JIT::emit_op_bitor): + (JSC::JIT::emitSlow_op_bitor): + (JSC::JIT::emit_op_bitxor): + (JSC::JIT::emitSlow_op_bitxor): + (JSC::JIT::emit_op_bitnot): + (JSC::JIT::emitSlow_op_bitnot): + (JSC::JIT::emit_op_post_inc): + (JSC::JIT::emitSlow_op_post_inc): + (JSC::JIT::emit_op_post_dec): + (JSC::JIT::emitSlow_op_post_dec): + (JSC::JIT::emit_op_pre_inc): + (JSC::JIT::emitSlow_op_pre_inc): + (JSC::JIT::emit_op_pre_dec): + (JSC::JIT::emitSlow_op_pre_dec): + (JSC::JIT::emit_op_add): + (JSC::JIT::emitAdd32Constant): + (JSC::JIT::emitSlow_op_add): + (JSC::JIT::emit_op_sub): + (JSC::JIT::emitSub32Constant): + (JSC::JIT::emitSlow_op_sub): + (JSC::JIT::emitBinaryDoubleOp): + (JSC::JIT::emit_op_mul): + (JSC::JIT::emitSlow_op_mul): + (JSC::JIT::emit_op_div): + (JSC::JIT::emitSlow_op_div): + (JSC::JIT::emit_op_mod): + (JSC::JIT::emitSlow_op_mod): + +2010-04-29 Zoltan Herczeg <zherczeg@webkit.org> + + Reviewed by Oliver Hunt + + Add sqrt() instruction support for ARM assembler (using VFP) + https://bugs.webkit.org/show_bug.cgi?id=38312 + + * assembler/ARMAssembler.h: + (JSC::ARMAssembler::): + (JSC::ARMAssembler::fsqrtd_r): + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::supportsFloatingPointSqrt): + (JSC::MacroAssemblerARM::sqrtDouble): + +2010-04-29 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Simon Hausmann. + + [Qt] Refactor qtscriptglobal.h + https://bugs.webkit.org/show_bug.cgi?id=37953 + + Use the same pattern in qtscriptglobal.h as in + qwebkitglobal.h without checking for specific OSs. + + * qt/api/qtscriptglobal.h: + +2010-04-29 Jedrzej Nowacki <jedrzej.nowacki@nokia.com> + + Reviewed by Simon Hausmann. + + Small cleanup. + + QScriptValuePrivate constructor shouldn't take QScriptEngine pointer + as a parameter, because it breaks a private / public separation rule. + QScriptEnginePrivate::get(QScriptEngine*) should return + a QScriptEnginePrivate pointer instead of a QScriptEnginePtr, it simplifies + implementation. + + [Qt] QScriptValuePrivate class needs some cleanup. + https://bugs.webkit.org/show_bug.cgi?id=37729 + + * qt/api/qscriptengine_p.h: + (QScriptEnginePrivate::get): + * qt/api/qscriptvalue.cpp: + (QScriptValue::QScriptValue): + * qt/api/qscriptvalue_p.h: + (QScriptValuePrivate::QScriptValuePrivate): + +2010-04-29 Kwang Yul Seo <skyul@company100.net> + + Reviewed by Simon Hausmann. + + [WINCE] Export g_stackBase with JS_EXPORTDATA + https://bugs.webkit.org/show_bug.cgi?id=37437 + + Export g_stackBase with JS_EXPORTDATA as it is used by SharedTimerWince.cpp. + + * runtime/Collector.cpp: + +2010-04-28 Oliver Hunt <oliver@apple.com> + + Do an unordered compare so that we don't treat NaN incorrectly. + + RS=Gavin Barraclough + + * jit/ThunkGenerators.cpp: + (JSC::powThunkGenerator): + +2010-04-28 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + Add fast paths for Math.pow and Math.sqrt + https://bugs.webkit.org/show_bug.cgi?id=38294 + + Add specialized thunks for Math.pow and Math.sqrt. + This requires adding a sqrtDouble function to the MacroAssembler + and sqrtsd to the x86 assembler. + + Math.pow is slightly more complicated, in that we have + to implement exponentiation ourselves rather than relying + on hardware support. The inline exponentiation is restricted + to positive integer exponents on a numeric base. Exponentiation + is finally performed through the "Exponentiation by Squaring" + algorithm. + + * assembler/AbstractMacroAssembler.h: + (JSC::AbstractMacroAssembler::ImmPtr::ImmPtr): + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::supportsFloatingPointSqrt): + (JSC::MacroAssemblerARM::loadDouble): + (JSC::MacroAssemblerARM::sqrtDouble): + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::supportsFloatingPointSqrt): + (JSC::MacroAssemblerARMv7::sqrtDouble): + * assembler/MacroAssemblerX86.h: + (JSC::MacroAssemblerX86::loadDouble): + (JSC::MacroAssemblerX86::supportsFloatingPointSqrt): + * assembler/MacroAssemblerX86Common.h: + (JSC::MacroAssemblerX86Common::sqrtDouble): + * assembler/MacroAssemblerX86_64.h: + (JSC::MacroAssemblerX86_64::loadDouble): + (JSC::MacroAssemblerX86_64::supportsFloatingPointSqrt): + * assembler/X86Assembler.h: + (JSC::X86Assembler::): + (JSC::X86Assembler::movsd_mr): + (JSC::X86Assembler::sqrtsd_rr): + (JSC::X86Assembler::X86InstructionFormatter::twoByteOp): + (JSC::X86Assembler::X86InstructionFormatter::memoryModRM): + * create_hash_table: + * jit/JIT.h: + * jit/JITInlineMethods.h: + * jit/JITOpcodes.cpp: + * jit/JITStubs.h: + (JSC::JITThunks::ctiNativeCallThunk): + * jit/JSInterfaceJIT.h: + (JSC::JSInterfaceJIT::emitLoadDouble): + (JSC::JSInterfaceJIT::emitJumpIfImmediateNumber): + (JSC::JSInterfaceJIT::emitJumpIfNotImmediateNumber): + (JSC::JSInterfaceJIT::emitLoadInt32): + * jit/SpecializedThunkJIT.h: + (JSC::SpecializedThunkJIT::loadDoubleArgument): + (JSC::SpecializedThunkJIT::loadInt32Argument): + (JSC::SpecializedThunkJIT::returnJSValue): + (JSC::SpecializedThunkJIT::returnDouble): + (JSC::SpecializedThunkJIT::finalize): + * jit/ThunkGenerators.cpp: + (JSC::sqrtThunkGenerator): + (JSC::powThunkGenerator): + * jit/ThunkGenerators.h: + * runtime/Executable.h: + (JSC::NativeExecutable::NativeExecutable): + * runtime/JSFunction.cpp: + (JSC::JSFunction::JSFunction): + +2010-04-28 Mike Thole <mthole@apple.com> + + Reviewed by Mark Rowe. + + Reenable WTF_USE_PROTECTION_SPACE_AUTH_CALLBACK now that an + exports file for it has been added. + + * wtf/Platform.h: + +2010-04-28 Mike Thole <mthole@apple.com> + + Build fix, not reviewed. + + * wtf/Platform.h: + Disable WTF_USE_PROTECTION_SPACE_AUTH_CALLBACK until an exports file is created. + +2010-04-28 Mike Thole <mthole@apple.com> + + Reviewed by David Kilzer. + + Add canAuthenticateAgainstProtectionSpace() to frame loader so that a protection space + can be inspected before attempting to authenticate against it + https://bugs.webkit.org/show_bug.cgi?id=38271 + + * wtf/Platform.h: Add WTF_USE_PROTECTION_SPACE_AUTH_CALLBACK define. + +2010-04-28 Darin Adler <darin@apple.com> + + Reviewed by Sam Weinig. + + Don't use CFAbsoluteTimeGetCurrent on Mac OS X, since it's just a cover + for gettimeofday anyway. + + * wtf/CurrentTime.cpp: + (WTF::currentTime): Remove the CF version of this. Change the "other POSIX" + version to pass 0 for the time zone instead of ignoring a return value. + Also get rid of unneeded type casts, since operations involving both + integers and doubles are always evaluated as doubles in C without explicit + type casting. + +2010-04-28 Darin Fisher <darin@chromium.org> + + Reviewed by David Levin. + + [Chromium] callOnMainThread should equate to MessageLoop::PostTask + https://bugs.webkit.org/show_bug.cgi?id=38276 + + * JavaScriptCore.gyp/JavaScriptCore.gyp: + * wtf/MainThread.cpp: + * wtf/chromium/ChromiumThreading.h: + * wtf/chromium/MainThreadChromium.cpp: + (WTF::initializeMainThread): + (WTF::callOnMainThread): + (WTF::callOnMainThreadAndWait): + (WTF::setMainThreadCallbacksPaused): + (WTF::isMainThread): + +2010-04-28 Simon Hausmann <simon.hausmann@nokia.com>, Kent Hansen <kent.hansen@nokia.com> + + Reviewed by Darin Adler. + + JSC's currentThreadStackBase is not reentrant on some platforms + https://bugs.webkit.org/show_bug.cgi?id=37195 + + This function needs to be reentrant to avoid memory corruption on platforms where + the implementation uses global variables. + + This patch adds a mutex lock where necessary and makes the Symbian implementation + reentrant. + + * runtime/Collector.cpp: + (JSC::currentThreadStackBaseMutex): + (JSC::currentThreadStackBase): + +2010-04-28 Thiago Macieira <thiago.macieira@nokia.com> + + Reviewed by Simon Hausmann. + + Fix compilation with gcc 3.4. + + AtomicStringImpl.h:29: error: base `WebCore::StringImpl' with only + non-default constructor in class without a constructor + + * wtf/text/AtomicStringImpl.h: + (WebCore::AtomicStringImpl::AtomicStringImpl): Provide a default constructor. + * wtf/text/StringImpl.h: Allow AtomicStringImpl to call a StringImpl constructor through a friend declaration. + +2010-04-27 Stephanie Lewis <slewis@apple.com> + + Fix Tiger build. + + * wtf/FastMalloc.cpp: + (WTF::TCMalloc_PageHeap::Carve): + +2010-04-26 Stephanie Lewis <slewis@apple.com> + + Reviewed by Geoff Garen. + + https://bugs.webkit.org/show_bug.cgi?id=38154 FastMalloc calls madvise too often. + <rdar://problem/7834433> REGRESSSION: 1.5% PLT regression due to 56028 (return memory quicker). + To save on madvise calls when recommitting memory recommit the entire span and then carve it + instead of carving the span up and only committing the part that will be used immediately. + + * wtf/FastMalloc.cpp: + (WTF::TCMalloc_PageHeap::New): + (WTF::TCMalloc_PageHeap::AllocLarge): + (WTF::TCMalloc_PageHeap::Carve): + +2010-04-26 Oliver Hunt <oliver@apple.com> + + Reviewed by Maciej Stachowiak. + + Add specialized thunks for a char code related string functions + https://bugs.webkit.org/show_bug.cgi?id=38177 + + This is a simple extension to my prior patch. Basically hoist the + existing character loading logic from the charCodeAt thunk and into + a helper function, then add a helper to load strings from the small + string cache. This allows trivial implementations of fromCharCode + and charAt. + + * create_hash_table: + * jit/SpecializedThunkJIT.h: + (JSC::SpecializedThunkJIT::returnJSCell): + (JSC::SpecializedThunkJIT::tagReturnAsJSCell): + * jit/ThunkGenerators.cpp: + (JSC::stringCharLoad): + (JSC::charToString): + (JSC::charCodeAtThunkGenerator): + (JSC::charAtThunkGenerator): + (JSC::fromCharCodeThunkGenerator): + * jit/ThunkGenerators.h: + * runtime/SmallStrings.h: + (JSC::SmallStrings::singleCharacterStrings): + * runtime/StringConstructor.cpp: + (JSC::StringConstructor::StringConstructor): + +2010-04-27 Thomas Zander <t.zander@nokia.com> + + Reviewed by Simon Hausmann. + + [Qt] Fix the build on Symbian on Linux using the Makefile based mkspec + + * JavaScriptCore.pri: It is necessary to specify the library search path + when linking against JavaScriptCore. + +2010-04-21 Jocelyn Turcotte <jocelyn.turcotte@nokia.com> + + Reviewed by Simon Hausmann. + + Compile fix for Visual Studio 2010 + https://bugs.webkit.org/show_bug.cgi?id=37867 + + Patch by Prasanth Ullattil <prasanth.ullattil@nokia.com> + + * runtime/Structure.cpp: + (JSC::Structure::transitionTableAdd): + * wtf/MathExtras.h: + * wtf/Platform.h: + +2010-04-27 Jocelyn Turcotte <jocelyn.turcotte@nokia.com> + + Reviewed by Simon Hausmann. + + Rename COMPILER(MSVC7) to COMPILER(MSVC7_OR_LOWER) + + * config.h: + (JSC::Structure::transitionTableAdd): + * wtf/Assertions.h: + * wtf/Atomics.h: + * wtf/CurrentTime.h: + (WTF::getLocalTime): + * wtf/Platform.h: + * wtf/StaticConstructors.h: + * wtf/StringExtras.h: + * wtf/Vector.h: + (WTF::::append): + +2010-04-15 Jocelyn Turcotte <jocelyn.turcotte@nokia.com> + + Reviewed by Tor Arne Vestbø. + + [Qt] Fix Mac build break. + + https://bugs.webkit.org/show_bug.cgi?id=37867 + - Make sure JavaScriptCore's debug_and_release config follows that + of WebCore. + - Use different name for JavaScriptCore target in debug and release + since they might be written in the same path at the same time on + parallel builds + - Consolidate the DESTDIR determination logic in JavaScriptCore.pri + + * JavaScriptCore.pri: + * JavaScriptCore.pro: + +2010-04-21 Jocelyn Turcotte <jocelyn.turcotte@nokia.com> + + Reviewed by Kenneth Rohde Christiansen. + + [Qt] Make sure WebKit is not compiled using C++0x. + https://bugs.webkit.org/show_bug.cgi?id=37867 + + As the rest of Qt compiles in the C++0x mode, people might start + compiling it in this mode. WebKit don't support this yet. + + Patch by Thiago Macieira <thiago.macieira@nokia.com> + + * JavaScriptCore.pro: + +2010-04-26 Oliver Hunt <oliver@apple.com> + + Fix windows + + * jit/SpecializedThunkJIT.h: + (JSC::SpecializedThunkJIT::argumentToVirtualRegister): + +2010-04-26 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + Need to support more efficient dispatch of lightweight builtins + https://bugs.webkit.org/show_bug.cgi?id=38155 + + The problem with calling lightweight builtins is that marshalling + the call from the nitro calling convention to the system calling + convention is very expensive relative to the cost of the actually + evaluating the function. To work around this problem this patch + adds the ability to define a custom thunk for a builtin. + + This allows us to use high performance custom implementations of + the common and sensible versions of simple builtins. This patch + includes a simple (use of which is currently hardcoded) thunk for + charCodeAt. + + This adds a JSInterfaceJIT subclass called SpecializedThunkJIT + that has helper functions to remove (or at least reduce) the need + to have separate thunk implementations for each JSValue encoding. + + * GNUmakefile.am: + * JavaScriptCore.pro: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + Many project file updates + + * create_hash_table: + Add thunk generation callbacks to the hash tables, currently + we hardcode the script to only support charCodeAt + + * jit/JITStubCall.h: + * jit/JITStubs.cpp: + (JSC::JITThunks::~JITThunks): + (JSC::JITThunks::specializedThunk): + * jit/JITStubs.h: + * jit/SpecializedThunkJIT.h: Added. + (JSC::SpecializedThunkJIT::SpecializedThunkJIT): + (JSC::SpecializedThunkJIT::loadCellArgument): + (JSC::SpecializedThunkJIT::loadJSStringArgument): + (JSC::SpecializedThunkJIT::loadInt32Argument): + (JSC::SpecializedThunkJIT::appendFailure): + (JSC::SpecializedThunkJIT::returnInt32): + (JSC::SpecializedThunkJIT::finalize): + (JSC::SpecializedThunkJIT::argumentToVirtualRegister): + (JSC::SpecializedThunkJIT::tagReturnAsInt32): + * jit/ThunkGenerators.cpp: Added. + (JSC::ThunkHelpers::stringImplDataOffset): + (JSC::ThunkHelpers::jsStringLengthOffset): + (JSC::ThunkHelpers::jsStringValueOffset): + (JSC::charCodeAtThunkGenerator): + * jit/ThunkGenerators.h: Added. + * runtime/Executable.h: + (JSC::NativeExecutable::NativeExecutable): + * runtime/JSFunction.cpp: + (JSC::JSFunction::JSFunction): + * runtime/JSFunction.h: + * runtime/JSGlobalData.h: + (JSC::JSGlobalData::getThunk): + * runtime/JSString.h: + (JSC::): + * runtime/JSValue.h: + Protect some of the JSVALUE32 and JSVALUE32_64 only constants + and function behind appropriate USE() guards to make it harder + to use the wrong flags for the target build. + * runtime/Lookup.cpp: + (JSC::HashTable::createTable): + (JSC::setUpStaticFunctionSlot): + * runtime/Lookup.h: + (JSC::HashEntry::initialize): + (JSC::HashEntry::generator): + (JSC::HashEntry::): + Make the lookup tables use a specialized thunkGenerator + if present + * wtf/text/StringImpl.h: + +2010-04-26 Oliver Hunt <oliver@apple.com> + + Build fix + + * runtime/JSImmediate.h: + * runtime/JSValue.h: + +2010-04-26 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + Factor some basic JS interface logic out of JIT and into a superclass + https://bugs.webkit.org/show_bug.cgi?id=38163 + + Create JSInterfaceJIT to hold some common low level functions for + interacting with the JS RegisterFile. Doing this separately from + https://bugs.webkit.org/show_bug.cgi?id=38155 to ease reviewing. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * jit/JIT.h: + * jit/JITInlineMethods.h: + (JSC::JIT::emitJumpSlowCaseIfNotJSCell): + * jit/JSInterfaceJIT.h: Added. + (JSC::JSInterfaceJIT::emitLoadJSCell): + (JSC::JSInterfaceJIT::emitJumpIfNotJSCell): + (JSC::JSInterfaceJIT::emitLoadInt32): + (JSC::JSInterfaceJIT::tagFor): + (JSC::JSInterfaceJIT::payloadFor): + (JSC::JSInterfaceJIT::addressFor): + +2010-04-26 Sam Weinig <sam@webkit.org> + + Fix Tiger build. + + * wtf/mac/MainThreadMac.mm: + (WTF::isMainThread): + +2010-04-26 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Sam Weinig. + + <rdar://problem/7766413> + + Fixed a crash seen when using the JavaScriptCore API with WebKit. + + No layout test because DumpRenderTree doesn't use the JavaScriptCore API + in this way. + + * interpreter/RegisterFile.cpp: + (JSC::RegisterFile::setGlobalObject): + (JSC::RegisterFile::clearGlobalObject): + (JSC::RegisterFile::globalObject): + * interpreter/RegisterFile.h: + (JSC::RegisterFile::RegisterFile): Use WeakGCPtr for managing m_globalObject, + since it's a weak pointer. (We never noticed this error before because, + in WebKit, global objects always have a self-reference in a global variable, + so marking the register file's global variables would keep m_globalObject + alive. In the JavaScriptCore API, you can allocate a global object with + no self-reference.) + + * runtime/JSActivation.h: Removed unneeded #include. + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::~JSGlobalObject): Don't use ==, since a weak + pointer is 0 when the object it points to runs its destructor. + + * runtime/WeakGCPtr.h: + (JSC::WeakGCPtr::clear): Changed to return a bool indicating whether the + clear actually happened. + (JSC::WeakGCPtr::assign): Changed to forbid assignment of 0 as a shorthand + for calling clear(). A client should never clear by assigning 0, since + clear() should be conditional on whether the object doing the clearing + is still pointed to by the weak pointer. (Otherwise, a zombie object might + clear a pointer to a new, valid object.) + +2010-04-25 Sam Weinig <sam@webkit.org> + + Reviewed by Maciej Stachowiak. + + Fix for https://bugs.webkit.org/show_bug.cgi?id=38097 + Disentangle initializing the main thread from initializing threading + + This is the first step in getting rid of the WEB_THREAD #define and + paving the way to allowing mac both WebKit and WebKit2 to use the same + WebCore. + + * JavaScriptCore.exp: Export initializeMainThread and initializeMainThreadToProcessMainThread. + * JavaScriptCore.xcodeproj/project.pbxproj: Sort files. + + * wtf/MainThread.cpp: + (WTF::mainThreadInitializationMutex): + (WTF::mainThreadFunctionQueueMutex): + (WTF::initializeMainThread): + (WTF::deprecatedInitializeMainThread): + * wtf/MainThread.h: + Added Mac only initializeMainThreadToProcessMainThread which sets up callOnMainThread + and isMainThead calls to assume that WebCore's main thread is also the + process's main thread. Since it is possible that both initializeMainThread + and initializeMainThreadToProcessMainThread could be called, the first one called + wins (either will work). + + * wtf/Threading.h: Moved to top of file. + + * wtf/ThreadingPthreads.cpp: + (WTF::initializeThreading): Remove call to initializeMainThread. + * wtf/ThreadingWin.cpp: + (WTF::initializeThreading): Ditto. + * wtf/gtk/ThreadingGtk.cpp: + (WTF::initializeThreading): Ditto. + + * wtf/mac/MainThreadMac.mm: + (WTF::initializeMainThreadPlatform): + (WTF::initializeMainThreadToProcessMainThread): + (WTF::scheduleDispatchFunctionsOnMainThread): + (WTF::isMainThread): + Add runtime switch between the old behavior of using the system's main + thread and a stored pointer to the main thread. Tiger always uses the + system's main thread. + + * wtf/qt/ThreadingQt.cpp: + (WTF::initializeThreading): Remove call to initializeMainThread. + * wtf/win/MainThreadWin.cpp: + (WTF::initializeMainThreadPlatform): Add call to initializeCurrentThreadInternal + removed from initializeThreading. + +2010-04-26 Jedrzej Nowacki <jedrzej.nowacki@nokia.com> + + Reviewed by Kenneth Rohde Christiansen. + + Fix a memory leak in the QScriptString. + + QScriptStringPrivate's constructor shouldn't call JSStringRetain as + QScriptConverter implicitly pass a JSStringRef ownership. + + [Qt] QScriptStringPrivate c'tor problem + https://bugs.webkit.org/show_bug.cgi?id=38110 + + * qt/api/qscriptstring_p.h: + (QScriptStringPrivate::QScriptStringPrivate): + +2010-04-24 Darin Adler <darin@apple.com> + + Reviewed by Dan Bernstein. + + REGRESSION (r56560): Crash in parseFloat if passed invalid UTF-16 data + https://bugs.webkit.org/show_bug.cgi?id=38083 + rdar://problem/7901044 + + Tests: fast/js/ToNumber.html + fast/js/parseFloat.html + + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::parseInt): Added a FIXME comment about a problem I noticed. + (JSC::parseFloat): Added a FIXME comment about a problem I noticed; + covered by test cases in the test I added. + * runtime/UString.cpp: + (JSC::UString::toDouble): Added FIXME comments about two problems I + noticed; covered by test cases in the tests I added. Added a return + statement so we don't crash when illegal UTF-16 sequences are present. + +2010-04-24 Anton Muhin <antonm@chromium.org> + + Reviewed by Darin Adler. + + Allow to construct HashTraits<WebCore::QualifiedName>::constructDeletedValue + + Former implementation attempted to use AtomicString(HashTableDeletedValue) + however those values cannot be used that way: one cannot construct + QualifiedNameImpl out of such AtomicString as we'll try to lookup this string + in the table, for example. + https://bugs.webkit.org/show_bug.cgi?id=37722 + + * wtf/RefPtr.h: expose hash table deleted value + +2010-04-23 Sam Weinig <sam@webkit.org> + + Reviewed by David Levin. + + Fix for https://bugs.webkit.org/show_bug.cgi?id=38060 + Split up Threading.h + + Move bits for of Threading.h into 3 new files. + - Atomics.h for atomic operations. + - ThreadSafeShared.h for the ThreadSafeShared class. + - ThreadingPrimitives.h for the primitives and platform types. + + Basic threading operations (creation, etc.) remain in Threading.h. + + * GNUmakefile.am: + * JavaScriptCore.gypi: + * JavaScriptCore.vcproj/WTF/WTF.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * wtf/Atomics.h: Copied from wtf/Threading.h. + * wtf/ThreadSafeShared.h: Copied from wtf/Threading.h. + * wtf/Threading.h: + * wtf/ThreadingPrimitives.h: Copied from wtf/Threading.h. + +2010-04-23 Sam Weinig <sam@webkit.org> + + Fix Qt build. + + * wtf/qt/MainThreadQt.cpp: #include <QThread> + +2010-04-22 Sam Weinig <sam@webkit.org> + + Reviewed by Anders Carlsson. + + Fix for https://bugs.webkit.org/show_bug.cgi?id=38022 + Move isMainThread predicate function to MainThread.h + + * wtf/MainThread.cpp: + (WTF::initializeMainThread): + (WTF::isMainThread): + * wtf/MainThread.h: + * wtf/Threading.h: + * wtf/ThreadingPthreads.cpp: + (WTF::initializeThreading): + * wtf/ThreadingWin.cpp: + (WTF::initializeThreading): + * wtf/gtk/ThreadingGtk.cpp: + (WTF::initializeThreading): + * wtf/mac/MainThreadMac.mm: + (WTF::initializeMainThreadPlatform): + (WTF::isMainThread): + * wtf/qt/MainThreadQt.cpp: + (WTF::isMainThread): + * wtf/qt/ThreadingQt.cpp: + (WTF::initializeThreading): + * wtf/text/AtomicString.cpp: + +2010-04-23 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu> + + Reviewed by Laszlo Gombos. + + Add RVCT support for Linux + + Developed in cooperation with Gabor Loki. + + * API/JSStringRef.h: + * jit/ExecutableAllocator.h: + * jit/ExecutableAllocatorPosix.cpp: + (JSC::ExecutableAllocator::cacheFlush): + * jit/JITStubs.cpp: + * wtf/MathExtras.h: + * wtf/unicode/qt4/UnicodeQt4.h: + +2010-04-23 Patrick Gansterer <paroga@paroga.com> + + Reviewed by Laszlo Gombos. + + [WIN] Move OwnPtrWin.cpp into platform specific folder. + https://bugs.webkit.org/show_bug.cgi?id=38042 + + * JavaScriptCore.gypi: + * JavaScriptCore.vcproj/WTF/WTF.vcproj: + * wtf/OwnPtrWin.cpp: Removed. + * wtf/win/OwnPtrWin.cpp: Copied from JavaScriptCore/wtf/OwnPtrWin.cpp. + +2010-04-23 Patrick Gansterer <paroga@paroga.com> + + Reviewed by Laszlo Gombos. + + [BREWMP] Move OwnPtrBrew.cpp into platform specific folder. + https://bugs.webkit.org/show_bug.cgi?id=38042 + + * wtf/OwnPtrBrew.cpp: Removed. + * wtf/brew/OwnPtrBrew.cpp: Copied from JavaScriptCore/wtf/OwnPtrBrew.cpp. + +2010-04-22 Steve Block <steveblock@google.com> + + Reviewed by Adam Barth. + + Update Android to use isfinite, isinf, isnan and signbit from namespace std. + https://bugs.webkit.org/show_bug.cgi?id=37948 + + * wtf/MathExtras.h: + +2010-04-22 Fumitoshi Ukai <ukai@chromium.org> + + Unreviewed build fix. + + * wtf/MD5.cpp: fix include path of CString.h + +2010-04-22 Fumitoshi Ukai <ukai@chromium.org> + + Reviewed by Adam Barth. + + MD5 is required for WebSocket new protocol implementation + https://bugs.webkit.org/show_bug.cgi?id=37913 + + * GNUmakefile.am: + * JavaScriptCore.exp: + * JavaScriptCore.gypi: + * JavaScriptCore.pro: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/WTF/WTF.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * wtf/MD5.cpp: Added. + * wtf/MD5.h: Added. + +2010-04-22 Gavin Barraclough <barraclough@apple.com> + + Reviewed by NOBODY (build fix). + Errk, accidentally committed commenting out two ASSERTs! reverting. + + * runtime/Collector.cpp: + (JSC::Heap::protect): + (JSC::Heap::unprotect): + +2010-04-22 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Geoff Garen. + + https://bugs.webkit.org/show_bug.cgi?id=38006 + Change lifetime of JSC::IdentifierTables used by WebCores to match AtomicStringTable + + Presently JSC's IdentifierTables are owned by the JSGlobalData. For + JSGlobalData objects created via the API this should continue to be the case, + but for the JSGlobalData objects used by WebCore (the main thread's common + global data, and those for workers) use a IdentifierTable provided (and owned) + by wtfThreadData. This allow the lifetime of these IdentifierTable to match + those of the corresponding AtomicStringTables. + + * API/APIShims.h: + (JSC::APIEntryShim::APIEntryShim): + * API/JSContextRef.cpp: + (JSContextGroupCreate): + * runtime/Collector.cpp: + (JSC::Heap::protect): + (JSC::Heap::unprotect): + (JSC::Heap::markRoots): + * runtime/JSGlobalData.cpp: + (JSC::JSGlobalData::JSGlobalData): + (JSC::JSGlobalData::~JSGlobalData): + (JSC::JSGlobalData::createContextGroup): + (JSC::JSGlobalData::create): + (JSC::JSGlobalData::sharedInstance): + * runtime/JSGlobalData.h: + (JSC::JSGlobalData::): + (JSC::JSGlobalData::isSharedInstance): + * runtime/JSLock.cpp: + (JSC::JSLock::JSLock): + (JSC::JSLock::lock): + (JSC::JSLock::unlock): + (JSC::JSLock::DropAllLocks::DropAllLocks): + * wtf/WTFThreadData.cpp: + (WTF::WTFThreadData::WTFThreadData): + (WTF::WTFThreadData::~WTFThreadData): + +2010-04-22 Sheriff Bot <webkit.review.bot@gmail.com> + + Unreviewed, rolling out r58110. + http://trac.webkit.org/changeset/58110 + https://bugs.webkit.org/show_bug.cgi?id=38007 + + Caused an internal compiler error on Qt (Requested by abarth + on #webkit). + + * wtf/MathExtras.h: + +2010-04-22 Gavin Barraclough <barraclough@apple.com> + + Reviewed by NOBODY (windows build fix). + + * API/JSWeakObjectMapRefPrivate.cpp: + +2010-04-22 Gavin Barraclough <barraclough@apple.com> + + Reviewed by NOBODY (windows build fix). + + * API/JSBase.cpp: + * API/JSCallbackObject.cpp: + +2010-04-22 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Geoff Garen. + + https://bugs.webkit.org/show_bug.cgi?id=37978 + Unify JSC::IdentifierTable and WebCore::AtomicStringTable implementations. + + These two classes both implement a HashSet of uniqued StringImpls, with + translator classes to avoid unnecessary object creation. The only difference + between the classes is which flag (isIdentifier or inTable) is set. + Combine the two classes using a template predicated on which flag to use. + + New class AtomicStringTable created, containing all the goodness from + IdentifierTable & AtomicStringTable, expect for Identifier's literalTable, + which has been moved onto JSGlobalData. Removed duplicate string translator + classes. Renamed StringImpl's inTable flag to more explicit 'isAtomic', + and set this on the empty string (which matches Identifier behaviour, and + removes a redundant check for zero-length). + + * GNUmakefile.am: + * JavaScriptCore.gypi: + * JavaScriptCore.vcproj/WTF/WTF.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * runtime/Identifier.cpp: + (JSC::createLiteralTable): + (JSC::deleteLiteralTable): + (JSC::Identifier::add): + (JSC::Identifier::addSlowCase): + * runtime/Identifier.h: + * runtime/JSGlobalData.cpp: + (JSC::JSGlobalData::JSGlobalData): + (JSC::JSGlobalData::~JSGlobalData): + * runtime/JSGlobalData.h: + * wtf/WTFThreadData.cpp: + (WTF::WTFThreadData::WTFThreadData): + (WTF::WTFThreadData::~WTFThreadData): + * wtf/WTFThreadData.h: + (WTF::WTFThreadData::atomicStringTable): + * wtf/text/AtomicString.cpp: + (WebCore::table): + (WebCore::operator==): + (WebCore::AtomicString::add): + (WebCore::AtomicString::find): + (WebCore::AtomicString::remove): + * wtf/text/AtomicStringTable.h: Added. + (WTF::CStringTranslator::hash): + (WTF::CStringTranslator::equal): + (WTF::CStringTranslator::translate): + (WTF::UCharBufferTranslator::hash): + (WTF::UCharBufferTranslator::equal): + (WTF::UCharBufferTranslator::translate): + (WTF::HashAndCharactersTranslator::hash): + (WTF::HashAndCharactersTranslator::equal): + (WTF::HashAndCharactersTranslator::translate): + (WTF::IdentifierOrAtomicStringTable::remove): + (WTF::::~IdentifierOrAtomicStringTable): + (WTF::::add): + (WTF::::find): + * wtf/text/StringImpl.cpp: + (WebCore::StringImpl::~StringImpl): + * wtf/text/StringImpl.h: + (WebCore::StringImpl::isAtomic): + (WebCore::StringImpl::setIsAtomic): + (WebCore::equal): + * wtf/text/StringImplBase.h: + (WTF::StringImplBase::StringImplBase): + +2010-04-22 Steve Block <steveblock@google.com> + + Reviewed by Adam Barth. + + Update Android to use isfinite, isinf, isnan and signbit from namespace std. + https://bugs.webkit.org/show_bug.cgi?id=37948 + + * wtf/MathExtras.h: + +2010-04-22 Jocelyn Turcotte <jocelyn.turcotte@nokia.com> + + Reviewed by Kenneth Rohde Christiansen. + + [Qt] Remove dependency of JSC to QtGui + https://bugs.webkit.org/show_bug.cgi?id=37867 + + The patch also make sure that hal.h is in the include path on Symbian. + The dependency to QtGui took care of that before. + + Patch by Thiago Macieira <thiago.macieira@nokia.com> + and Rohan McGovern <rohan.mcgovern@nokia.com> + + * JavaScriptCore.pri: + * JavaScriptCore.pro: + +2010-04-22 Jocelyn Turcotte <jocelyn.turcotte@nokia.com> + + Reviewed by Tor Arne Vestbø. + + [Qt] Corrects symbols visibility for JavaScriptCore. + + https://bugs.webkit.org/show_bug.cgi?id=37867 + + * JavaScriptCore.pro: + +2010-04-22 Gabor Loki <loki@webkit.org> + + Reviewed by Gavin Barraclough. + + Use BLX and BX to keep happy the return stack predictor above ARMv4 + https://bugs.webkit.org/show_bug.cgi?id=37862 + + Inspired by Jacob Bramley's patch from JaegerMonkey + + * assembler/ARMAssembler.cpp: + (JSC::ARMAssembler::executableCopy): + * assembler/ARMAssembler.h: + (JSC::ARMAssembler::): + (JSC::ARMAssembler::bx): + (JSC::ARMAssembler::blx): + (JSC::ARMAssembler::loadBranchTarget): + (JSC::ARMAssembler::jmp): + (JSC::ARMAssembler::getLdrImmAddress): + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::jump): + (JSC::MacroAssemblerARM::nearCall): + (JSC::MacroAssemblerARM::call): + (JSC::MacroAssemblerARM::ret): + (JSC::MacroAssemblerARM::prepareCall): + (JSC::MacroAssemblerARM::call32): + +2010-04-21 Andy Estes <aestes@apple.com> + + Rubber stamped by Mark Rowe. + + Export WTF::deleteOwnedPtr(HFONT). + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + 2010-04-21 Gavin Barraclough <barraclough@apple.com> Rubber Stamped by Oliver Hunt. diff --git a/JavaScriptCore/Configurations/Version.xcconfig b/JavaScriptCore/Configurations/Version.xcconfig index 6aeb263..cc5943e 100644 --- a/JavaScriptCore/Configurations/Version.xcconfig +++ b/JavaScriptCore/Configurations/Version.xcconfig @@ -22,7 +22,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. MAJOR_VERSION = 533; -MINOR_VERSION = 6; +MINOR_VERSION = 9; TINY_VERSION = 0; FULL_VERSION = $(MAJOR_VERSION).$(MINOR_VERSION); diff --git a/JavaScriptCore/GNUmakefile.am b/JavaScriptCore/GNUmakefile.am index 2d024c1..d3ca76c 100644 --- a/JavaScriptCore/GNUmakefile.am +++ b/JavaScriptCore/GNUmakefile.am @@ -89,12 +89,17 @@ javascriptcore_sources += \ JavaScriptCore/jit/JITPropertyAccess.cpp \ JavaScriptCore/jit/JITPropertyAccess32_64.cpp \ JavaScriptCore/jit/JITArithmetic.cpp \ + JavaScriptCore/jit/JITArithmetic32_64.cpp \ JavaScriptCore/jit/ExecutableAllocator.cpp \ JavaScriptCore/jit/JIT.h \ JavaScriptCore/jit/JITInlineMethods.h \ JavaScriptCore/jit/JITStubs.cpp \ JavaScriptCore/jit/JITStubs.h \ JavaScriptCore/jit/JITStubCall.h \ + JavaScriptCore/jit/JSInterfaceJIT.h \ + JavaScriptCore/jit/SpecializedThunkJIT.h \ + JavaScriptCore/jit/ThunkGenerators.cpp \ + JavaScriptCore/jit/ThunkGenerators.h \ JavaScriptCore/bytecode/StructureStubInfo.cpp \ JavaScriptCore/bytecode/StructureStubInfo.h \ JavaScriptCore/bytecode/CodeBlock.cpp \ @@ -224,6 +229,7 @@ javascriptcore_sources += \ JavaScriptCore/wtf/AlwaysInline.h \ JavaScriptCore/wtf/Assertions.cpp \ JavaScriptCore/wtf/Assertions.h \ + JavaScriptCore/wtf/Atomics.h \ JavaScriptCore/wtf/ByteArray.cpp \ JavaScriptCore/wtf/ByteArray.h \ JavaScriptCore/wtf/CrossThreadRefCounted.h \ @@ -246,6 +252,8 @@ javascriptcore_sources += \ JavaScriptCore/wtf/ListHashSet.h \ JavaScriptCore/wtf/ListRefPtr.h \ JavaScriptCore/wtf/Locker.h \ + JavaScriptCore/wtf/MD5.cpp \ + JavaScriptCore/wtf/MD5.h \ JavaScriptCore/wtf/MainThread.cpp \ JavaScriptCore/wtf/MainThread.h \ JavaScriptCore/wtf/MathExtras.h \ @@ -281,7 +289,9 @@ javascriptcore_sources += \ JavaScriptCore/wtf/ThreadIdentifierDataPthreads.h \ JavaScriptCore/wtf/Threading.cpp \ JavaScriptCore/wtf/Threading.h \ + JavaScriptCore/wtf/ThreadingPrimitives.h \ JavaScriptCore/wtf/ThreadingPthreads.cpp \ + JavaScriptCore/wtf/ThreadSafeShared.h \ JavaScriptCore/wtf/ThreadSpecific.h \ JavaScriptCore/wtf/TypeTraits.cpp \ JavaScriptCore/wtf/TypeTraits.h \ diff --git a/JavaScriptCore/JavaScriptCore.exp b/JavaScriptCore/JavaScriptCore.exp index e8e34ee..c08b54d 100644 --- a/JavaScriptCore/JavaScriptCore.exp +++ b/JavaScriptCore/JavaScriptCore.exp @@ -331,6 +331,7 @@ __ZN3WTF18dateToDaysFrom1970Eiii __ZN3WTF18monthFromDayInYearEib __ZN3WTF19initializeThreadingEv __ZN3WTF20fastMallocStatisticsEv +__ZN3WTF20initializeMainThreadEv __ZN3WTF21RefCountedLeakCounter16suppressMessagesEPKc __ZN3WTF21RefCountedLeakCounter24cancelMessageSuppressionEPKc __ZN3WTF21RefCountedLeakCounter9decrementEv @@ -346,6 +347,10 @@ __ZN3WTF32doubleToStringInJavaScriptFormatEdPcPj __ZN3WTF36lockAtomicallyInitializedStaticMutexEv __ZN3WTF37parseDateFromNullTerminatedCharactersEPKc __ZN3WTF38unlockAtomicallyInitializedStaticMutexEv +__ZN3WTF39initializeMainThreadToProcessMainThreadEv +__ZN3WTF3MD58addBytesEPKhm +__ZN3WTF3MD58checksumEv +__ZN3WTF3MD5C1Ev __ZN3WTF5Mutex4lockEv __ZN3WTF5Mutex6unlockEv __ZN3WTF5Mutex7tryLockEv diff --git a/JavaScriptCore/JavaScriptCore.gyp/JavaScriptCore.gyp b/JavaScriptCore/JavaScriptCore.gyp/JavaScriptCore.gyp index b2ccf1a..9e014dd 100644 --- a/JavaScriptCore/JavaScriptCore.gyp/JavaScriptCore.gyp +++ b/JavaScriptCore/JavaScriptCore.gyp/JavaScriptCore.gyp @@ -117,6 +117,7 @@ ['exclude', '/(gtk|glib|gobject)/.*\\.(cpp|h)$'], ['exclude', '(Default|Gtk|Mac|None|Qt|Win|Wx)\\.(cpp|mm)$'], ['exclude', 'wtf/CurrentTime\\.cpp$'], + ['exclude', 'wtf/MainThread.cpp$'], ['exclude', 'wtf/TC.*\\.(cpp|h)$'], ], 'direct_dependent_settings': { diff --git a/JavaScriptCore/JavaScriptCore.gypi b/JavaScriptCore/JavaScriptCore.gypi index ad2d09e..0e9774b 100644 --- a/JavaScriptCore/JavaScriptCore.gypi +++ b/JavaScriptCore/JavaScriptCore.gypi @@ -115,6 +115,7 @@ 'jit/JIT.cpp', 'jit/JIT.h', 'jit/JITArithmetic.cpp', + 'jit/JITArithmetic32_64.cpp', 'jit/JITCall.cpp', 'jit/JITCode.h', 'jit/JITInlineMethods.h', @@ -336,6 +337,7 @@ 'wtf/ASCIICType.h', 'wtf/Assertions.cpp', 'wtf/Assertions.h', + 'wtf/Atomics.h', 'wtf/AVLTree.h', 'wtf/ByteArray.cpp', 'wtf/ByteArray.h', @@ -370,6 +372,8 @@ 'wtf/ListHashSet.h', 'wtf/ListRefPtr.h', 'wtf/Locker.h', + 'wtf/MD5.cpp', + 'wtf/MD5.h', 'wtf/MainThread.cpp', 'wtf/MainThread.h', 'wtf/MallocZoneSupport.h', @@ -381,7 +385,6 @@ 'wtf/OwnFastMallocPtr.h', 'wtf/OwnPtr.h', 'wtf/OwnPtrCommon.h', - 'wtf/OwnPtrWin.cpp', 'wtf/PassOwnPtr.h', 'wtf/PassRefPtr.h', 'wtf/Platform.h', @@ -413,8 +416,10 @@ 'wtf/Threading.cpp', 'wtf/Threading.h', 'wtf/ThreadingNone.cpp', + 'wtf/ThreadingPrimitives.h', 'wtf/ThreadingPthreads.cpp', 'wtf/ThreadingWin.cpp', + 'wtf/ThreadSafeShared.h', 'wtf/ThreadSpecific.h', 'wtf/ThreadSpecificWin.cpp', 'wtf/TypeTraits.cpp', @@ -448,6 +453,7 @@ 'wtf/WTFThreadData.cpp', 'wtf/WTFThreadData.h', 'wtf/win/MainThreadWin.cpp', + 'wtf/win/OwnPtrWin.cpp', 'wtf/wx/MainThreadWx.cpp', 'yarr/RegexCompiler.cpp', 'yarr/RegexCompiler.h', diff --git a/JavaScriptCore/JavaScriptCore.pri b/JavaScriptCore/JavaScriptCore.pri index 24c8ce5..de5505f 100644 --- a/JavaScriptCore/JavaScriptCore.pri +++ b/JavaScriptCore/JavaScriptCore.pri @@ -1,7 +1,14 @@ # JavaScriptCore - Qt4 build info VPATH += $$PWD -JAVASCRIPTCORE_TARGET = jscore - +CONFIG(debug, debug|release) { + # Output in JavaScriptCore/<config> + JAVASCRIPTCORE_DESTDIR = debug + # Use a config-specific target to prevent parallel builds file clashes on Mac + JAVASCRIPTCORE_TARGET = jscored +} else { + JAVASCRIPTCORE_DESTDIR = release + JAVASCRIPTCORE_TARGET = jscore +} CONFIG(standalone_package) { isEmpty(JSC_GENERATED_SOURCES_DIR):JSC_GENERATED_SOURCES_DIR = $$PWD/generated } else { @@ -14,6 +21,8 @@ symbian: { # Need to guarantee this comes before system includes of /epoc32/include MMP_RULES += "USERINCLUDE ../JavaScriptCore/profiler" LIBS += -lhal + # For hal.h + INCLUDEPATH *= $$MW_LAYER_SYSTEMINCLUDE } INCLUDEPATH = \ @@ -63,9 +72,8 @@ wince* { defineTest(addJavaScriptCoreLib) { - pathToJavaScriptCoreOutput = $$ARGS - CONFIG(debug_and_release):CONFIG(debug, debug|release): pathToJavaScriptCoreOutput = $$pathToJavaScriptCoreOutput/debug - CONFIG(debug_and_release):CONFIG(release, debug|release): pathToJavaScriptCoreOutput = $$pathToJavaScriptCoreOutput/release + # Argument is the relative path to JavaScriptCore.pro's qmake output + pathToJavaScriptCoreOutput = $$ARGS/$$JAVASCRIPTCORE_DESTDIR win32-msvc*|wince* { LIBS += -L$$pathToJavaScriptCoreOutput @@ -73,6 +81,9 @@ defineTest(addJavaScriptCoreLib) { POST_TARGETDEPS += $${pathToJavaScriptCoreOutput}$${QMAKE_DIR_SEP}$${JAVASCRIPTCORE_TARGET}.lib } else:symbian { LIBS += -l$${JAVASCRIPTCORE_TARGET}.lib + # The default symbian build system does not use library paths at all. However when building with + # qmake's symbian makespec that uses Makefiles + QMAKE_LIBDIR += $$pathToJavaScriptCoreOutput POST_TARGETDEPS += $${pathToJavaScriptCoreOutput}$${QMAKE_DIR_SEP}$${JAVASCRIPTCORE_TARGET}.lib } else { # Make sure jscore will be early in the list of libraries to workaround a bug in MinGW diff --git a/JavaScriptCore/JavaScriptCore.pro b/JavaScriptCore/JavaScriptCore.pro index f33be05..fc242cf 100644 --- a/JavaScriptCore/JavaScriptCore.pro +++ b/JavaScriptCore/JavaScriptCore.pro @@ -8,16 +8,19 @@ CONFIG += staticlib # Don't use JavaScriptCore as the target name. qmake would create a JavaScriptCore.vcproj for msvc # which already exists as a directory TARGET = $$JAVASCRIPTCORE_TARGET +DESTDIR = $$JAVASCRIPTCORE_DESTDIR QT += core +QT -= gui CONFIG += depend_includepath contains(QT_CONFIG, embedded):CONFIG += embedded -CONFIG(debug_and_release):CONFIG(debug, debug|release): DESTDIR = debug -CONFIG(debug_and_release):CONFIG(release, debug|release): DESTDIR = release - -!CONFIG(QTDIR_build) { +CONFIG(QTDIR_build) { + # Make sure we compile both debug and release on mac when inside Qt. + # This line was extracted from qbase.pri instead of including the whole file + win32|mac:!macx-xcode:CONFIG += debug_and_release +} else { CONFIG(debug, debug|release) { OBJECTS_DIR = obj/debug } else { # Release @@ -27,6 +30,12 @@ CONFIG(debug_and_release):CONFIG(release, debug|release): DESTDIR = release mac:contains(QT_CONFIG, qt_framework):!CONFIG(webkit_no_framework):!build_pass:CONFIG += build_all } +# WebCore adds these config only when in a standalone build. +# qbase.pri takes care of that when in a QTDIR_build +# Here we add the config for both cases since we don't include qbase.pri +contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols +unix:contains(QT_CONFIG, reduce_relocations):CONFIG += bsymbolic_functions + CONFIG(QTDIR_build) { # Remove the following 2 lines if you want debug information in JavaScriptCore CONFIG -= separate_debug_info @@ -90,12 +99,14 @@ SOURCES += \ jit/ExecutableAllocatorWin.cpp \ jit/ExecutableAllocator.cpp \ jit/JITArithmetic.cpp \ + jit/JITArithmetic32_64.cpp \ jit/JITCall.cpp \ jit/JIT.cpp \ jit/JITOpcodes.cpp \ jit/JITPropertyAccess.cpp \ jit/JITPropertyAccess32_64.cpp \ jit/JITStubs.cpp \ + jit/ThunkGenerators.cpp \ parser/Lexer.cpp \ parser/Nodes.cpp \ parser/ParserArena.cpp \ @@ -194,6 +205,7 @@ SOURCES += \ wtf/dtoa.cpp \ wtf/FastMalloc.cpp \ wtf/HashTable.cpp \ + wtf/MD5.cpp \ wtf/MainThread.cpp \ wtf/qt/MainThreadQt.cpp \ wtf/qt/StringQt.cpp \ @@ -223,3 +235,6 @@ SOURCES += \ !contains(DEFINES, USE_SYSTEM_MALLOC) { SOURCES += wtf/TCSystemAlloc.cpp } + +# Disable C++0x mode in JSC for those who enabled it in their Qt's mkspec +*-g++*:QMAKE_CXXFLAGS -= -std=c++0x -std=gnu++0x diff --git a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def index 76f2fa7..faa1d01 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def +++ b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def @@ -11,6 +11,7 @@ EXPORTS ??0JSArray@JSC@@QAE@V?$NonNullPassRefPtr@VStructure@JSC@@@WTF@@ABVArgList@1@@Z ??0JSByteArray@JSC@@QAE@PAVExecState@1@V?$NonNullPassRefPtr@VStructure@JSC@@@WTF@@PAVByteArray@4@PBUClassInfo@1@@Z ??0JSFunction@JSC@@QAE@PAVExecState@1@V?$NonNullPassRefPtr@VStructure@JSC@@@WTF@@HABVIdentifier@1@P6I?AVJSValue@1@0PAVJSObject@1@V61@ABVArgList@1@@Z@Z + ??0MD5@WTF@@QAE@XZ ??0Mutex@WTF@@QAE@XZ ??0PrototypeFunction@JSC@@QAE@PAVExecState@1@HABVIdentifier@1@P6I?AVJSValue@1@0PAVJSObject@1@V41@ABVArgList@1@@Z@Z ??0PrototypeFunction@JSC@@QAE@PAVExecState@1@V?$NonNullPassRefPtr@VStructure@JSC@@@WTF@@HABVIdentifier@1@P6I?AVJSValue@1@0PAVJSObject@1@V61@ABVArgList@1@@Z@Z @@ -54,6 +55,7 @@ EXPORTS ?add@AtomicString@WebCore@@CA?AV?$PassRefPtr@VStringImpl@WebCore@@@WTF@@PB_WII@Z ?add@Identifier@JSC@@SA?AV?$PassRefPtr@VStringImpl@WebCore@@@WTF@@PAVExecState@2@PBD@Z ?add@PropertyNameArray@JSC@@QAEXPAVStringImpl@WebCore@@@Z + ?addBytes@MD5@WTF@@QAEXPBEI@Z ?addPropertyTransition@Structure@JSC@@SA?AV?$PassRefPtr@VStructure@JSC@@@WTF@@PAV12@ABVIdentifier@2@IPAVJSCell@2@AAI@Z ?addPropertyTransitionToExistingStructure@Structure@JSC@@SA?AV?$PassRefPtr@VStructure@JSC@@@WTF@@PAV12@ABVIdentifier@2@IPAVJSCell@2@AAI@Z ?addPropertyWithoutTransition@Structure@JSC@@QAEIABVIdentifier@2@IPAVJSCell@2@@Z @@ -86,12 +88,12 @@ EXPORTS ?checkCurrentIdentifierTable@Identifier@JSC@@CAXPAVExecState@2@@Z ?checkCurrentIdentifierTable@Identifier@JSC@@CAXPAVJSGlobalData@2@@Z ?checkSyntax@JSC@@YA?AVCompletion@1@PAVExecState@1@ABVSourceCode@1@@Z + ?checksum@MD5@WTF@@QAE?AV?$Vector@E$0BA@@2@XZ ?classInfo@InternalFunction@JSC@@UBEPBUClassInfo@2@XZ ?classInfo@JSCell@JSC@@UBEPBUClassInfo@2@XZ ?className@JSObject@JSC@@UBE?AVUString@2@XZ ?collate@Collator@WTF@@QBE?AW4Result@12@PB_WI0I@Z ?collectAllGarbage@Heap@JSC@@QAEXXZ - ?commentAtom@WebCore@@3VAtomicString@1@B ?configurable@PropertyDescriptor@JSC@@QBE_NXZ ?construct@JSC@@YAPAVJSObject@1@PAVExecState@1@VJSValue@1@W4ConstructType@1@ABTConstructData@1@ABVArgList@1@@Z ?constructArray@JSC@@YAPAVJSArray@1@PAVExecState@1@ABVArgList@1@@Z @@ -138,6 +140,7 @@ EXPORTS ?defineSetter@JSObject@JSC@@UAEXPAVExecState@2@ABVIdentifier@2@PAV12@I@Z ?deleteOwnedPtr@WTF@@YAXPAUHBITMAP__@@@Z ?deleteOwnedPtr@WTF@@YAXPAUHDC__@@@Z + ?deleteOwnedPtr@WTF@@YAXPAUHFONT__@@@Z ?deleteOwnedPtr@WTF@@YAXPAUHRGN__@@@Z ?deleteProperty@JSCell@JSC@@UAE_NPAVExecState@2@ABVIdentifier@2@@Z ?deleteProperty@JSCell@JSC@@UAE_NPAVExecState@2@I@Z @@ -156,7 +159,6 @@ EXPORTS ?doubleToStringInJavaScriptFormat@WTF@@YAXNQADPAI@Z ?dumpSampleData@JSGlobalData@JSC@@QAEXPAVExecState@2@@Z ?empty@StringImpl@WebCore@@SAPAV12@XZ - ?emptyAtom@WebCore@@3VAtomicString@1@B ?endsWith@StringImpl@WebCore@@QAE_NPAV12@_N@Z ?enumerable@PropertyDescriptor@JSC@@QBE_NXZ ?equal@Identifier@JSC@@SA_NPBVStringImpl@WebCore@@PBD@Z @@ -273,7 +275,6 @@ EXPORTS ?name@InternalFunction@JSC@@QAEABVUString@2@PAVExecState@2@@Z ?newUninitialized@CString@WTF@@SA?AV12@IAAPAD@Z ?nonInlineNaN@JSC@@YANXZ - ?nullAtom@WebCore@@3VAtomicString@1@B ?number@String@WebCore@@SA?AV12@G@Z ?number@String@WebCore@@SA?AV12@H@Z ?number@String@WebCore@@SA?AV12@I@Z @@ -346,11 +347,9 @@ EXPORTS ?split@String@WebCore@@QBEXABV12@_NAAV?$Vector@VString@WebCore@@$0A@@WTF@@@Z ?split@String@WebCore@@QBEX_WAAV?$Vector@VString@WebCore@@$0A@@WTF@@@Z ?split@String@WebCore@@QBEX_W_NAAV?$Vector@VString@WebCore@@$0A@@WTF@@@Z - ?starAtom@WebCore@@3VAtomicString@1@B ?startIgnoringLeaks@Structure@JSC@@SAXXZ ?startProfiling@Profiler@JSC@@QAEXPAVExecState@2@ABVUString@2@@Z ?startSampling@JSGlobalData@JSC@@QAEXXZ - ?staticData@WTFThreadData@WTF@@0PAV?$ThreadSpecific@VWTFThreadData@WTF@@@2@A ?stopIgnoringLeaks@Structure@JSC@@SAXXZ ?stopProfiling@Profiler@JSC@@QAE?AV?$PassRefPtr@VProfile@JSC@@@WTF@@PAVExecState@2@ABVUString@2@@Z ?stopSampling@JSGlobalData@JSC@@QAEXXZ @@ -361,7 +360,6 @@ EXPORTS ?substring@StringImpl@WebCore@@QAE?AV?$PassRefPtr@VStringImpl@WebCore@@@WTF@@II@Z ?symbolTableGet@JSVariableObject@JSC@@IAE_NABVIdentifier@2@AAVPropertyDescriptor@2@@Z ?synthesizePrototype@JSValue@JSC@@ABEPAVJSObject@2@PAVExecState@2@@Z - ?textAtom@WebCore@@3VAtomicString@1@B ?thisObject@DebuggerCallFrame@JSC@@QBEPAVJSObject@2@XZ ?threadsafeCopy@String@WebCore@@QBE?AV12@XZ ?throwError@JSC@@YAPAVJSObject@1@PAVExecState@1@W4ErrorType@1@@Z @@ -420,8 +418,6 @@ EXPORTS ?wait@ThreadCondition@WTF@@QAEXAAVMutex@2@@Z ?waitForThreadCompletion@WTF@@YAHIPAPAX@Z ?writable@PropertyDescriptor@JSC@@QBE_NXZ - ?xmlAtom@WebCore@@3VAtomicString@1@B - ?xmlnsAtom@WebCore@@3VAtomicString@1@B WTFLog WTFLogVerbose WTFReportArgumentAssertionFailure diff --git a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj index 158621a..dddf194 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj +++ b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj @@ -1669,6 +1669,10 @@ >
</File>
<File
+ RelativePath="..\..\jit\JITArithmetic32_64.cpp"
+ >
+ </File>
+ <File
RelativePath="..\..\jit\JITCall.cpp"
>
</File>
@@ -1704,6 +1708,22 @@ RelativePath="..\..\jit\JITStubs.h"
>
</File>
+ <File
+ RelativePath="..\..\jit\JSInterfaceJIT.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\jit\SpecializedThunkJIT.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\jit\ThunkGenerators.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\jit\ThunkGenerators.h"
+ >
+ </File>
</Filter>
<Filter
Name="Resources"
diff --git a/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj b/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj index 0145311..d094643 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj +++ b/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj @@ -239,6 +239,10 @@ RelativePath="..\..\wtf\win\MainThreadWin.cpp"
>
</File>
+ <File
+ RelativePath="..\..\wtf\win\OwnPtrWin.cpp"
+ >
+ </File>
</Filter>
<File
RelativePath="..\..\wtf\AlwaysInline.h"
@@ -257,6 +261,10 @@ >
</File>
<File
+ RelativePath="..\..\wtf\Atomics.h"
+ >
+ </File>
+ <File
RelativePath="..\..\wtf\ByteArray.cpp"
>
</File>
@@ -373,6 +381,14 @@ >
</File>
<File
+ RelativePath="..\..\wtf\MD5.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\wtf\MD5.h"
+ >
+ </File>
+ <File
RelativePath="..\..\wtf\MainThread.cpp"
>
</File>
@@ -413,10 +429,6 @@ >
</File>
<File
- RelativePath="..\..\wtf\OwnPtrWin.cpp"
- >
- </File>
- <File
RelativePath="..\..\wtf\PassOwnPtr.h"
>
</File>
@@ -505,10 +517,18 @@ >
</File>
<File
+ RelativePath="..\..\wtf\ThreadingPrimitives.h"
+ >
+ </File>
+ <File
RelativePath="..\..\wtf\ThreadingWin.cpp"
>
</File>
<File
+ RelativePath="..\..\wtf\ThreadSafeShared.h"
+ >
+ </File>
+ <File
RelativePath="..\..\wtf\ThreadSpecific.h"
>
</File>
diff --git a/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj index 9dff7ef..2c99612 100644 --- a/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj +++ b/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj @@ -176,6 +176,8 @@ 41359CF70FDD89CB00206180 /* DateMath.h in Headers */ = {isa = PBXBuildFile; fileRef = 41359CF50FDD89CB00206180 /* DateMath.h */; settings = {ATTRIBUTES = (Private, ); }; }; 4409D8470FAF80A200523B87 /* OwnPtrCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 440B7AED0FAF7FCB0073323E /* OwnPtrCommon.h */; settings = {ATTRIBUTES = (Private, ); }; }; 44DD48530FAEA85000D6B4EB /* PassOwnPtr.h in Headers */ = {isa = PBXBuildFile; fileRef = 44DD48520FAEA85000D6B4EB /* PassOwnPtr.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 511FC4C9117EE28700425272 /* MD5.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 511FC4C7117EE23D00425272 /* MD5.cpp */; }; + 511FC4CB117EE2A800425272 /* MD5.h in Headers */ = {isa = PBXBuildFile; fileRef = 511FC4CA117EE2A800425272 /* MD5.h */; settings = {ATTRIBUTES = (Private, ); }; }; 5D53726F0E1C54880021E549 /* Tracing.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D53726E0E1C54880021E549 /* Tracing.h */; }; 5D5D8AB60E0D0A7200F9C692 /* jsc in Copy Into Framework */ = {isa = PBXBuildFile; fileRef = 932F5BE10822A1C700736975 /* jsc */; }; 5D5D8AD10E0D0EBE00F9C692 /* libedit.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D5D8AD00E0D0EBE00F9C692 /* libedit.dylib */; }; @@ -209,6 +211,7 @@ 868BFA60117D048200B908B1 /* StaticConstructors.h in Headers */ = {isa = PBXBuildFile; fileRef = 868BFA5F117D048200B908B1 /* StaticConstructors.h */; settings = {ATTRIBUTES = (Private, ); }; }; 8698B86910D44D9400D8D01B /* StringBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 8698B86810D44D9400D8D01B /* StringBuilder.h */; settings = {ATTRIBUTES = (Private, ); }; }; 8698BB3910D86BAF00D8D01B /* UStringImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 8698BB3710D86BAF00D8D01B /* UStringImpl.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 869D04AF1193B54D00803475 /* CachedTranscendentalFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 869D04AE1193B54D00803475 /* CachedTranscendentalFunction.h */; settings = {ATTRIBUTES = (Private, ); }; }; 869EBCB70E8C6D4A008722CC /* ResultType.h in Headers */ = {isa = PBXBuildFile; fileRef = 869EBCB60E8C6D4A008722CC /* ResultType.h */; settings = {ATTRIBUTES = (Private, ); }; }; 86A90ED00EE7D51F00AB350D /* JITArithmetic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86A90ECF0EE7D51F00AB350D /* JITArithmetic.cpp */; }; 86ADD1450FDDEA980006EEC2 /* ARMv7Assembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86ADD1430FDDEA980006EEC2 /* ARMv7Assembler.h */; }; @@ -288,11 +291,16 @@ A72701B90DADE94900E548D7 /* ExceptionHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = A72701B30DADE94900E548D7 /* ExceptionHelpers.h */; }; A727FF6B0DA3092200E548D7 /* JSPropertyNameIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A727FF660DA3053B00E548D7 /* JSPropertyNameIterator.cpp */; }; A7280A2811557E3000D56957 /* JSObjectRefPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = A79EDB0811531CD60019E912 /* JSObjectRefPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; + A7386554118697B400540279 /* SpecializedThunkJIT.h in Headers */ = {isa = PBXBuildFile; fileRef = A7386551118697B400540279 /* SpecializedThunkJIT.h */; }; + A7386555118697B400540279 /* ThunkGenerators.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7386552118697B400540279 /* ThunkGenerators.cpp */; }; + A7386556118697B400540279 /* ThunkGenerators.h in Headers */ = {isa = PBXBuildFile; fileRef = A7386553118697B400540279 /* ThunkGenerators.h */; settings = {ATTRIBUTES = (Private, ); }; }; A7482B9311671147003B0712 /* JSWeakObjectMapRefPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = A7482B791166CDEA003B0712 /* JSWeakObjectMapRefPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; A7482B9411671147003B0712 /* JSWeakObjectMapRefPrivate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7482B7A1166CDEA003B0712 /* JSWeakObjectMapRefPrivate.cpp */; }; A7482E93116A7CAD003B0712 /* JSWeakObjectMapRefInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = A7482E37116A697B003B0712 /* JSWeakObjectMapRefInternal.h */; settings = {ATTRIBUTES = (Private, ); }; }; A74B3499102A5F8E0032AB98 /* MarkStack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A74B3498102A5F8E0032AB98 /* MarkStack.cpp */; }; + A75706DE118A2BCF0057F88F /* JITArithmetic32_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A75706DD118A2BCF0057F88F /* JITArithmetic32_64.cpp */; }; A766B44F0EE8DCD1009518CA /* ExecutableAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = A7B48DB50EE74CFC00DCBDB6 /* ExecutableAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; }; + A76C51761182748D00715B05 /* JSInterfaceJIT.h in Headers */ = {isa = PBXBuildFile; fileRef = A76C51741182748D00715B05 /* JSInterfaceJIT.h */; }; A76EE6590FAE59D5003F069A /* NativeFunctionWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = A76EE6580FAE59D5003F069A /* NativeFunctionWrapper.h */; settings = {ATTRIBUTES = (Private, ); }; }; A7795590101A74D500114E55 /* MarkStack.h in Headers */ = {isa = PBXBuildFile; fileRef = A779558F101A74D500114E55 /* MarkStack.h */; settings = {ATTRIBUTES = (Private, ); }; }; A782F1A50EEC9FA20036273F /* ExecutableAllocatorPosix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A782F1A40EEC9FA20036273F /* ExecutableAllocatorPosix.cpp */; }; @@ -458,6 +466,9 @@ BC3046070E1F497F003232CF /* Error.h in Headers */ = {isa = PBXBuildFile; fileRef = BC3046060E1F497F003232CF /* Error.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC3135640F302FA3003DFD3A /* DebuggerActivation.h in Headers */ = {isa = PBXBuildFile; fileRef = BC3135620F302FA3003DFD3A /* DebuggerActivation.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC3135650F302FA3003DFD3A /* DebuggerActivation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC3135630F302FA3003DFD3A /* DebuggerActivation.cpp */; }; + BC5F7BBE11823B590052C02C /* Atomics.h in Headers */ = {isa = PBXBuildFile; fileRef = BC5F7BBB11823B590052C02C /* Atomics.h */; settings = {ATTRIBUTES = (Private, ); }; }; + BC5F7BBF11823B590052C02C /* ThreadingPrimitives.h in Headers */ = {isa = PBXBuildFile; fileRef = BC5F7BBC11823B590052C02C /* ThreadingPrimitives.h */; settings = {ATTRIBUTES = (Private, ); }; }; + BC5F7BC011823B590052C02C /* ThreadSafeShared.h in Headers */ = {isa = PBXBuildFile; fileRef = BC5F7BBD11823B590052C02C /* ThreadSafeShared.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC6AAAE50E1F426500AD87D8 /* ClassInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = BC6AAAE40E1F426500AD87D8 /* ClassInfo.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC756FC90E2031B200DE7D12 /* JSGlobalObjectFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = BC756FC70E2031B200DE7D12 /* JSGlobalObjectFunctions.h */; }; BC7F8FB90E19D1C3008632C0 /* JSNumberCell.h in Headers */ = {isa = PBXBuildFile; fileRef = BC7F8FB80E19D1C3008632C0 /* JSNumberCell.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -671,6 +682,8 @@ 449097EE0F8F81B50076A327 /* FeatureDefines.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = FeatureDefines.xcconfig; sourceTree = "<group>"; }; 44DD48520FAEA85000D6B4EB /* PassOwnPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PassOwnPtr.h; sourceTree = "<group>"; }; 45E12D8806A49B0F00E9DF84 /* jsc.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = jsc.cpp; sourceTree = "<group>"; tabWidth = 4; }; + 511FC4C7117EE23D00425272 /* MD5.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MD5.cpp; sourceTree = "<group>"; }; + 511FC4CA117EE2A800425272 /* MD5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MD5.h; sourceTree = "<group>"; }; 5186111D0CC824830081412B /* Deque.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Deque.h; sourceTree = "<group>"; }; 51F0EB6105C86C6B00E6DF1B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; }; 51F0EC0705C86C9A00E6DF1B /* libobjc.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libobjc.dylib; path = /usr/lib/libobjc.dylib; sourceTree = "<absolute>"; }; @@ -751,6 +764,7 @@ 868BFA5F117D048200B908B1 /* StaticConstructors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaticConstructors.h; sourceTree = "<group>"; }; 8698B86810D44D9400D8D01B /* StringBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringBuilder.h; sourceTree = "<group>"; }; 8698BB3710D86BAF00D8D01B /* UStringImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UStringImpl.h; sourceTree = "<group>"; }; + 869D04AE1193B54D00803475 /* CachedTranscendentalFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CachedTranscendentalFunction.h; sourceTree = "<group>"; }; 869EBCB60E8C6D4A008722CC /* ResultType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResultType.h; sourceTree = "<group>"; }; 86A90ECF0EE7D51F00AB350D /* JITArithmetic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITArithmetic.cpp; sourceTree = "<group>"; }; 86ADD1430FDDEA980006EEC2 /* ARMv7Assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARMv7Assembler.h; sourceTree = "<group>"; }; @@ -862,10 +876,15 @@ A72701B30DADE94900E548D7 /* ExceptionHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExceptionHelpers.h; sourceTree = "<group>"; }; A727FF650DA3053B00E548D7 /* JSPropertyNameIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPropertyNameIterator.h; sourceTree = "<group>"; }; A727FF660DA3053B00E548D7 /* JSPropertyNameIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPropertyNameIterator.cpp; sourceTree = "<group>"; }; + A7386551118697B400540279 /* SpecializedThunkJIT.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpecializedThunkJIT.h; sourceTree = "<group>"; }; + A7386552118697B400540279 /* ThunkGenerators.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ThunkGenerators.cpp; sourceTree = "<group>"; }; + A7386553118697B400540279 /* ThunkGenerators.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThunkGenerators.h; sourceTree = "<group>"; }; A7482B791166CDEA003B0712 /* JSWeakObjectMapRefPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWeakObjectMapRefPrivate.h; sourceTree = "<group>"; }; A7482B7A1166CDEA003B0712 /* JSWeakObjectMapRefPrivate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWeakObjectMapRefPrivate.cpp; sourceTree = "<group>"; }; A7482E37116A697B003B0712 /* JSWeakObjectMapRefInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWeakObjectMapRefInternal.h; sourceTree = "<group>"; }; A74B3498102A5F8E0032AB98 /* MarkStack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MarkStack.cpp; sourceTree = "<group>"; }; + A75706DD118A2BCF0057F88F /* JITArithmetic32_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITArithmetic32_64.cpp; sourceTree = "<group>"; }; + A76C51741182748D00715B05 /* JSInterfaceJIT.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSInterfaceJIT.h; sourceTree = "<group>"; }; A76EE6580FAE59D5003F069A /* NativeFunctionWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NativeFunctionWrapper.h; sourceTree = "<group>"; }; A779558F101A74D500114E55 /* MarkStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkStack.h; sourceTree = "<group>"; }; A782F1A40EEC9FA20036273F /* ExecutableAllocatorPosix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExecutableAllocatorPosix.cpp; sourceTree = "<group>"; }; @@ -950,6 +969,9 @@ BC3135630F302FA3003DFD3A /* DebuggerActivation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DebuggerActivation.cpp; sourceTree = "<group>"; }; BC337BDE0E1AF0B80076918A /* GetterSetter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetterSetter.h; sourceTree = "<group>"; }; BC337BEA0E1B00CB0076918A /* Error.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Error.cpp; sourceTree = "<group>"; }; + BC5F7BBB11823B590052C02C /* Atomics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Atomics.h; sourceTree = "<group>"; }; + BC5F7BBC11823B590052C02C /* ThreadingPrimitives.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadingPrimitives.h; sourceTree = "<group>"; }; + BC5F7BBD11823B590052C02C /* ThreadSafeShared.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadSafeShared.h; sourceTree = "<group>"; }; BC6AAAE40E1F426500AD87D8 /* ClassInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClassInfo.h; sourceTree = "<group>"; }; BC756FC60E2031B200DE7D12 /* JSGlobalObjectFunctions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSGlobalObjectFunctions.cpp; sourceTree = "<group>"; }; BC756FC70E2031B200DE7D12 /* JSGlobalObjectFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGlobalObjectFunctions.h; sourceTree = "<group>"; }; @@ -1192,6 +1214,9 @@ 1429D92C0ED22D7000B89619 /* jit */ = { isa = PBXGroup; children = ( + A7386551118697B400540279 /* SpecializedThunkJIT.h */, + A7386552118697B400540279 /* ThunkGenerators.cpp */, + A7386553118697B400540279 /* ThunkGenerators.h */, A7B48DB60EE74CFC00DCBDB6 /* ExecutableAllocator.cpp */, A7B48DB50EE74CFC00DCBDB6 /* ExecutableAllocator.h */, 86DB64630F95C6FC00D7D921 /* ExecutableAllocatorFixedVMPool.cpp */, @@ -1200,6 +1225,7 @@ 1429D92D0ED22D7000B89619 /* JIT.cpp */, 1429D92E0ED22D7000B89619 /* JIT.h */, 86A90ECF0EE7D51F00AB350D /* JITArithmetic.cpp */, + A75706DD118A2BCF0057F88F /* JITArithmetic32_64.cpp */, 86CC85A20EE79B7400288682 /* JITCall.cpp */, 86CCEFDD0F413F8900FD7F9E /* JITCode.h */, 86CC85A00EE79A4700288682 /* JITInlineMethods.h */, @@ -1209,6 +1235,7 @@ 960626950FB8EC02009798AB /* JITStubCall.h */, 14A23D6C0F4E19CE0023CDAD /* JITStubs.cpp */, 14A6581A0F4E36F4000150FD /* JITStubs.h */, + A76C51741182748D00715B05 /* JSInterfaceJIT.h */, ); path = jit; sourceTree = "<group>"; @@ -1340,6 +1367,7 @@ 938C4F690CA06BC700D9310A /* ASCIICType.h */, 65E217B808E7EECC0023E5F6 /* Assertions.cpp */, 65E217B708E7EECC0023E5F6 /* Assertions.h */, + BC5F7BBB11823B590052C02C /* Atomics.h */, E1A596370DE3E1C300C17E37 /* AVLTree.h */, A7A1F7AA0F252B3C00E184E2 /* ByteArray.cpp */, A7A1F7AB0F252B3C00E184E2 /* ByteArray.h */, @@ -1372,6 +1400,8 @@ 06D358A30DAAD9C4003B174E /* MainThread.h */, 5DBD18AF0C5401A700C15EAE /* MallocZoneSupport.h */, BCF6553B0A2048DE0038A194 /* MathExtras.h */, + 511FC4C7117EE23D00425272 /* MD5.cpp */, + 511FC4CA117EE2A800425272 /* MD5.h */, E1EE798B0D6CA53D00FEA3BA /* MessageQueue.h */, 9303F5690991190000AD71B8 /* Noncopyable.h */, C0A2723F0E509F1E00E96E15 /* NotFound.h */, @@ -1406,7 +1436,9 @@ 18BAB52810DADFCD000D945B /* ThreadIdentifierDataPthreads.h */, 5D6A566A0F05995500266145 /* Threading.cpp */, E1EE79220D6C95CD00FEA3BA /* Threading.h */, + BC5F7BBC11823B590052C02C /* ThreadingPrimitives.h */, E1EE793C0D6C9B9200FEA3BA /* ThreadingPthreads.cpp */, + BC5F7BBD11823B590052C02C /* ThreadSafeShared.h */, E1B7C8BD0DA3A3360074B0DC /* ThreadSpecific.h */, 0B330C260F38C62300692DE3 /* TypeTraits.cpp */, 0B4D7E620F319AC800AD7E58 /* TypeTraits.h */, @@ -1493,6 +1525,7 @@ 704FD35305697E6D003DBED9 /* BooleanObject.h */, BC7952340E15EB5600A898AB /* BooleanPrototype.cpp */, BC7952350E15EB5600A898AB /* BooleanPrototype.h */, + 869D04AE1193B54D00803475 /* CachedTranscendentalFunction.h */, BCA62DFE0E2826230004F30D /* CallData.cpp */, 145C507F0D9DF63B0088F6B9 /* CallData.h */, BC6AAAE40E1F426500AD87D8 /* ClassInfo.h */, @@ -2089,6 +2122,14 @@ 86B99AB9117E391E00DF5A90 /* RopeImpl.h in Headers */, 86B99AE3117E578100DF5A90 /* StringBuffer.h in Headers */, 86B99AE4117E578100DF5A90 /* StringImplBase.h in Headers */, + 511FC4CB117EE2A800425272 /* MD5.h in Headers */, + BC5F7BBE11823B590052C02C /* Atomics.h in Headers */, + BC5F7BBF11823B590052C02C /* ThreadingPrimitives.h in Headers */, + BC5F7BC011823B590052C02C /* ThreadSafeShared.h in Headers */, + A76C51761182748D00715B05 /* JSInterfaceJIT.h in Headers */, + A7386554118697B400540279 /* SpecializedThunkJIT.h in Headers */, + A7386556118697B400540279 /* ThunkGenerators.h in Headers */, + 869D04AF1193B54D00803475 /* CachedTranscendentalFunction.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2536,6 +2577,9 @@ 868BFA0E117CEFD100B908B1 /* StringImpl.cpp in Sources */, 868BFA17117CF19900B908B1 /* WTFString.cpp in Sources */, 86B99AB8117E391E00DF5A90 /* RopeImpl.cpp in Sources */, + 511FC4C9117EE28700425272 /* MD5.cpp in Sources */, + A7386555118697B400540279 /* ThunkGenerators.cpp in Sources */, + A75706DE118A2BCF0057F88F /* JITArithmetic32_64.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/JavaScriptCore/assembler/ARMAssembler.cpp b/JavaScriptCore/assembler/ARMAssembler.cpp index 7393aa1..a181b7e 100644 --- a/JavaScriptCore/assembler/ARMAssembler.cpp +++ b/JavaScriptCore/assembler/ARMAssembler.cpp @@ -357,7 +357,7 @@ void* ARMAssembler::executableCopy(ExecutablePool* allocator) int pos = (*iter) & (~0x1); ARMWord* ldrAddr = reinterpret_cast<ARMWord*>(data + pos); ARMWord* addr = getLdrImmAddress(ldrAddr); - if (*addr != 0xffffffff) { + if (*addr != InvalidBranchTarget) { if (!(*iter & 1)) { int diff = reinterpret_cast<ARMWord*>(data + *addr) - (ldrAddr + DefaultPrefetching); diff --git a/JavaScriptCore/assembler/ARMAssembler.h b/JavaScriptCore/assembler/ARMAssembler.h index f93db68..2ca0949 100644 --- a/JavaScriptCore/assembler/ARMAssembler.h +++ b/JavaScriptCore/assembler/ARMAssembler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 University of Szeged + * Copyright (C) 2009, 2010 University of Szeged * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -123,6 +123,7 @@ namespace JSC { FSUBD = 0x0e300b40, FMULD = 0x0e200b00, FCMPD = 0x0eb40b40, + FSQRTD = 0x0eb10bc0, DTR = 0x05000000, LDRH = 0x00100090, STRH = 0x00000090, @@ -131,6 +132,9 @@ namespace JSC { FDTR = 0x0d000b00, B = 0x0a000000, BL = 0x0b000000, +#if WTF_ARM_ARCH_AT_LEAST(5) || defined(__ARM_ARCH_4T__) + BX = 0x012fff10, +#endif FMSR = 0x0e000a10, FMRS = 0x0e100a10, FSITOD = 0x0eb80bc0, @@ -139,6 +143,7 @@ namespace JSC { #if WTF_ARM_ARCH_AT_LEAST(5) CLZ = 0x016f0f10, BKPT = 0xe120070, + BLX = 0x012fff30, #endif #if WTF_ARM_ARCH_AT_LEAST(7) MOVW = 0x03000000, @@ -182,6 +187,7 @@ namespace JSC { }; static const ARMWord INVALID_IMM = 0xf0000000; + static const ARMWord InvalidBranchTarget = 0xffffffff; static const int DefaultPrefetching = 2; class JmpSrc { @@ -421,6 +427,11 @@ namespace JSC { emitInst(static_cast<ARMWord>(cc) | FCMPD, dd, 0, dm); } + void fsqrtd_r(int dd, int dm, Condition cc = AL) + { + emitInst(static_cast<ARMWord>(cc) | FSQRTD, dd, 0, dm); + } + void ldr_imm(int rd, ARMWord imm, Condition cc = AL) { m_buffer.putIntWithConstantInt(static_cast<ARMWord>(cc) | DTR | DT_LOAD | DT_UP | RN(ARMRegisters::pc) | RD(rd), imm, true); @@ -547,6 +558,30 @@ namespace JSC { #endif } + void bx(int rm, Condition cc = AL) + { +#if WTF_ARM_ARCH_AT_LEAST(5) || defined(__ARM_ARCH_4T__) + emitInst(static_cast<ARMWord>(cc) | BX, 0, 0, RM(rm)); +#else + mov_r(ARMRegisters::pc, RM(rm), cc); +#endif + } + + JmpSrc blx(int rm, Condition cc = AL) + { +#if WTF_ARM_ARCH_AT_LEAST(5) + int s = m_buffer.uncheckedSize(); + emitInst(static_cast<ARMWord>(cc) | BLX, 0, 0, RM(rm)); +#else + ASSERT(rm != 14); + ensureSpace(2 * sizeof(ARMWord), 0); + mov_r(ARMRegisters::lr, ARMRegisters::pc, cc); + int s = m_buffer.uncheckedSize(); + bx(rm, cc); +#endif + return JmpSrc(s); + } + static ARMWord lsl(int reg, ARMWord value) { ASSERT(reg <= ARMRegisters::pc); @@ -619,21 +654,34 @@ namespace JSC { return label(); } - JmpSrc jmp(Condition cc = AL, int useConstantPool = 0) + JmpSrc loadBranchTarget(int rd, Condition cc = AL, int useConstantPool = 0) { ensureSpace(sizeof(ARMWord), sizeof(ARMWord)); int s = m_buffer.uncheckedSize(); - ldr_un_imm(ARMRegisters::pc, 0xffffffff, cc); + ldr_un_imm(rd, InvalidBranchTarget, cc); m_jumps.append(s | (useConstantPool & 0x1)); return JmpSrc(s); } + JmpSrc jmp(Condition cc = AL, int useConstantPool = 0) + { + return loadBranchTarget(ARMRegisters::pc, cc, useConstantPool); + } + void* executableCopy(ExecutablePool* allocator); // Patching helpers static ARMWord* getLdrImmAddress(ARMWord* insn) { +#if WTF_ARM_ARCH_AT_LEAST(5) + // Check for call + if ((*insn & 0x0f7f0000) != 0x051f0000) { + // Must be BLX + ASSERT((*insn & 0x012fff30) == 0x012fff30); + insn--; + } +#endif // Must be an ldr ..., [pc +/- imm] ASSERT((*insn & 0x0f7f0000) == 0x051f0000); diff --git a/JavaScriptCore/assembler/AbstractMacroAssembler.h b/JavaScriptCore/assembler/AbstractMacroAssembler.h index f96e34a..1c7f269 100644 --- a/JavaScriptCore/assembler/AbstractMacroAssembler.h +++ b/JavaScriptCore/assembler/AbstractMacroAssembler.h @@ -160,7 +160,7 @@ public: // in a class requiring explicit construction in order to differentiate // from pointers used as absolute addresses to memory operations struct ImmPtr { - explicit ImmPtr(void* value) + explicit ImmPtr(const void* value) : m_value(value) { } @@ -170,7 +170,7 @@ public: return reinterpret_cast<intptr_t>(m_value); } - void* m_value; + const void* m_value; }; // Imm32: diff --git a/JavaScriptCore/assembler/MacroAssemblerARM.h b/JavaScriptCore/assembler/MacroAssemblerARM.h index 52c4fa2..40d2e4a 100644 --- a/JavaScriptCore/assembler/MacroAssemblerARM.h +++ b/JavaScriptCore/assembler/MacroAssemblerARM.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 Apple Inc. - * Copyright (C) 2009 University of Szeged + * Copyright (C) 2009, 2010 University of Szeged * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -178,6 +178,20 @@ public: { m_assembler.movs_r(dest, m_assembler.asr(dest, imm.m_value & 0x1f)); } + + void urshift32(RegisterID shift_amount, RegisterID dest) + { + ARMWord w = ARMAssembler::getOp2(0x1f); + ASSERT(w != ARMAssembler::INVALID_IMM); + m_assembler.and_r(ARMRegisters::S0, shift_amount, w); + + m_assembler.movs_r(dest, m_assembler.lsr_r(dest, ARMRegisters::S0)); + } + + void urshift32(Imm32 imm, RegisterID dest) + { + m_assembler.movs_r(dest, m_assembler.lsr(dest, imm.m_value & 0x1f)); + } void sub32(RegisterID src, RegisterID dest) { @@ -259,6 +273,14 @@ public: else m_assembler.ldrh_d(dest, ARMRegisters::S0, ARMAssembler::getOp2Byte(-address.offset)); } + + void load16(ImplicitAddress address, RegisterID dest) + { + if (address.offset >= 0) + m_assembler.ldrh_u(dest, address.base, ARMAssembler::getOp2Byte(address.offset)); + else + m_assembler.ldrh_d(dest, address.base, ARMAssembler::getOp2Byte(-address.offset)); + } DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) { @@ -474,7 +496,7 @@ public: void jump(RegisterID target) { - move(target, ARMRegisters::pc); + m_assembler.bx(target); } void jump(Address address) @@ -566,14 +588,19 @@ public: Call nearCall() { +#if WTF_ARM_ARCH_AT_LEAST(5) + ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord)); + m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true); + return Call(m_assembler.blx(ARMRegisters::S1), Call::LinkableNear); +#else prepareCall(); return Call(m_assembler.jmp(ARMAssembler::AL, true), Call::LinkableNear); +#endif } Call call(RegisterID target) { - prepareCall(); - move(ARMRegisters::pc, target); + m_assembler.blx(target); JmpSrc jmpSrc; return Call(jmpSrc, Call::None); } @@ -585,7 +612,7 @@ public: void ret() { - m_assembler.mov_r(ARMRegisters::pc, linkRegister); + m_assembler.bx(linkRegister); } void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) @@ -681,8 +708,14 @@ public: Call call() { +#if WTF_ARM_ARCH_AT_LEAST(5) + ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord)); + m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true); + return Call(m_assembler.blx(ARMRegisters::S1), Call::Linkable); +#else prepareCall(); return Call(m_assembler.jmp(ARMAssembler::AL, true), Call::Linkable); +#endif } Call tailRecursiveCall() @@ -740,12 +773,17 @@ public: return false; } + bool supportsFloatingPointSqrt() const + { + return s_isVFPPresent; + } + void loadDouble(ImplicitAddress address, FPRegisterID dest) { m_assembler.doubleTransfer(true, dest, address.base, address.offset); } - void loadDouble(void* address, FPRegisterID dest) + void loadDouble(const void* address, FPRegisterID dest) { m_assembler.ldr_un_imm(ARMRegisters::S0, (ARMWord)address); m_assembler.fdtr_u(true, dest, ARMRegisters::S0, 0); @@ -801,6 +839,11 @@ public: mulDouble(ARMRegisters::SD0, dest); } + void sqrtDouble(FPRegisterID src, FPRegisterID dest) + { + m_assembler.fsqrtd_r(dest, src); + } + void convertInt32ToDouble(RegisterID src, FPRegisterID dest) { m_assembler.fmsr_r(dest, src); @@ -886,44 +929,56 @@ protected: void prepareCall() { +#if WTF_ARM_ARCH_VERSION < 5 ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord)); m_assembler.mov_r(linkRegister, ARMRegisters::pc); +#endif } void call32(RegisterID base, int32_t offset) { +#if WTF_ARM_ARCH_AT_LEAST(5) + int targetReg = ARMRegisters::S1; +#else + int targetReg = ARMRegisters::pc; +#endif + int tmpReg = ARMRegisters::S1; + if (base == ARMRegisters::sp) offset += 4; if (offset >= 0) { if (offset <= 0xfff) { prepareCall(); - m_assembler.dtr_u(true, ARMRegisters::pc, base, offset); + m_assembler.dtr_u(true, targetReg, base, offset); } else if (offset <= 0xfffff) { - m_assembler.add_r(ARMRegisters::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); + m_assembler.add_r(tmpReg, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); prepareCall(); - m_assembler.dtr_u(true, ARMRegisters::pc, ARMRegisters::S0, offset & 0xfff); + m_assembler.dtr_u(true, targetReg, tmpReg, offset & 0xfff); } else { - ARMWord reg = m_assembler.getImm(offset, ARMRegisters::S0); + ARMWord reg = m_assembler.getImm(offset, tmpReg); prepareCall(); - m_assembler.dtr_ur(true, ARMRegisters::pc, base, reg); + m_assembler.dtr_ur(true, targetReg, base, reg); } } else { offset = -offset; if (offset <= 0xfff) { prepareCall(); - m_assembler.dtr_d(true, ARMRegisters::pc, base, offset); + m_assembler.dtr_d(true, targetReg, base, offset); } else if (offset <= 0xfffff) { - m_assembler.sub_r(ARMRegisters::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); + m_assembler.sub_r(tmpReg, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); prepareCall(); - m_assembler.dtr_d(true, ARMRegisters::pc, ARMRegisters::S0, offset & 0xfff); + m_assembler.dtr_d(true, targetReg, tmpReg, offset & 0xfff); } else { - ARMWord reg = m_assembler.getImm(offset, ARMRegisters::S0); + ARMWord reg = m_assembler.getImm(offset, tmpReg); prepareCall(); - m_assembler.dtr_dr(true, ARMRegisters::pc, base, reg); + m_assembler.dtr_dr(true, targetReg, base, reg); } } +#if WTF_ARM_ARCH_AT_LEAST(5) + m_assembler.blx(targetReg); +#endif } private: diff --git a/JavaScriptCore/assembler/MacroAssemblerARMv7.h b/JavaScriptCore/assembler/MacroAssemblerARMv7.h index 3d08f0e..31a68d9 100644 --- a/JavaScriptCore/assembler/MacroAssemblerARMv7.h +++ b/JavaScriptCore/assembler/MacroAssemblerARMv7.h @@ -257,6 +257,21 @@ public: { m_assembler.asr(dest, dest, imm.m_value & 0x1f); } + + void urshift32(RegisterID shift_amount, RegisterID dest) + { + // Clamp the shift to the range 0..31 + ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f); + ASSERT(armImm.isValid()); + m_assembler.ARM_and(dataTempRegister, shift_amount, armImm); + + m_assembler.lsr(dest, dest, dataTempRegister); + } + + void urshift32(Imm32 imm, RegisterID dest) + { + m_assembler.lsr(dest, dest, imm.m_value & 0x1f); + } void sub32(RegisterID src, RegisterID dest) { @@ -441,6 +456,11 @@ public: { m_assembler.ldrh(dest, makeBaseIndexBase(address), address.index, address.scale); } + + void load16(ImplicitAddress address, RegisterID dest) + { + m_assembler.ldrh(dest, address.base, address.offset); + } DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) { @@ -494,6 +514,11 @@ public: // In short, FIXME:. bool supportsFloatingPointTruncate() const { return false; } + bool supportsFloatingPointSqrt() const + { + return false; + } + void loadDouble(ImplicitAddress address, FPRegisterID dest) { RegisterID base = address.base; @@ -557,6 +582,11 @@ public: mulDouble(fpTempRegister, dest); } + void sqrtDouble(FPRegisterID, FPRegisterID) + { + ASSERT_NOT_REACHED(); + } + void convertInt32ToDouble(RegisterID src, FPRegisterID dest) { m_assembler.vmov(fpTempRegister, src); diff --git a/JavaScriptCore/assembler/MacroAssemblerX86.h b/JavaScriptCore/assembler/MacroAssemblerX86.h index 0366541..0918996 100644 --- a/JavaScriptCore/assembler/MacroAssemblerX86.h +++ b/JavaScriptCore/assembler/MacroAssemblerX86.h @@ -87,7 +87,7 @@ public: m_assembler.movl_mr(address, dest); } - void loadDouble(void* address, FPRegisterID dest) + void loadDouble(const void* address, FPRegisterID dest) { ASSERT(isSSE2Present()); m_assembler.movsd_mr(address, dest); @@ -172,6 +172,7 @@ public: bool supportsFloatingPoint() const { return m_isSSE2Present; } // See comment on MacroAssemblerARMv7::supportsFloatingPointTruncate() bool supportsFloatingPointTruncate() const { return m_isSSE2Present; } + bool supportsFloatingPointSqrt() const { return m_isSSE2Present; } private: const bool m_isSSE2Present; diff --git a/JavaScriptCore/assembler/MacroAssemblerX86Common.h b/JavaScriptCore/assembler/MacroAssemblerX86Common.h index 27c2f15..7296193 100644 --- a/JavaScriptCore/assembler/MacroAssemblerX86Common.h +++ b/JavaScriptCore/assembler/MacroAssemblerX86Common.h @@ -249,6 +249,33 @@ public: { m_assembler.sarl_i8r(imm.m_value, dest); } + + void urshift32(RegisterID shift_amount, RegisterID dest) + { + // On x86 we can only shift by ecx; if asked to shift by another register we'll + // need rejig the shift amount into ecx first, and restore the registers afterwards. + if (shift_amount != X86Registers::ecx) { + swap(shift_amount, X86Registers::ecx); + + // E.g. transform "shrl %eax, %eax" -> "xchgl %eax, %ecx; shrl %ecx, %ecx; xchgl %eax, %ecx" + if (dest == shift_amount) + m_assembler.shrl_CLr(X86Registers::ecx); + // E.g. transform "shrl %eax, %ecx" -> "xchgl %eax, %ecx; shrl %ecx, %eax; xchgl %eax, %ecx" + else if (dest == X86Registers::ecx) + m_assembler.shrl_CLr(shift_amount); + // E.g. transform "shrl %eax, %ebx" -> "xchgl %eax, %ecx; shrl %ecx, %ebx; xchgl %eax, %ecx" + else + m_assembler.shrl_CLr(dest); + + swap(shift_amount, X86Registers::ecx); + } else + m_assembler.shrl_CLr(dest); + } + + void urshift32(Imm32 imm, RegisterID dest) + { + m_assembler.shrl_i8r(imm.m_value, dest); + } void sub32(RegisterID src, RegisterID dest) { @@ -301,6 +328,10 @@ public: m_assembler.xorl_mr(src.offset, src.base, dest); } + void sqrtDouble(FPRegisterID src, FPRegisterID dst) + { + m_assembler.sqrtsd_rr(src, dst); + } // Memory access operations: // @@ -334,6 +365,11 @@ public: { m_assembler.movzwl_mr(address.offset, address.base, address.index, address.scale, dest); } + + void load16(Address address, RegisterID dest) + { + m_assembler.movzwl_mr(address.offset, address.base, dest); + } DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) { diff --git a/JavaScriptCore/assembler/MacroAssemblerX86_64.h b/JavaScriptCore/assembler/MacroAssemblerX86_64.h index 339eaa4..168c93f 100644 --- a/JavaScriptCore/assembler/MacroAssemblerX86_64.h +++ b/JavaScriptCore/assembler/MacroAssemblerX86_64.h @@ -86,7 +86,7 @@ public: } } - void loadDouble(void* address, FPRegisterID dest) + void loadDouble(const void* address, FPRegisterID dest) { move(ImmPtr(address), scratchRegister); loadDouble(scratchRegister, dest); @@ -427,6 +427,7 @@ public: bool supportsFloatingPoint() const { return true; } // See comment on MacroAssemblerARMv7::supportsFloatingPointTruncate() bool supportsFloatingPointTruncate() const { return true; } + bool supportsFloatingPointSqrt() const { return true; } private: friend class LinkBuffer; diff --git a/JavaScriptCore/assembler/X86Assembler.h b/JavaScriptCore/assembler/X86Assembler.h index 14a02f7..20d72f5 100644 --- a/JavaScriptCore/assembler/X86Assembler.h +++ b/JavaScriptCore/assembler/X86Assembler.h @@ -167,6 +167,7 @@ private: OP2_MULSD_VsdWsd = 0x59, OP2_SUBSD_VsdWsd = 0x5C, OP2_DIVSD_VsdWsd = 0x5E, + OP2_SQRTSD_VsdWsd = 0x51, OP2_XORPD_VpdWpd = 0x57, OP2_MOVD_VdEd = 0x6E, OP2_MOVD_EdVd = 0x7E, @@ -200,6 +201,7 @@ private: GROUP1A_OP_POP = 0, GROUP2_OP_SHL = 4, + GROUP2_OP_SHR = 5, GROUP2_OP_SAR = 7, GROUP3_OP_TEST = 0, @@ -672,6 +674,21 @@ public: { m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_SAR, dst); } + + void shrl_i8r(int imm, RegisterID dst) + { + if (imm == 1) + m_formatter.oneByteOp(OP_GROUP2_Ev1, GROUP2_OP_SHR, dst); + else { + m_formatter.oneByteOp(OP_GROUP2_EvIb, GROUP2_OP_SHR, dst); + m_formatter.immediate8(imm); + } + } + + void shrl_CLr(RegisterID dst) + { + m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_SHR, dst); + } void shll_i8r(int imm, RegisterID dst) { @@ -1393,7 +1410,7 @@ public: } #if !CPU(X86_64) - void movsd_mr(void* address, XMMRegisterID dst) + void movsd_mr(const void* address, XMMRegisterID dst) { m_formatter.prefix(PRE_SSE_F2); m_formatter.twoByteOp(OP2_MOVSD_VsdWsd, (RegisterID)dst, address); @@ -1461,6 +1478,12 @@ public: m_formatter.twoByteOp(OP2_XORPD_VpdWpd, (RegisterID)dst, (RegisterID)src); } + void sqrtsd_rr(XMMRegisterID src, XMMRegisterID dst) + { + m_formatter.prefix(PRE_SSE_F2); + m_formatter.twoByteOp(OP2_SQRTSD_VsdWsd, (RegisterID)dst, (RegisterID)src); + } + // Misc instructions: void int3() @@ -1746,7 +1769,7 @@ private: } #if !CPU(X86_64) - void twoByteOp(TwoByteOpcodeID opcode, int reg, void* address) + void twoByteOp(TwoByteOpcodeID opcode, int reg, const void* address) { m_buffer.ensureSpace(maxInstructionSize); m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); @@ -2057,7 +2080,7 @@ private: } #if !CPU(X86_64) - void memoryModRM(int reg, void* address) + void memoryModRM(int reg, const void* address) { // noBase + ModRmMemoryNoDisp means noBase + ModRmMemoryDisp32! putModRm(ModRmMemoryNoDisp, reg, noBase); diff --git a/JavaScriptCore/bytecode/CodeBlock.cpp b/JavaScriptCore/bytecode/CodeBlock.cpp index 8e77e12..d56d328 100644 --- a/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/JavaScriptCore/bytecode/CodeBlock.cpp @@ -931,6 +931,13 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& printf("[%4d] jless\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); break; } + case op_jlesseq: { + int r0 = (++it)->u.operand; + int r1 = (++it)->u.operand; + int offset = (++it)->u.operand; + printf("[%4d] jlesseq\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset); + break; + } case op_loop_if_lesseq: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; @@ -1366,12 +1373,12 @@ void CodeBlock::derefStructures(Instruction* vPC) const vPC[4].u.structure->deref(); return; } - if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_proto)) { + if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_proto) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_proto)) { vPC[4].u.structure->deref(); vPC[5].u.structure->deref(); return; } - if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_chain)) { + if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_chain) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_chain)) { vPC[4].u.structure->deref(); vPC[5].u.structureChain->deref(); return; @@ -1394,7 +1401,9 @@ void CodeBlock::derefStructures(Instruction* vPC) const if ((vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto_list)) || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self_list)) || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_proto_list)) - || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_self_list))) { + || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_self_list)) + || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_proto_list)) + || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_self_list))) { PolymorphicAccessStructureList* polymorphicStructures = vPC[4].u.polymorphicStructures; polymorphicStructures->derefStructures(vPC[5].u.operand); delete polymorphicStructures; @@ -1413,12 +1422,12 @@ void CodeBlock::refStructures(Instruction* vPC) const vPC[4].u.structure->ref(); return; } - if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_proto)) { + if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_proto) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_proto)) { vPC[4].u.structure->ref(); vPC[5].u.structure->ref(); return; } - if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_chain)) { + if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_chain) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_chain)) { vPC[4].u.structure->ref(); vPC[5].u.structureChain->ref(); return; diff --git a/JavaScriptCore/bytecode/Opcode.h b/JavaScriptCore/bytecode/Opcode.h index 0a7f3fa..b5a8c2d 100644 --- a/JavaScriptCore/bytecode/Opcode.h +++ b/JavaScriptCore/bytecode/Opcode.h @@ -138,6 +138,7 @@ namespace JSC { macro(op_jnless, 4) \ macro(op_jnlesseq, 4) \ macro(op_jless, 4) \ + macro(op_jlesseq, 4) \ macro(op_jmp_scopes, 3) \ macro(op_loop, 2) \ macro(op_loop_if_true, 3) \ diff --git a/JavaScriptCore/bytecode/SamplingTool.cpp b/JavaScriptCore/bytecode/SamplingTool.cpp index 8522e45..7191e38 100644 --- a/JavaScriptCore/bytecode/SamplingTool.cpp +++ b/JavaScriptCore/bytecode/SamplingTool.cpp @@ -43,7 +43,7 @@ namespace JSC { void SamplingFlags::sample() { - uint32_t mask = 1 << 31; + uint32_t mask = static_cast<uint32_t>(1 << 31); unsigned index; for (index = 0; index < 32; ++index) { diff --git a/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp index aa5c5f9..db79d67 100644 --- a/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp +++ b/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp @@ -635,7 +635,7 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label* tar instructions().append(target->bind(begin, instructions().size())); return target; } - } else if (m_lastOpcodeID == op_lesseq && !target->isForward()) { + } else if (m_lastOpcodeID == op_lesseq) { int dstIndex; int src1Index; int src2Index; @@ -646,7 +646,7 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label* tar rewindBinaryOp(); size_t begin = instructions().size(); - emitOpcode(op_loop_if_lesseq); + emitOpcode(target->isForward() ? op_jlesseq : op_loop_if_lesseq); instructions().append(src1Index); instructions().append(src2Index); instructions().append(target->bind(begin, instructions().size())); @@ -1631,8 +1631,13 @@ void BytecodeGenerator::emitPopScope() void BytecodeGenerator::emitDebugHook(DebugHookID debugHookID, int firstLine, int lastLine) { +#if ENABLE(DEBUG_WITH_BREAKPOINT) + if (debugHookID != DidReachBreakpoint) + return; +#else if (!m_shouldEmitDebugHooks) return; +#endif emitOpcode(op_debug); instructions().append(debugHookID); instructions().append(firstLine); diff --git a/JavaScriptCore/config.h b/JavaScriptCore/config.h index 791564a..9810885 100644 --- a/JavaScriptCore/config.h +++ b/JavaScriptCore/config.h @@ -44,7 +44,7 @@ #define max max #define min min -#if !COMPILER(MSVC7) && !OS(WINCE) +#if !COMPILER(MSVC7_OR_LOWER) && !OS(WINCE) // We need to define this before the first #include of stdlib.h or it won't contain rand_s. #ifndef _CRT_RAND_S #define _CRT_RAND_S diff --git a/JavaScriptCore/create_hash_table b/JavaScriptCore/create_hash_table index 77463fb..6078f97 100755 --- a/JavaScriptCore/create_hash_table +++ b/JavaScriptCore/create_hash_table @@ -247,6 +247,11 @@ sub output() { print "\nnamespace JSC {\n"; } my $count = scalar @keys + 1; + print "#if ENABLE(JIT)\n"; + print "#define THUNK_GENERATOR(generator) , generator\n"; + print "#else\n"; + print "#define THUNK_GENERATOR(generator)\n"; + print "#endif\n"; print "\nstatic const struct HashTableValue ${nameEntries}\[$count\] = {\n"; my $i = 0; foreach my $key (@keys) { @@ -266,11 +271,25 @@ sub output() { $firstValue = $values[$i]{"value"}; $secondValue = "0"; } - print " { \"$key\", $attrs[$i], (intptr_t)" . $castStr . "($firstValue), (intptr_t)$secondValue },\n"; + my $thunkGenerator = "0"; + if ($key eq "charCodeAt") { + $thunkGenerator = "charCodeAtThunkGenerator"; + } + if ($key eq "charAt") { + $thunkGenerator = "charAtThunkGenerator"; + } + if ($key eq "sqrt") { + $thunkGenerator = "sqrtThunkGenerator"; + } + if ($key eq "pow") { + $thunkGenerator = "powThunkGenerator"; + } + print " { \"$key\", $attrs[$i], (intptr_t)" . $castStr . "($firstValue), (intptr_t)$secondValue THUNK_GENERATOR($thunkGenerator) },\n"; $i++; } - print " { 0, 0, 0, 0 }\n"; + print " { 0, 0, 0, 0 THUNK_GENERATOR(0) }\n"; print "};\n\n"; + print "#undef THUNK_GENERATOR\n"; print "extern JSC_CONST_HASHTABLE HashTable $name =\n"; print " \{ $compactSize, $compactHashSizeMask, $nameEntries, 0 \};\n"; print "} // namespace\n"; diff --git a/JavaScriptCore/debugger/DebuggerCallFrame.cpp b/JavaScriptCore/debugger/DebuggerCallFrame.cpp index 05a385d..a734b1d 100644 --- a/JavaScriptCore/debugger/DebuggerCallFrame.cpp +++ b/JavaScriptCore/debugger/DebuggerCallFrame.cpp @@ -41,6 +41,9 @@ const UString* DebuggerCallFrame::functionName() const if (!m_callFrame->codeBlock()) return 0; + if (!m_callFrame->callee()) + return 0; + JSFunction* function = asFunction(m_callFrame->callee()); if (!function) return 0; @@ -51,7 +54,10 @@ UString DebuggerCallFrame::calculatedFunctionName() const { if (!m_callFrame->codeBlock()) return UString(); - + + if (!m_callFrame->callee()) + return UString(); + JSFunction* function = asFunction(m_callFrame->callee()); if (!function) return UString(); diff --git a/JavaScriptCore/interpreter/Interpreter.cpp b/JavaScriptCore/interpreter/Interpreter.cpp index 40f6458..e53f236 100644 --- a/JavaScriptCore/interpreter/Interpreter.cpp +++ b/JavaScriptCore/interpreter/Interpreter.cpp @@ -3211,6 +3211,29 @@ skip_id_custom_self: vPC += OPCODE_LENGTH(op_jnlesseq); NEXT_INSTRUCTION(); } + DEFINE_OPCODE(op_jlesseq) { + /* jlesseq src1(r) src2(r) target(offset) + + Checks whether register src1 is less than or equal to + register src2, as with the ECMAScript '<=' operator, + and then jumps to offset target from the current instruction, + if and only if the result of the comparison is true. + */ + JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue(); + JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue(); + int target = vPC[3].u.operand; + + bool result = jsLessEq(callFrame, src1, src2); + CHECK_FOR_EXCEPTION(); + + if (result) { + vPC += target; + NEXT_INSTRUCTION(); + } + + vPC += OPCODE_LENGTH(op_jlesseq); + NEXT_INSTRUCTION(); + } DEFINE_OPCODE(op_switch_imm) { /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r) diff --git a/JavaScriptCore/interpreter/RegisterFile.cpp b/JavaScriptCore/interpreter/RegisterFile.cpp index 510effe..63ea5b3 100644 --- a/JavaScriptCore/interpreter/RegisterFile.cpp +++ b/JavaScriptCore/interpreter/RegisterFile.cpp @@ -29,6 +29,8 @@ #include "config.h" #include "RegisterFile.h" +#include "JSGlobalObject.h" + namespace JSC { RegisterFile::~RegisterFile() @@ -56,4 +58,19 @@ void RegisterFile::releaseExcessCapacity() m_maxUsed = m_start; } +void RegisterFile::setGlobalObject(JSGlobalObject* globalObject) +{ + m_globalObject = globalObject; +} + +bool RegisterFile::clearGlobalObject(JSGlobalObject* globalObject) +{ + return m_globalObject.clear(globalObject); +} + +JSGlobalObject* RegisterFile::globalObject() +{ + return m_globalObject.get(); +} + } // namespace JSC diff --git a/JavaScriptCore/interpreter/RegisterFile.h b/JavaScriptCore/interpreter/RegisterFile.h index 1fc4f82..def9e25 100644 --- a/JavaScriptCore/interpreter/RegisterFile.h +++ b/JavaScriptCore/interpreter/RegisterFile.h @@ -32,6 +32,7 @@ #include "Collector.h" #include "ExecutableAllocator.h" #include "Register.h" +#include "WeakGCPtr.h" #include <stdio.h> #include <wtf/Noncopyable.h> #include <wtf/VMTags.h> @@ -124,8 +125,9 @@ namespace JSC { Register* end() const { return m_end; } size_t size() const { return m_end - m_start; } - void setGlobalObject(JSGlobalObject* globalObject) { m_globalObject = globalObject; } - JSGlobalObject* globalObject() { return m_globalObject; } + void setGlobalObject(JSGlobalObject*); + bool clearGlobalObject(JSGlobalObject*); + JSGlobalObject* globalObject(); bool grow(Register* newEnd); void shrink(Register* newEnd); @@ -153,7 +155,7 @@ namespace JSC { Register* m_commitEnd; #endif - JSGlobalObject* m_globalObject; // The global object whose vars are currently stored in the register file. + WeakGCPtr<JSGlobalObject> m_globalObject; // The global object whose vars are currently stored in the register file. }; // FIXME: Add a generic getpagesize() to WTF, then move this function to WTF as well. @@ -166,7 +168,6 @@ namespace JSC { , m_end(0) , m_max(0) , m_buffer(0) - , m_globalObject(0) { // Verify that our values will play nice with mmap and VirtualAlloc. ASSERT(isPageAligned(maxGlobals)); diff --git a/JavaScriptCore/jit/ExecutableAllocator.h b/JavaScriptCore/jit/ExecutableAllocator.h index 8f46dee..610b788 100644 --- a/JavaScriptCore/jit/ExecutableAllocator.h +++ b/JavaScriptCore/jit/ExecutableAllocator.h @@ -247,7 +247,9 @@ public: { User::IMB_Range(code, static_cast<char*>(code) + size); } -#elif CPU(ARM_TRADITIONAL) && OS(LINUX) +#elif CPU(ARM_TRADITIONAL) && OS(LINUX) && COMPILER(RVCT) + static __asm void cacheFlush(void* code, size_t size); +#elif CPU(ARM_TRADITIONAL) && OS(LINUX) && COMPILER(GCC) static void cacheFlush(void* code, size_t size) { asm volatile ( diff --git a/JavaScriptCore/jit/ExecutableAllocatorPosix.cpp b/JavaScriptCore/jit/ExecutableAllocatorPosix.cpp index 06375ad..eee8a7e 100644 --- a/JavaScriptCore/jit/ExecutableAllocatorPosix.cpp +++ b/JavaScriptCore/jit/ExecutableAllocatorPosix.cpp @@ -80,6 +80,21 @@ void ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSe } #endif +#if CPU(ARM_TRADITIONAL) && OS(LINUX) && COMPILER(RVCT) +__asm void ExecutableAllocator::cacheFlush(void* code, size_t size) +{ + ARM + push {r7} + add r1, r1, r0 + mov r7, #0xf0000 + add r7, r7, #0x2 + mov r2, #0x0 + svc #0x0 + pop {r7} + bx lr +} +#endif + } #endif // HAVE(ASSEMBLER) diff --git a/JavaScriptCore/jit/JIT.cpp b/JavaScriptCore/jit/JIT.cpp index ec23d8c..f7b06a0 100644 --- a/JavaScriptCore/jit/JIT.cpp +++ b/JavaScriptCore/jit/JIT.cpp @@ -200,7 +200,6 @@ void JIT::privateCompileMainPass() DEFINE_BINARY_OP(op_in) DEFINE_BINARY_OP(op_less) DEFINE_BINARY_OP(op_lesseq) - DEFINE_BINARY_OP(op_urshift) DEFINE_UNARY_OP(op_is_boolean) DEFINE_UNARY_OP(op_is_function) DEFINE_UNARY_OP(op_is_number) @@ -251,6 +250,7 @@ void JIT::privateCompileMainPass() DEFINE_OP(op_jneq_ptr) DEFINE_OP(op_jnless) DEFINE_OP(op_jless) + DEFINE_OP(op_jlesseq) DEFINE_OP(op_jnlesseq) DEFINE_OP(op_jsr) DEFINE_OP(op_jtrue) @@ -301,6 +301,7 @@ void JIT::privateCompileMainPass() DEFINE_OP(op_resolve_with_base) DEFINE_OP(op_ret) DEFINE_OP(op_rshift) + DEFINE_OP(op_urshift) DEFINE_OP(op_sret) DEFINE_OP(op_strcat) DEFINE_OP(op_stricteq) @@ -401,6 +402,7 @@ void JIT::privateCompileSlowCases() DEFINE_SLOWCASE_OP(op_jfalse) DEFINE_SLOWCASE_OP(op_jnless) DEFINE_SLOWCASE_OP(op_jless) + DEFINE_SLOWCASE_OP(op_jlesseq) DEFINE_SLOWCASE_OP(op_jnlesseq) DEFINE_SLOWCASE_OP(op_jtrue) DEFINE_SLOWCASE_OP(op_loop_if_less) @@ -427,6 +429,7 @@ void JIT::privateCompileSlowCases() DEFINE_SLOWCASE_OP(op_resolve_global) #endif DEFINE_SLOWCASE_OP(op_rshift) + DEFINE_SLOWCASE_OP(op_urshift) DEFINE_SLOWCASE_OP(op_stricteq) DEFINE_SLOWCASE_OP(op_sub) DEFINE_SLOWCASE_OP(op_to_jsnumber) diff --git a/JavaScriptCore/jit/JIT.h b/JavaScriptCore/jit/JIT.h index e757112..a7e8890 100644 --- a/JavaScriptCore/jit/JIT.h +++ b/JavaScriptCore/jit/JIT.h @@ -40,15 +40,10 @@ #include "CodeBlock.h" #include "Interpreter.h" -#include "JITCode.h" -#include "JITStubs.h" +#include "JSInterfaceJIT.h" #include "Opcode.h" -#include "RegisterFile.h" -#include "MacroAssembler.h" #include "Profiler.h" #include <bytecode/SamplingTool.h> -#include <wtf/AlwaysInline.h> -#include <wtf/Vector.h> namespace JSC { @@ -170,128 +165,13 @@ namespace JSC { void ctiPatchCallByReturnAddress(CodeBlock* codeblock, ReturnAddressPtr returnAddress, MacroAssemblerCodePtr newCalleeFunction); void ctiPatchCallByReturnAddress(CodeBlock* codeblock, ReturnAddressPtr returnAddress, FunctionPtr newCalleeFunction); - class JIT : private MacroAssembler { + class JIT : private JSInterfaceJIT { friend class JITStubCall; using MacroAssembler::Jump; using MacroAssembler::JumpList; using MacroAssembler::Label; - // NOTES: - // - // regT0 has two special meanings. The return value from a stub - // call will always be in regT0, and by default (unless - // a register is specified) emitPutVirtualRegister() will store - // the value from regT0. - // - // regT3 is required to be callee-preserved. - // - // tempRegister2 is has no such dependencies. It is important that - // on x86/x86-64 it is ecx for performance reasons, since the - // MacroAssembler will need to plant register swaps if it is not - - // however the code will still function correctly. -#if CPU(X86_64) - static const RegisterID returnValueRegister = X86Registers::eax; - static const RegisterID cachedResultRegister = X86Registers::eax; - static const RegisterID firstArgumentRegister = X86Registers::edi; - - static const RegisterID timeoutCheckRegister = X86Registers::r12; - static const RegisterID callFrameRegister = X86Registers::r13; - static const RegisterID tagTypeNumberRegister = X86Registers::r14; - static const RegisterID tagMaskRegister = X86Registers::r15; - - static const RegisterID regT0 = X86Registers::eax; - static const RegisterID regT1 = X86Registers::edx; - static const RegisterID regT2 = X86Registers::ecx; - static const RegisterID regT3 = X86Registers::ebx; - - static const FPRegisterID fpRegT0 = X86Registers::xmm0; - static const FPRegisterID fpRegT1 = X86Registers::xmm1; - static const FPRegisterID fpRegT2 = X86Registers::xmm2; -#elif CPU(X86) - static const RegisterID returnValueRegister = X86Registers::eax; - static const RegisterID cachedResultRegister = X86Registers::eax; - // On x86 we always use fastcall conventions = but on - // OS X if might make more sense to just use regparm. - static const RegisterID firstArgumentRegister = X86Registers::ecx; - - static const RegisterID timeoutCheckRegister = X86Registers::esi; - static const RegisterID callFrameRegister = X86Registers::edi; - - static const RegisterID regT0 = X86Registers::eax; - static const RegisterID regT1 = X86Registers::edx; - static const RegisterID regT2 = X86Registers::ecx; - static const RegisterID regT3 = X86Registers::ebx; - - static const FPRegisterID fpRegT0 = X86Registers::xmm0; - static const FPRegisterID fpRegT1 = X86Registers::xmm1; - static const FPRegisterID fpRegT2 = X86Registers::xmm2; -#elif CPU(ARM_THUMB2) - static const RegisterID returnValueRegister = ARMRegisters::r0; - static const RegisterID cachedResultRegister = ARMRegisters::r0; - static const RegisterID firstArgumentRegister = ARMRegisters::r0; - - static const RegisterID regT0 = ARMRegisters::r0; - static const RegisterID regT1 = ARMRegisters::r1; - static const RegisterID regT2 = ARMRegisters::r2; - static const RegisterID regT3 = ARMRegisters::r4; - - static const RegisterID callFrameRegister = ARMRegisters::r5; - static const RegisterID timeoutCheckRegister = ARMRegisters::r6; - - static const FPRegisterID fpRegT0 = ARMRegisters::d0; - static const FPRegisterID fpRegT1 = ARMRegisters::d1; - static const FPRegisterID fpRegT2 = ARMRegisters::d2; -#elif CPU(ARM_TRADITIONAL) - static const RegisterID returnValueRegister = ARMRegisters::r0; - static const RegisterID cachedResultRegister = ARMRegisters::r0; - static const RegisterID firstArgumentRegister = ARMRegisters::r0; - - static const RegisterID timeoutCheckRegister = ARMRegisters::r5; - static const RegisterID callFrameRegister = ARMRegisters::r4; - - static const RegisterID regT0 = ARMRegisters::r0; - static const RegisterID regT1 = ARMRegisters::r1; - static const RegisterID regT2 = ARMRegisters::r2; - // Callee preserved - static const RegisterID regT3 = ARMRegisters::r7; - - static const RegisterID regS0 = ARMRegisters::S0; - // Callee preserved - static const RegisterID regS1 = ARMRegisters::S1; - - static const RegisterID regStackPtr = ARMRegisters::sp; - static const RegisterID regLink = ARMRegisters::lr; - - static const FPRegisterID fpRegT0 = ARMRegisters::d0; - static const FPRegisterID fpRegT1 = ARMRegisters::d1; - static const FPRegisterID fpRegT2 = ARMRegisters::d2; -#elif CPU(MIPS) - static const RegisterID returnValueRegister = MIPSRegisters::v0; - static const RegisterID cachedResultRegister = MIPSRegisters::v0; - static const RegisterID firstArgumentRegister = MIPSRegisters::a0; - - // regT0 must be v0 for returning a 32-bit value. - static const RegisterID regT0 = MIPSRegisters::v0; - - // regT1 must be v1 for returning a pair of 32-bit value. - static const RegisterID regT1 = MIPSRegisters::v1; - - static const RegisterID regT2 = MIPSRegisters::t4; - - // regT3 must be saved in the callee, so use an S register. - static const RegisterID regT3 = MIPSRegisters::s2; - - static const RegisterID callFrameRegister = MIPSRegisters::s0; - static const RegisterID timeoutCheckRegister = MIPSRegisters::s1; - - static const FPRegisterID fpRegT0 = MIPSRegisters::f4; - static const FPRegisterID fpRegT1 = MIPSRegisters::f6; - static const FPRegisterID fpRegT2 = MIPSRegisters::f8; -#else - #error "JIT not supported on this platform." -#endif - static const int patchGetByIdDefaultStructure = -1; // Magic number - initial offset cannot be representable as a signed 8bit value, or the X86Assembler // will compress the displacement, and we may not be able to fit a patched offset. @@ -405,14 +285,9 @@ namespace JSC { void emitLoadDouble(unsigned index, FPRegisterID value); void emitLoadInt32ToDouble(unsigned index, FPRegisterID value); - Address addressFor(unsigned index, RegisterID base = callFrameRegister); - void testPrototype(Structure*, JumpList& failureCases); #if USE(JSVALUE32_64) - Address tagFor(unsigned index, RegisterID base = callFrameRegister); - Address payloadFor(unsigned index, RegisterID base = callFrameRegister); - bool getOperandConstantImmediateInt(unsigned op1, unsigned op2, unsigned& op, int32_t& constant); void emitLoadTag(unsigned index, RegisterID tag); @@ -549,8 +424,6 @@ namespace JSC { void emitJumpSlowCaseIfNotJSCell(RegisterID); void emitJumpSlowCaseIfNotJSCell(RegisterID, int VReg); #if USE(JSVALUE64) - JIT::Jump emitJumpIfImmediateNumber(RegisterID); - JIT::Jump emitJumpIfNotImmediateNumber(RegisterID); #else JIT::Jump emitJumpIfImmediateNumber(RegisterID reg) { @@ -799,6 +672,7 @@ namespace JSC { void emit_op_jneq_ptr(Instruction*); void emit_op_jnless(Instruction*); void emit_op_jless(Instruction*); + void emit_op_jlesseq(Instruction*, bool invert = false); void emit_op_jnlesseq(Instruction*); void emit_op_jsr(Instruction*); void emit_op_jtrue(Instruction*); @@ -861,6 +735,7 @@ namespace JSC { void emit_op_to_jsnumber(Instruction*); void emit_op_to_primitive(Instruction*); void emit_op_unexpected_load(Instruction*); + void emit_op_urshift(Instruction*); #if ENABLE(JIT_OPTIMIZE_MOD) void softModulo(); #endif @@ -885,6 +760,7 @@ namespace JSC { void emitSlow_op_jfalse(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_jnless(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_jless(Instruction*, Vector<SlowCaseEntry>::iterator&); + void emitSlow_op_jlesseq(Instruction*, Vector<SlowCaseEntry>::iterator&, bool invert = false); void emitSlow_op_jnlesseq(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_jtrue(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_loop_if_less(Instruction*, Vector<SlowCaseEntry>::iterator&); @@ -911,6 +787,11 @@ namespace JSC { void emitSlow_op_sub(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_to_jsnumber(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_to_primitive(Instruction*, Vector<SlowCaseEntry>::iterator&); + void emitSlow_op_urshift(Instruction*, Vector<SlowCaseEntry>::iterator&); + + + void emitRightShift(Instruction*, bool isUnsigned); + void emitRightShiftSlowCase(Instruction*, Vector<SlowCaseEntry>::iterator&, bool isUnsigned); /* These functions are deprecated: Please use JITStubCall instead. */ void emitPutJITStubArg(RegisterID src, unsigned argumentNumber); @@ -933,6 +814,7 @@ namespace JSC { JSValue getConstantOperand(unsigned src); bool isOperandConstantImmediateInt(unsigned src); + bool isOperandConstantImmediateChar(unsigned src); Jump getSlowCase(Vector<SlowCaseEntry>::iterator& iter) { @@ -956,6 +838,9 @@ namespace JSC { void restoreReturnAddressBeforeReturn(RegisterID); void restoreReturnAddressBeforeReturn(Address); + // Loads the character value of a single character string into dst. + void emitLoadCharacterString(RegisterID src, RegisterID dst, JumpList& failures); + void emitTimeoutCheck(); #ifndef NDEBUG void printBytecodeOperandTypes(unsigned src1, unsigned src2); diff --git a/JavaScriptCore/jit/JITArithmetic.cpp b/JavaScriptCore/jit/JITArithmetic.cpp index 2e1ff40..e5a4620 100644 --- a/JavaScriptCore/jit/JITArithmetic.cpp +++ b/JavaScriptCore/jit/JITArithmetic.cpp @@ -20,7 +20,7 @@ * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" @@ -46,1187 +46,7 @@ using namespace std; namespace JSC { -#if USE(JSVALUE32_64) - -void JIT::emit_op_negate(Instruction* currentInstruction) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned src = currentInstruction[2].u.operand; - - emitLoad(src, regT1, regT0); - - Jump srcNotInt = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)); - addSlowCase(branchTest32(Zero, regT0, Imm32(0x7fffffff))); - neg32(regT0); - emitStoreInt32(dst, regT0, (dst == src)); - - Jump end = jump(); - - srcNotInt.link(this); - addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag))); - - xor32(Imm32(1 << 31), regT1); - store32(regT1, tagFor(dst)); - if (dst != src) - store32(regT0, payloadFor(dst)); - - end.link(this); -} - -void JIT::emitSlow_op_negate(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) -{ - unsigned dst = currentInstruction[1].u.operand; - - linkSlowCase(iter); // 0x7fffffff check - linkSlowCase(iter); // double check - - JITStubCall stubCall(this, cti_op_negate); - stubCall.addArgument(regT1, regT0); - stubCall.call(dst); -} - -void JIT::emit_op_jnless(Instruction* currentInstruction) -{ - unsigned op1 = currentInstruction[1].u.operand; - unsigned op2 = currentInstruction[2].u.operand; - unsigned target = currentInstruction[3].u.operand; - - JumpList notInt32Op1; - JumpList notInt32Op2; - - // Int32 less. - if (isOperandConstantImmediateInt(op1)) { - emitLoad(op2, regT3, regT2); - notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); - addJump(branch32(LessThanOrEqual, regT2, Imm32(getConstantOperand(op1).asInt32())), target); - } else if (isOperandConstantImmediateInt(op2)) { - emitLoad(op1, regT1, regT0); - notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - addJump(branch32(GreaterThanOrEqual, regT0, Imm32(getConstantOperand(op2).asInt32())), target); - } else { - emitLoad2(op1, regT1, regT0, op2, regT3, regT2); - notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); - addJump(branch32(GreaterThanOrEqual, regT0, regT2), target); - } - - if (!supportsFloatingPoint()) { - addSlowCase(notInt32Op1); - addSlowCase(notInt32Op2); - return; - } - Jump end = jump(); - - // Double less. - emitBinaryDoubleOp(op_jnless, target, op1, op2, OperandTypes(), notInt32Op1, notInt32Op2, !isOperandConstantImmediateInt(op1), isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2)); - end.link(this); -} - -void JIT::emitSlow_op_jnless(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) -{ - unsigned op1 = currentInstruction[1].u.operand; - unsigned op2 = currentInstruction[2].u.operand; - unsigned target = currentInstruction[3].u.operand; - - if (!supportsFloatingPoint()) { - if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2)) - linkSlowCase(iter); // int32 check - linkSlowCase(iter); // int32 check - } else { - if (!isOperandConstantImmediateInt(op1)) { - linkSlowCase(iter); // double check - linkSlowCase(iter); // int32 check - } - if (isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2)) - linkSlowCase(iter); // double check - } - - JITStubCall stubCall(this, cti_op_jless); - stubCall.addArgument(op1); - stubCall.addArgument(op2); - stubCall.call(); - emitJumpSlowToHot(branchTest32(Zero, regT0), target); -} - -void JIT::emit_op_jless(Instruction* currentInstruction) -{ - unsigned op1 = currentInstruction[1].u.operand; - unsigned op2 = currentInstruction[2].u.operand; - unsigned target = currentInstruction[3].u.operand; - - JumpList notInt32Op1; - JumpList notInt32Op2; - - // Int32 less. - if (isOperandConstantImmediateInt(op1)) { - emitLoad(op2, regT3, regT2); - notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); - addJump(branch32(GreaterThan, regT2, Imm32(getConstantOperand(op1).asInt32())), target); - } else if (isOperandConstantImmediateInt(op2)) { - emitLoad(op1, regT1, regT0); - notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - addJump(branch32(LessThan, regT0, Imm32(getConstantOperand(op2).asInt32())), target); - } else { - emitLoad2(op1, regT1, regT0, op2, regT3, regT2); - notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); - addJump(branch32(LessThan, regT0, regT2), target); - } - - if (!supportsFloatingPoint()) { - addSlowCase(notInt32Op1); - addSlowCase(notInt32Op2); - return; - } - Jump end = jump(); - - // Double less. - emitBinaryDoubleOp(op_jless, target, op1, op2, OperandTypes(), notInt32Op1, notInt32Op2, !isOperandConstantImmediateInt(op1), isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2)); - end.link(this); -} - -void JIT::emitSlow_op_jless(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) -{ - unsigned op1 = currentInstruction[1].u.operand; - unsigned op2 = currentInstruction[2].u.operand; - unsigned target = currentInstruction[3].u.operand; - - if (!supportsFloatingPoint()) { - if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2)) - linkSlowCase(iter); // int32 check - linkSlowCase(iter); // int32 check - } else { - if (!isOperandConstantImmediateInt(op1)) { - linkSlowCase(iter); // double check - linkSlowCase(iter); // int32 check - } - if (isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2)) - linkSlowCase(iter); // double check - } - - JITStubCall stubCall(this, cti_op_jless); - stubCall.addArgument(op1); - stubCall.addArgument(op2); - stubCall.call(); - emitJumpSlowToHot(branchTest32(NonZero, regT0), target); -} - -void JIT::emit_op_jnlesseq(Instruction* currentInstruction) -{ - unsigned op1 = currentInstruction[1].u.operand; - unsigned op2 = currentInstruction[2].u.operand; - unsigned target = currentInstruction[3].u.operand; - - JumpList notInt32Op1; - JumpList notInt32Op2; - - // Int32 less. - if (isOperandConstantImmediateInt(op1)) { - emitLoad(op2, regT3, regT2); - notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); - addJump(branch32(LessThan, regT2, Imm32(getConstantOperand(op1).asInt32())), target); - } else if (isOperandConstantImmediateInt(op2)) { - emitLoad(op1, regT1, regT0); - notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - addJump(branch32(GreaterThan, regT0, Imm32(getConstantOperand(op2).asInt32())), target); - } else { - emitLoad2(op1, regT1, regT0, op2, regT3, regT2); - notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); - addJump(branch32(GreaterThan, regT0, regT2), target); - } - - if (!supportsFloatingPoint()) { - addSlowCase(notInt32Op1); - addSlowCase(notInt32Op2); - return; - } - Jump end = jump(); - - // Double less. - emitBinaryDoubleOp(op_jnlesseq, target, op1, op2, OperandTypes(), notInt32Op1, notInt32Op2, !isOperandConstantImmediateInt(op1), isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2)); - end.link(this); -} - -void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) -{ - unsigned op1 = currentInstruction[1].u.operand; - unsigned op2 = currentInstruction[2].u.operand; - unsigned target = currentInstruction[3].u.operand; - - if (!supportsFloatingPoint()) { - if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2)) - linkSlowCase(iter); // int32 check - linkSlowCase(iter); // int32 check - } else { - if (!isOperandConstantImmediateInt(op1)) { - linkSlowCase(iter); // double check - linkSlowCase(iter); // int32 check - } - if (isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2)) - linkSlowCase(iter); // double check - } - - JITStubCall stubCall(this, cti_op_jlesseq); - stubCall.addArgument(op1); - stubCall.addArgument(op2); - stubCall.call(); - emitJumpSlowToHot(branchTest32(Zero, regT0), target); -} - -// LeftShift (<<) - -void JIT::emit_op_lshift(Instruction* currentInstruction) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned op1 = currentInstruction[2].u.operand; - unsigned op2 = currentInstruction[3].u.operand; - - if (isOperandConstantImmediateInt(op2)) { - emitLoad(op1, regT1, regT0); - addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - lshift32(Imm32(getConstantOperand(op2).asInt32()), regT0); - emitStoreInt32(dst, regT0, dst == op1); - return; - } - - emitLoad2(op1, regT1, regT0, op2, regT3, regT2); - if (!isOperandConstantImmediateInt(op1)) - addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); - lshift32(regT2, regT0); - emitStoreInt32(dst, regT0, dst == op1 || dst == op2); -} - -void JIT::emitSlow_op_lshift(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned op1 = currentInstruction[2].u.operand; - unsigned op2 = currentInstruction[3].u.operand; - - if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2)) - linkSlowCase(iter); // int32 check - linkSlowCase(iter); // int32 check - - JITStubCall stubCall(this, cti_op_lshift); - stubCall.addArgument(op1); - stubCall.addArgument(op2); - stubCall.call(dst); -} - -// RightShift (>>) - -void JIT::emit_op_rshift(Instruction* currentInstruction) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned op1 = currentInstruction[2].u.operand; - unsigned op2 = currentInstruction[3].u.operand; - - if (isOperandConstantImmediateInt(op2)) { - emitLoad(op1, regT1, regT0); - addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - rshift32(Imm32(getConstantOperand(op2).asInt32()), regT0); - emitStoreInt32(dst, regT0, dst == op1); - return; - } - - emitLoad2(op1, regT1, regT0, op2, regT3, regT2); - if (!isOperandConstantImmediateInt(op1)) - addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); - rshift32(regT2, regT0); - emitStoreInt32(dst, regT0, dst == op1 || dst == op2); -} - -void JIT::emitSlow_op_rshift(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned op1 = currentInstruction[2].u.operand; - unsigned op2 = currentInstruction[3].u.operand; - - if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2)) - linkSlowCase(iter); // int32 check - linkSlowCase(iter); // int32 check - - JITStubCall stubCall(this, cti_op_rshift); - stubCall.addArgument(op1); - stubCall.addArgument(op2); - stubCall.call(dst); -} - -// BitAnd (&) - -void JIT::emit_op_bitand(Instruction* currentInstruction) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned op1 = currentInstruction[2].u.operand; - unsigned op2 = currentInstruction[3].u.operand; - - unsigned op; - int32_t constant; - if (getOperandConstantImmediateInt(op1, op2, op, constant)) { - emitLoad(op, regT1, regT0); - addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - and32(Imm32(constant), regT0); - emitStoreInt32(dst, regT0, (op == dst)); - return; - } - - emitLoad2(op1, regT1, regT0, op2, regT3, regT2); - addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); - and32(regT2, regT0); - emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst)); -} - -void JIT::emitSlow_op_bitand(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned op1 = currentInstruction[2].u.operand; - unsigned op2 = currentInstruction[3].u.operand; - - if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2)) - linkSlowCase(iter); // int32 check - linkSlowCase(iter); // int32 check - - JITStubCall stubCall(this, cti_op_bitand); - stubCall.addArgument(op1); - stubCall.addArgument(op2); - stubCall.call(dst); -} - -// BitOr (|) - -void JIT::emit_op_bitor(Instruction* currentInstruction) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned op1 = currentInstruction[2].u.operand; - unsigned op2 = currentInstruction[3].u.operand; - - unsigned op; - int32_t constant; - if (getOperandConstantImmediateInt(op1, op2, op, constant)) { - emitLoad(op, regT1, regT0); - addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - or32(Imm32(constant), regT0); - emitStoreInt32(dst, regT0, (op == dst)); - return; - } - - emitLoad2(op1, regT1, regT0, op2, regT3, regT2); - addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); - or32(regT2, regT0); - emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst)); -} - -void JIT::emitSlow_op_bitor(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned op1 = currentInstruction[2].u.operand; - unsigned op2 = currentInstruction[3].u.operand; - - if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2)) - linkSlowCase(iter); // int32 check - linkSlowCase(iter); // int32 check - - JITStubCall stubCall(this, cti_op_bitor); - stubCall.addArgument(op1); - stubCall.addArgument(op2); - stubCall.call(dst); -} - -// BitXor (^) - -void JIT::emit_op_bitxor(Instruction* currentInstruction) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned op1 = currentInstruction[2].u.operand; - unsigned op2 = currentInstruction[3].u.operand; - - unsigned op; - int32_t constant; - if (getOperandConstantImmediateInt(op1, op2, op, constant)) { - emitLoad(op, regT1, regT0); - addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - xor32(Imm32(constant), regT0); - emitStoreInt32(dst, regT0, (op == dst)); - return; - } - - emitLoad2(op1, regT1, regT0, op2, regT3, regT2); - addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); - xor32(regT2, regT0); - emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst)); -} - -void JIT::emitSlow_op_bitxor(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned op1 = currentInstruction[2].u.operand; - unsigned op2 = currentInstruction[3].u.operand; - - if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2)) - linkSlowCase(iter); // int32 check - linkSlowCase(iter); // int32 check - - JITStubCall stubCall(this, cti_op_bitxor); - stubCall.addArgument(op1); - stubCall.addArgument(op2); - stubCall.call(dst); -} - -// BitNot (~) - -void JIT::emit_op_bitnot(Instruction* currentInstruction) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned src = currentInstruction[2].u.operand; - - emitLoad(src, regT1, regT0); - addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - - not32(regT0); - emitStoreInt32(dst, regT0, (dst == src)); -} - -void JIT::emitSlow_op_bitnot(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) -{ - unsigned dst = currentInstruction[1].u.operand; - - linkSlowCase(iter); // int32 check - - JITStubCall stubCall(this, cti_op_bitnot); - stubCall.addArgument(regT1, regT0); - stubCall.call(dst); -} - -// PostInc (i++) - -void JIT::emit_op_post_inc(Instruction* currentInstruction) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned srcDst = currentInstruction[2].u.operand; - - emitLoad(srcDst, regT1, regT0); - addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - - if (dst == srcDst) // x = x++ is a noop for ints. - return; - - emitStoreInt32(dst, regT0); - - addSlowCase(branchAdd32(Overflow, Imm32(1), regT0)); - emitStoreInt32(srcDst, regT0, true); -} - -void JIT::emitSlow_op_post_inc(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned srcDst = currentInstruction[2].u.operand; - - linkSlowCase(iter); // int32 check - if (dst != srcDst) - linkSlowCase(iter); // overflow check - - JITStubCall stubCall(this, cti_op_post_inc); - stubCall.addArgument(srcDst); - stubCall.addArgument(Imm32(srcDst)); - stubCall.call(dst); -} - -// PostDec (i--) - -void JIT::emit_op_post_dec(Instruction* currentInstruction) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned srcDst = currentInstruction[2].u.operand; - - emitLoad(srcDst, regT1, regT0); - addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - - if (dst == srcDst) // x = x-- is a noop for ints. - return; - - emitStoreInt32(dst, regT0); - - addSlowCase(branchSub32(Overflow, Imm32(1), regT0)); - emitStoreInt32(srcDst, regT0, true); -} - -void JIT::emitSlow_op_post_dec(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned srcDst = currentInstruction[2].u.operand; - - linkSlowCase(iter); // int32 check - if (dst != srcDst) - linkSlowCase(iter); // overflow check - - JITStubCall stubCall(this, cti_op_post_dec); - stubCall.addArgument(srcDst); - stubCall.addArgument(Imm32(srcDst)); - stubCall.call(dst); -} - -// PreInc (++i) - -void JIT::emit_op_pre_inc(Instruction* currentInstruction) -{ - unsigned srcDst = currentInstruction[1].u.operand; - - emitLoad(srcDst, regT1, regT0); - - addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - addSlowCase(branchAdd32(Overflow, Imm32(1), regT0)); - emitStoreInt32(srcDst, regT0, true); -} - -void JIT::emitSlow_op_pre_inc(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) -{ - unsigned srcDst = currentInstruction[1].u.operand; - - linkSlowCase(iter); // int32 check - linkSlowCase(iter); // overflow check - - JITStubCall stubCall(this, cti_op_pre_inc); - stubCall.addArgument(srcDst); - stubCall.call(srcDst); -} - -// PreDec (--i) - -void JIT::emit_op_pre_dec(Instruction* currentInstruction) -{ - unsigned srcDst = currentInstruction[1].u.operand; - - emitLoad(srcDst, regT1, regT0); - - addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - addSlowCase(branchSub32(Overflow, Imm32(1), regT0)); - emitStoreInt32(srcDst, regT0, true); -} - -void JIT::emitSlow_op_pre_dec(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) -{ - unsigned srcDst = currentInstruction[1].u.operand; - - linkSlowCase(iter); // int32 check - linkSlowCase(iter); // overflow check - - JITStubCall stubCall(this, cti_op_pre_dec); - stubCall.addArgument(srcDst); - stubCall.call(srcDst); -} - -// Addition (+) - -void JIT::emit_op_add(Instruction* currentInstruction) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned op1 = currentInstruction[2].u.operand; - unsigned op2 = currentInstruction[3].u.operand; - OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); - - if (!types.first().mightBeNumber() || !types.second().mightBeNumber()) { - JITStubCall stubCall(this, cti_op_add); - stubCall.addArgument(op1); - stubCall.addArgument(op2); - stubCall.call(dst); - return; - } - - JumpList notInt32Op1; - JumpList notInt32Op2; - - unsigned op; - int32_t constant; - if (getOperandConstantImmediateInt(op1, op2, op, constant)) { - emitAdd32Constant(dst, op, constant, op == op1 ? types.first() : types.second()); - return; - } - - emitLoad2(op1, regT1, regT0, op2, regT3, regT2); - notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); - - // Int32 case. - addSlowCase(branchAdd32(Overflow, regT2, regT0)); - emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst)); - - if (!supportsFloatingPoint()) { - addSlowCase(notInt32Op1); - addSlowCase(notInt32Op2); - return; - } - Jump end = jump(); - - // Double case. - emitBinaryDoubleOp(op_add, dst, op1, op2, types, notInt32Op1, notInt32Op2); - end.link(this); -} - -void JIT::emitAdd32Constant(unsigned dst, unsigned op, int32_t constant, ResultType opType) -{ - // Int32 case. - emitLoad(op, regT1, regT0); - Jump notInt32 = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)); - addSlowCase(branchAdd32(Overflow, Imm32(constant), regT0)); - emitStoreInt32(dst, regT0, (op == dst)); - - // Double case. - if (!supportsFloatingPoint()) { - addSlowCase(notInt32); - return; - } - Jump end = jump(); - - notInt32.link(this); - if (!opType.definitelyIsNumber()) - addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag))); - move(Imm32(constant), regT2); - convertInt32ToDouble(regT2, fpRegT0); - emitLoadDouble(op, fpRegT1); - addDouble(fpRegT1, fpRegT0); - emitStoreDouble(dst, fpRegT0); - - end.link(this); -} - -void JIT::emitSlow_op_add(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned op1 = currentInstruction[2].u.operand; - unsigned op2 = currentInstruction[3].u.operand; - OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); - - if (!types.first().mightBeNumber() || !types.second().mightBeNumber()) - return; - - unsigned op; - int32_t constant; - if (getOperandConstantImmediateInt(op1, op2, op, constant)) { - linkSlowCase(iter); // overflow check - - if (!supportsFloatingPoint()) - linkSlowCase(iter); // non-sse case - else { - ResultType opType = op == op1 ? types.first() : types.second(); - if (!opType.definitelyIsNumber()) - linkSlowCase(iter); // double check - } - } else { - linkSlowCase(iter); // overflow check - - if (!supportsFloatingPoint()) { - linkSlowCase(iter); // int32 check - linkSlowCase(iter); // int32 check - } else { - if (!types.first().definitelyIsNumber()) - linkSlowCase(iter); // double check - - if (!types.second().definitelyIsNumber()) { - linkSlowCase(iter); // int32 check - linkSlowCase(iter); // double check - } - } - } - - JITStubCall stubCall(this, cti_op_add); - stubCall.addArgument(op1); - stubCall.addArgument(op2); - stubCall.call(dst); -} - -// Subtraction (-) - -void JIT::emit_op_sub(Instruction* currentInstruction) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned op1 = currentInstruction[2].u.operand; - unsigned op2 = currentInstruction[3].u.operand; - OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); - - JumpList notInt32Op1; - JumpList notInt32Op2; - - if (isOperandConstantImmediateInt(op2)) { - emitSub32Constant(dst, op1, getConstantOperand(op2).asInt32(), types.first()); - return; - } - - emitLoad2(op1, regT1, regT0, op2, regT3, regT2); - notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); - - // Int32 case. - addSlowCase(branchSub32(Overflow, regT2, regT0)); - emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst)); - - if (!supportsFloatingPoint()) { - addSlowCase(notInt32Op1); - addSlowCase(notInt32Op2); - return; - } - Jump end = jump(); - - // Double case. - emitBinaryDoubleOp(op_sub, dst, op1, op2, types, notInt32Op1, notInt32Op2); - end.link(this); -} - -void JIT::emitSub32Constant(unsigned dst, unsigned op, int32_t constant, ResultType opType) -{ - // Int32 case. - emitLoad(op, regT1, regT0); - Jump notInt32 = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)); - addSlowCase(branchSub32(Overflow, Imm32(constant), regT0)); - emitStoreInt32(dst, regT0, (op == dst)); - - // Double case. - if (!supportsFloatingPoint()) { - addSlowCase(notInt32); - return; - } - Jump end = jump(); - - notInt32.link(this); - if (!opType.definitelyIsNumber()) - addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag))); - move(Imm32(constant), regT2); - convertInt32ToDouble(regT2, fpRegT0); - emitLoadDouble(op, fpRegT1); - subDouble(fpRegT0, fpRegT1); - emitStoreDouble(dst, fpRegT1); - - end.link(this); -} - -void JIT::emitSlow_op_sub(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned op1 = currentInstruction[2].u.operand; - unsigned op2 = currentInstruction[3].u.operand; - OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); - - if (isOperandConstantImmediateInt(op2)) { - linkSlowCase(iter); // overflow check - - if (!supportsFloatingPoint() || !types.first().definitelyIsNumber()) - linkSlowCase(iter); // int32 or double check - } else { - linkSlowCase(iter); // overflow check - - if (!supportsFloatingPoint()) { - linkSlowCase(iter); // int32 check - linkSlowCase(iter); // int32 check - } else { - if (!types.first().definitelyIsNumber()) - linkSlowCase(iter); // double check - - if (!types.second().definitelyIsNumber()) { - linkSlowCase(iter); // int32 check - linkSlowCase(iter); // double check - } - } - } - - JITStubCall stubCall(this, cti_op_sub); - stubCall.addArgument(op1); - stubCall.addArgument(op2); - stubCall.call(dst); -} - -void JIT::emitBinaryDoubleOp(OpcodeID opcodeID, unsigned dst, unsigned op1, unsigned op2, OperandTypes types, JumpList& notInt32Op1, JumpList& notInt32Op2, bool op1IsInRegisters, bool op2IsInRegisters) -{ - JumpList end; - - if (!notInt32Op1.empty()) { - // Double case 1: Op1 is not int32; Op2 is unknown. - notInt32Op1.link(this); - - ASSERT(op1IsInRegisters); - - // Verify Op1 is double. - if (!types.first().definitelyIsNumber()) - addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag))); - - if (!op2IsInRegisters) - emitLoad(op2, regT3, regT2); - - Jump doubleOp2 = branch32(Below, regT3, Imm32(JSValue::LowestTag)); - - if (!types.second().definitelyIsNumber()) - addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); - - convertInt32ToDouble(regT2, fpRegT0); - Jump doTheMath = jump(); - - // Load Op2 as double into double register. - doubleOp2.link(this); - emitLoadDouble(op2, fpRegT0); - - // Do the math. - doTheMath.link(this); - switch (opcodeID) { - case op_mul: - emitLoadDouble(op1, fpRegT2); - mulDouble(fpRegT2, fpRegT0); - emitStoreDouble(dst, fpRegT0); - break; - case op_add: - emitLoadDouble(op1, fpRegT2); - addDouble(fpRegT2, fpRegT0); - emitStoreDouble(dst, fpRegT0); - break; - case op_sub: - emitLoadDouble(op1, fpRegT1); - subDouble(fpRegT0, fpRegT1); - emitStoreDouble(dst, fpRegT1); - break; - case op_div: - emitLoadDouble(op1, fpRegT1); - divDouble(fpRegT0, fpRegT1); - emitStoreDouble(dst, fpRegT1); - break; - case op_jnless: - emitLoadDouble(op1, fpRegT2); - addJump(branchDouble(DoubleLessThanOrEqualOrUnordered, fpRegT0, fpRegT2), dst); - break; - case op_jless: - emitLoadDouble(op1, fpRegT2); - addJump(branchDouble(DoubleLessThan, fpRegT2, fpRegT0), dst); - break; - case op_jnlesseq: - emitLoadDouble(op1, fpRegT2); - addJump(branchDouble(DoubleLessThanOrUnordered, fpRegT0, fpRegT2), dst); - break; - default: - ASSERT_NOT_REACHED(); - } - - if (!notInt32Op2.empty()) - end.append(jump()); - } - - if (!notInt32Op2.empty()) { - // Double case 2: Op1 is int32; Op2 is not int32. - notInt32Op2.link(this); - - ASSERT(op2IsInRegisters); - - if (!op1IsInRegisters) - emitLoadPayload(op1, regT0); - - convertInt32ToDouble(regT0, fpRegT0); - - // Verify op2 is double. - if (!types.second().definitelyIsNumber()) - addSlowCase(branch32(Above, regT3, Imm32(JSValue::LowestTag))); - - // Do the math. - switch (opcodeID) { - case op_mul: - emitLoadDouble(op2, fpRegT2); - mulDouble(fpRegT2, fpRegT0); - emitStoreDouble(dst, fpRegT0); - break; - case op_add: - emitLoadDouble(op2, fpRegT2); - addDouble(fpRegT2, fpRegT0); - emitStoreDouble(dst, fpRegT0); - break; - case op_sub: - emitLoadDouble(op2, fpRegT2); - subDouble(fpRegT2, fpRegT0); - emitStoreDouble(dst, fpRegT0); - break; - case op_div: - emitLoadDouble(op2, fpRegT2); - divDouble(fpRegT2, fpRegT0); - emitStoreDouble(dst, fpRegT0); - break; - case op_jnless: - emitLoadDouble(op2, fpRegT1); - addJump(branchDouble(DoubleLessThanOrEqualOrUnordered, fpRegT1, fpRegT0), dst); - break; - case op_jless: - emitLoadDouble(op2, fpRegT1); - addJump(branchDouble(DoubleLessThan, fpRegT0, fpRegT1), dst); - break; - case op_jnlesseq: - emitLoadDouble(op2, fpRegT1); - addJump(branchDouble(DoubleLessThanOrUnordered, fpRegT1, fpRegT0), dst); - break; - default: - ASSERT_NOT_REACHED(); - } - } - - end.link(this); -} - -// Multiplication (*) - -void JIT::emit_op_mul(Instruction* currentInstruction) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned op1 = currentInstruction[2].u.operand; - unsigned op2 = currentInstruction[3].u.operand; - OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); - - JumpList notInt32Op1; - JumpList notInt32Op2; - - emitLoad2(op1, regT1, regT0, op2, regT3, regT2); - notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); - - // Int32 case. - move(regT0, regT3); - addSlowCase(branchMul32(Overflow, regT2, regT0)); - addSlowCase(branchTest32(Zero, regT0)); - emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst)); - - if (!supportsFloatingPoint()) { - addSlowCase(notInt32Op1); - addSlowCase(notInt32Op2); - return; - } - Jump end = jump(); - - // Double case. - emitBinaryDoubleOp(op_mul, dst, op1, op2, types, notInt32Op1, notInt32Op2); - end.link(this); -} - -void JIT::emitSlow_op_mul(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned op1 = currentInstruction[2].u.operand; - unsigned op2 = currentInstruction[3].u.operand; - OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); - - Jump overflow = getSlowCase(iter); // overflow check - linkSlowCase(iter); // zero result check - - Jump negZero = branchOr32(Signed, regT2, regT3); - emitStoreInt32(dst, Imm32(0), (op1 == dst || op2 == dst)); - - emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_mul)); - - negZero.link(this); - overflow.link(this); - - if (!supportsFloatingPoint()) { - linkSlowCase(iter); // int32 check - linkSlowCase(iter); // int32 check - } - - if (supportsFloatingPoint()) { - if (!types.first().definitelyIsNumber()) - linkSlowCase(iter); // double check - - if (!types.second().definitelyIsNumber()) { - linkSlowCase(iter); // int32 check - linkSlowCase(iter); // double check - } - } - - Label jitStubCall(this); - JITStubCall stubCall(this, cti_op_mul); - stubCall.addArgument(op1); - stubCall.addArgument(op2); - stubCall.call(dst); -} - -// Division (/) - -void JIT::emit_op_div(Instruction* currentInstruction) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned op1 = currentInstruction[2].u.operand; - unsigned op2 = currentInstruction[3].u.operand; - OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); - - if (!supportsFloatingPoint()) { - addSlowCase(jump()); - return; - } - - // Int32 divide. - JumpList notInt32Op1; - JumpList notInt32Op2; - - JumpList end; - - emitLoad2(op1, regT1, regT0, op2, regT3, regT2); - - notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); - - convertInt32ToDouble(regT0, fpRegT0); - convertInt32ToDouble(regT2, fpRegT1); - divDouble(fpRegT1, fpRegT0); - - JumpList doubleResult; - branchConvertDoubleToInt32(fpRegT0, regT0, doubleResult, fpRegT1); - - // Int32 result. - emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst)); - end.append(jump()); - - // Double result. - doubleResult.link(this); - emitStoreDouble(dst, fpRegT0); - end.append(jump()); - - // Double divide. - emitBinaryDoubleOp(op_div, dst, op1, op2, types, notInt32Op1, notInt32Op2); - end.link(this); -} - -void JIT::emitSlow_op_div(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned op1 = currentInstruction[2].u.operand; - unsigned op2 = currentInstruction[3].u.operand; - OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); - - if (!supportsFloatingPoint()) - linkSlowCase(iter); - else { - if (!types.first().definitelyIsNumber()) - linkSlowCase(iter); // double check - - if (!types.second().definitelyIsNumber()) { - linkSlowCase(iter); // int32 check - linkSlowCase(iter); // double check - } - } - - JITStubCall stubCall(this, cti_op_div); - stubCall.addArgument(op1); - stubCall.addArgument(op2); - stubCall.call(dst); -} - -// Mod (%) - -/* ------------------------------ BEGIN: OP_MOD ------------------------------ */ - -#if CPU(X86) || CPU(X86_64) - -void JIT::emit_op_mod(Instruction* currentInstruction) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned op1 = currentInstruction[2].u.operand; - unsigned op2 = currentInstruction[3].u.operand; - - if (isOperandConstantImmediateInt(op2) && getConstantOperand(op2).asInt32() != 0) { - emitLoad(op1, X86Registers::edx, X86Registers::eax); - move(Imm32(getConstantOperand(op2).asInt32()), X86Registers::ecx); - addSlowCase(branch32(NotEqual, X86Registers::edx, Imm32(JSValue::Int32Tag))); - if (getConstantOperand(op2).asInt32() == -1) - addSlowCase(branch32(Equal, X86Registers::eax, Imm32(0x80000000))); // -2147483648 / -1 => EXC_ARITHMETIC - } else { - emitLoad2(op1, X86Registers::edx, X86Registers::eax, op2, X86Registers::ebx, X86Registers::ecx); - addSlowCase(branch32(NotEqual, X86Registers::edx, Imm32(JSValue::Int32Tag))); - addSlowCase(branch32(NotEqual, X86Registers::ebx, Imm32(JSValue::Int32Tag))); - - addSlowCase(branch32(Equal, X86Registers::eax, Imm32(0x80000000))); // -2147483648 / -1 => EXC_ARITHMETIC - addSlowCase(branch32(Equal, X86Registers::ecx, Imm32(0))); // divide by 0 - } - - move(X86Registers::eax, X86Registers::ebx); // Save dividend payload, in case of 0. - m_assembler.cdq(); - m_assembler.idivl_r(X86Registers::ecx); - - // If the remainder is zero and the dividend is negative, the result is -0. - Jump storeResult1 = branchTest32(NonZero, X86Registers::edx); - Jump storeResult2 = branchTest32(Zero, X86Registers::ebx, Imm32(0x80000000)); // not negative - emitStore(dst, jsNumber(m_globalData, -0.0)); - Jump end = jump(); - - storeResult1.link(this); - storeResult2.link(this); - emitStoreInt32(dst, X86Registers::edx, (op1 == dst || op2 == dst)); - end.link(this); -} - -void JIT::emitSlow_op_mod(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned op1 = currentInstruction[2].u.operand; - unsigned op2 = currentInstruction[3].u.operand; - - if (isOperandConstantImmediateInt(op2) && getConstantOperand(op2).asInt32() != 0) { - linkSlowCase(iter); // int32 check - if (getConstantOperand(op2).asInt32() == -1) - linkSlowCase(iter); // 0x80000000 check - } else { - linkSlowCase(iter); // int32 check - linkSlowCase(iter); // int32 check - linkSlowCase(iter); // 0 check - linkSlowCase(iter); // 0x80000000 check - } - - JITStubCall stubCall(this, cti_op_mod); - stubCall.addArgument(op1); - stubCall.addArgument(op2); - stubCall.call(dst); -} - -#else // CPU(X86) || CPU(X86_64) - -void JIT::emit_op_mod(Instruction* currentInstruction) -{ - unsigned dst = currentInstruction[1].u.operand; - unsigned op1 = currentInstruction[2].u.operand; - unsigned op2 = currentInstruction[3].u.operand; - -#if ENABLE(JIT_OPTIMIZE_MOD) - emitLoad2(op1, regT1, regT0, op2, regT3, regT2); - addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); - - addSlowCase(branch32(Equal, regT2, Imm32(0))); - - emitNakedCall(m_globalData->jitStubs.ctiSoftModulo()); - - emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst)); -#else - JITStubCall stubCall(this, cti_op_mod); - stubCall.addArgument(op1); - stubCall.addArgument(op2); - stubCall.call(dst); -#endif -} - -void JIT::emitSlow_op_mod(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) -{ -#if ENABLE(JIT_OPTIMIZE_MOD) - unsigned result = currentInstruction[1].u.operand; - unsigned op1 = currentInstruction[2].u.operand; - unsigned op2 = currentInstruction[3].u.operand; - linkSlowCase(iter); - linkSlowCase(iter); - linkSlowCase(iter); - JITStubCall stubCall(this, cti_op_mod); - stubCall.addArgument(op1); - stubCall.addArgument(op2); - stubCall.call(result); -#else - ASSERT_NOT_REACHED(); -#endif -} - -#endif // CPU(X86) || CPU(X86_64) - -/* ------------------------------ END: OP_MOD ------------------------------ */ - -#else // USE(JSVALUE32_64) +#if !USE(JSVALUE32_64) void JIT::emit_op_lshift(Instruction* currentInstruction) { @@ -1367,6 +187,118 @@ void JIT::emitSlow_op_rshift(Instruction* currentInstruction, Vector<SlowCaseEnt stubCall.call(result); } +void JIT::emit_op_urshift(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + + // Slow case of urshift makes assumptions about what registers hold the + // shift arguments, so any changes must be updated there as well. + if (isOperandConstantImmediateInt(op2)) { + emitGetVirtualRegister(op1, regT0); + emitJumpSlowCaseIfNotImmediateInteger(regT0); + emitFastArithImmToInt(regT0); + int shift = getConstantOperand(op2).asInt32(); + if (shift) + urshift32(Imm32(shift & 0x1f), regT0); + // unsigned shift < 0 or shift = k*2^32 may result in (essentially) + // a toUint conversion, which can result in a value we can represent + // as an immediate int. + if (shift < 0 || !(shift & 31)) + addSlowCase(branch32(LessThan, regT0, Imm32(0))); +#if USE(JSVALUE32) + addSlowCase(branchAdd32(Overflow, regT0, regT0)); + signExtend32ToPtr(regT0, regT0); +#endif + emitFastArithReTagImmediate(regT0, regT0); + emitPutVirtualRegister(dst, regT0); + return; + } + emitGetVirtualRegisters(op1, regT0, op2, regT1); + if (!isOperandConstantImmediateInt(op1)) + emitJumpSlowCaseIfNotImmediateInteger(regT0); + emitJumpSlowCaseIfNotImmediateInteger(regT1); + emitFastArithImmToInt(regT0); + emitFastArithImmToInt(regT1); + urshift32(regT1, regT0); + addSlowCase(branch32(LessThan, regT0, Imm32(0))); +#if USE(JSVALUE32) + addSlowCase(branchAdd32(Overflow, regT0, regT0)); + signExtend32ToPtr(regT0, regT0); +#endif + emitFastArithReTagImmediate(regT0, regT0); + emitPutVirtualRegister(dst, regT0); +} + +void JIT::emitSlow_op_urshift(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + if (isOperandConstantImmediateInt(op2)) { + int shift = getConstantOperand(op2).asInt32(); + // op1 = regT0 + linkSlowCase(iter); // int32 check +#if USE(JSVALUE64) + if (supportsFloatingPointTruncate()) { + JumpList failures; + failures.append(emitJumpIfNotImmediateNumber(regT0)); // op1 is not a double + addPtr(tagTypeNumberRegister, regT0); + movePtrToDouble(regT0, fpRegT0); + failures.append(branchTruncateDoubleToInt32(fpRegT0, regT0)); + if (shift) + urshift32(Imm32(shift & 0x1f), regT0); + if (shift < 0 || !(shift & 31)) + failures.append(branch32(LessThan, regT0, Imm32(0))); + emitFastArithReTagImmediate(regT0, regT0); + emitPutVirtualRegister(dst, regT0); + emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_rshift)); + failures.link(this); + } +#endif // JSVALUE64 + if (shift < 0 || !(shift & 31)) + linkSlowCase(iter); // failed to box in hot path +#if USE(JSVALUE32) + linkSlowCase(iter); // Couldn't box result +#endif + } else { + // op1 = regT0 + // op2 = regT1 + if (!isOperandConstantImmediateInt(op1)) { + linkSlowCase(iter); // int32 check -- op1 is not an int +#if USE(JSVALUE64) + if (supportsFloatingPointTruncate()) { + JumpList failures; + failures.append(emitJumpIfNotImmediateNumber(regT0)); // op1 is not a double + addPtr(tagTypeNumberRegister, regT0); + movePtrToDouble(regT0, fpRegT0); + failures.append(branchTruncateDoubleToInt32(fpRegT0, regT0)); + failures.append(emitJumpIfNotImmediateInteger(regT1)); // op2 is not an int + emitFastArithImmToInt(regT1); + urshift32(regT1, regT0); + failures.append(branch32(LessThan, regT0, Imm32(0))); + emitFastArithReTagImmediate(regT0, regT0); + emitPutVirtualRegister(dst, regT0); + emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_rshift)); + failures.link(this); + } +#endif + } + + linkSlowCase(iter); // int32 check - op2 is not an int + linkSlowCase(iter); // Can't represent unsigned result as an immediate +#if USE(JSVALUE32) + linkSlowCase(iter); // Couldn't box result +#endif + } + + JITStubCall stubCall(this, cti_op_urshift); + stubCall.addArgument(op1, regT0); + stubCall.addArgument(op2, regT1); + stubCall.call(dst); +} + void JIT::emit_op_jnless(Instruction* currentInstruction) { unsigned op1 = currentInstruction[1].u.operand; @@ -1378,6 +310,24 @@ void JIT::emit_op_jnless(Instruction* currentInstruction) // - constant int immediate to int immediate // - int immediate to int immediate + if (isOperandConstantImmediateChar(op1)) { + emitGetVirtualRegister(op2, regT0); + addSlowCase(emitJumpIfNotJSCell(regT0)); + JumpList failures; + emitLoadCharacterString(regT0, regT0, failures); + addSlowCase(failures); + addJump(branch32(LessThanOrEqual, regT0, Imm32(asString(getConstantOperand(op1))->tryGetValue()[0])), target); + return; + } + if (isOperandConstantImmediateChar(op2)) { + emitGetVirtualRegister(op1, regT0); + addSlowCase(emitJumpIfNotJSCell(regT0)); + JumpList failures; + emitLoadCharacterString(regT0, regT0, failures); + addSlowCase(failures); + addJump(branch32(GreaterThanOrEqual, regT0, Imm32(asString(getConstantOperand(op2))->tryGetValue()[0])), target); + return; + } if (isOperandConstantImmediateInt(op2)) { emitGetVirtualRegister(op1, regT0); emitJumpSlowCaseIfNotImmediateInteger(regT0); @@ -1415,6 +365,18 @@ void JIT::emitSlow_op_jnless(Instruction* currentInstruction, Vector<SlowCaseEnt // - floating-point number to constant int immediate // - constant int immediate to floating-point number // - floating-point number to floating-point number. + if (isOperandConstantImmediateChar(op1) || isOperandConstantImmediateChar(op2)) { + linkSlowCase(iter); + linkSlowCase(iter); + linkSlowCase(iter); + linkSlowCase(iter); + JITStubCall stubCall(this, cti_op_jlesseq); + stubCall.addArgument(op1, regT0); + stubCall.addArgument(op2, regT1); + stubCall.call(); + emitJumpSlowToHot(branchTest32(Zero, regT0), target); + return; + } if (isOperandConstantImmediateInt(op2)) { linkSlowCase(iter); @@ -1432,9 +394,9 @@ void JIT::emitSlow_op_jnless(Instruction* currentInstruction, Vector<SlowCaseEnt Jump fail2 = checkStructure(regT0, m_globalData->numberStructure.get()); loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0); #endif - + int32_t op2imm = getConstantOperand(op2).asInt32();; - + move(Imm32(op2imm), regT1); convertInt32ToDouble(regT1, fpRegT1); @@ -1469,13 +431,13 @@ void JIT::emitSlow_op_jnless(Instruction* currentInstruction, Vector<SlowCaseEnt Jump fail1; if (!m_codeBlock->isKnownNotImmediate(op2)) fail1 = emitJumpIfNotJSCell(regT1); - + Jump fail2 = checkStructure(regT1, m_globalData->numberStructure.get()); loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1); #endif - + int32_t op1imm = getConstantOperand(op1).asInt32();; - + move(Imm32(op1imm), regT0); convertInt32ToDouble(regT0, fpRegT0); @@ -1563,6 +525,24 @@ void JIT::emit_op_jless(Instruction* currentInstruction) // - constant int immediate to int immediate // - int immediate to int immediate + if (isOperandConstantImmediateChar(op1)) { + emitGetVirtualRegister(op2, regT0); + addSlowCase(emitJumpIfNotJSCell(regT0)); + JumpList failures; + emitLoadCharacterString(regT0, regT0, failures); + addSlowCase(failures); + addJump(branch32(GreaterThan, regT0, Imm32(asString(getConstantOperand(op1))->tryGetValue()[0])), target); + return; + } + if (isOperandConstantImmediateChar(op2)) { + emitGetVirtualRegister(op1, regT0); + addSlowCase(emitJumpIfNotJSCell(regT0)); + JumpList failures; + emitLoadCharacterString(regT0, regT0, failures); + addSlowCase(failures); + addJump(branch32(LessThan, regT0, Imm32(asString(getConstantOperand(op2))->tryGetValue()[0])), target); + return; + } if (isOperandConstantImmediateInt(op2)) { emitGetVirtualRegister(op1, regT0); emitJumpSlowCaseIfNotImmediateInteger(regT0); @@ -1600,6 +580,18 @@ void JIT::emitSlow_op_jless(Instruction* currentInstruction, Vector<SlowCaseEntr // - floating-point number to constant int immediate // - constant int immediate to floating-point number // - floating-point number to floating-point number. + if (isOperandConstantImmediateChar(op1) || isOperandConstantImmediateChar(op2)) { + linkSlowCase(iter); + linkSlowCase(iter); + linkSlowCase(iter); + linkSlowCase(iter); + JITStubCall stubCall(this, cti_op_jlesseq); + stubCall.addArgument(op1, regT0); + stubCall.addArgument(op2, regT1); + stubCall.call(); + emitJumpSlowToHot(branchTest32(NonZero, regT0), target); + return; + } if (isOperandConstantImmediateInt(op2)) { linkSlowCase(iter); @@ -1617,9 +609,9 @@ void JIT::emitSlow_op_jless(Instruction* currentInstruction, Vector<SlowCaseEntr Jump fail2 = checkStructure(regT0, m_globalData->numberStructure.get()); loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0); #endif - + int32_t op2imm = getConstantOperand(op2).asInt32(); - + move(Imm32(op2imm), regT1); convertInt32ToDouble(regT1, fpRegT1); @@ -1654,13 +646,13 @@ void JIT::emitSlow_op_jless(Instruction* currentInstruction, Vector<SlowCaseEntr Jump fail1; if (!m_codeBlock->isKnownNotImmediate(op2)) fail1 = emitJumpIfNotJSCell(regT1); - + Jump fail2 = checkStructure(regT1, m_globalData->numberStructure.get()); loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1); #endif - + int32_t op1imm = getConstantOperand(op1).asInt32(); - + move(Imm32(op1imm), regT0); convertInt32ToDouble(regT0, fpRegT0); @@ -1737,7 +729,7 @@ void JIT::emitSlow_op_jless(Instruction* currentInstruction, Vector<SlowCaseEntr } } -void JIT::emit_op_jnlesseq(Instruction* currentInstruction) +void JIT::emit_op_jlesseq(Instruction* currentInstruction, bool invert) { unsigned op1 = currentInstruction[1].u.operand; unsigned op2 = currentInstruction[2].u.operand; @@ -1748,6 +740,24 @@ void JIT::emit_op_jnlesseq(Instruction* currentInstruction) // - constant int immediate to int immediate // - int immediate to int immediate + if (isOperandConstantImmediateChar(op1)) { + emitGetVirtualRegister(op2, regT0); + addSlowCase(emitJumpIfNotJSCell(regT0)); + JumpList failures; + emitLoadCharacterString(regT0, regT0, failures); + addSlowCase(failures); + addJump(branch32(invert ? LessThan : GreaterThanOrEqual, regT0, Imm32(asString(getConstantOperand(op1))->tryGetValue()[0])), target); + return; + } + if (isOperandConstantImmediateChar(op2)) { + emitGetVirtualRegister(op1, regT0); + addSlowCase(emitJumpIfNotJSCell(regT0)); + JumpList failures; + emitLoadCharacterString(regT0, regT0, failures); + addSlowCase(failures); + addJump(branch32(invert ? GreaterThan : LessThanOrEqual, regT0, Imm32(asString(getConstantOperand(op2))->tryGetValue()[0])), target); + return; + } if (isOperandConstantImmediateInt(op2)) { emitGetVirtualRegister(op1, regT0); emitJumpSlowCaseIfNotImmediateInteger(regT0); @@ -1756,7 +766,7 @@ void JIT::emit_op_jnlesseq(Instruction* currentInstruction) #else int32_t op2imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op2))); #endif - addJump(branch32(GreaterThan, regT0, Imm32(op2imm)), target); + addJump(branch32(invert ? GreaterThan : LessThanOrEqual, regT0, Imm32(op2imm)), target); } else if (isOperandConstantImmediateInt(op1)) { emitGetVirtualRegister(op2, regT1); emitJumpSlowCaseIfNotImmediateInteger(regT1); @@ -1765,17 +775,17 @@ void JIT::emit_op_jnlesseq(Instruction* currentInstruction) #else int32_t op1imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op1))); #endif - addJump(branch32(LessThan, regT1, Imm32(op1imm)), target); + addJump(branch32(invert ? LessThan : GreaterThanOrEqual, regT1, Imm32(op1imm)), target); } else { emitGetVirtualRegisters(op1, regT0, op2, regT1); emitJumpSlowCaseIfNotImmediateInteger(regT0); emitJumpSlowCaseIfNotImmediateInteger(regT1); - addJump(branch32(GreaterThan, regT0, regT1), target); + addJump(branch32(invert ? GreaterThan : LessThanOrEqual, regT0, regT1), target); } } -void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +void JIT::emitSlow_op_jlesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter, bool invert) { unsigned op1 = currentInstruction[1].u.operand; unsigned op2 = currentInstruction[2].u.operand; @@ -1786,6 +796,19 @@ void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseE // - constant int immediate to floating-point number // - floating-point number to floating-point number. + if (isOperandConstantImmediateChar(op1) || isOperandConstantImmediateChar(op2)) { + linkSlowCase(iter); + linkSlowCase(iter); + linkSlowCase(iter); + linkSlowCase(iter); + JITStubCall stubCall(this, cti_op_jlesseq); + stubCall.addArgument(op1, regT0); + stubCall.addArgument(op2, regT1); + stubCall.call(); + emitJumpSlowToHot(branchTest32(invert ? Zero : NonZero, regT0), target); + return; + } + if (isOperandConstantImmediateInt(op2)) { linkSlowCase(iter); @@ -1802,13 +825,13 @@ void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseE Jump fail2 = checkStructure(regT0, m_globalData->numberStructure.get()); loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0); #endif - + int32_t op2imm = getConstantOperand(op2).asInt32();; - + move(Imm32(op2imm), regT1); convertInt32ToDouble(regT1, fpRegT1); - emitJumpSlowToHot(branchDouble(DoubleLessThanOrUnordered, fpRegT1, fpRegT0), target); + emitJumpSlowToHot(branchDouble(invert ? DoubleLessThanOrUnordered : DoubleGreaterThanOrEqual, fpRegT1, fpRegT0), target); emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnlesseq)); @@ -1825,7 +848,7 @@ void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseE stubCall.addArgument(regT0); stubCall.addArgument(op2, regT2); stubCall.call(); - emitJumpSlowToHot(branchTest32(Zero, regT0), target); + emitJumpSlowToHot(branchTest32(invert ? Zero : NonZero, regT0), target); } else if (isOperandConstantImmediateInt(op1)) { linkSlowCase(iter); @@ -1839,17 +862,17 @@ void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseE Jump fail1; if (!m_codeBlock->isKnownNotImmediate(op2)) fail1 = emitJumpIfNotJSCell(regT1); - + Jump fail2 = checkStructure(regT1, m_globalData->numberStructure.get()); loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1); #endif - + int32_t op1imm = getConstantOperand(op1).asInt32();; - + move(Imm32(op1imm), regT0); convertInt32ToDouble(regT0, fpRegT0); - emitJumpSlowToHot(branchDouble(DoubleLessThanOrUnordered, fpRegT1, fpRegT0), target); + emitJumpSlowToHot(branchDouble(invert ? DoubleLessThanOrUnordered : DoubleGreaterThanOrEqual, fpRegT1, fpRegT0), target); emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnlesseq)); @@ -1866,7 +889,7 @@ void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseE stubCall.addArgument(op1, regT2); stubCall.addArgument(regT1); stubCall.call(); - emitJumpSlowToHot(branchTest32(Zero, regT0), target); + emitJumpSlowToHot(branchTest32(invert ? Zero : NonZero, regT0), target); } else { linkSlowCase(iter); @@ -1895,7 +918,7 @@ void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseE loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1); #endif - emitJumpSlowToHot(branchDouble(DoubleLessThanOrUnordered, fpRegT1, fpRegT0), target); + emitJumpSlowToHot(branchDouble(invert ? DoubleLessThanOrUnordered : DoubleGreaterThanOrEqual, fpRegT1, fpRegT0), target); emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnlesseq)); @@ -1918,10 +941,20 @@ void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseE stubCall.addArgument(regT0); stubCall.addArgument(regT1); stubCall.call(); - emitJumpSlowToHot(branchTest32(Zero, regT0), target); + emitJumpSlowToHot(branchTest32(invert ? Zero : NonZero, regT0), target); } } +void JIT::emit_op_jnlesseq(Instruction* currentInstruction) +{ + emit_op_jlesseq(currentInstruction, true); +} + +void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + emitSlow_op_jlesseq(currentInstruction, iter, true); +} + void JIT::emit_op_bitand(Instruction* currentInstruction) { unsigned result = currentInstruction[1].u.operand; @@ -2164,11 +1197,11 @@ void JIT::emit_op_mod(Instruction* currentInstruction) unsigned op1 = currentInstruction[2].u.operand; unsigned op2 = currentInstruction[3].u.operand; -#if ENABLE(JIT_OPTIMIZE_MOD) +#if ENABLE(JIT_OPTIMIZE_MOD) emitGetVirtualRegisters(op1, regT0, op2, regT2); emitJumpSlowCaseIfNotImmediateInteger(regT0); emitJumpSlowCaseIfNotImmediateInteger(regT2); - + addSlowCase(branch32(Equal, regT2, Imm32(1))); emitNakedCall(m_globalData->jitStubs.ctiSoftModulo()); @@ -2229,7 +1262,7 @@ void JIT::compileBinaryArithOpSlowCase(OpcodeID opcodeID, Vector<SlowCaseEntry>: { // We assume that subtracting TagTypeNumber is equivalent to adding DoubleEncodeOffset. COMPILE_ASSERT(((JSImmediate::TagTypeNumber + JSImmediate::DoubleEncodeOffset) == 0), TagTypeNumber_PLUS_DoubleEncodeOffset_EQUALS_0); - + Jump notImm1; Jump notImm2; if (op1HasImmediateIntFastCase) { @@ -2422,7 +1455,7 @@ void JIT::emit_op_div(Instruction* currentInstruction) movePtrToDouble(regT0, fpRegT0); skipDoubleLoad.link(this); } - + if (isOperandConstantImmediateDouble(op2)) { emitGetVirtualRegister(op2, regT1); addPtr(tagTypeNumberRegister, regT1); @@ -2535,7 +1568,7 @@ void JIT::compileBinaryArithOp(OpcodeID opcodeID, unsigned dst, unsigned src1, u op1imm.link(this); emitFastArithImmToInt(regT0); convertInt32ToDouble(regT0, fpRegT0); - // (1c) + // (1c) loadedDouble.link(this); if (opcodeID == op_add) addDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0); @@ -2581,7 +1614,7 @@ void JIT::compileBinaryArithOp(OpcodeID opcodeID, unsigned dst, unsigned src1, u op2imm.link(this); emitFastArithImmToInt(regT1); convertInt32ToDouble(regT1, fpRegT1); - // (1c) + // (1c) loadedDouble.link(this); loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0); if (opcodeID == op_add) @@ -2622,7 +1655,7 @@ void JIT::compileBinaryArithOp(OpcodeID opcodeID, unsigned dst, unsigned src1, u Jump op2NonZero = branchTest32(NonZero, regT1); op1Zero.link(this); // if either input is zero, add the two together, and check if the result is < 0. - // If it is, we have a problem (N < 0), (N * 0) == -0, not representatble as a JSImmediate. + // If it is, we have a problem (N < 0), (N * 0) == -0, not representatble as a JSImmediate. move(regT0, regT2); addSlowCase(branchAdd32(Signed, regT1, regT2)); // Skip the above check if neither input is zero @@ -2801,7 +1834,7 @@ void JIT::emitSlow_op_sub(Instruction* currentInstruction, Vector<SlowCaseEntry> /* ------------------------------ END: OP_ADD, OP_SUB, OP_MUL ------------------------------ */ -#endif // USE(JSVALUE32_64) +#endif // !USE(JSVALUE32_64) } // namespace JSC diff --git a/JavaScriptCore/jit/JITArithmetic32_64.cpp b/JavaScriptCore/jit/JITArithmetic32_64.cpp new file mode 100644 index 0000000..962c066 --- /dev/null +++ b/JavaScriptCore/jit/JITArithmetic32_64.cpp @@ -0,0 +1,1411 @@ +/* +* Copyright (C) 2008 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 "JIT.h" + +#if ENABLE(JIT) + +#include "CodeBlock.h" +#include "JITInlineMethods.h" +#include "JITStubCall.h" +#include "JITStubs.h" +#include "JSArray.h" +#include "JSFunction.h" +#include "Interpreter.h" +#include "ResultType.h" +#include "SamplingTool.h" + +#ifndef NDEBUG +#include <stdio.h> +#endif + +using namespace std; + +namespace JSC { + +#if USE(JSVALUE32_64) + +void JIT::emit_op_negate(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned src = currentInstruction[2].u.operand; + + emitLoad(src, regT1, regT0); + + Jump srcNotInt = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)); + addSlowCase(branchTest32(Zero, regT0, Imm32(0x7fffffff))); + neg32(regT0); + emitStoreInt32(dst, regT0, (dst == src)); + + Jump end = jump(); + + srcNotInt.link(this); + addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag))); + + xor32(Imm32(1 << 31), regT1); + store32(regT1, tagFor(dst)); + if (dst != src) + store32(regT0, payloadFor(dst)); + + end.link(this); +} + +void JIT::emitSlow_op_negate(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + + linkSlowCase(iter); // 0x7fffffff check + linkSlowCase(iter); // double check + + JITStubCall stubCall(this, cti_op_negate); + stubCall.addArgument(regT1, regT0); + stubCall.call(dst); +} + +void JIT::emit_op_jnless(Instruction* currentInstruction) +{ + unsigned op1 = currentInstruction[1].u.operand; + unsigned op2 = currentInstruction[2].u.operand; + unsigned target = currentInstruction[3].u.operand; + + JumpList notInt32Op1; + JumpList notInt32Op2; + + // Character less. + if (isOperandConstantImmediateChar(op1)) { + emitLoad(op2, regT1, regT0); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag))); + JumpList failures; + emitLoadCharacterString(regT0, regT0, failures); + addSlowCase(failures); + addJump(branch32(LessThanOrEqual, regT0, Imm32(asString(getConstantOperand(op1))->tryGetValue()[0])), target); + return; + } + if (isOperandConstantImmediateChar(op2)) { + emitLoad(op1, regT1, regT0); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag))); + JumpList failures; + emitLoadCharacterString(regT0, regT0, failures); + addSlowCase(failures); + addJump(branch32(GreaterThanOrEqual, regT0, Imm32(asString(getConstantOperand(op2))->tryGetValue()[0])), target); + return; + } + if (isOperandConstantImmediateInt(op1)) { + // Int32 less. + emitLoad(op2, regT3, regT2); + notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); + addJump(branch32(LessThanOrEqual, regT2, Imm32(getConstantOperand(op1).asInt32())), target); + } else if (isOperandConstantImmediateInt(op2)) { + emitLoad(op1, regT1, regT0); + notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + addJump(branch32(GreaterThanOrEqual, regT0, Imm32(getConstantOperand(op2).asInt32())), target); + } else { + emitLoad2(op1, regT1, regT0, op2, regT3, regT2); + notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); + addJump(branch32(GreaterThanOrEqual, regT0, regT2), target); + } + + if (!supportsFloatingPoint()) { + addSlowCase(notInt32Op1); + addSlowCase(notInt32Op2); + return; + } + Jump end = jump(); + + // Double less. + emitBinaryDoubleOp(op_jnless, target, op1, op2, OperandTypes(), notInt32Op1, notInt32Op2, !isOperandConstantImmediateInt(op1), isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2)); + end.link(this); +} + +void JIT::emitSlow_op_jnless(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned op1 = currentInstruction[1].u.operand; + unsigned op2 = currentInstruction[2].u.operand; + unsigned target = currentInstruction[3].u.operand; + + if (isOperandConstantImmediateChar(op1) || isOperandConstantImmediateChar(op2)) { + linkSlowCase(iter); + linkSlowCase(iter); + linkSlowCase(iter); + linkSlowCase(iter); + } else { + if (!supportsFloatingPoint()) { + if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2)) + linkSlowCase(iter); // int32 check + linkSlowCase(iter); // int32 check + } else { + if (!isOperandConstantImmediateInt(op1)) { + linkSlowCase(iter); // double check + linkSlowCase(iter); // int32 check + } + if (isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2)) + linkSlowCase(iter); // double check + } + } + + JITStubCall stubCall(this, cti_op_jless); + stubCall.addArgument(op1); + stubCall.addArgument(op2); + stubCall.call(); + emitJumpSlowToHot(branchTest32(Zero, regT0), target); +} + +void JIT::emit_op_jless(Instruction* currentInstruction) +{ + unsigned op1 = currentInstruction[1].u.operand; + unsigned op2 = currentInstruction[2].u.operand; + unsigned target = currentInstruction[3].u.operand; + + JumpList notInt32Op1; + JumpList notInt32Op2; + + // Character less. + if (isOperandConstantImmediateChar(op1)) { + emitLoad(op2, regT1, regT0); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag))); + JumpList failures; + emitLoadCharacterString(regT0, regT0, failures); + addSlowCase(failures); + addJump(branch32(GreaterThan, regT0, Imm32(asString(getConstantOperand(op1))->tryGetValue()[0])), target); + return; + } + if (isOperandConstantImmediateChar(op2)) { + emitLoad(op1, regT1, regT0); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag))); + JumpList failures; + emitLoadCharacterString(regT0, regT0, failures); + addSlowCase(failures); + addJump(branch32(LessThan, regT0, Imm32(asString(getConstantOperand(op2))->tryGetValue()[0])), target); + return; + } + if (isOperandConstantImmediateInt(op1)) { + emitLoad(op2, regT3, regT2); + notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); + addJump(branch32(GreaterThan, regT2, Imm32(getConstantOperand(op1).asInt32())), target); + } else if (isOperandConstantImmediateInt(op2)) { + emitLoad(op1, regT1, regT0); + notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + addJump(branch32(LessThan, regT0, Imm32(getConstantOperand(op2).asInt32())), target); + } else { + emitLoad2(op1, regT1, regT0, op2, regT3, regT2); + notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); + addJump(branch32(LessThan, regT0, regT2), target); + } + + if (!supportsFloatingPoint()) { + addSlowCase(notInt32Op1); + addSlowCase(notInt32Op2); + return; + } + Jump end = jump(); + + // Double less. + emitBinaryDoubleOp(op_jless, target, op1, op2, OperandTypes(), notInt32Op1, notInt32Op2, !isOperandConstantImmediateInt(op1), isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2)); + end.link(this); +} + +void JIT::emitSlow_op_jless(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned op1 = currentInstruction[1].u.operand; + unsigned op2 = currentInstruction[2].u.operand; + unsigned target = currentInstruction[3].u.operand; + + if (isOperandConstantImmediateChar(op1) || isOperandConstantImmediateChar(op2)) { + linkSlowCase(iter); + linkSlowCase(iter); + linkSlowCase(iter); + linkSlowCase(iter); + } else { + if (!supportsFloatingPoint()) { + if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2)) + linkSlowCase(iter); // int32 check + linkSlowCase(iter); // int32 check + } else { + if (!isOperandConstantImmediateInt(op1)) { + linkSlowCase(iter); // double check + linkSlowCase(iter); // int32 check + } + if (isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2)) + linkSlowCase(iter); // double check + } + } + JITStubCall stubCall(this, cti_op_jless); + stubCall.addArgument(op1); + stubCall.addArgument(op2); + stubCall.call(); + emitJumpSlowToHot(branchTest32(NonZero, regT0), target); +} + +void JIT::emit_op_jlesseq(Instruction* currentInstruction, bool invert) +{ + unsigned op1 = currentInstruction[1].u.operand; + unsigned op2 = currentInstruction[2].u.operand; + unsigned target = currentInstruction[3].u.operand; + + JumpList notInt32Op1; + JumpList notInt32Op2; + + // Character less. + if (isOperandConstantImmediateChar(op1)) { + emitLoad(op2, regT1, regT0); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag))); + JumpList failures; + emitLoadCharacterString(regT0, regT0, failures); + addSlowCase(failures); + addJump(branch32(invert ? LessThan : GreaterThanOrEqual, regT0, Imm32(asString(getConstantOperand(op1))->tryGetValue()[0])), target); + return; + } + if (isOperandConstantImmediateChar(op2)) { + emitLoad(op1, regT1, regT0); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag))); + JumpList failures; + emitLoadCharacterString(regT0, regT0, failures); + addSlowCase(failures); + addJump(branch32(invert ? GreaterThan : LessThanOrEqual, regT0, Imm32(asString(getConstantOperand(op2))->tryGetValue()[0])), target); + return; + } + if (isOperandConstantImmediateInt(op1)) { + emitLoad(op2, regT3, regT2); + notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); + addJump(branch32(invert ? LessThan : GreaterThan, regT2, Imm32(getConstantOperand(op1).asInt32())), target); + } else if (isOperandConstantImmediateInt(op2)) { + emitLoad(op1, regT1, regT0); + notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + addJump(branch32(invert ? GreaterThan : LessThanOrEqual, regT0, Imm32(getConstantOperand(op2).asInt32())), target); + } else { + emitLoad2(op1, regT1, regT0, op2, regT3, regT2); + notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); + addJump(branch32(invert ? GreaterThan : LessThanOrEqual, regT0, regT2), target); + } + + if (!supportsFloatingPoint()) { + addSlowCase(notInt32Op1); + addSlowCase(notInt32Op2); + return; + } + Jump end = jump(); + + // Double less. + emitBinaryDoubleOp(invert ? op_jnlesseq : op_jlesseq, target, op1, op2, OperandTypes(), notInt32Op1, notInt32Op2, !isOperandConstantImmediateInt(op1), isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2)); + end.link(this); +} + +void JIT::emitSlow_op_jlesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter, bool invert) +{ + unsigned op1 = currentInstruction[1].u.operand; + unsigned op2 = currentInstruction[2].u.operand; + unsigned target = currentInstruction[3].u.operand; + + if (isOperandConstantImmediateChar(op1) || isOperandConstantImmediateChar(op2)) { + linkSlowCase(iter); + linkSlowCase(iter); + linkSlowCase(iter); + linkSlowCase(iter); + } else { + if (!supportsFloatingPoint()) { + if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2)) + linkSlowCase(iter); // int32 check + linkSlowCase(iter); // int32 check + } else { + if (!isOperandConstantImmediateInt(op1)) { + linkSlowCase(iter); // double check + linkSlowCase(iter); // int32 check + } + if (isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2)) + linkSlowCase(iter); // double check + } + } + + JITStubCall stubCall(this, cti_op_jlesseq); + stubCall.addArgument(op1); + stubCall.addArgument(op2); + stubCall.call(); + emitJumpSlowToHot(branchTest32(invert ? Zero : NonZero, regT0), target); +} + +void JIT::emit_op_jnlesseq(Instruction* currentInstruction) +{ + emit_op_jlesseq(currentInstruction, true); +} + +void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + emitSlow_op_jlesseq(currentInstruction, iter, true); +} + +// LeftShift (<<) + +void JIT::emit_op_lshift(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + + if (isOperandConstantImmediateInt(op2)) { + emitLoad(op1, regT1, regT0); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + lshift32(Imm32(getConstantOperand(op2).asInt32()), regT0); + emitStoreInt32(dst, regT0, dst == op1); + return; + } + + emitLoad2(op1, regT1, regT0, op2, regT3, regT2); + if (!isOperandConstantImmediateInt(op1)) + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); + lshift32(regT2, regT0); + emitStoreInt32(dst, regT0, dst == op1 || dst == op2); +} + +void JIT::emitSlow_op_lshift(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + + if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2)) + linkSlowCase(iter); // int32 check + linkSlowCase(iter); // int32 check + + JITStubCall stubCall(this, cti_op_lshift); + stubCall.addArgument(op1); + stubCall.addArgument(op2); + stubCall.call(dst); +} + +// RightShift (>>) and UnsignedRightShift (>>>) helper + +void JIT::emitRightShift(Instruction* currentInstruction, bool isUnsigned) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + + // Slow case of rshift makes assumptions about what registers hold the + // shift arguments, so any changes must be updated there as well. + if (isOperandConstantImmediateInt(op2)) { + emitLoad(op1, regT1, regT0); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + int shift = getConstantOperand(op2).asInt32(); + if (isUnsigned) { + if (shift) + urshift32(Imm32(shift & 0x1f), regT0); + // unsigned shift < 0 or shift = k*2^32 may result in (essentially) + // a toUint conversion, which can result in a value we can represent + // as an immediate int. + if (shift < 0 || !(shift & 31)) + addSlowCase(branch32(LessThan, regT0, Imm32(0))); + } else if (shift) { // signed right shift by zero is simply toInt conversion + rshift32(Imm32(shift & 0x1f), regT0); + } + emitStoreInt32(dst, regT0, dst == op1); + return; + } + + emitLoad2(op1, regT1, regT0, op2, regT3, regT2); + if (!isOperandConstantImmediateInt(op1)) + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); + if (isUnsigned) { + urshift32(regT2, regT0); + addSlowCase(branch32(LessThan, regT0, Imm32(0))); + } else + rshift32(regT2, regT0); + emitStoreInt32(dst, regT0, dst == op1 || dst == op2); +} + +void JIT::emitRightShiftSlowCase(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter, bool isUnsigned) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + if (isOperandConstantImmediateInt(op2)) { + int shift = getConstantOperand(op2).asInt32(); + // op1 = regT1:regT0 + linkSlowCase(iter); // int32 check + if (supportsFloatingPointTruncate()) { + JumpList failures; + failures.append(branch32(AboveOrEqual, regT1, Imm32(JSValue::LowestTag))); + emitLoadDouble(op1, fpRegT0); + failures.append(branchTruncateDoubleToInt32(fpRegT0, regT0)); + if (isUnsigned) { + if (shift) + urshift32(Imm32(shift & 0x1f), regT0); + if (shift < 0 || !(shift & 31)) + failures.append(branch32(LessThan, regT0, Imm32(0))); + } else if (shift) + rshift32(Imm32(shift & 0x1f), regT0); + emitStoreInt32(dst, regT0, dst == op1 || dst == op2); + emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_rshift)); + failures.link(this); + } + if (isUnsigned && (shift < 0 || !(shift & 31))) + linkSlowCase(iter); // failed to box in hot path + } else { + // op1 = regT1:regT0 + // op2 = regT3:regT2 + if (!isOperandConstantImmediateInt(op1)) { + linkSlowCase(iter); // int32 check -- op1 is not an int + if (supportsFloatingPointTruncate()) { + Jump notDouble = branch32(Above, regT1, Imm32(JSValue::LowestTag)); // op1 is not a double + emitLoadDouble(op1, fpRegT0); + Jump notInt = branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)); // op2 is not an int + Jump cantTruncate = branchTruncateDoubleToInt32(fpRegT0, regT0); + if (isUnsigned) + urshift32(regT2, regT0); + else + rshift32(regT2, regT0); + emitStoreInt32(dst, regT0, dst == op1 || dst == op2); + emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_rshift)); + notDouble.link(this); + notInt.link(this); + cantTruncate.link(this); + } + } + + linkSlowCase(iter); // int32 check - op2 is not an int + if (isUnsigned) + linkSlowCase(iter); // Can't represent unsigned result as an immediate + } + + JITStubCall stubCall(this, isUnsigned ? cti_op_urshift : cti_op_rshift); + stubCall.addArgument(op1); + stubCall.addArgument(op2); + stubCall.call(dst); +} + +// RightShift (>>) + +void JIT::emit_op_rshift(Instruction* currentInstruction) +{ + emitRightShift(currentInstruction, false); +} + +void JIT::emitSlow_op_rshift(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + emitRightShiftSlowCase(currentInstruction, iter, false); +} + +// UnsignedRightShift (>>>) + +void JIT::emit_op_urshift(Instruction* currentInstruction) +{ + emitRightShift(currentInstruction, true); +} + +void JIT::emitSlow_op_urshift(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + emitRightShiftSlowCase(currentInstruction, iter, true); +} + +// BitAnd (&) + +void JIT::emit_op_bitand(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + + unsigned op; + int32_t constant; + if (getOperandConstantImmediateInt(op1, op2, op, constant)) { + emitLoad(op, regT1, regT0); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + and32(Imm32(constant), regT0); + emitStoreInt32(dst, regT0, (op == dst)); + return; + } + + emitLoad2(op1, regT1, regT0, op2, regT3, regT2); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); + and32(regT2, regT0); + emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst)); +} + +void JIT::emitSlow_op_bitand(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + + if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2)) + linkSlowCase(iter); // int32 check + linkSlowCase(iter); // int32 check + + JITStubCall stubCall(this, cti_op_bitand); + stubCall.addArgument(op1); + stubCall.addArgument(op2); + stubCall.call(dst); +} + +// BitOr (|) + +void JIT::emit_op_bitor(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + + unsigned op; + int32_t constant; + if (getOperandConstantImmediateInt(op1, op2, op, constant)) { + emitLoad(op, regT1, regT0); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + or32(Imm32(constant), regT0); + emitStoreInt32(dst, regT0, (op == dst)); + return; + } + + emitLoad2(op1, regT1, regT0, op2, regT3, regT2); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); + or32(regT2, regT0); + emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst)); +} + +void JIT::emitSlow_op_bitor(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + + if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2)) + linkSlowCase(iter); // int32 check + linkSlowCase(iter); // int32 check + + JITStubCall stubCall(this, cti_op_bitor); + stubCall.addArgument(op1); + stubCall.addArgument(op2); + stubCall.call(dst); +} + +// BitXor (^) + +void JIT::emit_op_bitxor(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + + unsigned op; + int32_t constant; + if (getOperandConstantImmediateInt(op1, op2, op, constant)) { + emitLoad(op, regT1, regT0); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + xor32(Imm32(constant), regT0); + emitStoreInt32(dst, regT0, (op == dst)); + return; + } + + emitLoad2(op1, regT1, regT0, op2, regT3, regT2); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); + xor32(regT2, regT0); + emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst)); +} + +void JIT::emitSlow_op_bitxor(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + + if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2)) + linkSlowCase(iter); // int32 check + linkSlowCase(iter); // int32 check + + JITStubCall stubCall(this, cti_op_bitxor); + stubCall.addArgument(op1); + stubCall.addArgument(op2); + stubCall.call(dst); +} + +// BitNot (~) + +void JIT::emit_op_bitnot(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned src = currentInstruction[2].u.operand; + + emitLoad(src, regT1, regT0); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + + not32(regT0); + emitStoreInt32(dst, regT0, (dst == src)); +} + +void JIT::emitSlow_op_bitnot(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + + linkSlowCase(iter); // int32 check + + JITStubCall stubCall(this, cti_op_bitnot); + stubCall.addArgument(regT1, regT0); + stubCall.call(dst); +} + +// PostInc (i++) + +void JIT::emit_op_post_inc(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned srcDst = currentInstruction[2].u.operand; + + emitLoad(srcDst, regT1, regT0); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + + if (dst == srcDst) // x = x++ is a noop for ints. + return; + + emitStoreInt32(dst, regT0); + + addSlowCase(branchAdd32(Overflow, Imm32(1), regT0)); + emitStoreInt32(srcDst, regT0, true); +} + +void JIT::emitSlow_op_post_inc(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned srcDst = currentInstruction[2].u.operand; + + linkSlowCase(iter); // int32 check + if (dst != srcDst) + linkSlowCase(iter); // overflow check + + JITStubCall stubCall(this, cti_op_post_inc); + stubCall.addArgument(srcDst); + stubCall.addArgument(Imm32(srcDst)); + stubCall.call(dst); +} + +// PostDec (i--) + +void JIT::emit_op_post_dec(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned srcDst = currentInstruction[2].u.operand; + + emitLoad(srcDst, regT1, regT0); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + + if (dst == srcDst) // x = x-- is a noop for ints. + return; + + emitStoreInt32(dst, regT0); + + addSlowCase(branchSub32(Overflow, Imm32(1), regT0)); + emitStoreInt32(srcDst, regT0, true); +} + +void JIT::emitSlow_op_post_dec(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned srcDst = currentInstruction[2].u.operand; + + linkSlowCase(iter); // int32 check + if (dst != srcDst) + linkSlowCase(iter); // overflow check + + JITStubCall stubCall(this, cti_op_post_dec); + stubCall.addArgument(srcDst); + stubCall.addArgument(Imm32(srcDst)); + stubCall.call(dst); +} + +// PreInc (++i) + +void JIT::emit_op_pre_inc(Instruction* currentInstruction) +{ + unsigned srcDst = currentInstruction[1].u.operand; + + emitLoad(srcDst, regT1, regT0); + + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + addSlowCase(branchAdd32(Overflow, Imm32(1), regT0)); + emitStoreInt32(srcDst, regT0, true); +} + +void JIT::emitSlow_op_pre_inc(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned srcDst = currentInstruction[1].u.operand; + + linkSlowCase(iter); // int32 check + linkSlowCase(iter); // overflow check + + JITStubCall stubCall(this, cti_op_pre_inc); + stubCall.addArgument(srcDst); + stubCall.call(srcDst); +} + +// PreDec (--i) + +void JIT::emit_op_pre_dec(Instruction* currentInstruction) +{ + unsigned srcDst = currentInstruction[1].u.operand; + + emitLoad(srcDst, regT1, regT0); + + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + addSlowCase(branchSub32(Overflow, Imm32(1), regT0)); + emitStoreInt32(srcDst, regT0, true); +} + +void JIT::emitSlow_op_pre_dec(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned srcDst = currentInstruction[1].u.operand; + + linkSlowCase(iter); // int32 check + linkSlowCase(iter); // overflow check + + JITStubCall stubCall(this, cti_op_pre_dec); + stubCall.addArgument(srcDst); + stubCall.call(srcDst); +} + +// Addition (+) + +void JIT::emit_op_add(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); + + if (!types.first().mightBeNumber() || !types.second().mightBeNumber()) { + JITStubCall stubCall(this, cti_op_add); + stubCall.addArgument(op1); + stubCall.addArgument(op2); + stubCall.call(dst); + return; + } + + JumpList notInt32Op1; + JumpList notInt32Op2; + + unsigned op; + int32_t constant; + if (getOperandConstantImmediateInt(op1, op2, op, constant)) { + emitAdd32Constant(dst, op, constant, op == op1 ? types.first() : types.second()); + return; + } + + emitLoad2(op1, regT1, regT0, op2, regT3, regT2); + notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); + + // Int32 case. + addSlowCase(branchAdd32(Overflow, regT2, regT0)); + emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst)); + + if (!supportsFloatingPoint()) { + addSlowCase(notInt32Op1); + addSlowCase(notInt32Op2); + return; + } + Jump end = jump(); + + // Double case. + emitBinaryDoubleOp(op_add, dst, op1, op2, types, notInt32Op1, notInt32Op2); + end.link(this); +} + +void JIT::emitAdd32Constant(unsigned dst, unsigned op, int32_t constant, ResultType opType) +{ + // Int32 case. + emitLoad(op, regT1, regT0); + Jump notInt32 = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)); + addSlowCase(branchAdd32(Overflow, Imm32(constant), regT0)); + emitStoreInt32(dst, regT0, (op == dst)); + + // Double case. + if (!supportsFloatingPoint()) { + addSlowCase(notInt32); + return; + } + Jump end = jump(); + + notInt32.link(this); + if (!opType.definitelyIsNumber()) + addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag))); + move(Imm32(constant), regT2); + convertInt32ToDouble(regT2, fpRegT0); + emitLoadDouble(op, fpRegT1); + addDouble(fpRegT1, fpRegT0); + emitStoreDouble(dst, fpRegT0); + + end.link(this); +} + +void JIT::emitSlow_op_add(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); + + if (!types.first().mightBeNumber() || !types.second().mightBeNumber()) + return; + + unsigned op; + int32_t constant; + if (getOperandConstantImmediateInt(op1, op2, op, constant)) { + linkSlowCase(iter); // overflow check + + if (!supportsFloatingPoint()) + linkSlowCase(iter); // non-sse case + else { + ResultType opType = op == op1 ? types.first() : types.second(); + if (!opType.definitelyIsNumber()) + linkSlowCase(iter); // double check + } + } else { + linkSlowCase(iter); // overflow check + + if (!supportsFloatingPoint()) { + linkSlowCase(iter); // int32 check + linkSlowCase(iter); // int32 check + } else { + if (!types.first().definitelyIsNumber()) + linkSlowCase(iter); // double check + + if (!types.second().definitelyIsNumber()) { + linkSlowCase(iter); // int32 check + linkSlowCase(iter); // double check + } + } + } + + JITStubCall stubCall(this, cti_op_add); + stubCall.addArgument(op1); + stubCall.addArgument(op2); + stubCall.call(dst); +} + +// Subtraction (-) + +void JIT::emit_op_sub(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); + + JumpList notInt32Op1; + JumpList notInt32Op2; + + if (isOperandConstantImmediateInt(op2)) { + emitSub32Constant(dst, op1, getConstantOperand(op2).asInt32(), types.first()); + return; + } + + emitLoad2(op1, regT1, regT0, op2, regT3, regT2); + notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); + + // Int32 case. + addSlowCase(branchSub32(Overflow, regT2, regT0)); + emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst)); + + if (!supportsFloatingPoint()) { + addSlowCase(notInt32Op1); + addSlowCase(notInt32Op2); + return; + } + Jump end = jump(); + + // Double case. + emitBinaryDoubleOp(op_sub, dst, op1, op2, types, notInt32Op1, notInt32Op2); + end.link(this); +} + +void JIT::emitSub32Constant(unsigned dst, unsigned op, int32_t constant, ResultType opType) +{ + // Int32 case. + emitLoad(op, regT1, regT0); + Jump notInt32 = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)); + addSlowCase(branchSub32(Overflow, Imm32(constant), regT0)); + emitStoreInt32(dst, regT0, (op == dst)); + + // Double case. + if (!supportsFloatingPoint()) { + addSlowCase(notInt32); + return; + } + Jump end = jump(); + + notInt32.link(this); + if (!opType.definitelyIsNumber()) + addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag))); + move(Imm32(constant), regT2); + convertInt32ToDouble(regT2, fpRegT0); + emitLoadDouble(op, fpRegT1); + subDouble(fpRegT0, fpRegT1); + emitStoreDouble(dst, fpRegT1); + + end.link(this); +} + +void JIT::emitSlow_op_sub(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); + + if (isOperandConstantImmediateInt(op2)) { + linkSlowCase(iter); // overflow check + + if (!supportsFloatingPoint() || !types.first().definitelyIsNumber()) + linkSlowCase(iter); // int32 or double check + } else { + linkSlowCase(iter); // overflow check + + if (!supportsFloatingPoint()) { + linkSlowCase(iter); // int32 check + linkSlowCase(iter); // int32 check + } else { + if (!types.first().definitelyIsNumber()) + linkSlowCase(iter); // double check + + if (!types.second().definitelyIsNumber()) { + linkSlowCase(iter); // int32 check + linkSlowCase(iter); // double check + } + } + } + + JITStubCall stubCall(this, cti_op_sub); + stubCall.addArgument(op1); + stubCall.addArgument(op2); + stubCall.call(dst); +} + +void JIT::emitBinaryDoubleOp(OpcodeID opcodeID, unsigned dst, unsigned op1, unsigned op2, OperandTypes types, JumpList& notInt32Op1, JumpList& notInt32Op2, bool op1IsInRegisters, bool op2IsInRegisters) +{ + JumpList end; + + if (!notInt32Op1.empty()) { + // Double case 1: Op1 is not int32; Op2 is unknown. + notInt32Op1.link(this); + + ASSERT(op1IsInRegisters); + + // Verify Op1 is double. + if (!types.first().definitelyIsNumber()) + addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag))); + + if (!op2IsInRegisters) + emitLoad(op2, regT3, regT2); + + Jump doubleOp2 = branch32(Below, regT3, Imm32(JSValue::LowestTag)); + + if (!types.second().definitelyIsNumber()) + addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); + + convertInt32ToDouble(regT2, fpRegT0); + Jump doTheMath = jump(); + + // Load Op2 as double into double register. + doubleOp2.link(this); + emitLoadDouble(op2, fpRegT0); + + // Do the math. + doTheMath.link(this); + switch (opcodeID) { + case op_mul: + emitLoadDouble(op1, fpRegT2); + mulDouble(fpRegT2, fpRegT0); + emitStoreDouble(dst, fpRegT0); + break; + case op_add: + emitLoadDouble(op1, fpRegT2); + addDouble(fpRegT2, fpRegT0); + emitStoreDouble(dst, fpRegT0); + break; + case op_sub: + emitLoadDouble(op1, fpRegT1); + subDouble(fpRegT0, fpRegT1); + emitStoreDouble(dst, fpRegT1); + break; + case op_div: + emitLoadDouble(op1, fpRegT1); + divDouble(fpRegT0, fpRegT1); + emitStoreDouble(dst, fpRegT1); + break; + case op_jnless: + emitLoadDouble(op1, fpRegT2); + addJump(branchDouble(DoubleLessThanOrEqualOrUnordered, fpRegT0, fpRegT2), dst); + break; + case op_jless: + emitLoadDouble(op1, fpRegT2); + addJump(branchDouble(DoubleLessThan, fpRegT2, fpRegT0), dst); + break; + case op_jlesseq: + emitLoadDouble(op1, fpRegT2); + addJump(branchDouble(DoubleLessThanOrEqual, fpRegT2, fpRegT0), dst); + break; + case op_jnlesseq: + emitLoadDouble(op1, fpRegT2); + addJump(branchDouble(DoubleLessThanOrUnordered, fpRegT0, fpRegT2), dst); + break; + default: + ASSERT_NOT_REACHED(); + } + + if (!notInt32Op2.empty()) + end.append(jump()); + } + + if (!notInt32Op2.empty()) { + // Double case 2: Op1 is int32; Op2 is not int32. + notInt32Op2.link(this); + + ASSERT(op2IsInRegisters); + + if (!op1IsInRegisters) + emitLoadPayload(op1, regT0); + + convertInt32ToDouble(regT0, fpRegT0); + + // Verify op2 is double. + if (!types.second().definitelyIsNumber()) + addSlowCase(branch32(Above, regT3, Imm32(JSValue::LowestTag))); + + // Do the math. + switch (opcodeID) { + case op_mul: + emitLoadDouble(op2, fpRegT2); + mulDouble(fpRegT2, fpRegT0); + emitStoreDouble(dst, fpRegT0); + break; + case op_add: + emitLoadDouble(op2, fpRegT2); + addDouble(fpRegT2, fpRegT0); + emitStoreDouble(dst, fpRegT0); + break; + case op_sub: + emitLoadDouble(op2, fpRegT2); + subDouble(fpRegT2, fpRegT0); + emitStoreDouble(dst, fpRegT0); + break; + case op_div: + emitLoadDouble(op2, fpRegT2); + divDouble(fpRegT2, fpRegT0); + emitStoreDouble(dst, fpRegT0); + break; + case op_jnless: + emitLoadDouble(op2, fpRegT1); + addJump(branchDouble(DoubleLessThanOrEqualOrUnordered, fpRegT1, fpRegT0), dst); + break; + case op_jless: + emitLoadDouble(op2, fpRegT1); + addJump(branchDouble(DoubleLessThan, fpRegT0, fpRegT1), dst); + break; + case op_jnlesseq: + emitLoadDouble(op2, fpRegT1); + addJump(branchDouble(DoubleLessThanOrUnordered, fpRegT1, fpRegT0), dst); + break; + case op_jlesseq: + emitLoadDouble(op2, fpRegT1); + addJump(branchDouble(DoubleLessThanOrEqual, fpRegT1, fpRegT0), dst); + break; + default: + ASSERT_NOT_REACHED(); + } + } + + end.link(this); +} + +// Multiplication (*) + +void JIT::emit_op_mul(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); + + JumpList notInt32Op1; + JumpList notInt32Op2; + + emitLoad2(op1, regT1, regT0, op2, regT3, regT2); + notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); + + // Int32 case. + move(regT0, regT3); + addSlowCase(branchMul32(Overflow, regT2, regT0)); + addSlowCase(branchTest32(Zero, regT0)); + emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst)); + + if (!supportsFloatingPoint()) { + addSlowCase(notInt32Op1); + addSlowCase(notInt32Op2); + return; + } + Jump end = jump(); + + // Double case. + emitBinaryDoubleOp(op_mul, dst, op1, op2, types, notInt32Op1, notInt32Op2); + end.link(this); +} + +void JIT::emitSlow_op_mul(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); + + Jump overflow = getSlowCase(iter); // overflow check + linkSlowCase(iter); // zero result check + + Jump negZero = branchOr32(Signed, regT2, regT3); + emitStoreInt32(dst, Imm32(0), (op1 == dst || op2 == dst)); + + emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_mul)); + + negZero.link(this); + overflow.link(this); + + if (!supportsFloatingPoint()) { + linkSlowCase(iter); // int32 check + linkSlowCase(iter); // int32 check + } + + if (supportsFloatingPoint()) { + if (!types.first().definitelyIsNumber()) + linkSlowCase(iter); // double check + + if (!types.second().definitelyIsNumber()) { + linkSlowCase(iter); // int32 check + linkSlowCase(iter); // double check + } + } + + Label jitStubCall(this); + JITStubCall stubCall(this, cti_op_mul); + stubCall.addArgument(op1); + stubCall.addArgument(op2); + stubCall.call(dst); +} + +// Division (/) + +void JIT::emit_op_div(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); + + if (!supportsFloatingPoint()) { + addSlowCase(jump()); + return; + } + + // Int32 divide. + JumpList notInt32Op1; + JumpList notInt32Op2; + + JumpList end; + + emitLoad2(op1, regT1, regT0, op2, regT3, regT2); + + notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); + + convertInt32ToDouble(regT0, fpRegT0); + convertInt32ToDouble(regT2, fpRegT1); + divDouble(fpRegT1, fpRegT0); + + JumpList doubleResult; + branchConvertDoubleToInt32(fpRegT0, regT0, doubleResult, fpRegT1); + + // Int32 result. + emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst)); + end.append(jump()); + + // Double result. + doubleResult.link(this); + emitStoreDouble(dst, fpRegT0); + end.append(jump()); + + // Double divide. + emitBinaryDoubleOp(op_div, dst, op1, op2, types, notInt32Op1, notInt32Op2); + end.link(this); +} + +void JIT::emitSlow_op_div(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); + + if (!supportsFloatingPoint()) + linkSlowCase(iter); + else { + if (!types.first().definitelyIsNumber()) + linkSlowCase(iter); // double check + + if (!types.second().definitelyIsNumber()) { + linkSlowCase(iter); // int32 check + linkSlowCase(iter); // double check + } + } + + JITStubCall stubCall(this, cti_op_div); + stubCall.addArgument(op1); + stubCall.addArgument(op2); + stubCall.call(dst); +} + +// Mod (%) + +/* ------------------------------ BEGIN: OP_MOD ------------------------------ */ + +#if CPU(X86) || CPU(X86_64) + +void JIT::emit_op_mod(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + + if (isOperandConstantImmediateInt(op2) && getConstantOperand(op2).asInt32() != 0) { + emitLoad(op1, X86Registers::edx, X86Registers::eax); + move(Imm32(getConstantOperand(op2).asInt32()), X86Registers::ecx); + addSlowCase(branch32(NotEqual, X86Registers::edx, Imm32(JSValue::Int32Tag))); + if (getConstantOperand(op2).asInt32() == -1) + addSlowCase(branch32(Equal, X86Registers::eax, Imm32(0x80000000))); // -2147483648 / -1 => EXC_ARITHMETIC + } else { + emitLoad2(op1, X86Registers::edx, X86Registers::eax, op2, X86Registers::ebx, X86Registers::ecx); + addSlowCase(branch32(NotEqual, X86Registers::edx, Imm32(JSValue::Int32Tag))); + addSlowCase(branch32(NotEqual, X86Registers::ebx, Imm32(JSValue::Int32Tag))); + + addSlowCase(branch32(Equal, X86Registers::eax, Imm32(0x80000000))); // -2147483648 / -1 => EXC_ARITHMETIC + addSlowCase(branch32(Equal, X86Registers::ecx, Imm32(0))); // divide by 0 + } + + move(X86Registers::eax, X86Registers::ebx); // Save dividend payload, in case of 0. + m_assembler.cdq(); + m_assembler.idivl_r(X86Registers::ecx); + + // If the remainder is zero and the dividend is negative, the result is -0. + Jump storeResult1 = branchTest32(NonZero, X86Registers::edx); + Jump storeResult2 = branchTest32(Zero, X86Registers::ebx, Imm32(0x80000000)); // not negative + emitStore(dst, jsNumber(m_globalData, -0.0)); + Jump end = jump(); + + storeResult1.link(this); + storeResult2.link(this); + emitStoreInt32(dst, X86Registers::edx, (op1 == dst || op2 == dst)); + end.link(this); +} + +void JIT::emitSlow_op_mod(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + + if (isOperandConstantImmediateInt(op2) && getConstantOperand(op2).asInt32() != 0) { + linkSlowCase(iter); // int32 check + if (getConstantOperand(op2).asInt32() == -1) + linkSlowCase(iter); // 0x80000000 check + } else { + linkSlowCase(iter); // int32 check + linkSlowCase(iter); // int32 check + linkSlowCase(iter); // 0 check + linkSlowCase(iter); // 0x80000000 check + } + + JITStubCall stubCall(this, cti_op_mod); + stubCall.addArgument(op1); + stubCall.addArgument(op2); + stubCall.call(dst); +} + +#else // CPU(X86) || CPU(X86_64) + +void JIT::emit_op_mod(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + +#if ENABLE(JIT_OPTIMIZE_MOD) + emitLoad2(op1, regT1, regT0, op2, regT3, regT2); + addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); + + addSlowCase(branch32(Equal, regT2, Imm32(0))); + + emitNakedCall(m_globalData->jitStubs.ctiSoftModulo()); + + emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst)); +#else + JITStubCall stubCall(this, cti_op_mod); + stubCall.addArgument(op1); + stubCall.addArgument(op2); + stubCall.call(dst); +#endif +} + +void JIT::emitSlow_op_mod(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ +#if ENABLE(JIT_OPTIMIZE_MOD) + unsigned result = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + linkSlowCase(iter); + linkSlowCase(iter); + linkSlowCase(iter); + JITStubCall stubCall(this, cti_op_mod); + stubCall.addArgument(op1); + stubCall.addArgument(op2); + stubCall.call(result); +#else + ASSERT_NOT_REACHED(); +#endif +} + +#endif // CPU(X86) || CPU(X86_64) + +/* ------------------------------ END: OP_MOD ------------------------------ */ + +#endif // USE(JSVALUE32_64) + +} + +#endif // ENABLE(JIT) diff --git a/JavaScriptCore/jit/JITInlineMethods.h b/JavaScriptCore/jit/JITInlineMethods.h index 96a2e5b..892ab36 100644 --- a/JavaScriptCore/jit/JITInlineMethods.h +++ b/JavaScriptCore/jit/JITInlineMethods.h @@ -93,6 +93,16 @@ ALWAYS_INLINE void JIT::emitGetFromCallFrameHeaderPtr(RegisterFile::CallFrameHea #endif } +ALWAYS_INLINE void JIT::emitLoadCharacterString(RegisterID src, RegisterID dst, JumpList& failures) +{ + failures.append(branchPtr(NotEqual, Address(src), ImmPtr(m_globalData->jsStringVPtr))); + failures.append(branchTest32(NonZero, Address(src, OBJECT_OFFSETOF(JSString, m_fiberCount)))); + failures.append(branch32(NotEqual, MacroAssembler::Address(src, ThunkHelpers::jsStringLengthOffset()), Imm32(1))); + loadPtr(MacroAssembler::Address(src, ThunkHelpers::jsStringValueOffset()), dst); + loadPtr(MacroAssembler::Address(dst, ThunkHelpers::stringImplDataOffset()), dst); + load16(MacroAssembler::Address(dst, 0), dst); +} + ALWAYS_INLINE void JIT::emitGetFromCallFrameHeader32(RegisterFile::CallFrameHeaderEntry entry, RegisterID to, RegisterID from) { load32(Address(from, entry * sizeof(Register)), to); @@ -323,23 +333,13 @@ ALWAYS_INLINE void JIT::sampleCodeBlock(CodeBlock* codeBlock) #endif #endif -inline JIT::Address JIT::addressFor(unsigned index, RegisterID base) +ALWAYS_INLINE bool JIT::isOperandConstantImmediateChar(unsigned src) { - return Address(base, (index * sizeof(Register))); + return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isString() && asString(getConstantOperand(src).asCell())->length() == 1; } #if USE(JSVALUE32_64) -inline JIT::Address JIT::tagFor(unsigned index, RegisterID base) -{ - return Address(base, (index * sizeof(Register)) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)); -} - -inline JIT::Address JIT::payloadFor(unsigned index, RegisterID base) -{ - return Address(base, (index * sizeof(Register)) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)); -} - inline void JIT::emitLoadTag(unsigned index, RegisterID tag) { RegisterID mappedTag; @@ -560,7 +560,7 @@ inline bool JIT::getMappedTag(unsigned virtualRegisterIndex, RegisterID& tag) inline void JIT::emitJumpSlowCaseIfNotJSCell(unsigned virtualRegisterIndex) { if (!m_codeBlock->isKnownNotImmediate(virtualRegisterIndex)) - addSlowCase(branch32(NotEqual, tagFor(virtualRegisterIndex), Imm32(JSValue::CellTag))); + addSlowCase(emitJumpIfNotJSCell(virtualRegisterIndex)); } inline void JIT::emitJumpSlowCaseIfNotJSCell(unsigned virtualRegisterIndex, RegisterID tag) @@ -737,14 +737,6 @@ ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotJSCell(RegisterID reg, int vReg) } #if USE(JSVALUE64) -ALWAYS_INLINE JIT::Jump JIT::emitJumpIfImmediateNumber(RegisterID reg) -{ - return branchTestPtr(NonZero, reg, tagTypeNumberRegister); -} -ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotImmediateNumber(RegisterID reg) -{ - return branchTestPtr(Zero, reg, tagTypeNumberRegister); -} inline void JIT::emitLoadDouble(unsigned index, FPRegisterID value) { diff --git a/JavaScriptCore/jit/JITOpcodes.cpp b/JavaScriptCore/jit/JITOpcodes.cpp index 0dd6a40..2ad79c6 100644 --- a/JavaScriptCore/jit/JITOpcodes.cpp +++ b/JavaScriptCore/jit/JITOpcodes.cpp @@ -400,7 +400,7 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable *executablePool = finalCode.m_executablePool; trampolines->ctiVirtualCall = trampolineAt(finalCode, virtualCallBegin); - trampolines->ctiNativeCallThunk = trampolineAt(finalCode, nativeCallThunk); + trampolines->ctiNativeCallThunk = adoptRef(new NativeExecutable(JITCode(JITCode::HostFunction(trampolineAt(finalCode, nativeCallThunk))))); #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) trampolines->ctiStringLengthTrampoline = trampolineAt(finalCode, stringLengthBegin); #else @@ -1430,11 +1430,16 @@ void JIT::emit_op_new_error(Instruction* currentInstruction) void JIT::emit_op_debug(Instruction* currentInstruction) { +#if ENABLE(DEBUG_WITH_BREAKPOINT) + UNUSED_PARAM(currentInstruction); + breakpoint(); +#else JITStubCall stubCall(this, cti_op_debug); stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); stubCall.addArgument(Imm32(currentInstruction[2].u.operand)); stubCall.addArgument(Imm32(currentInstruction[3].u.operand)); stubCall.call(); +#endif } @@ -1937,7 +1942,7 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable trampolines->ctiVirtualCallLink = trampolineAt(finalCode, virtualCallLinkBegin); trampolines->ctiVirtualCall = trampolineAt(finalCode, virtualCallBegin); - trampolines->ctiNativeCallThunk = trampolineAt(finalCode, nativeCallThunk); + trampolines->ctiNativeCallThunk = adoptRef(new NativeExecutable(JITCode(JITCode::HostFunction(trampolineAt(finalCode, nativeCallThunk))))); #if ENABLE(JIT_OPTIMIZE_MOD) trampolines->ctiSoftModulo = trampolineAt(finalCode, softModBegin); #endif @@ -2721,11 +2726,16 @@ void JIT::emit_op_new_error(Instruction* currentInstruction) void JIT::emit_op_debug(Instruction* currentInstruction) { +#if ENABLE(DEBUG_WITH_BREAKPOINT) + UNUSED_PARAM(currentInstruction); + breakpoint(); +#else JITStubCall stubCall(this, cti_op_debug); stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); stubCall.addArgument(Imm32(currentInstruction[2].u.operand)); stubCall.addArgument(Imm32(currentInstruction[3].u.operand)); stubCall.call(); +#endif } void JIT::emit_op_eq_null(Instruction* currentInstruction) diff --git a/JavaScriptCore/jit/JITStubCall.h b/JavaScriptCore/jit/JITStubCall.h index cfbd7dc..70d2893 100644 --- a/JavaScriptCore/jit/JITStubCall.h +++ b/JavaScriptCore/jit/JITStubCall.h @@ -116,13 +116,15 @@ namespace JSC { m_jit->poke(argument, m_stackIndex); m_stackIndex += stackIndexStep; } - + +#if USE(JSVALUE32_64) void addArgument(const JSValue& value) { m_jit->poke(JIT::Imm32(value.payload()), m_stackIndex); m_jit->poke(JIT::Imm32(value.tag()), m_stackIndex + 1); m_stackIndex += stackIndexStep; } +#endif void addArgument(JIT::RegisterID tag, JIT::RegisterID payload) { diff --git a/JavaScriptCore/jit/JITStubs.cpp b/JavaScriptCore/jit/JITStubs.cpp index c32f2ce..ebd26bb 100644 --- a/JavaScriptCore/jit/JITStubs.cpp +++ b/JavaScriptCore/jit/JITStubs.cpp @@ -578,6 +578,9 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" #elif COMPILER(RVCT) && CPU(ARM_TRADITIONAL) +#define THUNK_RETURN_ADDRESS_OFFSET 32 +#define PRESERVEDR4_OFFSET 36 + __asm EncodedJSValue ctiTrampoline(void*, RegisterFile*, CallFrame*, JSValue*, Profiler**, JSGlobalData*) { ARM @@ -835,6 +838,10 @@ JITThunks::JITThunks(JSGlobalData* globalData) #endif } +JITThunks::~JITThunks() +{ +} + #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const PutPropertySlot& slot, StructureStubInfo* stubInfo) @@ -3300,6 +3307,15 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, to_object) return JSValue::encode(stackFrame.args[0].jsValue().toObject(callFrame)); } +NativeExecutable* JITThunks::specializedThunk(JSGlobalData* globalData, ThunkGenerator generator) +{ + std::pair<ThunkMap::iterator, bool> entry = m_thunkMap.add(generator, 0); + if (!entry.second) + return entry.first->second.get(); + entry.first->second = generator(globalData, m_executablePool.get()); + return entry.first->second.get(); +} + } // namespace JSC #endif // ENABLE(JIT) diff --git a/JavaScriptCore/jit/JITStubs.h b/JavaScriptCore/jit/JITStubs.h index f419c8c..fe4bcfb 100644 --- a/JavaScriptCore/jit/JITStubs.h +++ b/JavaScriptCore/jit/JITStubs.h @@ -31,6 +31,8 @@ #include "MacroAssemblerCodeRef.h" #include "Register.h" +#include "ThunkGenerators.h" +#include <wtf/HashMap.h> #if ENABLE(JIT) @@ -43,16 +45,16 @@ namespace JSC { class FunctionExecutable; class Identifier; class JSGlobalData; - class JSGlobalData; + class JSGlobalObject; class JSObject; class JSPropertyNameIterator; class JSValue; class JSValueEncodedAsPointer; + class NativeExecutable; class Profiler; class PropertySlot; class PutPropertySlot; class RegisterFile; - class JSGlobalObject; class RegExp; union JITStubArg { @@ -77,7 +79,7 @@ namespace JSC { MacroAssemblerCodePtr ctiStringLengthTrampoline; MacroAssemblerCodePtr ctiVirtualCallLink; MacroAssemblerCodePtr ctiVirtualCall; - MacroAssemblerCodePtr ctiNativeCallThunk; + RefPtr<NativeExecutable> ctiNativeCallThunk; MacroAssemblerCodePtr ctiSoftModulo; }; @@ -265,6 +267,7 @@ namespace JSC { class JITThunks { public: JITThunks(JSGlobalData*); + ~JITThunks(); static void tryCacheGetByID(CallFrame*, CodeBlock*, ReturnAddressPtr returnAddress, JSValue baseValue, const Identifier& propertyName, const PropertySlot&, StructureStubInfo* stubInfo); static void tryCachePutByID(CallFrame*, CodeBlock*, ReturnAddressPtr returnAddress, JSValue baseValue, const PutPropertySlot&, StructureStubInfo* stubInfo); @@ -272,10 +275,13 @@ namespace JSC { MacroAssemblerCodePtr ctiStringLengthTrampoline() { return m_trampolineStructure.ctiStringLengthTrampoline; } MacroAssemblerCodePtr ctiVirtualCallLink() { return m_trampolineStructure.ctiVirtualCallLink; } MacroAssemblerCodePtr ctiVirtualCall() { return m_trampolineStructure.ctiVirtualCall; } - MacroAssemblerCodePtr ctiNativeCallThunk() { return m_trampolineStructure.ctiNativeCallThunk; } + NativeExecutable* ctiNativeCallThunk() { return m_trampolineStructure.ctiNativeCallThunk.get(); } MacroAssemblerCodePtr ctiSoftModulo() { return m_trampolineStructure.ctiSoftModulo; } + NativeExecutable* specializedThunk(JSGlobalData* globalData, ThunkGenerator generator); private: + typedef HashMap<ThunkGenerator, RefPtr<NativeExecutable> > ThunkMap; + ThunkMap m_thunkMap; RefPtr<ExecutablePool> m_executablePool; TrampolineStructure m_trampolineStructure; diff --git a/JavaScriptCore/jit/JSInterfaceJIT.h b/JavaScriptCore/jit/JSInterfaceJIT.h new file mode 100644 index 0000000..2cd0e33 --- /dev/null +++ b/JavaScriptCore/jit/JSInterfaceJIT.h @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#ifndef JSInterfaceJIT_h +#define JSInterfaceJIT_h + +#include "JITCode.h" +#include "JITStubs.h" +#include "JSImmediate.h" +#include "MacroAssembler.h" +#include "RegisterFile.h" +#include <wtf/AlwaysInline.h> +#include <wtf/Vector.h> + +namespace JSC { + class JSInterfaceJIT : public MacroAssembler { + public: + // NOTES: + // + // regT0 has two special meanings. The return value from a stub + // call will always be in regT0, and by default (unless + // a register is specified) emitPutVirtualRegister() will store + // the value from regT0. + // + // regT3 is required to be callee-preserved. + // + // tempRegister2 is has no such dependencies. It is important that + // on x86/x86-64 it is ecx for performance reasons, since the + // MacroAssembler will need to plant register swaps if it is not - + // however the code will still function correctly. +#if CPU(X86_64) + static const RegisterID returnValueRegister = X86Registers::eax; + static const RegisterID cachedResultRegister = X86Registers::eax; + static const RegisterID firstArgumentRegister = X86Registers::edi; + + static const RegisterID timeoutCheckRegister = X86Registers::r12; + static const RegisterID callFrameRegister = X86Registers::r13; + static const RegisterID tagTypeNumberRegister = X86Registers::r14; + static const RegisterID tagMaskRegister = X86Registers::r15; + + static const RegisterID regT0 = X86Registers::eax; + static const RegisterID regT1 = X86Registers::edx; + static const RegisterID regT2 = X86Registers::ecx; + static const RegisterID regT3 = X86Registers::ebx; + + static const FPRegisterID fpRegT0 = X86Registers::xmm0; + static const FPRegisterID fpRegT1 = X86Registers::xmm1; + static const FPRegisterID fpRegT2 = X86Registers::xmm2; + static const FPRegisterID fpRegT3 = X86Registers::xmm3; +#elif CPU(X86) + static const RegisterID returnValueRegister = X86Registers::eax; + static const RegisterID cachedResultRegister = X86Registers::eax; + // On x86 we always use fastcall conventions = but on + // OS X if might make more sense to just use regparm. + static const RegisterID firstArgumentRegister = X86Registers::ecx; + + static const RegisterID timeoutCheckRegister = X86Registers::esi; + static const RegisterID callFrameRegister = X86Registers::edi; + + static const RegisterID regT0 = X86Registers::eax; + static const RegisterID regT1 = X86Registers::edx; + static const RegisterID regT2 = X86Registers::ecx; + static const RegisterID regT3 = X86Registers::ebx; + + static const FPRegisterID fpRegT0 = X86Registers::xmm0; + static const FPRegisterID fpRegT1 = X86Registers::xmm1; + static const FPRegisterID fpRegT2 = X86Registers::xmm2; + static const FPRegisterID fpRegT3 = X86Registers::xmm3; +#elif CPU(ARM_THUMB2) + static const RegisterID returnValueRegister = ARMRegisters::r0; + static const RegisterID cachedResultRegister = ARMRegisters::r0; + static const RegisterID firstArgumentRegister = ARMRegisters::r0; + + static const RegisterID regT0 = ARMRegisters::r0; + static const RegisterID regT1 = ARMRegisters::r1; + static const RegisterID regT2 = ARMRegisters::r2; + static const RegisterID regT3 = ARMRegisters::r4; + + static const RegisterID callFrameRegister = ARMRegisters::r5; + static const RegisterID timeoutCheckRegister = ARMRegisters::r6; + + static const FPRegisterID fpRegT0 = ARMRegisters::d0; + static const FPRegisterID fpRegT1 = ARMRegisters::d1; + static const FPRegisterID fpRegT2 = ARMRegisters::d2; + static const FPRegisterID fpRegT3 = ARMRegisters::d3; +#elif CPU(ARM_TRADITIONAL) + static const RegisterID returnValueRegister = ARMRegisters::r0; + static const RegisterID cachedResultRegister = ARMRegisters::r0; + static const RegisterID firstArgumentRegister = ARMRegisters::r0; + + static const RegisterID timeoutCheckRegister = ARMRegisters::r5; + static const RegisterID callFrameRegister = ARMRegisters::r4; + + static const RegisterID regT0 = ARMRegisters::r0; + static const RegisterID regT1 = ARMRegisters::r1; + static const RegisterID regT2 = ARMRegisters::r2; + // Callee preserved + static const RegisterID regT3 = ARMRegisters::r7; + + static const RegisterID regS0 = ARMRegisters::S0; + // Callee preserved + static const RegisterID regS1 = ARMRegisters::S1; + + static const RegisterID regStackPtr = ARMRegisters::sp; + static const RegisterID regLink = ARMRegisters::lr; + + static const FPRegisterID fpRegT0 = ARMRegisters::d0; + static const FPRegisterID fpRegT1 = ARMRegisters::d1; + static const FPRegisterID fpRegT2 = ARMRegisters::d2; + static const FPRegisterID fpRegT3 = ARMRegisters::d3; +#elif CPU(MIPS) + static const RegisterID returnValueRegister = MIPSRegisters::v0; + static const RegisterID cachedResultRegister = MIPSRegisters::v0; + static const RegisterID firstArgumentRegister = MIPSRegisters::a0; + + // regT0 must be v0 for returning a 32-bit value. + static const RegisterID regT0 = MIPSRegisters::v0; + + // regT1 must be v1 for returning a pair of 32-bit value. + static const RegisterID regT1 = MIPSRegisters::v1; + + static const RegisterID regT2 = MIPSRegisters::t4; + + // regT3 must be saved in the callee, so use an S register. + static const RegisterID regT3 = MIPSRegisters::s2; + + static const RegisterID callFrameRegister = MIPSRegisters::s0; + static const RegisterID timeoutCheckRegister = MIPSRegisters::s1; + + static const FPRegisterID fpRegT0 = MIPSRegisters::f4; + static const FPRegisterID fpRegT1 = MIPSRegisters::f6; + static const FPRegisterID fpRegT2 = MIPSRegisters::f8; + static const FPRegisterID fpRegT2 = MIPSRegisters::f10; +#else +#error "JIT not supported on this platform." +#endif + + inline Jump emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID payload); + inline Jump emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst); + inline Jump emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch); + +#if USE(JSVALUE32_64) + inline Jump emitJumpIfNotJSCell(unsigned virtualRegisterIndex); + inline Address tagFor(unsigned index, RegisterID base = callFrameRegister); +#endif + +#if USE(JSVALUE32) || USE(JSVALUE64) + Jump emitJumpIfImmediateNumber(RegisterID reg); + Jump emitJumpIfNotImmediateNumber(RegisterID reg); +#endif + + inline Address payloadFor(unsigned index, RegisterID base = callFrameRegister); + inline Address addressFor(unsigned index, RegisterID base = callFrameRegister); + }; + + struct ThunkHelpers { + static unsigned stringImplDataOffset() { return WebCore::StringImpl::dataOffset(); } + static unsigned jsStringLengthOffset() { return OBJECT_OFFSETOF(JSString, m_length); } + static unsigned jsStringValueOffset() { return OBJECT_OFFSETOF(JSString, m_value); } + }; + +#if USE(JSVALUE32_64) + inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID payload) + { + loadPtr(payloadFor(virtualRegisterIndex), payload); + return emitJumpIfNotJSCell(virtualRegisterIndex); + } + + inline JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotJSCell(unsigned virtualRegisterIndex) + { + return branch32(NotEqual, tagFor(virtualRegisterIndex), Imm32(JSValue::CellTag)); + } + + inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst) + { + loadPtr(payloadFor(virtualRegisterIndex), dst); + return branch32(NotEqual, tagFor(virtualRegisterIndex), Imm32(JSValue::Int32Tag)); + } + + inline JSInterfaceJIT::Address JSInterfaceJIT::tagFor(unsigned index, RegisterID base) + { + return Address(base, (index * sizeof(Register)) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)); + } + + inline JSInterfaceJIT::Address JSInterfaceJIT::payloadFor(unsigned index, RegisterID base) + { + return Address(base, (index * sizeof(Register)) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)); + } + + inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch) + { + loadPtr(tagFor(virtualRegisterIndex), scratch); + Jump isDouble = branch32(Below, scratch, Imm32(JSValue::LowestTag)); + Jump notInt = branch32(NotEqual, scratch, Imm32(JSValue::Int32Tag)); + loadPtr(payloadFor(virtualRegisterIndex), scratch); + convertInt32ToDouble(scratch, dst); + Jump done = jump(); + isDouble.link(this); + loadDouble(addressFor(virtualRegisterIndex), dst); + done.link(this); + return notInt; + } +#endif + +#if USE(JSVALUE64) + ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfImmediateNumber(RegisterID reg) + { + return branchTestPtr(NonZero, reg, tagTypeNumberRegister); + } + ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotImmediateNumber(RegisterID reg) + { + return branchTestPtr(Zero, reg, tagTypeNumberRegister); + } + inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID dst) + { + loadPtr(addressFor(virtualRegisterIndex), dst); + return branchTestPtr(NonZero, dst, tagMaskRegister); + } + + inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst) + { + loadPtr(addressFor(virtualRegisterIndex), dst); + Jump result = branchPtr(Below, dst, tagTypeNumberRegister); + zeroExtend32ToPtr(dst, dst); + return result; + } + + inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch) + { + loadPtr(addressFor(virtualRegisterIndex), scratch); + Jump notNumber = emitJumpIfNotImmediateNumber(scratch); + Jump notInt = branchPtr(Below, scratch, tagTypeNumberRegister); + convertInt32ToDouble(scratch, dst); + Jump done = jump(); + notInt.link(this); + addPtr(tagTypeNumberRegister, scratch); + movePtrToDouble(scratch, dst); + done.link(this); + return notNumber; + } + +#endif + +#if USE(JSVALUE32) + inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID dst) + { + loadPtr(addressFor(virtualRegisterIndex), dst); + return branchTest32(NonZero, dst, Imm32(JSImmediate::TagMask)); + } + + inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst) + { + loadPtr(addressFor(virtualRegisterIndex), dst); + Jump result = branchTest32(Zero, dst, Imm32(JSImmediate::TagTypeNumber)); + rshift32(Imm32(JSImmediate::IntegerPayloadShift), dst); + return result; + } + + inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadDouble(unsigned, FPRegisterID, RegisterID) + { + ASSERT_NOT_REACHED(); + return jump(); + } +#endif + +#if !USE(JSVALUE32_64) + inline JSInterfaceJIT::Address JSInterfaceJIT::payloadFor(unsigned index, RegisterID base) + { + return addressFor(index, base); + } +#endif + + inline JSInterfaceJIT::Address JSInterfaceJIT::addressFor(unsigned index, RegisterID base) + { + return Address(base, (index * sizeof(Register))); + } + +} + +#endif // JSInterfaceJIT_h diff --git a/JavaScriptCore/jit/SpecializedThunkJIT.h b/JavaScriptCore/jit/SpecializedThunkJIT.h new file mode 100644 index 0000000..e41411d --- /dev/null +++ b/JavaScriptCore/jit/SpecializedThunkJIT.h @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#ifndef SpecializedThunkJIT_h +#define SpecializedThunkJIT_h + +#if ENABLE(JIT) + +#include "Executable.h" +#include "JSInterfaceJIT.h" +#include "LinkBuffer.h" + +namespace JSC { + + class SpecializedThunkJIT : public JSInterfaceJIT { + public: + static const int ThisArgument = -1; + SpecializedThunkJIT(int expectedArgCount, JSGlobalData* globalData, ExecutablePool* pool) + : m_expectedArgCount(expectedArgCount) + , m_globalData(globalData) + , m_pool(pool) + { + // Check that we have the expected number of arguments + m_failures.append(branch32(NotEqual, Address(callFrameRegister, RegisterFile::ArgumentCount * (int)sizeof(Register)), Imm32(expectedArgCount + 1))); + } + + void loadDoubleArgument(int argument, FPRegisterID dst, RegisterID scratch) + { + unsigned src = argumentToVirtualRegister(argument); + m_failures.append(emitLoadDouble(src, dst, scratch)); + } + + void loadCellArgument(int argument, RegisterID dst) + { + unsigned src = argumentToVirtualRegister(argument); + m_failures.append(emitLoadJSCell(src, dst)); + } + + void loadJSStringArgument(int argument, RegisterID dst) + { + loadCellArgument(argument, dst); + m_failures.append(branchPtr(NotEqual, Address(dst, 0), ImmPtr(m_globalData->jsStringVPtr))); + m_failures.append(branchTest32(NonZero, Address(dst, OBJECT_OFFSETOF(JSString, m_fiberCount)))); + } + + void loadInt32Argument(int argument, RegisterID dst, Jump& failTarget) + { + unsigned src = argumentToVirtualRegister(argument); + failTarget = emitLoadInt32(src, dst); + } + + void loadInt32Argument(int argument, RegisterID dst) + { + Jump conversionFailed; + loadInt32Argument(argument, dst, conversionFailed); + m_failures.append(conversionFailed); + } + + void appendFailure(const Jump& failure) + { + m_failures.append(failure); + } + + void returnJSValue(RegisterID src) + { + if (src != regT0) + move(src, regT0); + loadPtr(Address(callFrameRegister, RegisterFile::CallerFrame * (int)sizeof(Register)), callFrameRegister); + ret(); + } + + void returnDouble(FPRegisterID src) + { +#if USE(JSVALUE64) + moveDoubleToPtr(src, regT0); + subPtr(tagTypeNumberRegister, regT0); +#elif USE(JSVALUE32_64) + storeDouble(src, Address(stackPointerRegister, -(int)sizeof(double))); + loadPtr(Address(stackPointerRegister, OBJECT_OFFSETOF(JSValue, u.asBits.tag) - sizeof(double)), regT1); + loadPtr(Address(stackPointerRegister, OBJECT_OFFSETOF(JSValue, u.asBits.payload) - sizeof(double)), regT0); +#else + UNUSED_PARAM(src); + ASSERT_NOT_REACHED(); + m_failures.append(jump()); +#endif + loadPtr(Address(callFrameRegister, RegisterFile::CallerFrame * (int)sizeof(Register)), callFrameRegister); + ret(); + } + + void returnInt32(RegisterID src) + { + if (src != regT0) + move(src, regT0); + tagReturnAsInt32(); + loadPtr(Address(callFrameRegister, RegisterFile::CallerFrame * (int)sizeof(Register)), callFrameRegister); + ret(); + } + + void returnJSCell(RegisterID src) + { + if (src != regT0) + move(src, regT0); + tagReturnAsJSCell(); + loadPtr(Address(callFrameRegister, RegisterFile::CallerFrame * (int)sizeof(Register)), callFrameRegister); + ret(); + } + + PassRefPtr<NativeExecutable> finalize() + { + LinkBuffer patchBuffer(this, m_pool.get()); + patchBuffer.link(m_failures, CodeLocationLabel(m_globalData->jitStubs.ctiNativeCallThunk()->generatedJITCode().addressForCall())); + return adoptRef(new NativeExecutable(patchBuffer.finalizeCode())); + } + + private: + int argumentToVirtualRegister(unsigned argument) + { + return -static_cast<int>(RegisterFile::CallFrameHeaderSize + (m_expectedArgCount - argument)); + } + + void tagReturnAsInt32() + { +#if USE(JSVALUE64) + orPtr(tagTypeNumberRegister, regT0); +#elif USE(JSVALUE32_64) + move(Imm32(JSValue::Int32Tag), regT1); +#else + signExtend32ToPtr(regT0, regT0); + // If we can't tag the result, give up and jump to the slow case + m_failures.append(branchAddPtr(Overflow, regT0, regT0)); + addPtr(Imm32(JSImmediate::TagTypeNumber), regT0); +#endif + } + + void tagReturnAsJSCell() + { +#if USE(JSVALUE32_64) + move(Imm32(JSValue::CellTag), regT1); +#endif + } + + int m_expectedArgCount; + JSGlobalData* m_globalData; + RefPtr<ExecutablePool> m_pool; + MacroAssembler::JumpList m_failures; + }; + +} + +#endif // ENABLE(JIT) + +#endif // SpecializedThunkJIT_h diff --git a/JavaScriptCore/jit/ThunkGenerators.cpp b/JavaScriptCore/jit/ThunkGenerators.cpp new file mode 100644 index 0000000..c625c3d --- /dev/null +++ b/JavaScriptCore/jit/ThunkGenerators.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#include "config.h" +#include "ThunkGenerators.h" +#include <wtf/text/StringImpl.h> + +#include "SpecializedThunkJIT.h" + +#if ENABLE(JIT) + +namespace JSC { + +static void stringCharLoad(SpecializedThunkJIT& jit) +{ + // load string + jit.loadJSStringArgument(SpecializedThunkJIT::ThisArgument, SpecializedThunkJIT::regT0); + // regT0 now contains this, and is a non-rope JSString* + + // Load string length to regT2, and start the process of loading the data pointer into regT0 + jit.load32(MacroAssembler::Address(SpecializedThunkJIT::regT0, ThunkHelpers::jsStringLengthOffset()), SpecializedThunkJIT::regT2); + jit.loadPtr(MacroAssembler::Address(SpecializedThunkJIT::regT0, ThunkHelpers::jsStringValueOffset()), SpecializedThunkJIT::regT0); + jit.loadPtr(MacroAssembler::Address(SpecializedThunkJIT::regT0, ThunkHelpers::stringImplDataOffset()), SpecializedThunkJIT::regT0); + + // load index + jit.loadInt32Argument(0, SpecializedThunkJIT::regT1); // regT1 contains the index + + // Do an unsigned compare to simultaneously filter negative indices as well as indices that are too large + jit.appendFailure(jit.branch32(MacroAssembler::AboveOrEqual, SpecializedThunkJIT::regT1, SpecializedThunkJIT::regT2)); + + // Load the character + jit.load16(MacroAssembler::BaseIndex(SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1, MacroAssembler::TimesTwo, 0), SpecializedThunkJIT::regT0); +} + +static void charToString(SpecializedThunkJIT& jit, JSGlobalData* globalData, MacroAssembler::RegisterID src, MacroAssembler::RegisterID dst, MacroAssembler::RegisterID scratch) +{ + jit.appendFailure(jit.branch32(MacroAssembler::AboveOrEqual, src, MacroAssembler::Imm32(0x100))); + jit.move(MacroAssembler::ImmPtr(globalData->smallStrings.singleCharacterStrings()), scratch); + jit.loadPtr(MacroAssembler::BaseIndex(scratch, src, MacroAssembler::ScalePtr, 0), dst); + jit.appendFailure(jit.branchTestPtr(MacroAssembler::Zero, dst)); +} + +PassRefPtr<NativeExecutable> charCodeAtThunkGenerator(JSGlobalData* globalData, ExecutablePool* pool) +{ + SpecializedThunkJIT jit(1, globalData, pool); + stringCharLoad(jit); + jit.returnInt32(SpecializedThunkJIT::regT0); + return jit.finalize(); +} + +PassRefPtr<NativeExecutable> charAtThunkGenerator(JSGlobalData* globalData, ExecutablePool* pool) +{ + SpecializedThunkJIT jit(1, globalData, pool); + stringCharLoad(jit); + charToString(jit, globalData, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1); + jit.returnJSCell(SpecializedThunkJIT::regT0); + return jit.finalize(); +} + +PassRefPtr<NativeExecutable> fromCharCodeThunkGenerator(JSGlobalData* globalData, ExecutablePool* pool) +{ + SpecializedThunkJIT jit(1, globalData, pool); + // load char code + jit.loadInt32Argument(0, SpecializedThunkJIT::regT0); + charToString(jit, globalData, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1); + jit.returnJSCell(SpecializedThunkJIT::regT0); + return jit.finalize(); +} + +PassRefPtr<NativeExecutable> sqrtThunkGenerator(JSGlobalData* globalData, ExecutablePool* pool) +{ +#if USE(JSVALUE64) || USE(JSVALUE32_64) + SpecializedThunkJIT jit(1, globalData, pool); + if (!jit.supportsFloatingPointSqrt()) + return globalData->jitStubs.ctiNativeCallThunk(); + + jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0); + jit.sqrtDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT0); + jit.returnDouble(SpecializedThunkJIT::fpRegT0); + return jit.finalize(); +#else + UNUSED_PARAM(pool); + return globalData->jitStubs.ctiNativeCallThunk(); +#endif +} + +static const double oneConstant = 1.0; +static const double negativeHalfConstant = -0.5; + +PassRefPtr<NativeExecutable> powThunkGenerator(JSGlobalData* globalData, ExecutablePool* pool) +{ +#if USE(JSVALUE64) || USE(JSVALUE32_64) + SpecializedThunkJIT jit(2, globalData, pool); + if (!jit.supportsFloatingPoint()) + return globalData->jitStubs.ctiNativeCallThunk(); + + jit.loadDouble(&oneConstant, SpecializedThunkJIT::fpRegT1); + jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0); + MacroAssembler::Jump nonIntExponent; + jit.loadInt32Argument(1, SpecializedThunkJIT::regT0, nonIntExponent); + jit.appendFailure(jit.branch32(MacroAssembler::LessThan, SpecializedThunkJIT::regT0, MacroAssembler::Imm32(0))); + + MacroAssembler::Jump exponentIsZero = jit.branchTest32(MacroAssembler::Zero, SpecializedThunkJIT::regT0); + MacroAssembler::Label startLoop(jit.label()); + + MacroAssembler::Jump exponentIsEven = jit.branchTest32(MacroAssembler::Zero, SpecializedThunkJIT::regT0, MacroAssembler::Imm32(1)); + jit.mulDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1); + exponentIsEven.link(&jit); + jit.mulDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT0); + jit.rshift32(MacroAssembler::Imm32(1), SpecializedThunkJIT::regT0); + jit.branchTest32(MacroAssembler::NonZero, SpecializedThunkJIT::regT0).linkTo(startLoop, &jit); + + exponentIsZero.link(&jit); + jit.returnDouble(SpecializedThunkJIT::fpRegT1); + + if (jit.supportsFloatingPointSqrt()) { + nonIntExponent.link(&jit); + jit.loadDouble(&negativeHalfConstant, SpecializedThunkJIT::fpRegT3); + jit.loadDoubleArgument(1, SpecializedThunkJIT::fpRegT2, SpecializedThunkJIT::regT0); + jit.appendFailure(jit.branchDouble(MacroAssembler::DoubleLessThanOrEqual, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1)); + jit.appendFailure(jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, SpecializedThunkJIT::fpRegT2, SpecializedThunkJIT::fpRegT3)); + jit.sqrtDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT0); + jit.divDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1); + jit.returnDouble(SpecializedThunkJIT::fpRegT1); + } else + jit.appendFailure(nonIntExponent); + + return jit.finalize(); +#else + UNUSED_PARAM(pool); + return globalData->jitStubs.ctiNativeCallThunk(); +#endif +} + +} + +#endif // ENABLE(JIT) diff --git a/JavaScriptCore/jit/ThunkGenerators.h b/JavaScriptCore/jit/ThunkGenerators.h new file mode 100644 index 0000000..c3374f2 --- /dev/null +++ b/JavaScriptCore/jit/ThunkGenerators.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#ifndef ThunkGenerators_h +#define ThunkGenerators_h + +#if ENABLE(JIT) +#include <wtf/PassRefPtr.h> + +namespace JSC { + class ExecutablePool; + class JSGlobalData; + class NativeExecutable; + + typedef PassRefPtr<NativeExecutable> (*ThunkGenerator)(JSGlobalData*, ExecutablePool*); + PassRefPtr<NativeExecutable> charCodeAtThunkGenerator(JSGlobalData*, ExecutablePool*); + PassRefPtr<NativeExecutable> charAtThunkGenerator(JSGlobalData*, ExecutablePool*); + PassRefPtr<NativeExecutable> fromCharCodeThunkGenerator(JSGlobalData*, ExecutablePool*); + PassRefPtr<NativeExecutable> sqrtThunkGenerator(JSGlobalData*, ExecutablePool*); + PassRefPtr<NativeExecutable> powThunkGenerator(JSGlobalData*, ExecutablePool*); +} +#endif + +#endif // ThunkGenerator_h diff --git a/JavaScriptCore/qt/api/qscriptengine_p.h b/JavaScriptCore/qt/api/qscriptengine_p.h index 2bda68e..c6c64dd 100644 --- a/JavaScriptCore/qt/api/qscriptengine_p.h +++ b/JavaScriptCore/qt/api/qscriptengine_p.h @@ -35,7 +35,7 @@ class QScriptSyntaxCheckResultPrivate; class QScriptEnginePrivate : public QSharedData { public: - static QScriptEnginePtr get(const QScriptEngine* q) { Q_ASSERT(q); return q->d_ptr; } + static QScriptEnginePrivate* get(const QScriptEngine* q) { Q_ASSERT(q); return q->d_ptr.data(); } static QScriptEngine* get(const QScriptEnginePrivate* d) { Q_ASSERT(d); return d->q_ptr; } QScriptEnginePrivate(const QScriptEngine*); diff --git a/JavaScriptCore/qt/api/qscriptstring_p.h b/JavaScriptCore/qt/api/qscriptstring_p.h index f4fd117..d4fc88e 100644 --- a/JavaScriptCore/qt/api/qscriptstring_p.h +++ b/JavaScriptCore/qt/api/qscriptstring_p.h @@ -56,7 +56,7 @@ QScriptStringPrivate::QScriptStringPrivate() {} QScriptStringPrivate::QScriptStringPrivate(const QString& qtstring) - : m_string(JSStringRetain(QScriptConverter::toString(qtstring))) + : m_string(QScriptConverter::toString(qtstring)) {} QScriptStringPrivate::~QScriptStringPrivate() diff --git a/JavaScriptCore/qt/api/qscriptvalue.cpp b/JavaScriptCore/qt/api/qscriptvalue.cpp index 127fe04..f692817 100644 --- a/JavaScriptCore/qt/api/qscriptvalue.cpp +++ b/JavaScriptCore/qt/api/qscriptvalue.cpp @@ -115,8 +115,11 @@ QScriptValue::QScriptValue(QScriptValuePrivate* d) registers it with the script \a engine. */ QScriptValue::QScriptValue(QScriptEngine* engine, bool value) - : d_ptr(new QScriptValuePrivate(engine, value)) { + if (engine) + d_ptr = new QScriptValuePrivate(QScriptEnginePrivate::get(engine), value); + else + d_ptr = new QScriptValuePrivate(value); } /*! @@ -126,8 +129,11 @@ QScriptValue::QScriptValue(QScriptEngine* engine, bool value) registers it with the script \a engine. */ QScriptValue::QScriptValue(QScriptEngine* engine, int value) - : d_ptr(new QScriptValuePrivate(engine, value)) { + if (engine) + d_ptr = new QScriptValuePrivate(QScriptEnginePrivate::get(engine), value); + else + d_ptr = new QScriptValuePrivate(value); } /*! @@ -137,8 +143,11 @@ QScriptValue::QScriptValue(QScriptEngine* engine, int value) registers it with the script \a engine. */ QScriptValue::QScriptValue(QScriptEngine* engine, uint value) - : d_ptr(new QScriptValuePrivate(engine, value)) { + if (engine) + d_ptr = new QScriptValuePrivate(QScriptEnginePrivate::get(engine), value); + else + d_ptr = new QScriptValuePrivate(value); } /*! @@ -148,8 +157,11 @@ QScriptValue::QScriptValue(QScriptEngine* engine, uint value) registers it with the script \a engine. */ QScriptValue::QScriptValue(QScriptEngine* engine, qsreal value) - : d_ptr(new QScriptValuePrivate(engine, value)) { + if (engine) + d_ptr = new QScriptValuePrivate(QScriptEnginePrivate::get(engine), value); + else + d_ptr = new QScriptValuePrivate(value); } /*! @@ -159,8 +171,11 @@ QScriptValue::QScriptValue(QScriptEngine* engine, qsreal value) registers it with the script \a engine. */ QScriptValue::QScriptValue(QScriptEngine* engine, const QString& value) - : d_ptr(new QScriptValuePrivate(engine, value)) { + if (engine) + d_ptr = new QScriptValuePrivate(QScriptEnginePrivate::get(engine), value); + else + d_ptr = new QScriptValuePrivate(value); } /*! @@ -170,8 +185,11 @@ QScriptValue::QScriptValue(QScriptEngine* engine, const QString& value) registers it with the script \a engine. */ QScriptValue::QScriptValue(QScriptEngine* engine, const char* value) - : d_ptr(new QScriptValuePrivate(engine, QString::fromUtf8(value))) { + if (engine) + d_ptr = new QScriptValuePrivate(QScriptEnginePrivate::get(engine), QString::fromUtf8(value)); + else + d_ptr = new QScriptValuePrivate(QString::fromUtf8(value)); } /*! @@ -181,8 +199,11 @@ QScriptValue::QScriptValue(QScriptEngine* engine, const char* value) registers it with the script \a engine. */ QScriptValue::QScriptValue(QScriptEngine* engine, SpecialValue value) - : d_ptr(new QScriptValuePrivate(engine, value)) { + if (engine) + d_ptr = new QScriptValuePrivate(QScriptEnginePrivate::get(engine), value); + else + d_ptr = new QScriptValuePrivate(value); } /*! diff --git a/JavaScriptCore/qt/api/qscriptvalue_p.h b/JavaScriptCore/qt/api/qscriptvalue_p.h index 830b38e..03e8621 100644 --- a/JavaScriptCore/qt/api/qscriptvalue_p.h +++ b/JavaScriptCore/qt/api/qscriptvalue_p.h @@ -24,6 +24,7 @@ #include "qscriptengine_p.h" #include "qscriptvalue.h" #include <JavaScriptCore/JavaScript.h> +#include <JavaScriptCore/JSRetainPtr.h> #include <QtCore/qmath.h> #include <QtCore/qnumeric.h> #include <QtCore/qshareddata.h> @@ -76,12 +77,12 @@ public: inline QScriptValuePrivate(qsreal number); inline QScriptValuePrivate(QScriptValue::SpecialValue value); - inline QScriptValuePrivate(const QScriptEngine* engine, bool value); - inline QScriptValuePrivate(const QScriptEngine* engine, int value); - inline QScriptValuePrivate(const QScriptEngine* engine, uint value); - inline QScriptValuePrivate(const QScriptEngine* engine, qsreal value); - inline QScriptValuePrivate(const QScriptEngine* engine, const QString& value); - inline QScriptValuePrivate(const QScriptEngine* engine, QScriptValue::SpecialValue value); + inline QScriptValuePrivate(const QScriptEnginePrivate* engine, bool value); + inline QScriptValuePrivate(const QScriptEnginePrivate* engine, int value); + inline QScriptValuePrivate(const QScriptEnginePrivate* engine, uint value); + inline QScriptValuePrivate(const QScriptEnginePrivate* engine, qsreal value); + inline QScriptValuePrivate(const QScriptEnginePrivate* engine, const QString& value); + inline QScriptValuePrivate(const QScriptEnginePrivate* engine, QScriptValue::SpecialValue value); inline QScriptValuePrivate(const QScriptEnginePrivate* engine, JSValueRef value); inline QScriptValuePrivate(const QScriptEnginePrivate* engine, JSValueRef value, JSObjectRef object); @@ -209,94 +210,58 @@ QScriptValuePrivate::QScriptValuePrivate(QScriptValue::SpecialValue value) { } -QScriptValuePrivate::QScriptValuePrivate(const QScriptEngine* engine, bool value) +QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, bool value) : m_state(JSPrimitive) + , m_engine(const_cast<QScriptEnginePrivate*>(engine)) + , m_value(engine->makeJSValue(value)) { - if (!engine) { - // slower path reinitialization - m_state = CBool; - m_number = value; - m_value = 0; - } else { - m_engine = QScriptEnginePrivate::get(engine); - m_value = m_engine->makeJSValue(value); - JSValueProtect(context(), m_value); - } + Q_ASSERT(engine); + JSValueProtect(context(), m_value); } -QScriptValuePrivate::QScriptValuePrivate(const QScriptEngine* engine, int value) +QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, int value) : m_state(JSPrimitive) + , m_engine(const_cast<QScriptEnginePrivate*>(engine)) + , m_value(m_engine->makeJSValue(value)) { - if (!engine) { - // slower path reinitialization - m_state = CNumber; - m_number = value; - m_value = 0; - } else { - m_engine = QScriptEnginePrivate::get(engine); - m_value = m_engine->makeJSValue(value); - JSValueProtect(context(), m_value); - } + Q_ASSERT(engine); + JSValueProtect(context(), m_value); } -QScriptValuePrivate::QScriptValuePrivate(const QScriptEngine* engine, uint value) +QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, uint value) : m_state(JSPrimitive) + , m_engine(const_cast<QScriptEnginePrivate*>(engine)) + , m_value(m_engine->makeJSValue(value)) { - if (!engine) { - // slower path reinitialization - m_state = CNumber; - m_number = value; - m_value = 0; - } else { - m_engine = QScriptEnginePrivate::get(engine); - m_value = m_engine->makeJSValue(value); - JSValueProtect(context(), m_value); - } + Q_ASSERT(engine); + JSValueProtect(context(), m_value); } -QScriptValuePrivate::QScriptValuePrivate(const QScriptEngine* engine, qsreal value) +QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, qsreal value) : m_state(JSPrimitive) + , m_engine(const_cast<QScriptEnginePrivate*>(engine)) + , m_value(m_engine->makeJSValue(value)) { - if (!engine) { - // slower path reinitialization - m_state = CNumber; - m_number = value; - m_value = 0; - } else { - m_engine = QScriptEnginePrivate::get(engine); - m_value = m_engine->makeJSValue(value); - JSValueProtect(context(), m_value); - } + Q_ASSERT(engine); + JSValueProtect(context(), m_value); } -QScriptValuePrivate::QScriptValuePrivate(const QScriptEngine* engine, const QString& value) +QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, const QString& value) : m_state(JSPrimitive) + , m_engine(const_cast<QScriptEnginePrivate*>(engine)) + , m_value(m_engine->makeJSValue(value)) { - if (!engine) { - // slower path reinitialization - m_state = CString; - m_string = value; - m_value = 0; - } else { - m_engine = QScriptEnginePrivate::get(engine); - m_value = m_engine->makeJSValue(value); - JSValueProtect(context(), m_value); - } + Q_ASSERT(engine); + JSValueProtect(context(), m_value); } -QScriptValuePrivate::QScriptValuePrivate(const QScriptEngine* engine, QScriptValue::SpecialValue value) +QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, QScriptValue::SpecialValue value) : m_state(JSPrimitive) + , m_engine(const_cast<QScriptEnginePrivate*>(engine)) + , m_value(m_engine->makeJSValue(value)) { - if (!engine) { - // slower path reinitialization - m_state = CSpecial; - m_number = value; - m_value = 0; - } else { - m_engine = QScriptEnginePrivate::get(engine); - m_value = m_engine->makeJSValue(value); - JSValueProtect(context(), m_value); - } + Q_ASSERT(engine); + JSValueProtect(context(), m_value); } QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, JSValueRef value) @@ -305,6 +270,7 @@ QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, JSV , m_value(value) { Q_ASSERT(engine); + Q_ASSERT(value); JSValueProtect(context(), m_value); } @@ -315,6 +281,8 @@ QScriptValuePrivate::QScriptValuePrivate(const QScriptEnginePrivate* engine, JSV , m_object(object) { Q_ASSERT(engine); + Q_ASSERT(value); + Q_ASSERT(object); JSValueProtect(context(), m_value); } @@ -457,7 +425,8 @@ QString QScriptValuePrivate::toString() const case JSValue: case JSPrimitive: case JSObject: - return QScriptConverter::toString(JSValueToStringCopy(context(), value(), /* exception */ 0)); + JSRetainPtr<JSStringRef> ptr(Adopt, JSValueToStringCopy(context(), value(), /* exception */ 0)); + return QScriptConverter::toString(ptr.get()); } Q_ASSERT_X(false, "toString()", "Not all states are included in the previous switch statement."); diff --git a/JavaScriptCore/qt/api/qtscriptglobal.h b/JavaScriptCore/qt/api/qtscriptglobal.h index 29749c0..efdfc50 100644 --- a/JavaScriptCore/qt/api/qtscriptglobal.h +++ b/JavaScriptCore/qt/api/qtscriptglobal.h @@ -22,23 +22,22 @@ #include <QtCore/qglobal.h> -#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) -# if defined(QT_NODLL) -# elif defined(QT_MAKEDLL) /* create a Qt DLL library */ -# if defined(QT_BUILD_JAVASCRIPT_LIB) -# define Q_JAVASCRIPT_EXPORT Q_DECL_EXPORT -# else -# define Q_JAVASCRIPT_EXPORT Q_DECL_IMPORT -# endif -# elif defined(QT_DLL) /* use a Qt DLL library */ -# define Q_JAVASCRIPT_EXPORT +#if defined(QT_MAKEDLL) /* create a Qt DLL library */ +# if defined(QT_BUILD_JAVASCRIPT_LIB) +# define Q_JAVASCRIPT_EXPORT Q_DECL_EXPORT +# else +# define Q_JAVASCRIPT_EXPORT Q_DECL_IMPORT # endif +#elif defined(QT_DLL) /* use a Qt DLL library */ +# define Q_JAVASCRIPT_EXPORT #endif -#if defined(QT_SHARED) -# define Q_JAVASCRIPT_EXPORT Q_DECL_EXPORT -#else -# define Q_JAVASCRIPT_EXPORT +#if !defined(Q_JAVASCRIPT_EXPORT) +# if defined(QT_SHARED) +# define Q_JAVASCRIPT_EXPORT Q_DECL_EXPORT +# else +# define Q_JAVASCRIPT_EXPORT +# endif #endif #endif diff --git a/JavaScriptCore/runtime/ArrayPrototype.cpp b/JavaScriptCore/runtime/ArrayPrototype.cpp index bd14e64..4c4eb48 100644 --- a/JavaScriptCore/runtime/ArrayPrototype.cpp +++ b/JavaScriptCore/runtime/ArrayPrototype.cpp @@ -268,7 +268,24 @@ JSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec, JSObject*, JSValue thi separator = args.at(0).toString(exec); unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - for (unsigned k = 0; k < length; k++) { + unsigned k = 0; + if (isJSArray(&exec->globalData(), thisObj)) { + JSArray* array = asArray(thisObj); + for (; k < length; k++) { + if (!array->canGetIndex(k)) + break; + if (k >= 1) { + if (separator.isNull()) + strBuffer.append(','); + else + strBuffer.append(separator); + } + JSValue element = array->getIndex(k); + if (!element.isUndefinedOrNull()) + strBuffer.append(element.toString(exec)); + } + } + for (; k < length; k++) { if (k >= 1) { if (separator.isNull()) strBuffer.append(','); diff --git a/JavaScriptCore/runtime/CachedTranscendentalFunction.h b/JavaScriptCore/runtime/CachedTranscendentalFunction.h new file mode 100644 index 0000000..04f7f62 --- /dev/null +++ b/JavaScriptCore/runtime/CachedTranscendentalFunction.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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 CachedTranscendentalFunction_h +#define CachedTranscendentalFunction_h + +#include "JSValue.h" + +namespace JSC { + +extern const double NaN; + +typedef double (*TranscendentalFunctionPtr)(double); + +// CachedTranscendentalFunction provides a generic mechanism to cache results +// for pure functions with the signature "double func(double)", and where NaN +// maps to NaN. +template<TranscendentalFunctionPtr orignalFunction> +class CachedTranscendentalFunction { + struct CacheEntry { + double operand; + double result; + }; + +public: + CachedTranscendentalFunction() + : m_cache(0) + { + } + + ~CachedTranscendentalFunction() + { + if (m_cache) + fastFree(m_cache); + } + + JSValue operator() (ExecState* exec, double operand) + { + if (UNLIKELY(!m_cache)) + initialize(); + CacheEntry* entry = &m_cache[hash(operand)]; + + if (entry->operand == operand) + return jsDoubleNumber(exec, entry->result); + double result = orignalFunction(operand); + entry->operand = operand; + entry->result = result; + return jsDoubleNumber(exec, result); + } + +private: + void initialize() + { + // Lazily allocate the table, populate with NaN->NaN mapping. + m_cache = static_cast<CacheEntry*>(fastMalloc(s_cacheSize * sizeof(CacheEntry))); + for (unsigned x = 0; x < s_cacheSize; ++x) { + m_cache[x].operand = NaN; + m_cache[x].result = NaN; + } + } + + static unsigned hash(double d) + { + union doubleAndUInt64 { + double d; + uint32_t is[2]; + } u; + u.d = d; + + unsigned x = u.is[0] ^ u.is[1]; + x = (x >> 20) ^ (x >> 8); + return x & (s_cacheSize - 1); + } + + static const unsigned s_cacheSize = 0x1000; + CacheEntry* m_cache; +}; + +} + +#endif // CachedTranscendentalFunction_h diff --git a/JavaScriptCore/runtime/Collector.cpp b/JavaScriptCore/runtime/Collector.cpp index 9b72755..05f2bb5 100644 --- a/JavaScriptCore/runtime/Collector.cpp +++ b/JavaScriptCore/runtime/Collector.cpp @@ -449,7 +449,7 @@ void Heap::shrinkBlocks(size_t neededBlocks) } #if OS(WINCE) -void* g_stackBase = 0; +JS_EXPORTDATA void* g_stackBase = 0; inline bool isPageWritable(void* page) { @@ -558,6 +558,8 @@ static inline void* currentThreadStackBase() PNT_TIB64 pTib = reinterpret_cast<PNT_TIB64>(NtCurrentTeb()); return reinterpret_cast<void*>(pTib->StackBase); #elif OS(QNX) + AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex); + MutexLocker locker(mutex); return currentThreadStackBaseQNX(); #elif OS(SOLARIS) stack_t s; @@ -569,19 +571,17 @@ static inline void* currentThreadStackBase() pthread_stackseg_np(thread, &stack); return stack.ss_sp; #elif OS(SYMBIAN) - static void* stackBase = 0; - if (stackBase == 0) { - TThreadStackInfo info; - RThread thread; - thread.StackInfo(info); - stackBase = (void*)info.iBase; - } - return (void*)stackBase; + TThreadStackInfo info; + RThread thread; + thread.StackInfo(info); + return (void*)info.iBase; #elif OS(HAIKU) thread_info threadInfo; get_thread_info(find_thread(NULL), &threadInfo); return threadInfo.stack_end; #elif OS(UNIX) + AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex); + MutexLocker locker(mutex); static void* stackBase = 0; static size_t stackSize = 0; static pthread_t stackThread; @@ -604,6 +604,8 @@ static inline void* currentThreadStackBase() } return static_cast<char*>(stackBase) + stackSize; #elif OS(WINCE) + AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex); + MutexLocker locker(mutex); if (g_stackBase) return g_stackBase; else { @@ -972,7 +974,7 @@ void Heap::markStackObjectsConservatively(MarkStack& markStack) void Heap::protect(JSValue k) { ASSERT(k); - ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance); + ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance()); if (!k.isCell()) return; @@ -983,7 +985,7 @@ void Heap::protect(JSValue k) bool Heap::unprotect(JSValue k) { ASSERT(k); - ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance); + ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance()); if (!k.isCell()) return false; @@ -1064,7 +1066,7 @@ void Heap::sweep() void Heap::markRoots() { #ifndef NDEBUG - if (m_globalData->isSharedInstance) { + if (m_globalData->isSharedInstance()) { ASSERT(JSLock::lockCount() > 0); ASSERT(JSLock::currentThreadIsHoldingLock()); } diff --git a/JavaScriptCore/runtime/Executable.h b/JavaScriptCore/runtime/Executable.h index f74abe9..ac691e4 100644 --- a/JavaScriptCore/runtime/Executable.h +++ b/JavaScriptCore/runtime/Executable.h @@ -85,7 +85,12 @@ namespace JSC { NativeExecutable(ExecState* exec) : ExecutableBase(NUM_PARAMETERS_IS_HOST) { - m_jitCode = JITCode(JITCode::HostFunction(exec->globalData().jitStubs.ctiNativeCallThunk())); + m_jitCode = exec->globalData().jitStubs.ctiNativeCallThunk()->m_jitCode; + } + NativeExecutable(JITCode thunk) + : ExecutableBase(NUM_PARAMETERS_IS_HOST) + { + m_jitCode = thunk; } ~NativeExecutable(); diff --git a/JavaScriptCore/runtime/JSActivation.h b/JavaScriptCore/runtime/JSActivation.h index 91c960c..ece8753 100644 --- a/JavaScriptCore/runtime/JSActivation.h +++ b/JavaScriptCore/runtime/JSActivation.h @@ -31,7 +31,6 @@ #include "CodeBlock.h" #include "JSVariableObject.h" -#include "RegisterFile.h" #include "SymbolTable.h" #include "Nodes.h" diff --git a/JavaScriptCore/runtime/JSFunction.cpp b/JavaScriptCore/runtime/JSFunction.cpp index cba6795..5b73642 100644 --- a/JavaScriptCore/runtime/JSFunction.cpp +++ b/JavaScriptCore/runtime/JSFunction.cpp @@ -56,10 +56,27 @@ JSFunction::JSFunction(NonNullPassRefPtr<Structure> structure) { } +JSFunction::JSFunction(ExecState* exec, NonNullPassRefPtr<Structure> structure, int length, const Identifier& name, NativeExecutable* thunk, NativeFunction func) + : Base(&exec->globalData(), structure, name) +#if ENABLE(JIT) + , m_executable(thunk) +#endif +{ +#if ENABLE(JIT) + setNativeFunction(func); + putDirect(exec->propertyNames().length, jsNumber(exec, length), DontDelete | ReadOnly | DontEnum); +#else + UNUSED_PARAM(thunk); + UNUSED_PARAM(length); + UNUSED_PARAM(func); + ASSERT_NOT_REACHED(); +#endif +} + JSFunction::JSFunction(ExecState* exec, NonNullPassRefPtr<Structure> structure, int length, const Identifier& name, NativeFunction func) : Base(&exec->globalData(), structure, name) #if ENABLE(JIT) - , m_executable(adoptRef(new NativeExecutable(exec))) + , m_executable(exec->globalData().jitStubs.ctiNativeCallThunk()) #endif { #if ENABLE(JIT) diff --git a/JavaScriptCore/runtime/JSFunction.h b/JavaScriptCore/runtime/JSFunction.h index afa24a8..301b908 100644 --- a/JavaScriptCore/runtime/JSFunction.h +++ b/JavaScriptCore/runtime/JSFunction.h @@ -33,6 +33,7 @@ namespace JSC { class FunctionPrototype; class JSActivation; class JSGlobalObject; + class NativeExecutable; class JSFunction : public InternalFunction { friend class JIT; @@ -42,6 +43,7 @@ namespace JSC { public: JSFunction(ExecState*, NonNullPassRefPtr<Structure>, int length, const Identifier&, NativeFunction); + JSFunction(ExecState*, NonNullPassRefPtr<Structure>, int length, const Identifier&, NativeExecutable*, NativeFunction); JSFunction(ExecState*, NonNullPassRefPtr<FunctionExecutable>, ScopeChainNode*); virtual ~JSFunction(); diff --git a/JavaScriptCore/runtime/JSGlobalData.cpp b/JavaScriptCore/runtime/JSGlobalData.cpp index 2948d1c..12fa2be 100644 --- a/JavaScriptCore/runtime/JSGlobalData.cpp +++ b/JavaScriptCore/runtime/JSGlobalData.cpp @@ -103,8 +103,8 @@ void JSGlobalData::storeVPtrs() jsFunction->~JSCell(); } -JSGlobalData::JSGlobalData(bool isShared, ThreadStackType threadStackType) - : isSharedInstance(isShared) +JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType threadStackType) + : globalDataType(globalDataType) , clientData(0) , arrayTable(fastNew<HashTable>(JSC::arrayTable)) , dateTable(fastNew<HashTable>(JSC::dateTable)) @@ -128,7 +128,7 @@ JSGlobalData::JSGlobalData(bool isShared, ThreadStackType threadStackType) #if USE(JSVALUE32) , numberStructure(JSNumberCell::createStructure(jsNull())) #endif - , identifierTable(createIdentifierTable()) + , identifierTable(globalDataType == Default ? wtfThreadData().currentIdentifierTable() : createIdentifierTable()) , propertyNames(new CommonIdentifiers(this)) , emptyList(new MarkedArgumentBuffer) , lexer(new Lexer(this)) @@ -192,21 +192,20 @@ JSGlobalData::~JSGlobalData() delete emptyList; delete propertyNames; - deleteIdentifierTable(identifierTable); + if (globalDataType != Default) + deleteIdentifierTable(identifierTable); delete clientData; } -PassRefPtr<JSGlobalData> JSGlobalData::createNonDefault(ThreadStackType type) +PassRefPtr<JSGlobalData> JSGlobalData::createContextGroup(ThreadStackType type) { - return adoptRef(new JSGlobalData(false, type)); + return adoptRef(new JSGlobalData(APIContextGroup, type)); } PassRefPtr<JSGlobalData> JSGlobalData::create(ThreadStackType type) { - JSGlobalData* globalData = new JSGlobalData(false, type); - wtfThreadData().initializeIdentifierTable(globalData->identifierTable); - return adoptRef(globalData); + return adoptRef(new JSGlobalData(Default, type)); } PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(ThreadStackType type) @@ -226,7 +225,7 @@ JSGlobalData& JSGlobalData::sharedInstance() { JSGlobalData*& instance = sharedInstanceInternal(); if (!instance) { - instance = new JSGlobalData(true, ThreadStackTypeSmall); + instance = new JSGlobalData(APIShared, ThreadStackTypeSmall); #if ENABLE(JSC_MULTIPLE_THREADS) instance->makeUsableFromMultipleThreads(); #endif diff --git a/JavaScriptCore/runtime/JSGlobalData.h b/JavaScriptCore/runtime/JSGlobalData.h index a90bf2c..711e148 100644 --- a/JavaScriptCore/runtime/JSGlobalData.h +++ b/JavaScriptCore/runtime/JSGlobalData.h @@ -29,6 +29,7 @@ #ifndef JSGlobalData_h #define JSGlobalData_h +#include "CachedTranscendentalFunction.h" #include "Collector.h" #include "DateInstanceCache.h" #include "ExecutableAllocator.h" @@ -91,16 +92,27 @@ namespace JSC { class JSGlobalData : public RefCounted<JSGlobalData> { public: + // WebCore has a one-to-one mapping of threads to JSGlobalDatas; + // either create() or createLeaked() should only be called once + // on a thread, this is the 'default' JSGlobalData (it uses the + // thread's default string uniquing table from wtfThreadData). + // API contexts created using the new context group aware interface + // create APIContextGroup objects which require less locking of JSC + // than the old singleton APIShared JSGlobalData created for use by + // the original API. + enum GlobalDataType { Default, APIContextGroup, APIShared }; + struct ClientData { virtual ~ClientData() = 0; }; + bool isSharedInstance() { return globalDataType == APIShared; } static bool sharedInstanceExists(); static JSGlobalData& sharedInstance(); static PassRefPtr<JSGlobalData> create(ThreadStackType); static PassRefPtr<JSGlobalData> createLeaked(ThreadStackType); - static PassRefPtr<JSGlobalData> createNonDefault(ThreadStackType); + static PassRefPtr<JSGlobalData> createContextGroup(ThreadStackType); ~JSGlobalData(); #if ENABLE(JSC_MULTIPLE_THREADS) @@ -108,7 +120,7 @@ namespace JSC { void makeUsableFromMultipleThreads() { heap.makeUsableFromMultipleThreads(); } #endif - bool isSharedInstance; + GlobalDataType globalDataType; ClientData* clientData; const HashTable* arrayTable; @@ -158,6 +170,10 @@ namespace JSC { Interpreter* interpreter; #if ENABLE(JIT) JITThunks jitStubs; + NativeExecutable* getThunk(ThunkGenerator generator) + { + return jitStubs.specializedThunk(this, generator); + } #endif TimeoutChecker timeoutChecker; Terminator terminator; @@ -197,17 +213,19 @@ namespace JSC { ThreadIdentifier exclusiveThread; #endif + CachedTranscendentalFunction<sin> cachedSin; + void resetDateCache(); void startSampling(); void stopSampling(); void dumpSampleData(ExecState* exec); private: - JSGlobalData(bool isShared, ThreadStackType); + JSGlobalData(GlobalDataType, ThreadStackType); static JSGlobalData*& sharedInstanceInternal(); void createNativeThunk(); }; - + } // namespace JSC #endif // JSGlobalData_h diff --git a/JavaScriptCore/runtime/JSGlobalObject.cpp b/JavaScriptCore/runtime/JSGlobalObject.cpp index 86690bd..7568ffd 100644 --- a/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -117,10 +117,8 @@ JSGlobalObject::~JSGlobalObject() (*it)->clearGlobalObject(); RegisterFile& registerFile = globalData()->interpreter->registerFile(); - if (registerFile.globalObject() == this) { - registerFile.setGlobalObject(0); + if (registerFile.clearGlobalObject(this)) registerFile.setNumGlobals(0); - } d()->destructor(d()); } diff --git a/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp b/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp index 5b6369a..5da5194 100644 --- a/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp +++ b/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp @@ -241,6 +241,7 @@ static double parseInt(const UString& s, int radix) } if (number >= mantissaOverflowLowerBound) { + // FIXME: It is incorrect to use UString::ascii() here because it's not thread-safe. if (radix == 10) number = WTF::strtod(s.substr(firstDigitPosition, p - firstDigitPosition).ascii(), 0); else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32) @@ -269,6 +270,8 @@ static double parseFloat(const UString& s) if (length - p >= 2 && data[p] == '0' && (data[p + 1] == 'x' || data[p + 1] == 'X')) return 0; + // FIXME: UString::toDouble will ignore leading ASCII spaces, but we need to ignore + // other StrWhiteSpaceChar values as well. return s.toDouble(true /*tolerant*/, false /* NaN for empty string */); } diff --git a/JavaScriptCore/runtime/JSImmediate.h b/JavaScriptCore/runtime/JSImmediate.h index 0f54f60..9127b6a 100644 --- a/JavaScriptCore/runtime/JSImmediate.h +++ b/JavaScriptCore/runtime/JSImmediate.h @@ -136,6 +136,8 @@ namespace JSC { friend class JIT; friend class JSValue; friend class JSFastMath; + friend class JSInterfaceJIT; + friend class SpecializedThunkJIT; friend JSValue jsNumber(ExecState* exec, double d); friend JSValue jsNumber(ExecState*, char i); friend JSValue jsNumber(ExecState*, unsigned char i); @@ -164,7 +166,7 @@ namespace JSC { // This value is 2^48, used to encode doubles such that the encoded value will begin // with a 16-bit pattern within the range 0x0001..0xFFFE. static const intptr_t DoubleEncodeOffset = 0x1000000000000ll; -#else +#elif USE(JSVALUE32) static const intptr_t TagTypeNumber = 0x1; // bottom bit set indicates integer, this dominates the following bit #endif static const intptr_t TagBitTypeOther = 0x2; // second bit set indicates immediate other than an integer diff --git a/JavaScriptCore/runtime/JSLock.cpp b/JavaScriptCore/runtime/JSLock.cpp index 8f056c8..a1cffbd 100644 --- a/JavaScriptCore/runtime/JSLock.cpp +++ b/JavaScriptCore/runtime/JSLock.cpp @@ -60,7 +60,7 @@ static void setLockCount(intptr_t count) } JSLock::JSLock(ExecState* exec) - : m_lockBehavior(exec->globalData().isSharedInstance ? LockForReal : SilenceAssertionsOnly) + : m_lockBehavior(exec->globalData().isSharedInstance() ? LockForReal : SilenceAssertionsOnly) { lock(m_lockBehavior); } @@ -105,12 +105,12 @@ void JSLock::unlock(JSLockBehavior lockBehavior) void JSLock::lock(ExecState* exec) { - lock(exec->globalData().isSharedInstance ? LockForReal : SilenceAssertionsOnly); + lock(exec->globalData().isSharedInstance() ? LockForReal : SilenceAssertionsOnly); } void JSLock::unlock(ExecState* exec) { - unlock(exec->globalData().isSharedInstance ? LockForReal : SilenceAssertionsOnly); + unlock(exec->globalData().isSharedInstance() ? LockForReal : SilenceAssertionsOnly); } bool JSLock::currentThreadIsHoldingLock() @@ -162,7 +162,7 @@ bool JSLock::currentThreadIsHoldingLock() static unsigned lockDropDepth = 0; JSLock::DropAllLocks::DropAllLocks(ExecState* exec) - : m_lockBehavior(exec->globalData().isSharedInstance ? LockForReal : SilenceAssertionsOnly) + : m_lockBehavior(exec->globalData().isSharedInstance() ? LockForReal : SilenceAssertionsOnly) { pthread_once(&createJSLockCountOnce, createJSLockCount); diff --git a/JavaScriptCore/runtime/JSString.h b/JavaScriptCore/runtime/JSString.h index b1dccfa..85d3c8e 100644 --- a/JavaScriptCore/runtime/JSString.h +++ b/JavaScriptCore/runtime/JSString.h @@ -66,6 +66,8 @@ namespace JSC { public: friend class JIT; friend class JSGlobalData; + friend class SpecializedThunkJIT; + friend struct ThunkHelpers; class RopeBuilder { public: diff --git a/JavaScriptCore/runtime/JSValue.h b/JavaScriptCore/runtime/JSValue.h index b37adc0..bcf82ee 100644 --- a/JavaScriptCore/runtime/JSValue.h +++ b/JavaScriptCore/runtime/JSValue.h @@ -66,6 +66,8 @@ namespace JSC { friend class JIT; friend class JITStubs; friend class JITStubCall; + friend class JSInterfaceJIT; + friend class SpecializedThunkJIT; public: static EncodedJSValue encode(JSValue value); @@ -214,6 +216,10 @@ namespace JSC { JSObject* toObjectSlowCase(ExecState*) const; JSObject* toThisObjectSlowCase(ExecState*) const; + JSObject* synthesizePrototype(ExecState*) const; + JSObject* synthesizeObject(ExecState*) const; + +#if USE(JSVALUE32_64) enum { Int32Tag = 0xffffffff }; enum { CellTag = 0xfffffffe }; enum { TrueTag = 0xfffffffd }; @@ -222,16 +228,12 @@ namespace JSC { enum { UndefinedTag = 0xfffffffa }; enum { EmptyValueTag = 0xfffffff9 }; enum { DeletedValueTag = 0xfffffff8 }; - + enum { LowestTag = DeletedValueTag }; - + uint32_t tag() const; int32_t payload() const; - JSObject* synthesizePrototype(ExecState*) const; - JSObject* synthesizeObject(ExecState*) const; - -#if USE(JSVALUE32_64) union { EncodedJSValue asEncodedJSValue; double asDouble; diff --git a/JavaScriptCore/runtime/Lookup.cpp b/JavaScriptCore/runtime/Lookup.cpp index 4e9e086..0042e4d 100644 --- a/JavaScriptCore/runtime/Lookup.cpp +++ b/JavaScriptCore/runtime/Lookup.cpp @@ -46,7 +46,11 @@ void HashTable::createTable(JSGlobalData* globalData) const entry = entry->next(); } - entry->initialize(identifier, values[i].attributes, values[i].value1, values[i].value2); + entry->initialize(identifier, values[i].attributes, values[i].value1, values[i].value2 +#if ENABLE(JIT) + , values[i].generator +#endif + ); } table = entries; } @@ -70,7 +74,13 @@ void setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* JSValue* location = thisObj->getDirectLocation(propertyName); if (!location) { - InternalFunction* function = new (exec) NativeFunctionWrapper(exec, exec->lexicalGlobalObject()->prototypeFunctionStructure(), entry->functionLength(), propertyName, entry->function()); + InternalFunction* function; +#if ENABLE(JIT) + if (entry->generator()) + function = new (exec) NativeFunctionWrapper(exec, exec->lexicalGlobalObject()->prototypeFunctionStructure(), entry->functionLength(), propertyName, exec->globalData().getThunk(entry->generator()), entry->function()); + else +#endif + function = new (exec) NativeFunctionWrapper(exec, exec->lexicalGlobalObject()->prototypeFunctionStructure(), entry->functionLength(), propertyName, entry->function()); thisObj->putDirectFunction(propertyName, function, entry->attributes()); location = thisObj->getDirectLocation(propertyName); diff --git a/JavaScriptCore/runtime/Lookup.h b/JavaScriptCore/runtime/Lookup.h index 995aeee..dd36400 100644 --- a/JavaScriptCore/runtime/Lookup.h +++ b/JavaScriptCore/runtime/Lookup.h @@ -37,13 +37,15 @@ #endif namespace JSC { - // Hash table generated by the create_hash_table script. struct HashTableValue { const char* key; // property name unsigned char attributes; // JSObject attributes intptr_t value1; intptr_t value2; +#if ENABLE(JIT) + ThunkGenerator generator; +#endif }; // FIXME: There is no reason this get function can't be simpler. @@ -53,12 +55,19 @@ namespace JSC { class HashEntry : public FastAllocBase { public: - void initialize(UString::Rep* key, unsigned char attributes, intptr_t v1, intptr_t v2) + void initialize(UString::Rep* key, unsigned char attributes, intptr_t v1, intptr_t v2 +#if ENABLE(JIT) + , ThunkGenerator generator = 0 +#endif + ) { m_key = key; m_attributes = attributes; m_u.store.value1 = v1; m_u.store.value2 = v2; +#if ENABLE(JIT) + m_u.function.generator = generator; +#endif m_next = 0; } @@ -67,6 +76,9 @@ namespace JSC { unsigned char attributes() const { return m_attributes; } +#if ENABLE(JIT) + ThunkGenerator generator() const { ASSERT(m_attributes & Function); return m_u.function.generator; } +#endif NativeFunction function() const { ASSERT(m_attributes & Function); return m_u.function.functionValue; } unsigned char functionLength() const { ASSERT(m_attributes & Function); return static_cast<unsigned char>(m_u.function.length); } @@ -90,6 +102,9 @@ namespace JSC { struct { NativeFunction functionValue; intptr_t length; // number of arguments for function +#if ENABLE(JIT) + ThunkGenerator generator; +#endif } function; struct { GetFunction get; diff --git a/JavaScriptCore/runtime/MathObject.cpp b/JavaScriptCore/runtime/MathObject.cpp index 16d32a0..1e28dfa 100644 --- a/JavaScriptCore/runtime/MathObject.cpp +++ b/JavaScriptCore/runtime/MathObject.cpp @@ -223,7 +223,7 @@ JSValue JSC_HOST_CALL mathProtoFuncRound(ExecState* exec, JSObject*, JSValue, co JSValue JSC_HOST_CALL mathProtoFuncSin(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsDoubleNumber(exec, sin(args.at(0).toNumber(exec))); + return exec->globalData().cachedSin(exec, args.at(0).toNumber(exec)); } JSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState* exec, JSObject*, JSValue, const ArgList& args) diff --git a/JavaScriptCore/runtime/SmallStrings.h b/JavaScriptCore/runtime/SmallStrings.h index cc11d0a..bc337c9 100644 --- a/JavaScriptCore/runtime/SmallStrings.h +++ b/JavaScriptCore/runtime/SmallStrings.h @@ -60,7 +60,9 @@ namespace JSC { void clear(); unsigned count() const; - +#if ENABLE(JIT) + JSString** singleCharacterStrings() { return m_singleCharacterStrings; } +#endif private: void createEmptyString(JSGlobalData*); void createSingleCharacterString(JSGlobalData*, unsigned char); diff --git a/JavaScriptCore/runtime/StringConstructor.cpp b/JavaScriptCore/runtime/StringConstructor.cpp index c7b62bf..42f98c3 100644 --- a/JavaScriptCore/runtime/StringConstructor.cpp +++ b/JavaScriptCore/runtime/StringConstructor.cpp @@ -54,8 +54,11 @@ StringConstructor::StringConstructor(ExecState* exec, NonNullPassRefPtr<Structur putDirectWithoutTransition(exec->propertyNames().prototype, stringPrototype, ReadOnly | DontEnum | DontDelete); // ECMA 15.5.3.2 fromCharCode() +#if ENABLE(JIT) + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().fromCharCode, exec->globalData().getThunk(fromCharCodeThunkGenerator), stringFromCharCode), DontEnum); +#else putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().fromCharCode, stringFromCharCode), DontEnum); - +#endif // no. of arguments for constructor putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 1), ReadOnly | DontEnum | DontDelete); } diff --git a/JavaScriptCore/runtime/Structure.cpp b/JavaScriptCore/runtime/Structure.cpp index 6f23c7d..6d13f4b 100644 --- a/JavaScriptCore/runtime/Structure.cpp +++ b/JavaScriptCore/runtime/Structure.cpp @@ -168,14 +168,14 @@ inline void Structure::transitionTableAdd(const StructureTransitionTableHash::Ke if (!specificValue) { TransitionTable::iterator find = transitionTable()->find(key); if (find == transitionTable()->end()) - transitionTable()->add(key, Transition(structure, 0)); + transitionTable()->add(key, Transition(structure, static_cast<Structure*>(0))); else find->second.first = structure; } else { // If we're adding a transition to a specific value, then there cannot be // an existing transition ASSERT(!transitionTable()->contains(key)); - transitionTable()->add(key, Transition(0, structure)); + transitionTable()->add(key, Transition(static_cast<Structure*>(0), structure)); } } diff --git a/JavaScriptCore/runtime/UString.cpp b/JavaScriptCore/runtime/UString.cpp index ce91040..6b16274 100644 --- a/JavaScriptCore/runtime/UString.cpp +++ b/JavaScriptCore/runtime/UString.cpp @@ -254,7 +254,15 @@ double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) co return NaN; } + // FIXME: If tolerateTrailingJunk is true, then we want to tolerate junk + // after the number, even if it contains invalid UTF-16 sequences. So we + // shouldn't use the UTF8String function, which returns null when it + // encounters invalid UTF-16. Further, we have no need to convert the + // non-ASCII characters to UTF-8, so the UTF8String does quite a bit of + // unnecessary work. CString s = UTF8String(); + if (s.isNull()) + return NaN; const char* c = s.data(); // skip leading white space @@ -318,6 +326,7 @@ double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) co while (isASCIISpace(*c)) c++; // don't allow anything after - unless tolerant=true + // FIXME: If string contains a U+0000 character, then this check is incorrect. if (!tolerateTrailingJunk && *c != '\0') d = NaN; diff --git a/JavaScriptCore/runtime/WeakGCPtr.h b/JavaScriptCore/runtime/WeakGCPtr.h index 5f58374..9dce858 100644 --- a/JavaScriptCore/runtime/WeakGCPtr.h +++ b/JavaScriptCore/runtime/WeakGCPtr.h @@ -44,10 +44,13 @@ public: return m_ptr; } - void clear(JSCell* ptr) + bool clear(JSCell* ptr) { - if (ptr == m_ptr) + if (ptr == m_ptr) { m_ptr = 0; + return true; + } + return false; } T& operator*() const { return *get(); } @@ -72,8 +75,8 @@ public: private: void assign(T* ptr) { - if (ptr) - Heap::markCell(ptr); + ASSERT(ptr); + Heap::markCell(ptr); m_ptr = ptr; } diff --git a/JavaScriptCore/wtf/Assertions.h b/JavaScriptCore/wtf/Assertions.h index df8646f..d26b939 100644 --- a/JavaScriptCore/wtf/Assertions.h +++ b/JavaScriptCore/wtf/Assertions.h @@ -62,7 +62,7 @@ #define ASSERTIONS_DISABLED_DEFAULT 0 #endif -#if COMPILER(MSVC7) || COMPILER(WINSCW) +#if COMPILER(MSVC7_OR_LOWER) || COMPILER(WINSCW) #define HAVE_VARIADIC_MACRO 0 #else #define HAVE_VARIADIC_MACRO 1 @@ -224,7 +224,7 @@ while (0) /* ASSERT_WITH_MESSAGE */ -#if COMPILER(MSVC7) +#if COMPILER(MSVC7_OR_LOWER) #define ASSERT_WITH_MESSAGE(assertion) ((void)0) #elif COMPILER(WINSCW) #define ASSERT_WITH_MESSAGE(assertion, arg...) ((void)0) @@ -264,7 +264,7 @@ while (0) /* FATAL */ -#if COMPILER(MSVC7) +#if COMPILER(MSVC7_OR_LOWER) #define FATAL() ((void)0) #elif COMPILER(WINSCW) #define FATAL(arg...) ((void)0) @@ -279,7 +279,7 @@ while (0) /* LOG_ERROR */ -#if COMPILER(MSVC7) +#if COMPILER(MSVC7_OR_LOWER) #define LOG_ERROR() ((void)0) #elif COMPILER(WINSCW) #define LOG_ERROR(arg...) ((void)0) @@ -291,7 +291,7 @@ while (0) /* LOG */ -#if COMPILER(MSVC7) +#if COMPILER(MSVC7_OR_LOWER) #define LOG() ((void)0) #elif COMPILER(WINSCW) #define LOG(arg...) ((void)0) @@ -305,7 +305,7 @@ while (0) /* LOG_VERBOSE */ -#if COMPILER(MSVC7) +#if COMPILER(MSVC7_OR_LOWER) #define LOG_VERBOSE(channel) ((void)0) #elif COMPILER(WINSCW) #define LOG_VERBOSE(channel, arg...) ((void)0) diff --git a/JavaScriptCore/wtf/Atomics.h b/JavaScriptCore/wtf/Atomics.h new file mode 100644 index 0000000..1d190a3 --- /dev/null +++ b/JavaScriptCore/wtf/Atomics.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2007, 2008, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Note: The implementations of InterlockedIncrement and InterlockedDecrement are based + * on atomic_increment and atomic_exchange_and_add from the Boost C++ Library. The license + * is virtually identical to the Apple license above but is included here for completeness. + * + * Boost Software License - Version 1.0 - August 17th, 2003 + * + * Permission is hereby granted, free of charge, to any person or organization + * obtaining a copy of the software and accompanying documentation covered by + * this license (the "Software") to use, reproduce, display, distribute, + * execute, and transmit the Software, and to prepare derivative works of the + * Software, and to permit third-parties to whom the Software is furnished to + * do so, all subject to the following: + * + * The copyright notices in the Software and this entire statement, including + * the above license grant, this restriction and the following disclaimer, + * must be included in all copies of the Software, in whole or in part, and + * all derivative works of the Software, unless such copies or derivative + * works are solely in the form of machine-executable object code generated by + * a source language processor. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef Atomics_h +#define Atomics_h + +#include "Platform.h" + +#if OS(WINDOWS) +#include <windows.h> +#elif OS(DARWIN) +#include <libkern/OSAtomic.h> +#elif OS(ANDROID) +#include <cutils/atomic.h> +#elif COMPILER(GCC) && !OS(SYMBIAN) +#if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) +#include <ext/atomicity.h> +#else +#include <bits/atomicity.h> +#endif +#endif + +namespace WTF { + +#if OS(WINDOWS) +#define WTF_USE_LOCKFREE_THREADSAFESHARED 1 + +#if COMPILER(MINGW) || COMPILER(MSVC7_OR_LOWER) || OS(WINCE) +inline int atomicIncrement(int* addend) { return InterlockedIncrement(reinterpret_cast<long*>(addend)); } +inline int atomicDecrement(int* addend) { return InterlockedDecrement(reinterpret_cast<long*>(addend)); } +#else +inline int atomicIncrement(int volatile* addend) { return InterlockedIncrement(reinterpret_cast<long volatile*>(addend)); } +inline int atomicDecrement(int volatile* addend) { return InterlockedDecrement(reinterpret_cast<long volatile*>(addend)); } +#endif + +#elif OS(DARWIN) +#define WTF_USE_LOCKFREE_THREADSAFESHARED 1 + +inline int atomicIncrement(int volatile* addend) { return OSAtomicIncrement32Barrier(const_cast<int*>(addend)); } +inline int atomicDecrement(int volatile* addend) { return OSAtomicDecrement32Barrier(const_cast<int*>(addend)); } + +#elif OS(ANDROID) + +inline int atomicIncrement(int volatile* addend) { return android_atomic_inc(addend); } +inline int atomicDecrement(int volatile* addend) { return android_atomic_dec(addend); } + +#elif COMPILER(GCC) && !CPU(SPARC64) && !OS(SYMBIAN) // sizeof(_Atomic_word) != sizeof(int) on sparc64 gcc +#define WTF_USE_LOCKFREE_THREADSAFESHARED 1 + +inline int atomicIncrement(int volatile* addend) { return __gnu_cxx::__exchange_and_add(addend, 1) + 1; } +inline int atomicDecrement(int volatile* addend) { return __gnu_cxx::__exchange_and_add(addend, -1) - 1; } + +#endif + +} // namespace WTF + +#if USE(LOCKFREE_THREADSAFESHARED) +using WTF::atomicDecrement; +using WTF::atomicIncrement; +#endif + +#endif // Atomics_h diff --git a/JavaScriptCore/wtf/CurrentTime.cpp b/JavaScriptCore/wtf/CurrentTime.cpp index 30ca7c3..08fffa2 100644 --- a/JavaScriptCore/wtf/CurrentTime.cpp +++ b/JavaScriptCore/wtf/CurrentTime.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006, 2010 Apple Inc. All rights reserved. * Copyright (C) 2008 Google Inc. All rights reserved. * Copyright (C) 2007-2009 Torch Mobile, Inc. * @@ -53,15 +53,13 @@ extern "C" time_t mktime(struct tm *t); #endif #endif -#elif PLATFORM(CF) -#include <CoreFoundation/CFDate.h> #elif PLATFORM(GTK) #include <glib.h> #elif PLATFORM(WX) #include <wx/datetime.h> #elif PLATFORM(BREWMP) #include <AEEStdLib.h> -#else // Posix systems relying on the gettimeofday() +#else #include <sys/time.h> #endif @@ -251,13 +249,6 @@ double currentTime() #endif // USE(QUERY_PERFORMANCE_COUNTER) -#elif PLATFORM(CF) - -double currentTime() -{ - return CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970; -} - #elif PLATFORM(GTK) // Note: GTK on Windows will pick up the PLATFORM(WIN) implementation above which provides @@ -293,15 +284,13 @@ double currentTime() return static_cast<double>(diffSeconds + GETUTCSECONDS() + ((GETTIMEMS() % 1000) / msPerSecond)); } -#else // Other Posix systems rely on the gettimeofday(). +#else double currentTime() { struct timeval now; - struct timezone zone; - - gettimeofday(&now, &zone); - return static_cast<double>(now.tv_sec) + (double)(now.tv_usec / 1000000.0); + gettimeofday(&now, 0); + return now.tv_sec + now.tv_usec / 1000000.0; } #endif diff --git a/JavaScriptCore/wtf/CurrentTime.h b/JavaScriptCore/wtf/CurrentTime.h index 033448f..dcb1f6c 100644 --- a/JavaScriptCore/wtf/CurrentTime.h +++ b/JavaScriptCore/wtf/CurrentTime.h @@ -49,7 +49,7 @@ namespace WTF { inline void getLocalTime(const time_t* localTime, struct tm* localTM) { - #if COMPILER(MSVC7) || COMPILER(MINGW) || OS(WINCE) + #if COMPILER(MSVC7_OR_LOWER) || COMPILER(MINGW) || OS(WINCE) *localTM = *localtime(localTime); #elif COMPILER(MSVC) localtime_s(localTM, localTime); diff --git a/JavaScriptCore/wtf/FastMalloc.cpp b/JavaScriptCore/wtf/FastMalloc.cpp index 7824159..9dfbc6b 100644 --- a/JavaScriptCore/wtf/FastMalloc.cpp +++ b/JavaScriptCore/wtf/FastMalloc.cpp @@ -1273,8 +1273,12 @@ static const int kScavengeDelayInSeconds = 2; // scavenge. static const float kScavengePercentage = .5f; -// Number of free committed pages that we want to keep around. -static const size_t kMinimumFreeCommittedPageCount = 512; +// number of span lists to keep spans in when memory is returned. +static const int kMinSpanListsWithSpans = 32; + +// Number of free committed pages that we want to keep around. The minimum number of pages used when there +// is 1 span in each of the first kMinSpanListsWithSpans spanlists. Currently 528 pages. +static const size_t kMinimumFreeCommittedPageCount = kMinSpanListsWithSpans * ((1.0f+kMinSpanListsWithSpans) / 2.0f); #endif @@ -1534,20 +1538,25 @@ void TCMalloc_PageHeap::scavenge() size_t pagesToRelease = min_free_committed_pages_since_last_scavenge_ * kScavengePercentage; size_t targetPageCount = std::max<size_t>(kMinimumFreeCommittedPageCount, free_committed_pages_ - pagesToRelease); - for (int i = kMaxPages; i >= 0 && free_committed_pages_ > targetPageCount; i--) { - SpanList* slist = (static_cast<size_t>(i) == kMaxPages) ? &large_ : &free_[i]; - while (!DLL_IsEmpty(&slist->normal) && free_committed_pages_ > targetPageCount) { - Span* s = slist->normal.prev; - DLL_Remove(s); - ASSERT(!s->decommitted); - if (!s->decommitted) { - TCMalloc_SystemRelease(reinterpret_cast<void*>(s->start << kPageShift), - static_cast<size_t>(s->length << kPageShift)); - ASSERT(free_committed_pages_ >= s->length); - free_committed_pages_ -= s->length; - s->decommitted = true; + while (free_committed_pages_ > targetPageCount) { + for (int i = kMaxPages; i > 0 && free_committed_pages_ >= targetPageCount; i--) { + SpanList* slist = (static_cast<size_t>(i) == kMaxPages) ? &large_ : &free_[i]; + // If the span size is bigger than kMinSpanListsWithSpans pages return all the spans in the list, else return all but 1 span. + // Return only 50% of a spanlist at a time so spans of size 1 are not the only ones left. + size_t numSpansToReturn = (i > kMinSpanListsWithSpans) ? DLL_Length(&slist->normal) : static_cast<size_t>(.5 * DLL_Length(&slist->normal)); + for (int j = 0; static_cast<size_t>(j) < numSpansToReturn && !DLL_IsEmpty(&slist->normal) && free_committed_pages_ > targetPageCount; j++) { + Span* s = slist->normal.prev; + DLL_Remove(s); + ASSERT(!s->decommitted); + if (!s->decommitted) { + TCMalloc_SystemRelease(reinterpret_cast<void*>(s->start << kPageShift), + static_cast<size_t>(s->length << kPageShift)); + ASSERT(free_committed_pages_ >= s->length); + free_committed_pages_ -= s->length; + s->decommitted = true; + } + DLL_Prepend(&slist->returned, s); } - DLL_Prepend(&slist->returned, s); } } @@ -1583,19 +1592,13 @@ inline Span* TCMalloc_PageHeap::New(Length n) { Span* result = ll->next; Carve(result, n, released); - if (result->decommitted) { - TCMalloc_SystemCommit(reinterpret_cast<void*>(result->start << kPageShift), static_cast<size_t>(n << kPageShift)); - result->decommitted = false; - } #if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY - else { - // The newly allocated memory is from a span that's in the normal span list (already committed). Update the - // free committed pages count. - ASSERT(free_committed_pages_ >= n); - free_committed_pages_ -= n; - if (free_committed_pages_ < min_free_committed_pages_since_last_scavenge_) - min_free_committed_pages_since_last_scavenge_ = free_committed_pages_; - } + // The newly allocated memory is from a span that's in the normal span list (already committed). Update the + // free committed pages count. + ASSERT(free_committed_pages_ >= n); + free_committed_pages_ -= n; + if (free_committed_pages_ < min_free_committed_pages_since_last_scavenge_) + min_free_committed_pages_since_last_scavenge_ = free_committed_pages_; #endif // USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY ASSERT(Check()); free_pages_ -= n; @@ -1653,19 +1656,13 @@ Span* TCMalloc_PageHeap::AllocLarge(Length n) { if (best != NULL) { Carve(best, n, from_released); - if (best->decommitted) { - TCMalloc_SystemCommit(reinterpret_cast<void*>(best->start << kPageShift), static_cast<size_t>(n << kPageShift)); - best->decommitted = false; - } #if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY - else { - // The newly allocated memory is from a span that's in the normal span list (already committed). Update the - // free committed pages count. - ASSERT(free_committed_pages_ >= n); - free_committed_pages_ -= n; - if (free_committed_pages_ < min_free_committed_pages_since_last_scavenge_) - min_free_committed_pages_since_last_scavenge_ = free_committed_pages_; - } + // The newly allocated memory is from a span that's in the normal span list (already committed). Update the + // free committed pages count. + ASSERT(free_committed_pages_ >= n); + free_committed_pages_ -= n; + if (free_committed_pages_ < min_free_committed_pages_since_last_scavenge_) + min_free_committed_pages_since_last_scavenge_ = free_committed_pages_; #endif // USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY ASSERT(Check()); free_pages_ -= n; @@ -1691,29 +1688,34 @@ Span* TCMalloc_PageHeap::Split(Span* span, Length n) { return leftover; } -static ALWAYS_INLINE void propagateDecommittedState(Span* destination, Span* source) -{ - destination->decommitted = source->decommitted; -} - inline void TCMalloc_PageHeap::Carve(Span* span, Length n, bool released) { ASSERT(n > 0); DLL_Remove(span); span->free = 0; Event(span, 'A', n); + if (released) { + // If the span chosen to carve from is decommited, commit the entire span at once to avoid committing spans 1 page at a time. + ASSERT(span->decommitted); + TCMalloc_SystemCommit(reinterpret_cast<void*>(span->start << kPageShift), static_cast<size_t>(span->length << kPageShift)); + span->decommitted = false; +#if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY + free_committed_pages_ += span->length; +#endif + } + const int extra = static_cast<int>(span->length - n); ASSERT(extra >= 0); if (extra > 0) { Span* leftover = NewSpan(span->start + n, extra); leftover->free = 1; - propagateDecommittedState(leftover, span); + leftover->decommitted = false; Event(leftover, 'S', extra); RecordSpan(leftover); // Place leftover span on appropriate free list SpanList* listpair = (static_cast<size_t>(extra) < kMaxPages) ? &free_[extra] : &large_; - Span* dst = released ? &listpair->returned : &listpair->normal; + Span* dst = &listpair->normal; DLL_Prepend(dst, leftover); span->length = n; @@ -2336,7 +2338,7 @@ static TCMalloc_Central_FreeListPadded central_cache[kNumClasses]; // Page-level allocator static SpinLock pageheap_lock = SPINLOCK_INITIALIZER; -static void* pageheap_memory[(sizeof(TCMalloc_PageHeap) + sizeof(void*) - 1) / sizeof(void*)]; +static AllocAlignmentInteger pageheap_memory[(sizeof(TCMalloc_PageHeap) + sizeof(AllocAlignmentInteger) - 1) / sizeof(AllocAlignmentInteger)]; static bool phinited = false; // Avoid extra level of indirection by making "pageheap" be just an alias diff --git a/JavaScriptCore/wtf/MD5.cpp b/JavaScriptCore/wtf/MD5.cpp new file mode 100644 index 0000000..cd1837a --- /dev/null +++ b/JavaScriptCore/wtf/MD5.cpp @@ -0,0 +1,304 @@ +// The original file was copied from sqlite, and was in the public domain. +// Modifications Copyright 2006 Google Inc. All Rights Reserved +/* + * Copyright (C) 2010 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, construct an + * MD5 instance, call addBytes as needed on buffers full of bytes, + * and then call checksum, which will fill a supplied 16-byte array + * with the digest. + */ + +#include "config.h" +#include "MD5.h" + +#include "Assertions.h" +#ifndef NDEBUG +#include "StringExtras.h" +#include "text/CString.h" +#endif + +namespace WTF { + +#ifdef NDEBUG +static inline void testMD5() { } +#else +// MD5 test case. +static bool isTestMD5Done; + +static void expectMD5(CString input, CString expected) +{ + MD5 md5; + md5.addBytes(reinterpret_cast<const uint8_t*>(input.data()), input.length()); + Vector<uint8_t, 16> digest = md5.checksum(); + char* buf = 0; + CString actual = CString::newUninitialized(32, buf); + for (size_t i = 0; i < 16; i++) { + snprintf(buf, 3, "%02x", digest.at(i)); + buf += 2; + } + ASSERT_WITH_MESSAGE(actual == expected, "input:%s[%d] actual:%s expected:%s", input.data(), input.length(), actual.data(), expected.data()); +} + +static void testMD5() +{ + if (isTestMD5Done) + return; + isTestMD5Done = true; + + // MD5 Test suite from http://www.ietf.org/rfc/rfc1321.txt + expectMD5("", "d41d8cd98f00b204e9800998ecf8427e"); + expectMD5("a", "0cc175b9c0f1b6a831c399e269772661"); + expectMD5("abc", "900150983cd24fb0d6963f7d28e17f72"); + expectMD5("message digest", "f96b697d7cb7938d525a2f31aaf161d0"); + expectMD5("abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b"); + expectMD5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "d174ab98d277d9f5a5611c2c9f419d9f"); + expectMD5("12345678901234567890123456789012345678901234567890123456789012345678901234567890", "57edf4a22be3c955ac49da2e2107b67a"); +} +#endif + +// Note: this code is harmless on little-endian machines. + +static void reverseBytes(uint8_t* buf, unsigned longs) +{ + ASSERT(longs > 0); + do { + uint32_t t = static_cast<uint32_t>(buf[3] << 8 | buf[2]) << 16 | buf[1] << 8 | buf[0]; + ASSERT_WITH_MESSAGE(!(reinterpret_cast<uintptr_t>(buf) % sizeof(t)), "alignment error of buf"); + *reinterpret_cast<uint32_t *>(buf) = t; + buf += 4; + } while (--longs); +} + +// The four core functions. +// F1 is originally defined as (x & y | ~x & z), but optimized somewhat: 4 bit ops -> 3 bit ops. +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +// This is the central step in the MD5 algorithm. +#define MD5STEP(f, w, x, y, z, data, s) \ + (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x) + +static void MD5Transform(uint32_t buf[4], const uint32_t in[16]) +{ + uint32_t a = buf[0]; + uint32_t b = buf[1]; + uint32_t c = buf[2]; + uint32_t d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +MD5::MD5() +{ + testMD5(); + m_buf[0] = 0x67452301; + m_buf[1] = 0xefcdab89; + m_buf[2] = 0x98badcfe; + m_buf[3] = 0x10325476; + m_bits[0] = 0; + m_bits[1] = 0; + memset(m_in, 0, sizeof(m_in)); + ASSERT_WITH_MESSAGE(!(reinterpret_cast<uintptr_t>(m_in) % sizeof(uint32_t)), "alignment error of m_in"); +} + +void MD5::addBytes(const uint8_t* input, size_t length) +{ + const uint8_t* buf = input; + + // Update bitcount + uint32_t t = m_bits[0]; + m_bits[0] = t + (length << 3); + if (m_bits[0] < t) + m_bits[1]++; // Carry from low to high + m_bits[1] += length >> 29; + + t = (t >> 3) & 0x3f; // Bytes already in shsInfo->data + + // Handle any leading odd-sized chunks + + if (t) { + uint8_t* p = m_in + t; + + t = 64 - t; + if (length < t) { + memcpy(p, buf, length); + return; + } + memcpy(p, buf, t); + reverseBytes(m_in, 16); + MD5Transform(m_buf, reinterpret_cast<uint32_t*>(m_in)); // m_in is 4-byte aligned. + buf += t; + length -= t; + } + + // Process data in 64-byte chunks + + while (length >= 64) { + memcpy(m_in, buf, 64); + reverseBytes(m_in, 16); + MD5Transform(m_buf, reinterpret_cast<uint32_t*>(m_in)); // m_in is 4-byte aligned. + buf += 64; + length -= 64; + } + + // Handle any remaining bytes of data. + memcpy(m_in, buf, length); +} + +Vector<uint8_t, 16> MD5::checksum() +{ + // Compute number of bytes mod 64 + unsigned count = (m_bits[0] >> 3) & 0x3F; + + // Set the first char of padding to 0x80. This is safe since there is + // always at least one byte free + uint8_t* p = m_in + count; + *p++ = 0x80; + + // Bytes of padding needed to make 64 bytes + count = 64 - 1 - count; + + // Pad out to 56 mod 64 + if (count < 8) { + // Two lots of padding: Pad the first block to 64 bytes + memset(p, 0, count); + reverseBytes(m_in, 16); + MD5Transform(m_buf, reinterpret_cast<uint32_t *>(m_in)); // m_in is 4-byte aligned. + + // Now fill the next block with 56 bytes + memset(m_in, 0, 56); + } else { + // Pad block to 56 bytes + memset(p, 0, count - 8); + } + reverseBytes(m_in, 14); + + // Append length in bits and transform + // m_in is 4-byte aligned. + (reinterpret_cast<uint32_t*>(m_in))[14] = m_bits[0]; + (reinterpret_cast<uint32_t*>(m_in))[15] = m_bits[1]; + + MD5Transform(m_buf, reinterpret_cast<uint32_t*>(m_in)); + reverseBytes(reinterpret_cast<uint8_t*>(m_buf), 4); + Vector<uint8_t, 16> digest; + digest.append(reinterpret_cast<uint8_t*>(m_buf), 16); + + // In case it's sensitive + memset(m_buf, 0, sizeof(m_buf)); + memset(m_bits, 0, sizeof(m_bits)); + memset(m_in, 0, sizeof(m_in)); + return digest; +} + +} // namespace WTF diff --git a/JavaScriptCore/wtf/MD5.h b/JavaScriptCore/wtf/MD5.h new file mode 100644 index 0000000..8ebfc45 --- /dev/null +++ b/JavaScriptCore/wtf/MD5.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2010 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WTF_MD5_h +#define WTF_MD5_h + +#include <wtf/Vector.h> + +namespace WTF { + +class MD5 { +public: + MD5(); + + void addBytes(const Vector<uint8_t>& input) + { + addBytes(input.data(), input.size()); + } + void addBytes(const uint8_t* input, size_t length); + + // checksum has a side effect of resetting the state of the object. + Vector<uint8_t, 16> checksum(); + +private: + uint32_t m_buf[4]; + uint32_t m_bits[2]; + uint8_t m_in[64]; +}; + +} // namespace WTF + +using WTF::MD5; + +#endif // WTF_MD5_h diff --git a/JavaScriptCore/wtf/MainThread.cpp b/JavaScriptCore/wtf/MainThread.cpp index 40a4ae5..a041bb2 100644 --- a/JavaScriptCore/wtf/MainThread.cpp +++ b/JavaScriptCore/wtf/MainThread.cpp @@ -29,11 +29,15 @@ #include "config.h" #include "MainThread.h" -#include "StdLibExtras.h" #include "CurrentTime.h" #include "Deque.h" +#include "StdLibExtras.h" #include "Threading.h" +#if PLATFORM(CHROMIUM) +#error Chromium uses a different main thread implementation +#endif + namespace WTF { struct FunctionWithContext { @@ -52,8 +56,11 @@ struct FunctionWithContext { typedef Deque<FunctionWithContext> FunctionQueue; static bool callbacksPaused; // This global variable is only accessed from main thread. +#if !PLATFORM(MAC) && !PLATFORM(QT) +static ThreadIdentifier mainThreadIdentifier; +#endif -Mutex& mainThreadFunctionQueueMutex() +static Mutex& mainThreadFunctionQueueMutex() { DEFINE_STATIC_LOCAL(Mutex, staticMutex, ()); return staticMutex; @@ -65,12 +72,51 @@ static FunctionQueue& functionQueue() return staticFunctionQueue; } + +#if !PLATFORM(MAC) + void initializeMainThread() { + static bool initializedMainThread; + if (initializedMainThread) + return; + initializedMainThread = true; + +#if !PLATFORM(QT) + mainThreadIdentifier = currentThread(); +#endif + + mainThreadFunctionQueueMutex(); + initializeMainThreadPlatform(); +} + +#else + +static pthread_once_t initializeMainThreadKeyOnce = PTHREAD_ONCE_INIT; + +static void initializeMainThreadOnce() +{ mainThreadFunctionQueueMutex(); initializeMainThreadPlatform(); } +void initializeMainThread() +{ + pthread_once(&initializeMainThreadKeyOnce, initializeMainThreadOnce); +} + +static void initializeMainThreadToProcessMainThreadOnce() +{ + mainThreadFunctionQueueMutex(); + initializeMainThreadToProcessMainThreadPlatform(); +} + +void initializeMainThreadToProcessMainThread() +{ + pthread_once(&initializeMainThreadKeyOnce, initializeMainThreadToProcessMainThreadOnce); +} +#endif + // 0.1 sec delays in UI is approximate threshold when they become noticeable. Have a limit that's half of that. static const double maxRunLoopSuspensionTime = 0.05; @@ -152,4 +198,11 @@ void setMainThreadCallbacksPaused(bool paused) scheduleDispatchFunctionsOnMainThread(); } +#if !PLATFORM(MAC) && !PLATFORM(QT) +bool isMainThread() +{ + return currentThread() == mainThreadIdentifier; +} +#endif + } // namespace WTF diff --git a/JavaScriptCore/wtf/MainThread.h b/JavaScriptCore/wtf/MainThread.h index 8c0275b..d037d0b 100644 --- a/JavaScriptCore/wtf/MainThread.h +++ b/JavaScriptCore/wtf/MainThread.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2010 Apple Inc. All rights reserved. * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com) * * Redistribution and use in source and binary forms, with or without @@ -30,32 +30,40 @@ #ifndef MainThread_h #define MainThread_h -namespace WTF { +#include <stdint.h> -class Mutex; +namespace WTF { +typedef uint32_t ThreadIdentifier; typedef void MainThreadFunction(void*); -void callOnMainThread(MainThreadFunction*, void* context); +// Must be called from the main thread. +void initializeMainThread(); -// Blocks the thread until the call finishes on the main thread. Misusing this can easily cause deadlocks. +void callOnMainThread(MainThreadFunction*, void* context); void callOnMainThreadAndWait(MainThreadFunction*, void* context); - void setMainThreadCallbacksPaused(bool paused); -// Must be called from the main thread (Darwin is an exception to this rule). -void initializeMainThread(); +bool isMainThread(); -// These functions are internal to the callOnMainThread implementation. +// NOTE: these functions are internal to the callOnMainThread implementation. void initializeMainThreadPlatform(); void scheduleDispatchFunctionsOnMainThread(); -Mutex& mainThreadFunctionQueueMutex(); void dispatchFunctionsFromMainThread(); +#if PLATFORM(MAC) +// This version of initializeMainThread sets up the main thread as corresponding +// to the process's main thread, and not necessarily the thread that calls this +// function. It should only be used as a legacy aid for Mac WebKit. +void initializeMainThreadToProcessMainThread(); +void initializeMainThreadToProcessMainThreadPlatform(); +#endif + } // namespace WTF using WTF::callOnMainThread; using WTF::callOnMainThreadAndWait; using WTF::setMainThreadCallbacksPaused; +using WTF::isMainThread; #endif // MainThread_h diff --git a/JavaScriptCore/wtf/MathExtras.h b/JavaScriptCore/wtf/MathExtras.h index ac9bf60..25e724a 100644 --- a/JavaScriptCore/wtf/MathExtras.h +++ b/JavaScriptCore/wtf/MathExtras.h @@ -122,8 +122,10 @@ inline double trunc(double num) { return num > 0 ? floor(num) : ceil(num); } #endif #if COMPILER(MSVC) - +// The 64bit version of abs() is already defined in stdlib.h which comes with VC10 +#if COMPILER(MSVC9_OR_LOWER) inline long long abs(long long num) { return _abs64(num); } +#endif inline bool isinf(double num) { return !_finite(num) && !_isnan(num); } inline bool isnan(double num) { return !!_isnan(num); } @@ -188,7 +190,11 @@ inline float deg2turn(float d) { return d / 360.0f; } inline float rad2grad(float r) { return r * 200.0f / piFloat; } inline float grad2rad(float g) { return g * piFloat / 200.0f; } +<<<<<<< HEAD:JavaScriptCore/wtf/MathExtras.h #if !COMPILER(MSVC) && !COMPILER(RVCT) && !COMPILER(WINSCW) +======= +#if !COMPILER(MSVC) && !COMPILER(WINSCW) && !(COMPILER(RVCT) && OS(SYMBIAN)) +>>>>>>> webkit.org at r58956:JavaScriptCore/wtf/MathExtras.h using std::isfinite; using std::isinf; using std::isnan; diff --git a/JavaScriptCore/wtf/Platform.h b/JavaScriptCore/wtf/Platform.h index 405d3e7..f667b9a 100644 --- a/JavaScriptCore/wtf/Platform.h +++ b/JavaScriptCore/wtf/Platform.h @@ -58,11 +58,14 @@ /* ==== COMPILER() - the compiler being used to build the project ==== */ /* COMPILER(MSVC) Microsoft Visual C++ */ -/* COMPILER(MSVC7) Microsoft Visual C++ v7 or lower*/ +/* COMPILER(MSVC7_OR_LOWER) Microsoft Visual C++ 2003 or lower*/ +/* COMPILER(MSVC9_OR_LOWER) Microsoft Visual C++ 2008 or lower*/ #if defined(_MSC_VER) #define WTF_COMPILER_MSVC 1 #if _MSC_VER < 1400 -#define WTF_COMPILER_MSVC7 1 +#define WTF_COMPILER_MSVC7_OR_LOWER 1 +#elif _MSC_VER < 1600 +#define WTF_COMPILER_MSVC9_OR_LOWER 1 #endif #endif @@ -584,8 +587,8 @@ #if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_TIGER) && CPU(X86_64) #define WTF_USE_PLUGIN_HOST_PROCESS 1 #endif -#if !defined(ENABLE_MAC_JAVA_BRIDGE) -#define ENABLE_MAC_JAVA_BRIDGE 1 +#if !defined(ENABLE_JAVA_BRIDGE) +#define ENABLE_JAVA_BRIDGE 1 #endif #if !defined(ENABLE_DASHBOARD_SUPPORT) #define ENABLE_DASHBOARD_SUPPORT 1 @@ -616,7 +619,7 @@ #define ENABLE_GEOLOCATION 1 #define ENABLE_ICONDATABASE 0 #define ENABLE_INSPECTOR 0 -#define ENABLE_MAC_JAVA_BRIDGE 0 +#define ENABLE_JAVA_BRIDGE 0 #define ENABLE_NETSCAPE_PLUGIN_API 0 #define ENABLE_ORIENTATION_EVENTS 1 #define ENABLE_REPAINT_THROTTLING 1 @@ -630,7 +633,7 @@ #define WTF_USE_PTHREADS 1 #define WTF_PLATFORM_SKIA 1 #define USE_SYSTEM_MALLOC 1 -#define ENABLE_MAC_JAVA_BRIDGE 1 +#define ENABLE_JAVA_BRIDGE 1 #define LOG_DISABLED 1 /* Prevents Webkit from drawing the caret in textfields and textareas This prevents unnecessary invals. */ @@ -648,6 +651,11 @@ #define ENABLE_GLOBAL_FASTMALLOC_NEW 0 #if OS(DARWIN) #define WTF_PLATFORM_CF 1 +#ifndef BUILDING_ON_TIGER +#define WTF_USE_CORE_TEXT 1 +#else +#define WTF_USE_ATSUI 1 +#endif #endif #endif @@ -828,8 +836,8 @@ #define ENABLE_INSPECTOR 1 #endif -#if !defined(ENABLE_MAC_JAVA_BRIDGE) -#define ENABLE_MAC_JAVA_BRIDGE 0 +#if !defined(ENABLE_JAVA_BRIDGE) +#define ENABLE_JAVA_BRIDGE 0 #endif #if !defined(ENABLE_NETSCAPE_PLUGIN_API) @@ -852,6 +860,7 @@ #define ENABLE_GLOBAL_FASTMALLOC_NEW 1 #endif +#define ENABLE_DEBUG_WITH_BREAKPOINT 0 #define ENABLE_SAMPLING_COUNTERS 0 #define ENABLE_SAMPLING_FLAGS 0 #define ENABLE_OPCODE_SAMPLING 0 @@ -955,6 +964,8 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */ #define ENABLE_JIT 1 #elif CPU(ARM_TRADITIONAL) && OS(LINUX) #define ENABLE_JIT 1 +#elif CPU(ARM_TRADITIONAL) && OS(SYMBIAN) && COMPILER(RVCT) + #define ENABLE_JIT 1 #elif CPU(MIPS) && OS(LINUX) #define ENABLE_JIT 1 #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 0 @@ -1027,7 +1038,10 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */ || (CPU(X86) && OS(LINUX) && GCC_VERSION >= 40100) \ || (CPU(X86_64) && OS(LINUX) && GCC_VERSION >= 40100) \ || (CPU(ARM_TRADITIONAL) && OS(LINUX)) \ - || (CPU(MIPS) && OS(LINUX)) + || (CPU(ARM_TRADITIONAL) && OS(SYMBIAN) && COMPILER(RVCT)) \ + || (CPU(MIPS) && OS(LINUX)) \ + || (CPU(X86) && OS(DARWIN)) \ + || (CPU(X86_64) && OS(DARWIN)) #define ENABLE_YARR 1 #define ENABLE_YARR_JIT 1 #endif @@ -1092,6 +1106,10 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */ #endif #endif +#if (PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)) || PLATFORM(IPHONE) +#define WTF_USE_PROTECTION_SPACE_AUTH_CALLBACK 1 +#endif + #if COMPILER(GCC) #define WARN_UNUSED_RETURN __attribute__ ((warn_unused_result)) #else diff --git a/JavaScriptCore/wtf/RandomNumber.h b/JavaScriptCore/wtf/RandomNumber.h index fe1687c..e54e9ae 100644 --- a/JavaScriptCore/wtf/RandomNumber.h +++ b/JavaScriptCore/wtf/RandomNumber.h @@ -39,4 +39,7 @@ namespace WTF { } +using WTF::randomNumber; +using WTF::weakRandomNumber; + #endif diff --git a/JavaScriptCore/wtf/RefPtr.h b/JavaScriptCore/wtf/RefPtr.h index 84e841c..eed7933 100644 --- a/JavaScriptCore/wtf/RefPtr.h +++ b/JavaScriptCore/wtf/RefPtr.h @@ -18,6 +18,8 @@ * */ +// RefPtr and PassRefPtr are documented at http://webkit.org/coding/RefPtr.html + #ifndef WTF_RefPtr_h #define WTF_RefPtr_h @@ -79,9 +81,9 @@ namespace WTF { void swap(RefPtr&); - private: static T* hashTableDeletedValue() { return reinterpret_cast<T*>(-1); } + private: T* m_ptr; }; diff --git a/JavaScriptCore/wtf/StaticConstructors.h b/JavaScriptCore/wtf/StaticConstructors.h index 97af339..8b2df9d 100644 --- a/JavaScriptCore/wtf/StaticConstructors.h +++ b/JavaScriptCore/wtf/StaticConstructors.h @@ -51,7 +51,7 @@ #ifndef SKIP_STATIC_CONSTRUCTORS_ON_GCC // Define an global in the normal way. -#if COMPILER(MSVC7) +#if COMPILER(MSVC7_OR_LOWER) #define DEFINE_GLOBAL(type, name) \ const type name; #elif COMPILER(WINSCW) @@ -65,7 +65,7 @@ #else // Define an correctly-sized array of pointers to avoid static initialization. // Use an array of pointers instead of an array of char in case there is some alignment issue. -#if COMPILER(MSVC7) +#if COMPILER(MSVC7_OR_LOWER) #define DEFINE_GLOBAL(type, name) \ void * name[(sizeof(type) + sizeof(void *) - 1) / sizeof(void *)]; #elif COMPILER(WINSCW) diff --git a/JavaScriptCore/wtf/StringExtras.h b/JavaScriptCore/wtf/StringExtras.h index b1ec09f..28e80b8 100644 --- a/JavaScriptCore/wtf/StringExtras.h +++ b/JavaScriptCore/wtf/StringExtras.h @@ -46,7 +46,7 @@ inline int snprintf(char* buffer, size_t count, const char* format, ...) return result; } -#if COMPILER(MSVC7) || OS(WINCE) +#if COMPILER(MSVC7_OR_LOWER) || OS(WINCE) inline int vsnprintf(char* buffer, size_t count, const char* format, va_list args) { diff --git a/JavaScriptCore/wtf/ThreadSafeShared.h b/JavaScriptCore/wtf/ThreadSafeShared.h new file mode 100644 index 0000000..688747e --- /dev/null +++ b/JavaScriptCore/wtf/ThreadSafeShared.h @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2007, 2008, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Note: The implementations of InterlockedIncrement and InterlockedDecrement are based + * on atomic_increment and atomic_exchange_and_add from the Boost C++ Library. The license + * is virtually identical to the Apple license above but is included here for completeness. + * + * Boost Software License - Version 1.0 - August 17th, 2003 + * + * Permission is hereby granted, free of charge, to any person or organization + * obtaining a copy of the software and accompanying documentation covered by + * this license (the "Software") to use, reproduce, display, distribute, + * execute, and transmit the Software, and to prepare derivative works of the + * Software, and to permit third-parties to whom the Software is furnished to + * do so, all subject to the following: + * + * The copyright notices in the Software and this entire statement, including + * the above license grant, this restriction and the following disclaimer, + * must be included in all copies of the Software, in whole or in part, and + * all derivative works of the Software, unless such copies or derivative + * works are solely in the form of machine-executable object code generated by + * a source language processor. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef ThreadSafeShared_h +#define ThreadSafeShared_h + +#include "Platform.h" + +#include <wtf/Atomics.h> +#include <wtf/Noncopyable.h> +#include <wtf/ThreadingPrimitives.h> + +namespace WTF { + +class ThreadSafeSharedBase : public Noncopyable { +public: + ThreadSafeSharedBase(int initialRefCount = 1) + : m_refCount(initialRefCount) + { + } + + void ref() + { +#if USE(LOCKFREE_THREADSAFESHARED) + atomicIncrement(&m_refCount); +#else + MutexLocker locker(m_mutex); + ++m_refCount; +#endif + } + + bool hasOneRef() + { + return refCount() == 1; + } + + int refCount() const + { +#if !USE(LOCKFREE_THREADSAFESHARED) + MutexLocker locker(m_mutex); +#endif + return static_cast<int const volatile &>(m_refCount); + } + +protected: + // Returns whether the pointer should be freed or not. + bool derefBase() + { +#if USE(LOCKFREE_THREADSAFESHARED) + if (atomicDecrement(&m_refCount) <= 0) + return true; +#else + int refCount; + { + MutexLocker locker(m_mutex); + --m_refCount; + refCount = m_refCount; + } + if (refCount <= 0) + return true; +#endif + return false; + } + +private: + template<class T> + friend class CrossThreadRefCounted; + + int m_refCount; +#if !USE(LOCKFREE_THREADSAFESHARED) + mutable Mutex m_mutex; +#endif +}; + +template<class T> class ThreadSafeShared : public ThreadSafeSharedBase { +public: + ThreadSafeShared(int initialRefCount = 1) + : ThreadSafeSharedBase(initialRefCount) + { + } + + void deref() + { + if (derefBase()) + delete static_cast<T*>(this); + } +}; + +} // namespace WTF + +using WTF::ThreadSafeShared; + +#endif // ThreadSafeShared_h diff --git a/JavaScriptCore/wtf/Threading.h b/JavaScriptCore/wtf/Threading.h index 768aecf..415a8fc 100644 --- a/JavaScriptCore/wtf/Threading.h +++ b/JavaScriptCore/wtf/Threading.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2010 Apple Inc. All rights reserved. * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com) * * Redistribution and use in source and binary forms, with or without @@ -61,45 +61,14 @@ #include "Platform.h" -#if OS(WINCE) -#include <windows.h> -#endif - +#include <stdint.h> #include <wtf/Assertions.h> +#include <wtf/Atomics.h> #include <wtf/Locker.h> +#include <wtf/MainThread.h> #include <wtf/Noncopyable.h> - -#if OS(WINDOWS) && !OS(WINCE) -#include <windows.h> -#elif OS(DARWIN) -#include <libkern/OSAtomic.h> -#elif OS(ANDROID) -#include <cutils/atomic.h> -#elif COMPILER(GCC) && !OS(SYMBIAN) -#if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) -#include <ext/atomicity.h> -#else -#include <bits/atomicity.h> -#endif -#endif - -#if USE(PTHREADS) -#include <pthread.h> -#elif PLATFORM(GTK) -#include "GOwnPtr.h" -typedef struct _GMutex GMutex; -typedef struct _GCond GCond; -#endif - -#if PLATFORM(QT) -#include <qglobal.h> -QT_BEGIN_NAMESPACE -class QMutex; -class QWaitCondition; -QT_END_NAMESPACE -#endif - -#include <stdint.h> +#include <wtf/ThreadSafeShared.h> +#include <wtf/ThreadingPrimitives.h> // For portability, we do not use thread-safe statics natively supported by some compilers (e.g. gcc). #define AtomicallyInitializedStatic(T, name) \ @@ -112,6 +81,11 @@ namespace WTF { typedef uint32_t ThreadIdentifier; typedef void* (*ThreadFunction)(void* argument); +// This function must be called from the main thread. It is safe to call it repeatedly. +// Darwin is an exception to this rule: it is OK to call it from any thread, the only +// requirement is that the calls are not reentrant. +void initializeThreading(); + // Returns 0 if thread creation failed. // The thread name must be a literal since on some platforms it's passed in to the thread. ThreadIdentifier createThread(ThreadFunction, void*, const char* threadName); @@ -124,226 +98,18 @@ ThreadIdentifier createThreadInternal(ThreadFunction, void*, const char* threadN void initializeCurrentThreadInternal(const char* threadName); ThreadIdentifier currentThread(); -bool isMainThread(); int waitForThreadCompletion(ThreadIdentifier, void**); void detachThread(ThreadIdentifier); -#if USE(PTHREADS) -typedef pthread_mutex_t PlatformMutex; -#if HAVE(PTHREAD_RWLOCK) -typedef pthread_rwlock_t PlatformReadWriteLock; -#else -typedef void* PlatformReadWriteLock; -#endif -typedef pthread_cond_t PlatformCondition; -#elif PLATFORM(GTK) -typedef GOwnPtr<GMutex> PlatformMutex; -typedef void* PlatformReadWriteLock; // FIXME: Implement. -typedef GOwnPtr<GCond> PlatformCondition; -#elif PLATFORM(QT) -typedef QT_PREPEND_NAMESPACE(QMutex)* PlatformMutex; -typedef void* PlatformReadWriteLock; // FIXME: Implement. -typedef QT_PREPEND_NAMESPACE(QWaitCondition)* PlatformCondition; -#elif OS(WINDOWS) -struct PlatformMutex { - CRITICAL_SECTION m_internalMutex; - size_t m_recursionCount; -}; -typedef void* PlatformReadWriteLock; // FIXME: Implement. -struct PlatformCondition { - size_t m_waitersGone; - size_t m_waitersBlocked; - size_t m_waitersToUnblock; - HANDLE m_blockLock; - HANDLE m_blockQueue; - HANDLE m_unblockLock; - - bool timedWait(PlatformMutex&, DWORD durationMilliseconds); - void signal(bool unblockAll); -}; -#else -typedef void* PlatformMutex; -typedef void* PlatformReadWriteLock; -typedef void* PlatformCondition; -#endif - -class Mutex : public Noncopyable { -public: - Mutex(); - ~Mutex(); - - void lock(); - bool tryLock(); - void unlock(); - -public: - PlatformMutex& impl() { return m_mutex; } -private: - PlatformMutex m_mutex; -}; - -typedef Locker<Mutex> MutexLocker; - -class ReadWriteLock : public Noncopyable { -public: - ReadWriteLock(); - ~ReadWriteLock(); - - void readLock(); - bool tryReadLock(); - - void writeLock(); - bool tryWriteLock(); - - void unlock(); - -private: - PlatformReadWriteLock m_readWriteLock; -}; - -class ThreadCondition : public Noncopyable { -public: - ThreadCondition(); - ~ThreadCondition(); - - void wait(Mutex& mutex); - // Returns true if the condition was signaled before absoluteTime, false if the absoluteTime was reached or is in the past. - // The absoluteTime is in seconds, starting on January 1, 1970. The time is assumed to use the same time zone as WTF::currentTime(). - bool timedWait(Mutex&, double absoluteTime); - void signal(); - void broadcast(); - -private: - PlatformCondition m_condition; -}; - -#if OS(WINDOWS) -#define WTF_USE_LOCKFREE_THREADSAFESHARED 1 - -#if COMPILER(MINGW) || COMPILER(MSVC7) || OS(WINCE) -inline int atomicIncrement(int* addend) { return InterlockedIncrement(reinterpret_cast<long*>(addend)); } -inline int atomicDecrement(int* addend) { return InterlockedDecrement(reinterpret_cast<long*>(addend)); } -#else -inline int atomicIncrement(int volatile* addend) { return InterlockedIncrement(reinterpret_cast<long volatile*>(addend)); } -inline int atomicDecrement(int volatile* addend) { return InterlockedDecrement(reinterpret_cast<long volatile*>(addend)); } -#endif - -#elif OS(DARWIN) -#define WTF_USE_LOCKFREE_THREADSAFESHARED 1 - -inline int atomicIncrement(int volatile* addend) { return OSAtomicIncrement32Barrier(const_cast<int*>(addend)); } -inline int atomicDecrement(int volatile* addend) { return OSAtomicDecrement32Barrier(const_cast<int*>(addend)); } - -#elif OS(ANDROID) - -inline int atomicIncrement(int volatile* addend) { return android_atomic_inc(addend); } -inline int atomicDecrement(int volatile* addend) { return android_atomic_dec(addend); } - -#elif COMPILER(GCC) && !CPU(SPARC64) && !OS(SYMBIAN) // sizeof(_Atomic_word) != sizeof(int) on sparc64 gcc -#define WTF_USE_LOCKFREE_THREADSAFESHARED 1 - -inline int atomicIncrement(int volatile* addend) { return __gnu_cxx::__exchange_and_add(addend, 1) + 1; } -inline int atomicDecrement(int volatile* addend) { return __gnu_cxx::__exchange_and_add(addend, -1) - 1; } - -#endif - -class ThreadSafeSharedBase : public Noncopyable { -public: - ThreadSafeSharedBase(int initialRefCount = 1) - : m_refCount(initialRefCount) - { - } - - void ref() - { -#if USE(LOCKFREE_THREADSAFESHARED) - atomicIncrement(&m_refCount); -#else - MutexLocker locker(m_mutex); - ++m_refCount; -#endif - } - - bool hasOneRef() - { - return refCount() == 1; - } - - int refCount() const - { -#if !USE(LOCKFREE_THREADSAFESHARED) - MutexLocker locker(m_mutex); -#endif - return static_cast<int const volatile &>(m_refCount); - } - -protected: - // Returns whether the pointer should be freed or not. - bool derefBase() - { -#if USE(LOCKFREE_THREADSAFESHARED) - if (atomicDecrement(&m_refCount) <= 0) - return true; -#else - int refCount; - { - MutexLocker locker(m_mutex); - --m_refCount; - refCount = m_refCount; - } - if (refCount <= 0) - return true; -#endif - return false; - } - -private: - template<class T> - friend class CrossThreadRefCounted; - - int m_refCount; -#if !USE(LOCKFREE_THREADSAFESHARED) - mutable Mutex m_mutex; -#endif -}; - -template<class T> class ThreadSafeShared : public ThreadSafeSharedBase { -public: - ThreadSafeShared(int initialRefCount = 1) - : ThreadSafeSharedBase(initialRefCount) - { - } - - void deref() - { - if (derefBase()) - delete static_cast<T*>(this); - } -}; - -// This function must be called from the main thread. It is safe to call it repeatedly. -// Darwin is an exception to this rule: it is OK to call it from any thread, the only requirement is that the calls are not reentrant. -void initializeThreading(); void lockAtomicallyInitializedStaticMutex(); void unlockAtomicallyInitializedStaticMutex(); } // namespace WTF -using WTF::Mutex; -using WTF::MutexLocker; -using WTF::ThreadCondition; using WTF::ThreadIdentifier; -using WTF::ThreadSafeShared; - -#if USE(LOCKFREE_THREADSAFESHARED) -using WTF::atomicDecrement; -using WTF::atomicIncrement; -#endif - using WTF::createThread; using WTF::currentThread; -using WTF::isMainThread; using WTF::detachThread; using WTF::waitForThreadCompletion; diff --git a/JavaScriptCore/wtf/ThreadingPrimitives.h b/JavaScriptCore/wtf/ThreadingPrimitives.h new file mode 100644 index 0000000..66801c0 --- /dev/null +++ b/JavaScriptCore/wtf/ThreadingPrimitives.h @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2007, 2008, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef ThreadingPrimitives_h +#define ThreadingPrimitives_h + +#include "Platform.h" + +#include <wtf/Assertions.h> +#include <wtf/Locker.h> +#include <wtf/Noncopyable.h> + +#if OS(WINDOWS) +#include <windows.h> +#endif + +#if USE(PTHREADS) +#include <pthread.h> +#elif PLATFORM(GTK) +#include "GOwnPtr.h" +typedef struct _GMutex GMutex; +typedef struct _GCond GCond; +#endif + +#if PLATFORM(QT) +#include <qglobal.h> +QT_BEGIN_NAMESPACE +class QMutex; +class QWaitCondition; +QT_END_NAMESPACE +#endif + +namespace WTF { + +#if USE(PTHREADS) +typedef pthread_mutex_t PlatformMutex; +#if HAVE(PTHREAD_RWLOCK) +typedef pthread_rwlock_t PlatformReadWriteLock; +#else +typedef void* PlatformReadWriteLock; +#endif +typedef pthread_cond_t PlatformCondition; +#elif PLATFORM(GTK) +typedef GOwnPtr<GMutex> PlatformMutex; +typedef void* PlatformReadWriteLock; // FIXME: Implement. +typedef GOwnPtr<GCond> PlatformCondition; +#elif PLATFORM(QT) +typedef QT_PREPEND_NAMESPACE(QMutex)* PlatformMutex; +typedef void* PlatformReadWriteLock; // FIXME: Implement. +typedef QT_PREPEND_NAMESPACE(QWaitCondition)* PlatformCondition; +#elif OS(WINDOWS) +struct PlatformMutex { + CRITICAL_SECTION m_internalMutex; + size_t m_recursionCount; +}; +typedef void* PlatformReadWriteLock; // FIXME: Implement. +struct PlatformCondition { + size_t m_waitersGone; + size_t m_waitersBlocked; + size_t m_waitersToUnblock; + HANDLE m_blockLock; + HANDLE m_blockQueue; + HANDLE m_unblockLock; + + bool timedWait(PlatformMutex&, DWORD durationMilliseconds); + void signal(bool unblockAll); +}; +#else +typedef void* PlatformMutex; +typedef void* PlatformReadWriteLock; +typedef void* PlatformCondition; +#endif + +class Mutex : public Noncopyable { +public: + Mutex(); + ~Mutex(); + + void lock(); + bool tryLock(); + void unlock(); + +public: + PlatformMutex& impl() { return m_mutex; } +private: + PlatformMutex m_mutex; +}; + +typedef Locker<Mutex> MutexLocker; + +class ReadWriteLock : public Noncopyable { +public: + ReadWriteLock(); + ~ReadWriteLock(); + + void readLock(); + bool tryReadLock(); + + void writeLock(); + bool tryWriteLock(); + + void unlock(); + +private: + PlatformReadWriteLock m_readWriteLock; +}; + +class ThreadCondition : public Noncopyable { +public: + ThreadCondition(); + ~ThreadCondition(); + + void wait(Mutex& mutex); + // Returns true if the condition was signaled before absoluteTime, false if the absoluteTime was reached or is in the past. + // The absoluteTime is in seconds, starting on January 1, 1970. The time is assumed to use the same time zone as WTF::currentTime(). + bool timedWait(Mutex&, double absoluteTime); + void signal(); + void broadcast(); + +private: + PlatformCondition m_condition; +}; + +} // namespace WTF + +using WTF::Mutex; +using WTF::MutexLocker; +using WTF::ThreadCondition; + +#endif // ThreadingPrimitives_h diff --git a/JavaScriptCore/wtf/ThreadingPthreads.cpp b/JavaScriptCore/wtf/ThreadingPthreads.cpp index 5a7ff55..7ff9266 100644 --- a/JavaScriptCore/wtf/ThreadingPthreads.cpp +++ b/JavaScriptCore/wtf/ThreadingPthreads.cpp @@ -57,10 +57,6 @@ typedef HashMap<ThreadIdentifier, pthread_t> ThreadMap; static Mutex* atomicallyInitializedStaticMutex; -#if !OS(DARWIN) || PLATFORM(CHROMIUM) || USE(WEB_THREAD) -static pthread_t mainThread; // The thread that was the first to call initializeThreading(), which must be the main thread. -#endif - void clearPthreadHandleForIdentifier(ThreadIdentifier); static Mutex& threadMapMutex() @@ -71,15 +67,12 @@ static Mutex& threadMapMutex() void initializeThreading() { - if (!atomicallyInitializedStaticMutex) { - atomicallyInitializedStaticMutex = new Mutex; - threadMapMutex(); - initializeRandomNumberGenerator(); -#if !OS(DARWIN) || PLATFORM(CHROMIUM) || USE(WEB_THREAD) - mainThread = pthread_self(); -#endif - initializeMainThread(); - } + if (atomicallyInitializedStaticMutex) + return; + + atomicallyInitializedStaticMutex = new Mutex; + threadMapMutex(); + initializeRandomNumberGenerator(); } void lockAtomicallyInitializedStaticMutex() @@ -240,15 +233,6 @@ ThreadIdentifier currentThread() return id; } -bool isMainThread() -{ -#if OS(DARWIN) && !PLATFORM(CHROMIUM) && !USE(WEB_THREAD) - return pthread_main_np(); -#else - return pthread_equal(pthread_self(), mainThread); -#endif -} - Mutex::Mutex() { pthread_mutex_init(&m_mutex, NULL); diff --git a/JavaScriptCore/wtf/ThreadingWin.cpp b/JavaScriptCore/wtf/ThreadingWin.cpp index 73c3f0c..c16be5a 100644 --- a/JavaScriptCore/wtf/ThreadingWin.cpp +++ b/JavaScriptCore/wtf/ThreadingWin.cpp @@ -145,8 +145,6 @@ void unlockAtomicallyInitializedStaticMutex() atomicallyInitializedStaticMutex->unlock(); } -static ThreadIdentifier mainThreadIdentifier; - static Mutex& threadMapMutex() { static Mutex mutex; @@ -155,14 +153,12 @@ static Mutex& threadMapMutex() void initializeThreading() { - if (!atomicallyInitializedStaticMutex) { - atomicallyInitializedStaticMutex = new Mutex; - threadMapMutex(); - initializeRandomNumberGenerator(); - initializeMainThread(); - mainThreadIdentifier = currentThread(); - initializeCurrentThreadInternal("Main Thread"); - } + if (atomicallyInitializedStaticMutex) + return; + + atomicallyInitializedStaticMutex = new Mutex; + threadMapMutex(); + initializeRandomNumberGenerator(); } static HashMap<DWORD, HANDLE>& threadMap() @@ -275,11 +271,6 @@ ThreadIdentifier currentThread() return static_cast<ThreadIdentifier>(GetCurrentThreadId()); } -bool isMainThread() -{ - return currentThread() == mainThreadIdentifier; -} - Mutex::Mutex() { m_mutex.m_recursionCount = 0; diff --git a/JavaScriptCore/wtf/Vector.h b/JavaScriptCore/wtf/Vector.h index 6f55e53..e495067 100644 --- a/JavaScriptCore/wtf/Vector.h +++ b/JavaScriptCore/wtf/Vector.h @@ -939,7 +939,7 @@ namespace WTF { return; } -#if COMPILER(MSVC7) +#if COMPILER(MSVC7_OR_LOWER) // FIXME: MSVC7 generates compilation errors when trying to assign // a pointer to a Vector of its base class (i.e. can't downcast). So far // I've been unable to determine any logical reason for this, so I can diff --git a/JavaScriptCore/wtf/WTFThreadData.cpp b/JavaScriptCore/wtf/WTFThreadData.cpp index bbc9986..0716dc9 100644 --- a/JavaScriptCore/wtf/WTFThreadData.cpp +++ b/JavaScriptCore/wtf/WTFThreadData.cpp @@ -39,8 +39,8 @@ WTFThreadData::WTFThreadData() : m_atomicStringTable(0) , m_atomicStringTableDestructor(0) #if USE(JSC) - , m_defaultIdentifierTable(0) - , m_currentIdentifierTable(0) + , m_defaultIdentifierTable(new JSC::IdentifierTable()) + , m_currentIdentifierTable(m_defaultIdentifierTable) #endif { } @@ -49,6 +49,9 @@ WTFThreadData::~WTFThreadData() { if (m_atomicStringTableDestructor) m_atomicStringTableDestructor(m_atomicStringTable); +#if USE(JSC) + delete m_defaultIdentifierTable; +#endif } } // namespace WebCore diff --git a/JavaScriptCore/wtf/OwnPtrBrew.cpp b/JavaScriptCore/wtf/brew/OwnPtrBrew.cpp index c8384e1..c8384e1 100644 --- a/JavaScriptCore/wtf/OwnPtrBrew.cpp +++ b/JavaScriptCore/wtf/brew/OwnPtrBrew.cpp diff --git a/JavaScriptCore/wtf/chromium/ChromiumThreading.h b/JavaScriptCore/wtf/chromium/ChromiumThreading.h index b2c5075..3938621 100644 --- a/JavaScriptCore/wtf/chromium/ChromiumThreading.h +++ b/JavaScriptCore/wtf/chromium/ChromiumThreading.h @@ -36,8 +36,7 @@ namespace WTF { // An interface to the embedding layer, which provides threading support. class ChromiumThreading { public: - static void initializeMainThread(); - static void scheduleDispatchFunctionsOnMainThread(); + static void callOnMainThread(void (*func)(void*), void* context); }; } // namespace WTF diff --git a/JavaScriptCore/wtf/chromium/MainThreadChromium.cpp b/JavaScriptCore/wtf/chromium/MainThreadChromium.cpp index 394370f..9e6592b 100644 --- a/JavaScriptCore/wtf/chromium/MainThreadChromium.cpp +++ b/JavaScriptCore/wtf/chromium/MainThreadChromium.cpp @@ -31,18 +31,42 @@ #include "config.h" #include "MainThread.h" +#include "Assertions.h" #include "ChromiumThreading.h" +#include "Threading.h" namespace WTF { -void initializeMainThreadPlatform() +static ThreadIdentifier mainThreadIdentifier; + +void initializeMainThread() +{ + static bool initializedMainThread; + if (initializedMainThread) + return; + initializedMainThread = true; + + mainThreadIdentifier = currentThread(); +} + +void callOnMainThread(MainThreadFunction* function, void* context) +{ + ChromiumThreading::callOnMainThread(function, context); +} + +void callOnMainThreadAndWait(MainThreadFunction*, void*) +{ + ASSERT_NOT_REACHED(); +} + +void setMainThreadCallbacksPaused(bool) { - ChromiumThreading::initializeMainThread(); + ASSERT_NOT_REACHED(); } -void scheduleDispatchFunctionsOnMainThread() +bool isMainThread() { - ChromiumThreading::scheduleDispatchFunctionsOnMainThread(); + return currentThread() == mainThreadIdentifier; } } // namespace WTF diff --git a/JavaScriptCore/wtf/gobject/GRefPtr.h b/JavaScriptCore/wtf/gobject/GRefPtr.h index 66739ef..3a33605 100644 --- a/JavaScriptCore/wtf/gobject/GRefPtr.h +++ b/JavaScriptCore/wtf/gobject/GRefPtr.h @@ -27,6 +27,9 @@ #include <algorithm> typedef struct _GHashTable GHashTable; +typedef void* gpointer; +extern "C" void g_object_unref(gpointer object); +extern "C" gpointer g_object_ref_sink(gpointer object); namespace WTF { diff --git a/JavaScriptCore/wtf/gtk/ThreadingGtk.cpp b/JavaScriptCore/wtf/gtk/ThreadingGtk.cpp index a6ec8f7..0c5cf0c 100644 --- a/JavaScriptCore/wtf/gtk/ThreadingGtk.cpp +++ b/JavaScriptCore/wtf/gtk/ThreadingGtk.cpp @@ -44,8 +44,6 @@ namespace WTF { static Mutex* atomicallyInitializedStaticMutex; -static ThreadIdentifier mainThreadIdentifier; - static Mutex& threadMapMutex() { static Mutex mutex; @@ -62,8 +60,6 @@ void initializeThreading() atomicallyInitializedStaticMutex = new Mutex; threadMapMutex(); initializeRandomNumberGenerator(); - mainThreadIdentifier = currentThread(); - initializeMainThread(); } } @@ -168,11 +164,6 @@ ThreadIdentifier currentThread() return establishIdentifierForThread(currentThread); } -bool isMainThread() -{ - return currentThread() == mainThreadIdentifier; -} - Mutex::Mutex() : m_mutex(g_mutex_new()) { diff --git a/JavaScriptCore/wtf/mac/MainThreadMac.mm b/JavaScriptCore/wtf/mac/MainThreadMac.mm index 586ef4d..17363bc 100644 --- a/JavaScriptCore/wtf/mac/MainThreadMac.mm +++ b/JavaScriptCore/wtf/mac/MainThreadMac.mm @@ -31,6 +31,7 @@ #import <CoreFoundation/CoreFoundation.h> #import <Foundation/NSThread.h> +#import <stdio.h> #import <wtf/Assertions.h> #import <wtf/Threading.h> @@ -50,22 +51,38 @@ namespace WTF { -static WTFMainThreadCaller* staticMainThreadCaller = nil; -#if USE(WEB_THREAD) -static NSThread* webThread = nil; -#endif +static WTFMainThreadCaller* staticMainThreadCaller; +static bool isTimerPosted; // This is only accessed on the 'main' thread. +static bool mainThreadEstablishedAsPthreadMain; +static pthread_t mainThreadPthread; +static NSThread* mainThreadNSThread; void initializeMainThreadPlatform() { +#if !defined(BUILDING_ON_TIGER) ASSERT(!staticMainThreadCaller); staticMainThreadCaller = [[WTFMainThreadCaller alloc] init]; -#if USE(WEB_THREAD) - webThread = [[NSThread currentThread] retain]; + mainThreadEstablishedAsPthreadMain = false; + mainThreadPthread = pthread_self(); + mainThreadNSThread = [[NSThread currentThread] retain]; +#else + ASSERT_NOT_REACHED(); #endif } -static bool isTimerPosted; // This is only accessed on the 'main' thread. +void initializeMainThreadToProcessMainThreadPlatform() +{ + if (!pthread_main_np()) + NSLog(@"WebKit Threading Violation - initial use of WebKit from a secondary thread."); + + ASSERT(!staticMainThreadCaller); + staticMainThreadCaller = [[WTFMainThreadCaller alloc] init]; + + mainThreadEstablishedAsPthreadMain = true; + mainThreadPthread = 0; + mainThreadNSThread = nil; +} static void timerFired(CFRunLoopTimerRef timer, void*) { @@ -85,7 +102,6 @@ static void postTimer() CFRunLoopAddTimer(CFRunLoopGetCurrent(), CFRunLoopTimerCreate(0, 0, 0, 0, 0, timerFired, 0), kCFRunLoopCommonModes); } - void scheduleDispatchFunctionsOnMainThread() { ASSERT(staticMainThreadCaller); @@ -95,10 +111,33 @@ void scheduleDispatchFunctionsOnMainThread() return; } -#if USE(WEB_THREAD) - [staticMainThreadCaller performSelector:@selector(call) onThread:webThread withObject:nil waitUntilDone:NO]; + if (mainThreadEstablishedAsPthreadMain) { + ASSERT(!mainThreadNSThread); + [staticMainThreadCaller performSelectorOnMainThread:@selector(call) withObject:nil waitUntilDone:NO]; + return; + } + +#if !defined(BUILDING_ON_TIGER) + ASSERT(mainThreadNSThread); + [staticMainThreadCaller performSelector:@selector(call) onThread:mainThreadNSThread withObject:nil waitUntilDone:NO]; +#else + ASSERT_NOT_REACHED(); +#endif +} + +bool isMainThread() +{ + if (mainThreadEstablishedAsPthreadMain) { + ASSERT(!mainThreadPthread); + return pthread_main_np(); + } + +#if !defined(BUILDING_ON_TIGER) + ASSERT(mainThreadPthread); + return pthread_equal(pthread_self(), mainThreadPthread); #else - [staticMainThreadCaller performSelectorOnMainThread:@selector(call) withObject:nil waitUntilDone:NO]; + ASSERT_NOT_REACHED(); + return false; #endif } diff --git a/JavaScriptCore/wtf/qt/MainThreadQt.cpp b/JavaScriptCore/wtf/qt/MainThreadQt.cpp index 7b2d0f2..98b6a0c 100644 --- a/JavaScriptCore/wtf/qt/MainThreadQt.cpp +++ b/JavaScriptCore/wtf/qt/MainThreadQt.cpp @@ -33,7 +33,7 @@ #include <QtCore/QObject> #include <QtCore/QCoreApplication> - +#include <QThread> namespace WTF { @@ -67,6 +67,11 @@ void scheduleDispatchFunctionsOnMainThread() QMetaObject::invokeMethod(webkit_main_thread_invoker(), "dispatch", Qt::QueuedConnection); } +bool isMainThread() +{ + return QThread::currentThread() == QCoreApplication::instance()->thread(); +} + } // namespace WTF #include "MainThreadQt.moc" diff --git a/JavaScriptCore/wtf/qt/ThreadingQt.cpp b/JavaScriptCore/wtf/qt/ThreadingQt.cpp index dc04a68..7f81646 100644 --- a/JavaScriptCore/wtf/qt/ThreadingQt.cpp +++ b/JavaScriptCore/wtf/qt/ThreadingQt.cpp @@ -84,8 +84,6 @@ public Q_SLOTS: static Mutex* atomicallyInitializedStaticMutex; -static ThreadIdentifier mainThreadIdentifier; - static Mutex& threadMapMutex() { static Mutex mutex; @@ -146,11 +144,6 @@ void initializeThreading() atomicallyInitializedStaticMutex = new Mutex; threadMapMutex(); initializeRandomNumberGenerator(); - QThread* mainThread = QCoreApplication::instance()->thread(); - mainThreadIdentifier = identifierByQthreadHandle(mainThread); - if (!mainThreadIdentifier) - mainThreadIdentifier = establishIdentifierForThread(mainThread); - initializeMainThread(); } } @@ -215,11 +208,6 @@ ThreadIdentifier currentThread() return establishIdentifierForThread(currentThread); } -bool isMainThread() -{ - return QThread::currentThread() == QCoreApplication::instance()->thread(); -} - Mutex::Mutex() : m_mutex(new QMutex()) { diff --git a/JavaScriptCore/wtf/text/AtomicString.cpp b/JavaScriptCore/wtf/text/AtomicString.cpp index 79b9ab5..ab52488 100644 --- a/JavaScriptCore/wtf/text/AtomicString.cpp +++ b/JavaScriptCore/wtf/text/AtomicString.cpp @@ -28,8 +28,8 @@ #include "StaticConstructors.h" #include "StringHash.h" -#include <wtf/Threading.h> #include <wtf/HashSet.h> +#include <wtf/Threading.h> #include <wtf/WTFThreadData.h> namespace WebCore { @@ -55,6 +55,9 @@ public: private: static void destroy(AtomicStringTable* table) { + HashSet<StringImpl*>::iterator end = table->m_table.end(); + for (HashSet<StringImpl*>::iterator iter = table->m_table.begin(); iter != end; ++iter) + (*iter)->setIsAtomic(false); delete table; } @@ -92,7 +95,7 @@ struct CStringTranslator { { location = StringImpl::create(c).releaseRef(); location->setHash(hash); - location->setInTable(); + location->setIsAtomic(true); } }; @@ -171,7 +174,7 @@ struct UCharBufferTranslator { { location = StringImpl::create(buf.s, buf.length).releaseRef(); location->setHash(hash); - location->setInTable(); + location->setIsAtomic(true); } }; @@ -197,7 +200,7 @@ struct HashAndCharactersTranslator { { location = StringImpl::create(buffer.characters, buffer.length).releaseRef(); location->setHash(hash); - location->setInTable(); + location->setIsAtomic(true); } }; @@ -254,7 +257,7 @@ PassRefPtr<StringImpl> AtomicString::add(const UChar* s) PassRefPtr<StringImpl> AtomicString::add(StringImpl* r) { - if (!r || r->inTable()) + if (!r || r->isAtomic()) return r; if (r->length() == 0) @@ -262,7 +265,7 @@ PassRefPtr<StringImpl> AtomicString::add(StringImpl* r) StringImpl* result = *stringTable().add(r).first; if (result == r) - r->setInTable(); + r->setIsAtomic(true); return result; } diff --git a/JavaScriptCore/wtf/text/AtomicStringImpl.h b/JavaScriptCore/wtf/text/AtomicStringImpl.h index d21a00a..4b813f8 100644 --- a/JavaScriptCore/wtf/text/AtomicStringImpl.h +++ b/JavaScriptCore/wtf/text/AtomicStringImpl.h @@ -29,6 +29,8 @@ namespace WebCore { class AtomicStringImpl : public StringImpl { +public: + AtomicStringImpl() : StringImpl(0) {} }; } diff --git a/JavaScriptCore/wtf/text/StringImpl.cpp b/JavaScriptCore/wtf/text/StringImpl.cpp index 287e529..ff69737 100644 --- a/JavaScriptCore/wtf/text/StringImpl.cpp +++ b/JavaScriptCore/wtf/text/StringImpl.cpp @@ -42,7 +42,7 @@ StringImpl::~StringImpl() { ASSERT(!isStatic()); - if (inTable()) + if (isAtomic()) AtomicString::remove(this); #if USE(JSC) if (isIdentifier()) @@ -879,7 +879,7 @@ Vector<char> StringImpl::ascii() for (unsigned i = 0; i != m_length; ++i) { UChar c = m_data[i]; if ((c >= 0x20 && c < 0x7F) || c == 0x00) - buffer[i] = c; + buffer[i] = static_cast<char>(c); else buffer[i] = '?'; } diff --git a/JavaScriptCore/wtf/text/StringImpl.h b/JavaScriptCore/wtf/text/StringImpl.h index 6ac9e40..dbf51e3 100644 --- a/JavaScriptCore/wtf/text/StringImpl.h +++ b/JavaScriptCore/wtf/text/StringImpl.h @@ -27,6 +27,7 @@ #include <wtf/ASCIICType.h> #include <wtf/CrossThreadRefCounted.h> #include <wtf/OwnFastMallocPtr.h> +#include <wtf/StdLibExtras.h> #include <wtf/StringHashFunctions.h> #include <wtf/Vector.h> #include <wtf/text/StringImplBase.h> @@ -72,6 +73,7 @@ class StringImpl : public StringImplBase { friend struct CStringTranslator; friend struct HashAndCharactersTranslator; friend struct UCharBufferTranslator; + friend class AtomicStringImpl; private: // Used to construct static strings, which have an special refCount that can never hit zero. // This means that the static string will never be destroyed, which is important because @@ -178,6 +180,7 @@ public: return adoptRef(new(resultImpl) StringImpl(length)); } + static unsigned dataOffset() { return OBJECT_OFFSETOF(StringImpl, m_data); } static PassRefPtr<StringImpl> createWithTerminatingNullCharacter(const StringImpl&); static PassRefPtr<StringImpl> createStrippingNullCharacters(const UChar*, unsigned length); @@ -220,8 +223,15 @@ public: bool hasTerminatingNullCharacter() const { return m_refCountAndFlags & s_refCountFlagHasTerminatingNullCharacter; } - bool inTable() const { return m_refCountAndFlags & s_refCountFlagInTable; } - void setInTable() { m_refCountAndFlags |= s_refCountFlagInTable; } + bool isAtomic() const { return m_refCountAndFlags & s_refCountFlagIsAtomic; } + void setIsAtomic(bool isIdentifier) + { + ASSERT(!isStatic()); + if (isIdentifier) + m_refCountAndFlags |= s_refCountFlagIsAtomic; + else + m_refCountAndFlags &= ~s_refCountFlagIsAtomic; + } unsigned hash() const { if (!m_hash) m_hash = computeHash(m_data, m_length); return m_hash; } unsigned existingHash() const { ASSERT(m_hash); return m_hash; } @@ -317,7 +327,6 @@ private: BufferOwnership bufferOwnership() const { return static_cast<BufferOwnership>(m_refCountAndFlags & s_refCountMaskBufferOwnership); } bool isStatic() const { return m_refCountAndFlags & s_refCountFlagStatic; } - const UChar* m_data; union { void* m_buffer; diff --git a/JavaScriptCore/wtf/text/StringImplBase.h b/JavaScriptCore/wtf/text/StringImplBase.h index a8e3385..6567672 100644 --- a/JavaScriptCore/wtf/text/StringImplBase.h +++ b/JavaScriptCore/wtf/text/StringImplBase.h @@ -83,7 +83,7 @@ protected: static const unsigned s_refCountIncrement = 0x80; static const unsigned s_refCountFlagStatic = 0x40; static const unsigned s_refCountFlagHasTerminatingNullCharacter = 0x20; - static const unsigned s_refCountFlagInTable = 0x10; + static const unsigned s_refCountFlagIsAtomic = 0x10; static const unsigned s_refCountFlagShouldReportedCost = 0x8; static const unsigned s_refCountFlagIsIdentifier = 0x4; static const unsigned s_refCountMaskBufferOwnership = 0x3; diff --git a/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h b/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h index 9b1754a..97c42b7 100644 --- a/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h +++ b/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h @@ -56,7 +56,7 @@ namespace QUnicodeTables { QT_END_NAMESPACE // ugly hack to make UChar compatible with JSChar in API/JSStringRef.h -#if defined(Q_OS_WIN) || COMPILER(WINSCW) || COMPILER(RVCT) +#if defined(Q_OS_WIN) || COMPILER(WINSCW) || (COMPILER(RVCT) && OS(SYMBIAN)) typedef wchar_t UChar; #else typedef uint16_t UChar; diff --git a/JavaScriptCore/wtf/url/src/URLComponent.h b/JavaScriptCore/wtf/url/src/URLComponent.h new file mode 100644 index 0000000..ca7e6f3 --- /dev/null +++ b/JavaScriptCore/wtf/url/src/URLComponent.h @@ -0,0 +1,71 @@ +// Copyright 2010, Google 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: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef URLComponent_h +#define URLComponent_h + +namespace WTF { + +// Represents a substring for URL parsing. +class URLComponent { +public: + URLComponent() : m_begin(0), m_length(-1) { } + URLComponent(int begin, int length) : m_begin(begin), m_length(length) { } + + // Returns true if this component is valid, meaning the length is given. Even + // valid components may be empty to record the fact that they exist. + bool isValid() const { return m_length != -1; } + + // Returns true if the given component is specified on false, the component + // is either empty or invalid. + bool isNonempty() const { return m_length > 0; } + + void reset() + { + m_begin = 0; + m_length = -1; + } + + bool operator==(const URLComponent& other) const { return m_begin == other.m_begin && m_length == other.m_length; } + + int begin() const { return m_begin; } + void setBegin(int begin) { m_begin = begin; } + + int length() const { return m_length; } + void setLength(int length) { m_length = length; } + + int end() const { return m_begin + m_length; } + +private: + int m_begin; // Byte offset in the string of this component. + int m_length; // Will be -1 if the component is unspecified. +}; + +} // namespace WTF + +#endif // URLComponent_h diff --git a/JavaScriptCore/wtf/url/src/URLSegments.cpp b/JavaScriptCore/wtf/url/src/URLSegments.cpp new file mode 100644 index 0000000..bb9542f --- /dev/null +++ b/JavaScriptCore/wtf/url/src/URLSegments.cpp @@ -0,0 +1,110 @@ +/* Based on nsURLParsers.cc from Mozilla + * ------------------------------------- + * Copyright (C) 1998 Netscape Communications Corporation. + * + * Other contributors: + * Darin Fisher (original author) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Alternatively, the contents of this file may be used under the terms + * of either the Mozilla Public License Version 1.1, found at + * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public + * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html + * (the "GPL"), in which case the provisions of the MPL or the GPL are + * applicable instead of those above. If you wish to allow use of your + * version of this file only under the terms of one of those two + * licenses (the MPL or the GPL) and not to allow others to use your + * version of this file under the LGPL, indicate your decision by + * deletingthe provisions above and replace them with the notice and + * other provisions required by the MPL or the GPL, as the case may be. + * If you do not delete the provisions above, a recipient may use your + * version of this file under any of the LGPL, the MPL or the GPL. + */ + +#include "config.h" +#include "URLSegments.h" + +namespace WTF { + +int URLSegments::length() const +{ + if (fragment.isValid()) + return fragment.end(); + return charactersBefore(Fragment, false); +} + +int URLSegments::charactersBefore(ComponentType type, bool includeDelimiter) const +{ + if (type == Scheme) + return scheme.begin(); + + int current = 0; + if (scheme.isValid()) + current = scheme.end() + 1; // Advance over the ':' at the end of the scheme. + + if (username.isValid()) { + if (type <= Username) + return username.begin(); + current = username.end() + 1; // Advance over the '@' or ':' at the end. + } + + if (password.isValid()) { + if (type <= Password) + return password.begin(); + current = password.end() + 1; // Advance over the '@' at the end. + } + + if (host.isValid()) { + if (type <= Host) + return host.begin(); + current = host.end(); + } + + if (port.isValid()) { + if (type < Port || (type == Port && includeDelimiter)) + return port.begin() - 1; // Back over delimiter. + if (type == Port) + return port.begin(); // Don't want delimiter counted. + current = port.end(); + } + + if (path.isValid()) { + if (type <= Path) + return path.begin(); + current = path.end(); + } + + if (query.isValid()) { + if (type < Query || (type == Query && includeDelimiter)) + return query.begin() - 1; // Back over delimiter. + if (type == Query) + return query.begin(); // Don't want delimiter counted. + current = query.end(); + } + + if (fragment.isValid()) { + if (type == Fragment && !includeDelimiter) + return fragment.begin(); // Back over delimiter. + + // When there is a fragment and we get here, the component we wanted was before + // this and not found, so we always know the beginning of the fragment is right. + return fragment.begin() - 1; // Don't want delimiter counted. + } + + return current; +} + +} // namespace WTF diff --git a/JavaScriptCore/wtf/url/src/URLSegments.h b/JavaScriptCore/wtf/url/src/URLSegments.h new file mode 100644 index 0000000..436c7fe --- /dev/null +++ b/JavaScriptCore/wtf/url/src/URLSegments.h @@ -0,0 +1,105 @@ +// Copyright 2007, Google 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: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef URLSegments_h +#define URLSegments_h + +#include "URLComponent.h" + +namespace WTF { + +// A structure that holds the identified parts of an input URL. This structure +// does NOT store the URL itself. The caller will have to store the URL text +// and its corresponding Parsed structure separately. +class URLSegments { +public: + // Identifies different components. + enum ComponentType { + Scheme, + Username, + Password, + Host, + Port, + Path, + Query, + Fragment, + }; + + URLSegments() { } + + // Returns the length of the URL (the end of the last component). + // + // Note that for some invalid, non-canonical URLs, this may not be the length + // of the string. For example "http://": the parsed structure will only + // contain an entry for the four-character scheme, and it doesn't know about + // the "://". For all other last-components, it will return the real length. + int length() const; + + // Returns the number of characters before the given component if it exists, + // or where the component would be if it did exist. This will return the + // string length if the component would be appended to the end. + // + // Note that this can get a little funny for the port, query, and fragment + // components which have a delimiter that is not counted as part of the + // component. The |includeDelimiter| flag controls if you want this counted + // as part of the component or not when the component exists. + // + // This example shows the difference between the two flags for two of these + // delimited components that is present (the port and query) and one that + // isn't (the reference). The components that this flag affects are marked + // with a *. + // 0 1 2 + // 012345678901234567890 + // Example input: http://foo:80/?query + // include_delim=true, ...=false ("<-" indicates different) + // Scheme: 0 0 + // Username: 5 5 + // Password: 5 5 + // Host: 7 7 + // *Port: 10 11 <- + // Path: 13 13 + // *Query: 14 15 <- + // *Fragment: 20 20 + // + int charactersBefore(ComponentType, bool includeDelimiter) const; + + // Each component excludes the related delimiters and has a length of -1 + // if that component is absent but 0 if the component exists but is empty. + URLComponent scheme; + URLComponent username; + URLComponent password; + URLComponent host; + URLComponent port; + URLComponent path; + URLComponent query; + URLComponent fragment; +}; + +} // namespace WTF + +#endif // URLSegments_h diff --git a/JavaScriptCore/wtf/url/wtfurl.gyp b/JavaScriptCore/wtf/url/wtfurl.gyp new file mode 100644 index 0000000..f254ae4 --- /dev/null +++ b/JavaScriptCore/wtf/url/wtfurl.gyp @@ -0,0 +1,58 @@ +# Copyright (C) 2009 Google 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: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +{ + 'variables': { + 'chromium_code': 1, + }, + 'targets': [ + { + 'target_name': 'wtfurl', + 'type': '<(library)', + 'msvs_guid': 'EF5E94AB-B646-4E5B-A058-52EF07B8351C', + 'dependencies': [ + ], + 'sources': [ + 'src/URLComponent.h', + 'src/URLSegments.cpp', + 'src/URLSegments.h', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + 'src', + ], + }, + }, + ], +} + +# Local Variables: +# tab-width:2 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=2 shiftwidth=2: diff --git a/JavaScriptCore/wtf/win/MainThreadWin.cpp b/JavaScriptCore/wtf/win/MainThreadWin.cpp index ee70b59..ee3a273 100644 --- a/JavaScriptCore/wtf/win/MainThreadWin.cpp +++ b/JavaScriptCore/wtf/win/MainThreadWin.cpp @@ -77,6 +77,8 @@ void initializeMainThreadPlatform() threadingWindowHandle = CreateWindow(kThreadingWindowClassName, 0, 0, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, hWndParent, 0, 0, 0); threadingFiredMessage = RegisterWindowMessage(L"com.apple.WebKit.MainThreadFired"); + + initializeCurrentThreadInternal("Main Thread"); } void scheduleDispatchFunctionsOnMainThread() diff --git a/JavaScriptCore/wtf/OwnPtrWin.cpp b/JavaScriptCore/wtf/win/OwnPtrWin.cpp index 67a32ff..67a32ff 100644 --- a/JavaScriptCore/wtf/OwnPtrWin.cpp +++ b/JavaScriptCore/wtf/win/OwnPtrWin.cpp diff --git a/JavaScriptCore/wtf/wx/MainThreadWx.cpp b/JavaScriptCore/wtf/wx/MainThreadWx.cpp index bcd5f05..e1d15c9 100644 --- a/JavaScriptCore/wtf/wx/MainThreadWx.cpp +++ b/JavaScriptCore/wtf/wx/MainThreadWx.cpp @@ -29,6 +29,29 @@ #include "config.h" #include "MainThread.h" +#include <wx/defs.h> +#include <wx/app.h> +#include <wx/event.h> + +const wxEventType wxEVT_CALL_AFTER = wxNewEventType(); + +class wxCallAfter : public wxEvtHandler +{ +public: + wxCallAfter() + : wxEvtHandler() + { + wxTheApp->Connect(-1, -1, wxEVT_CALL_AFTER, wxCommandEventHandler(wxCallAfter::OnCallback)); + wxCommandEvent event(wxEVT_CALL_AFTER); + wxPostEvent(wxTheApp, event); + } + + void OnCallback(wxCommandEvent& event) + { + WTF::dispatchFunctionsFromMainThread(); + } +}; + namespace WTF { void initializeMainThreadPlatform() @@ -37,6 +60,7 @@ void initializeMainThreadPlatform() void scheduleDispatchFunctionsOnMainThread() { + wxCallAfter(); } } // namespace WTF |