diff options
author | Kristian Monsen <kristianm@google.com> | 2010-09-08 12:18:00 +0100 |
---|---|---|
committer | Kristian Monsen <kristianm@google.com> | 2010-09-11 12:08:58 +0100 |
commit | 5ddde30071f639962dd557c453f2ad01f8f0fd00 (patch) | |
tree | 775803c4ab35af50aa5f5472cd1fb95fe9d5152d /JavaScriptCore | |
parent | 3e63d9b33b753ca86d0765d1b3d711114ba9e34f (diff) | |
download | external_webkit-5ddde30071f639962dd557c453f2ad01f8f0fd00.zip external_webkit-5ddde30071f639962dd557c453f2ad01f8f0fd00.tar.gz external_webkit-5ddde30071f639962dd557c453f2ad01f8f0fd00.tar.bz2 |
Merge WebKit at r66666 : Initial merge by git.
Change-Id: I57dedeb49859adc9c539e760f0e749768c66626f
Diffstat (limited to 'JavaScriptCore')
72 files changed, 2026 insertions, 1607 deletions
diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog index fd23733..1cf4ccd 100644 --- a/JavaScriptCore/ChangeLog +++ b/JavaScriptCore/ChangeLog @@ -1,3 +1,579 @@ +2010-09-02 Alexey Proskuryakov <ap@apple.com> + + Reviewed by Oliver Hunt. + + https://bugs.webkit.org/show_bug.cgi?id=43230 + <rdar://problem/8254215> REGRESSION: Memory leak within JSParser::JSParser + + One can't delete a ThreadSpecific object that has data in it. It's not even possible to + enumerate data objects in all threads, much less destroy them from a thread that's destroying + the ThreadSpecific. + + * parser/JSParser.cpp: + (JSC::JSParser::JSParser): + * runtime/JSGlobalData.h: + * wtf/WTFThreadData.cpp: + (WTF::WTFThreadData::WTFThreadData): + * wtf/WTFThreadData.h: + (WTF::WTFThreadData::approximatedStackStart): + Moved stack guard tracking from JSGlobalData to WTFThreadData. + + * wtf/ThreadSpecific.h: Made destructor unimplemented. It's dangerous, and we probably won't + ever face a situation where we'd want to delete a ThreadSpecific object. + +2010-09-01 Gavin Barraclough <barraclough@apple.com> + + Rubber stamped by Oliver Hunt. + + Ecma-262 15.11.1.1 states that if the argument is undefined then an + Error object's message property should be set to the empty string. + + * runtime/ErrorInstance.cpp: + (JSC::ErrorInstance::ErrorInstance): + (JSC::ErrorInstance::create): + * runtime/ErrorInstance.h: + * runtime/ErrorPrototype.cpp: + (JSC::ErrorPrototype::ErrorPrototype): + +2010-08-31 Darin Adler <darin@apple.com> + + Reviewed by Anders Carlsson. + + * wtf/FastMalloc.cpp: + (WTF::TCMalloc_PageHeap::scavenge): Replaced somewhat-quirky code that + mixed types with code that uses size_t. + + * wtf/TCPageMap.h: Removed names of unused arguments to avoid warning. + +2010-08-31 Martin Robinson <mrobinson@igalia.com> + + Reviewed by Gustavo Noronha Silva. + + [GTK] Isolate all GTK+ typedefs into one file + https://bugs.webkit.org/show_bug.cgi?id=44900 + + * GNUmakefile.am: Add GtkTypedefs.h to the source lists. + * wtf/Platform.h: #include GtkTypedefs.h for the GTK+ build. + * wtf/ThreadingPrimitives.h: Remove GTK+ typedefs. + * wtf/gobject/GOwnPtr.h: Ditto. + * wtf/gobject/GRefPtr.h: Ditto. + * wtf/gtk/GtkTypedefs.h: Added. + +2010-08-31 Martin Robinson <mrobinson@igalia.com> + + Reviewed by Gustavo Noronha Silva. + + [GTK] Fix 'make dist' in preparation of the 1.3.3 release + https://bugs.webkit.org/show_bug.cgi?id=44978 + + * GNUmakefile.am: Adding missing headers to the sources list. + +2010-08-31 Chao-ying Fu <fu@mips.com> + + Reviewed by Oliver Hunt. + + Support emit_op_mod() for MIPS + https://bugs.webkit.org/show_bug.cgi?id=42855 + + This patch uses MIPS div instructions for op_mod to improve performance. + + * assembler/MIPSAssembler.h: + (JSC::MIPSAssembler::div): + * jit/JITArithmetic.cpp: + (JSC::JIT::emit_op_mod): + (JSC::JIT::emitSlow_op_mod): + +2010-08-31 Csaba Osztrogonác <ossy@webkit.org> + + Reviewed by Darin Adler. + + Modify ASSERT_UNUSED and UNUSED_PARAM similar to Qt's Q_UNUSED. + https://bugs.webkit.org/show_bug.cgi?id=44870 + + * wtf/Assertions.h: + * wtf/UnusedParam.h: + +2010-08-31 Benjamin Poulain <benjamin.poulain@nokia.com> + + Reviewed by Kenneth Rohde Christiansen. + + JSC TimeoutChecker::didTimeOut overflows on ARM + https://bugs.webkit.org/show_bug.cgi?id=38538 + + Make getCPUTime() return values relative to the first call. + The previous implementation relied on simply on currentTime(), which + return a time since epoch and not a time since the thread started. This + made the return value of getCPUTime() overflow on 32 bits. + + * runtime/TimeoutChecker.cpp: + (JSC::getCPUTime): + +2010-08-30 Mihai Parparita <mihaip@chromium.org> + + Reviewed by Adam Barth. + + HISTORY_ALWAYS_ASYNC should be removed (history should always be async) + https://bugs.webkit.org/show_bug.cgi?id=44315 + + Remove ENABLE_HISTORY_ALWAYS_ASYNC #define. + + * wtf/Platform.h: + +2010-08-30 Chris Rogers <crogers@google.com> + + Reviewed by Kenneth Russell. + + Fix namespace for wtf/Complex.h and wtf/Vector3.h + https://bugs.webkit.org/show_bug.cgi?id=44892 + + * wtf/Complex.h: + * wtf/Vector3.h: + +2010-08-30 Andy Estes <aestes@apple.com> + + Reviewed by Eric Carlson. + + Strings returned by asciiDebug() should be NULL-terminated. + https://bugs.webkit.org/show_bug.cgi?id=44866 + + * wtf/text/WTFString.cpp: + (asciiDebug): + +2010-08-30 Zoltan Herczeg <zherczeg@webkit.org> + + Reviewed by Darin Adler. + + Refactor number parsing in the lexer + https://bugs.webkit.org/show_bug.cgi?id=44104 + + Number parsing was full of gotos, and needed a complete + redesign to remove them (Only one remained). Furthermore + integer arithmetic is empolyed for fast cases (= small + integer numbers). + + * parser/Lexer.cpp: + (JSC::Lexer::parseHex): + (JSC::Lexer::parseOctal): + (JSC::Lexer::parseDecimal): + (JSC::Lexer::parseNumberAfterDecimalPoint): + (JSC::Lexer::parseNumberAfterExponentIndicator): + (JSC::Lexer::lex): + * parser/Lexer.h: + +2010-08-29 Darin Adler <darin@apple.com> + + Fix Qt build. + + * wtf/unicode/glib/UnicodeMacrosFromICU.h: Added U_IS_BMP. + * wtf/unicode/qt4/UnicodeQt4.h: Ditto. + * wtf/unicode/wince/UnicodeWince.h: Ditto. + +2010-08-29 Kwang Yul Seo <skyul@company100.net> + + Reviewed by Kent Tamura. + + [BREWMP] Port vprintf_stderr_common + https://bugs.webkit.org/show_bug.cgi?id=33568 + + Use BREW's DBGPRINTF to output debug messages. + + * wtf/Assertions.cpp: + +2010-08-28 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Oliver Hunt. + + Bug 44830 - In Array's prototype functyions we're incorrectly handing large index values + + We are in places casting doubles to unsigneds, and unsigneds to ints, without always check + that the result is within bounds. This is problematic in the case of double-to-unsigned + conversion because we should be saturating to array length. + + Also, the error return value from Array.splice should be [], not undefined. + + I don't see any security concerns here. These methods are spec'ed in such a way that they + can be applied to non Array objects, so in all cases the (potentially bogus) indices are + being passed to functions that will safely check accesses are within bounds. + + * runtime/ArrayPrototype.cpp: + (JSC::argumentClampedIndexFromStartOrEnd): + (JSC::arrayProtoFuncJoin): + (JSC::arrayProtoFuncConcat): + (JSC::arrayProtoFuncReverse): + (JSC::arrayProtoFuncShift): + (JSC::arrayProtoFuncSlice): + (JSC::arrayProtoFuncSort): + (JSC::arrayProtoFuncSplice): + (JSC::arrayProtoFuncUnShift): + (JSC::arrayProtoFuncFilter): + (JSC::arrayProtoFuncMap): + (JSC::arrayProtoFuncEvery): + (JSC::arrayProtoFuncForEach): + (JSC::arrayProtoFuncSome): + (JSC::arrayProtoFuncReduce): + (JSC::arrayProtoFuncReduceRight): + (JSC::arrayProtoFuncIndexOf): + (JSC::arrayProtoFuncLastIndexOf): + * runtime/JSValue.h: + (JSC::JSValue::toUInt32): + +2010-08-28 Pratik Solanki <psolanki@apple.com> + + Reviewed by Dan Bernstein. + + Add an ENABLE define for purgeable memory support + https://bugs.webkit.org/show_bug.cgi?id=44777 + + * wtf/Platform.h: + +2010-08-27 Kimmo Kinnunen <kimmo.t.kinnunen@nokia.com> + + Reviewed by Kenneth Rohde Christiansen. + + [Qt] NPAPI Plugin metadata should be cached, and loading a plugin should not require loading every plugin + https://bugs.webkit.org/show_bug.cgi?id=43179 + + Add ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE flag to enable persistent + NPAPI Plugin Cache. The flag is enabled by default. + + * wtf/Platform.h: Add ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE + +2010-07-27 Jer Noble <jer.noble@apple.com> + + Reviewed by Eric Carlson. + + Add JavaScript API to allow a page to go fullscreen. + rdar://problem/6867795 + https://bugs.webkit.org/show_bug.cgi?id=43099 + + * wtf/Platform.h: Enable FULLSCREEN_API mode for the Mac (except iOS). + +2010-08-27 Gavin Barraclough <barraclough@apple.com> + + Windows build fix pt 2. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + +2010-08-27 Gavin Barraclough <barraclough@apple.com> + + Windows build fix pt 1. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + +2010-08-27 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Oliver Hunt. + + Bug 44745 - Number.toFixed/toExponential/toPrecision are inaccurate. + + These methods should be using a version of dtoa that can generate results accurate + to the requested precision, whereas our version of dtoa is only currently able to + support producing results sufficiently accurate to distinguish the value from any + other IEEE-754 double precision number. + + This change has no impact on benchmarks we track. + + On microbenchmarks for these functions, this is a slight regression where a high + precision is requested (dtoa now need to iterate further to generate a a greater + number of digits), but with smaller precision values (hopefully more common) this + improves performance, since it reduced the accurate of result dtoa is required, + to produce, and removes the need to pre-round values before calling dtoa. + + * JavaScriptCore.exp: + doubleToStringInJavaScriptFormat renamed to numberToString + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + doubleToStringInJavaScriptFormat renamed to numberToString + + * runtime/UString.cpp: + (JSC::UString::number): + doubleToStringInJavaScriptFormat renamed to numberToString + + * wtf/DecimalNumber.h: + (WTF::DecimalNumber::DecimalNumber): + (WTF::DecimalNumber::toStringDecimal): + (WTF::DecimalNumber::toStringExponential): + Remove all pre-rounding of values, instead call dtoa correctly. + + * wtf/dtoa.cpp: + (WTF::dtoa): + * wtf/dtoa.h: + Reenable support for rounding to specific-figures/decimal-places in dtoa. + Modify to remove unbiased rounding, provide ECMA required away-from-zero. + Rewrite doubleToStringInJavaScriptFormat to use DecimalNumber, rename to + numberToString. + +2010-08-27 Chao-ying Fu <fu@mips.com> + + Reviewed by Oliver Hunt. + + Byte alignment issue on MIPS + https://bugs.webkit.org/show_bug.cgi?id=29415 + + MIPS accesses one byte at a time for now to avoid the help from the + kernel to fix unaligned accesses. + + * wtf/text/AtomicString.cpp: + (WebCore::equal): + * wtf/text/StringHash.h: + (WebCore::StringHash::equal): + +2010-08-27 Xan Lopez <xlopez@igalia.com> + + Reviewed by Tor Arne Vestbø. + + Fix a couple of typos in comment. + + * bytecode/CodeBlock.h: + +2010-08-26 Gavin Barraclough <barraclough@apple.com> + + Windows build fix. + + * wtf/dtoa.cpp: + +2010-08-26 Gavin Barraclough <baraclough@apple.com> + + Reviewed by Sam Weinig. + + Bug 44735 - Clean up dtoa.cpp + Remove unused & unmaintained code paths, reformat code to match + coding standard & use platform #defines from Platform.h directly. + + * wtf/dtoa.cpp: + (WTF::storeInc): + (WTF::multadd): + (WTF::s2b): + (WTF::lo0bits): + (WTF::mult): + (WTF::pow5mult): + (WTF::lshift): + (WTF::diff): + (WTF::ulp): + (WTF::b2d): + (WTF::d2b): + (WTF::ratio): + (WTF::): + (WTF::strtod): + (WTF::quorem): + (WTF::dtoa): + +2010-08-26 Gavin Barraclough <barraclough@apple.com> + + Rubber Stamped by Oliver Hunt. + + Partially revert r65959. The toString changes regressed the v8 tests, + but keep the toFixed/toExponential/toPrecision changes. + + * JavaScriptCore.exp: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * runtime/NumberPrototype.cpp: + * runtime/UString.cpp: + (JSC::UString::number): + * wtf/DecimalNumber.h: + * wtf/dtoa.cpp: + (WTF::append): + (WTF::doubleToStringInJavaScriptFormat): + * wtf/dtoa.h: + * wtf/text/WTFString.cpp: + * wtf/text/WTFString.h: + +2010-08-26 James Robinson <jamesr@chromium.org> + + Reviewed by Darin Fisher. + + [chromium] Remove the USE(GLES2_RENDERING) define and associated code + https://bugs.webkit.org/show_bug.cgi?id=43761 + + Remove WTF_USE_GLES2_RENDERING from the list of defines in chromium, it's unused. + + * wtf/Platform.h: + +2010-08-26 Gavin Barraclough <barraclough@apple.com> + + Rolling out r64608, this regressed performance. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * assembler/ARMAssembler.cpp: + (JSC::ARMAssembler::executableCopy): + * assembler/LinkBuffer.h: + (JSC::LinkBuffer::LinkBuffer): + (JSC::LinkBuffer::~LinkBuffer): + (JSC::LinkBuffer::performFinalization): + * assembler/MIPSAssembler.h: + (JSC::MIPSAssembler::executableCopy): + * assembler/X86Assembler.h: + (JSC::X86Assembler::executableCopy): + * bytecode/StructureStubInfo.h: + (JSC::StructureStubInfo::initGetByIdProto): + (JSC::StructureStubInfo::initGetByIdChain): + (JSC::StructureStubInfo::initGetByIdSelfList): + (JSC::StructureStubInfo::initGetByIdProtoList): + (JSC::StructureStubInfo::initPutByIdTransition): + * jit/ExecutableAllocator.cpp: + (JSC::ExecutablePool::systemAlloc): + * jit/ExecutableAllocator.h: + (JSC::ExecutablePool::create): + (JSC::ExecutableAllocator::ExecutableAllocator): + (JSC::ExecutableAllocator::poolForSize): + (JSC::ExecutablePool::ExecutablePool): + (JSC::ExecutablePool::poolAllocate): + * jit/ExecutableAllocatorFixedVMPool.cpp: + (JSC::FixedVMPoolAllocator::allocInternal): + * jit/JIT.cpp: + (JSC::JIT::privateCompile): + * jit/JIT.h: + (JSC::JIT::compileGetByIdProto): + (JSC::JIT::compileGetByIdSelfList): + (JSC::JIT::compileGetByIdProtoList): + (JSC::JIT::compileGetByIdChainList): + (JSC::JIT::compileGetByIdChain): + (JSC::JIT::compilePutByIdTransition): + (JSC::JIT::compilePatchGetArrayLength): + * jit/JITOpcodes.cpp: + (JSC::JIT::privateCompileCTIMachineTrampolines): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::privateCompileCTIMachineTrampolines): + (JSC::JIT::privateCompileCTINativeCall): + * jit/JITPropertyAccess.cpp: + (JSC::JIT::stringGetByValStubGenerator): + (JSC::JIT::privateCompilePutByIdTransition): + (JSC::JIT::privateCompilePatchGetArrayLength): + (JSC::JIT::privateCompileGetByIdProto): + (JSC::JIT::privateCompileGetByIdSelfList): + (JSC::JIT::privateCompileGetByIdProtoList): + (JSC::JIT::privateCompileGetByIdChainList): + (JSC::JIT::privateCompileGetByIdChain): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::stringGetByValStubGenerator): + (JSC::JIT::privateCompilePutByIdTransition): + (JSC::JIT::privateCompilePatchGetArrayLength): + (JSC::JIT::privateCompileGetByIdProto): + (JSC::JIT::privateCompileGetByIdSelfList): + (JSC::JIT::privateCompileGetByIdProtoList): + (JSC::JIT::privateCompileGetByIdChainList): + (JSC::JIT::privateCompileGetByIdChain): + * jit/JITStubs.cpp: + (JSC::JITThunks::tryCachePutByID): + (JSC::JITThunks::tryCacheGetByID): + (JSC::DEFINE_STUB_FUNCTION): + (JSC::getPolymorphicAccessStructureListSlot): + * jit/JITStubs.h: + * jit/SpecializedThunkJIT.h: + (JSC::SpecializedThunkJIT::finalize): + * runtime/ExceptionHelpers.cpp: + * runtime/ExceptionHelpers.h: + * runtime/Executable.cpp: + (JSC::EvalExecutable::compileInternal): + (JSC::ProgramExecutable::compileInternal): + (JSC::FunctionExecutable::compileForCallInternal): + (JSC::FunctionExecutable::compileForConstructInternal): + (JSC::FunctionExecutable::reparseExceptionInfo): + (JSC::EvalExecutable::reparseExceptionInfo): + * yarr/RegexJIT.cpp: + (JSC::Yarr::RegexGenerator::compile): + +2010-08-26 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Brady Eidson. + + Bug 44655 - Add debug only convenience methods to obtain a Vector<char> from a String/StringImpl. + + * wtf/text/WTFString.cpp: + (asciiDebug): + Return a Vector<char> containing the contents of a string as ASCII. + +2010-08-26 Sam Weinig <sam@webkit.org> + + Reviewed by Darin Adler. + + Add PassOwnArrayPtr + https://bugs.webkit.org/show_bug.cgi?id=44627 + + * GNUmakefile.am: + * JavaScriptCore.vcproj/WTF/WTF.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + Add the new files. + + * wtf/Forward.h: + Forward declare PassOwnArrayPtr. + + * wtf/OwnArrayPtr.h: + Mimic the OwnPtr interface. + + * wtf/OwnArrayPtrCommon.h: Added. + (WTF::deleteOwnedArrayPtr): + Move delete function here so it can be shared by OwnArrayPtr and + PassOwnArrayPtr. + + * wtf/PassOwnArrayPtr.h: Added. + Mimic the PassOwnPtr interface. + +2010-08-26 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + [JSC] JavaScript parsing error when loading Equifax web page + https://bugs.webkit.org/show_bug.cgi?id=42900 + + '-->' is ostensibly only meant to occur when there is only + whitespace preceeding it on the line. However firefox treats + multiline comments as a space character, so they are allowed. + One side effect of the firefox model is that any line terminators + inside the multiline comment are ignored, so + + foo/* + */--> + + is treated as + + foo --> + + and so '-->' will not be a comment in this case. Happily this simply + means that to fix this issue all we need to do is stop updating + m_atLineStart when handling multiline comments. + + * parser/Lexer.cpp: + (JSC::Lexer::lex): + +2010-08-25 Oliver Hunt <oliver@apple.com> + + Reviewed by Geoffrey Garen. + + Improve overflow handling in StringImpl::Replace + https://bugs.webkit.org/show_bug.cgi?id=42502 + <rdar://problem/8203794> + + Harden StringImpl::replace against overflow -- I can't see how this + could be abused, but it's better to be safe than sorry. + + * wtf/text/StringImpl.cpp: + (WTF::StringImpl::replace): + +2010-08-26 Martin Robinson <mrobinson@igalia.com> + + Reviewed by Xan Lopez. + + [GTK] The GNUmakefile.am files contain a myriad of confusing preprocessor and compiler flag definitions + https://bugs.webkit.org/show_bug.cgi?id=44624 + + Clean up GNUmakefile.am. + + * GNUmakefile.am: Alphabetize the include order in javascriptcore_cppflags. Move + a couple include lines from the top-level GNUmakefile.am. + +2010-08-25 Xan Lopez <xlopez@igalia.com> + + Reviewed by Kent Tamura. + + Local variables 'k' and 'y' in s2b() in dtoa.cpp are computed but not used + https://bugs.webkit.org/show_bug.cgi?id=29259 + + Remove unused code in dtoa.cpp, spotted by Wan-Teh Chang. + + * wtf/dtoa.cpp: + (WTF::s2b): + 2010-08-25 Kwang Yul Seo <skyul@company100.net> Reviewed by Kevin Ollivier. diff --git a/JavaScriptCore/Configurations/Version.xcconfig b/JavaScriptCore/Configurations/Version.xcconfig index 811d9c4..29f35ef 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 = 534; -MINOR_VERSION = 6; +MINOR_VERSION = 7; TINY_VERSION = 0; FULL_VERSION = $(MAJOR_VERSION).$(MINOR_VERSION); diff --git a/JavaScriptCore/GNUmakefile.am b/JavaScriptCore/GNUmakefile.am index ecd7ffe..b4c658e 100644 --- a/JavaScriptCore/GNUmakefile.am +++ b/JavaScriptCore/GNUmakefile.am @@ -1,24 +1,28 @@ javascriptcore_cppflags += \ -I$(srcdir)/JavaScriptCore \ -I$(srcdir)/JavaScriptCore/API \ - -I$(srcdir)/JavaScriptCore/ForwardingHeaders \ - -I$(srcdir)/JavaScriptCore/interpreter \ + -I$(srcdir)/JavaScriptCore/assembler \ -I$(srcdir)/JavaScriptCore/bytecode \ -I$(srcdir)/JavaScriptCore/bytecompiler \ -I$(srcdir)/JavaScriptCore/debugger \ + -I$(srcdir)/JavaScriptCore/ForwardingHeaders \ + -I$(srcdir)/JavaScriptCore/interpreter \ + -I$(srcdir)/JavaScriptCore/jit \ -I$(srcdir)/JavaScriptCore/jit \ + -I$(srcdir)/JavaScriptCore/parser \ -I$(srcdir)/JavaScriptCore/pcre \ -I$(srcdir)/JavaScriptCore/profiler \ -I$(srcdir)/JavaScriptCore/runtime \ - -I$(srcdir)/JavaScriptCore/jit \ - -I$(srcdir)/JavaScriptCore/assembler \ -I$(srcdir)/JavaScriptCore/wtf \ + -I$(srcdir)/JavaScriptCore/wtf \ + -I$(srcdir)/JavaScriptCore/wtf/gobject \ + -I$(srcdir)/JavaScriptCore/wtf/gtk \ -I$(srcdir)/JavaScriptCore/wtf/text \ -I$(srcdir)/JavaScriptCore/wtf/unicode \ -I$(srcdir)/JavaScriptCore/yarr \ -I$(top_builddir)/JavaScriptCore \ - -I$(top_builddir)/JavaScriptCore/pcre \ -I$(top_builddir)/JavaScriptCore/parser \ + -I$(top_builddir)/JavaScriptCore/pcre \ -I$(top_builddir)/JavaScriptCore/runtime javascriptcore_h_api += \ @@ -385,6 +389,7 @@ javascriptcore_sources += \ JavaScriptCore/runtime/SmallStrings.cpp \ JavaScriptCore/runtime/SmallStrings.h \ JavaScriptCore/runtime/StringBuilder.h \ + JavaScriptCore/runtime/StringConcatenate.h \ JavaScriptCore/runtime/StringConstructor.cpp \ JavaScriptCore/runtime/StringConstructor.h \ JavaScriptCore/runtime/StringObject.cpp \ @@ -404,7 +409,6 @@ javascriptcore_sources += \ JavaScriptCore/runtime/Tracing.h \ JavaScriptCore/runtime/UString.cpp \ JavaScriptCore/runtime/UString.h \ - JavaScriptCore/runtime/UStringImpl.h \ JavaScriptCore/runtime/WeakGCMap.h \ JavaScriptCore/runtime/WeakGCPtr.h \ JavaScriptCore/runtime/WeakRandom.h \ @@ -423,6 +427,7 @@ javascriptcore_sources += \ JavaScriptCore/wtf/CurrentTime.h \ JavaScriptCore/wtf/DateMath.cpp \ JavaScriptCore/wtf/DateMath.h \ + JavaScriptCore/wtf/DecimalNumber.h \ JavaScriptCore/wtf/Deque.h \ JavaScriptCore/wtf/DisallowCType.h \ JavaScriptCore/wtf/dtoa.cpp \ @@ -437,6 +442,7 @@ javascriptcore_sources += \ JavaScriptCore/wtf/gobject/GOwnPtr.h \ JavaScriptCore/wtf/gobject/GRefPtr.cpp \ JavaScriptCore/wtf/gobject/GRefPtr.h \ + JavaScriptCore/wtf/gtk/GtkTypedefs.h \ JavaScriptCore/wtf/gtk/MainThreadGtk.cpp \ JavaScriptCore/wtf/gtk/ThreadingGtk.cpp \ JavaScriptCore/wtf/HashCountedSet.h \ @@ -461,11 +467,13 @@ javascriptcore_sources += \ JavaScriptCore/wtf/NotFound.h \ JavaScriptCore/wtf/OwnArrayPtr.h \ JavaScriptCore/wtf/OwnFastMallocPtr.h \ + JavaScriptCore/wtf/OwnArrayPtrCommon.h \ JavaScriptCore/wtf/OwnPtrCommon.h \ JavaScriptCore/wtf/OwnPtr.h \ JavaScriptCore/wtf/PageAllocation.cpp \ JavaScriptCore/wtf/PageAllocation.h \ JavaScriptCore/wtf/PageReservation.h \ + JavaScriptCore/wtf/PassOwnArrayPtr.h \ JavaScriptCore/wtf/PassOwnPtr.h \ JavaScriptCore/wtf/PassRefPtr.h \ JavaScriptCore/wtf/Platform.h \ diff --git a/JavaScriptCore/JavaScriptCore.exp b/JavaScriptCore/JavaScriptCore.exp index 4542730..30f5aa8 100644 --- a/JavaScriptCore/JavaScriptCore.exp +++ b/JavaScriptCore/JavaScriptCore.exp @@ -377,7 +377,7 @@ __ZN3WTF13currentThreadEv __ZN3WTF13tryFastCallocEmm __ZN3WTF13tryFastMallocEm __ZN3WTF14fastMallocSizeEPKv -__ZN3WTF14numberToStringEdRA96_t +__ZN3WTF14numberToStringEdPt __ZN3WTF15ThreadCondition4waitERNS_5MutexE __ZN3WTF15ThreadCondition6signalEv __ZN3WTF15ThreadCondition9broadcastEv diff --git a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def index eac99b9..cb9c820 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def +++ b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def @@ -126,7 +126,6 @@ EXPORTS ?detach@Debugger@JSC@@UAEXPAVJSGlobalObject@2@@Z ?detachThread@WTF@@YAXI@Z ?didTimeOut@TimeoutChecker@JSC@@QAE_NPAVExecState@2@@Z - ?dtoa@WTF@@YAXQADNHPAH1PAPAD@Z ?dumpSampleData@JSGlobalData@JSC@@QAEXPAVExecState@2@@Z ?empty@StringImpl@WTF@@SAPAV12@XZ ?enumerable@PropertyDescriptor@JSC@@QBE_NXZ @@ -149,7 +148,7 @@ EXPORTS ?number@UString@JSC@@SA?AV12@H@Z ?number@UString@JSC@@SA?AV12@I@Z ?number@UString@JSC@@SA?AV12@N@Z - ?numberToString@WTF@@YAINAAY0GA@_W@Z + ?numberToString@WTF@@YAINQA_W@Z ?functionGetter@PropertySlot@JSC@@ABE?AVJSValue@2@PAVExecState@2@@Z ?functionName@DebuggerCallFrame@JSC@@QBEPBVUString@2@XZ ?get@Structure@JSC@@QAEIPBVStringImpl@WTF@@AAIAAPAVJSCell@2@@Z diff --git a/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj b/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj index aedc122..7bb2e2a 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj +++ b/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj @@ -425,6 +425,10 @@ >
</File>
<File
+ RelativePath="..\..\wtf\OwnArrayPtrCommon.h"
+ >
+ </File>
+ <File
RelativePath="..\..\wtf\OwnPtrCommon.h"
>
</File>
@@ -441,6 +445,10 @@ >
</File>
<File
+ RelativePath="..\..\wtf\PassOwnArrayPtr.h"
+ >
+ </File>
+ <File
RelativePath="..\..\wtf\PassOwnPtr.h"
>
</File>
diff --git a/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj index e11672c..f9a547e 100644 --- a/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj +++ b/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj @@ -509,6 +509,8 @@ BCDE3AB80E6C82F5001453A7 /* Structure.h in Headers */ = {isa = PBXBuildFile; fileRef = BCDE3AB10E6C82CF001453A7 /* Structure.h */; settings = {ATTRIBUTES = (Private, ); }; }; BCDE3B430E6C832D001453A7 /* Structure.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCDE3AB00E6C82CF001453A7 /* Structure.cpp */; }; BCF605140E203EF800B9A64D /* ArgList.h in Headers */ = {isa = PBXBuildFile; fileRef = BCF605120E203EF800B9A64D /* ArgList.h */; settings = {ATTRIBUTES = (Private, ); }; }; + BCFBE696122560E800309E9D /* PassOwnArrayPtr.h in Headers */ = {isa = PBXBuildFile; fileRef = BCFBE695122560E800309E9D /* PassOwnArrayPtr.h */; settings = {ATTRIBUTES = (Private, ); }; }; + BCFBE698122561D200309E9D /* OwnArrayPtrCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = BCFBE697122561D200309E9D /* OwnArrayPtrCommon.h */; settings = {ATTRIBUTES = (Private, ); }; }; BCFD8C920EEB2EE700283848 /* JumpTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCFD8C900EEB2EE700283848 /* JumpTable.cpp */; }; BCFD8C930EEB2EE700283848 /* JumpTable.h in Headers */ = {isa = PBXBuildFile; fileRef = BCFD8C910EEB2EE700283848 /* JumpTable.h */; }; C0A272630E50A06300E96E15 /* NotFound.h in Headers */ = {isa = PBXBuildFile; fileRef = C0A2723F0E509F1E00E96E15 /* NotFound.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -1063,6 +1065,8 @@ BCF605110E203EF800B9A64D /* ArgList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArgList.cpp; sourceTree = "<group>"; }; BCF605120E203EF800B9A64D /* ArgList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArgList.h; sourceTree = "<group>"; }; BCF6553B0A2048DE0038A194 /* MathExtras.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MathExtras.h; sourceTree = "<group>"; }; + BCFBE695122560E800309E9D /* PassOwnArrayPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PassOwnArrayPtr.h; sourceTree = "<group>"; }; + BCFBE697122561D200309E9D /* OwnArrayPtrCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OwnArrayPtrCommon.h; sourceTree = "<group>"; }; BCFD8C900EEB2EE700283848 /* JumpTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JumpTable.cpp; sourceTree = "<group>"; }; BCFD8C910EEB2EE700283848 /* JumpTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JumpTable.h; sourceTree = "<group>"; }; C0A2723F0E509F1E00E96E15 /* NotFound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NotFound.h; sourceTree = "<group>"; }; @@ -1472,12 +1476,14 @@ 9303F5690991190000AD71B8 /* Noncopyable.h */, C0A2723F0E509F1E00E96E15 /* NotFound.h */, 9303F5A409911A5800AD71B8 /* OwnArrayPtr.h */, + BCFBE697122561D200309E9D /* OwnArrayPtrCommon.h */, 0BDFFAD10FC616EC00D69EF4 /* OwnFastMallocPtr.h */, 9303F567099118FA00AD71B8 /* OwnPtr.h */, 440B7AED0FAF7FCB0073323E /* OwnPtrCommon.h */, 8627E5E911F1281900A313B5 /* PageAllocation.cpp */, 8627E5EA11F1281900A313B5 /* PageAllocation.h */, 8690231412092D5C00630AF9 /* PageReservation.h */, + BCFBE695122560E800309E9D /* PassOwnArrayPtr.h */, 44DD48520FAEA85000D6B4EB /* PassOwnPtr.h */, 6580F795094070560082C219 /* PassRefPtr.h */, 65D6D87E09B5A32E0002E4D7 /* Platform.h */, @@ -2237,6 +2243,8 @@ 86F38859121130CA007A7CE3 /* AtomicStringHash.h in Headers */, 86B6DA0212132B9A000D316F /* StringConcatenate.h in Headers */, 862AF4B612239C7B0024E5B8 /* DecimalNumber.h in Headers */, + BCFBE696122560E800309E9D /* PassOwnArrayPtr.h in Headers */, + BCFBE698122561D200309E9D /* OwnArrayPtrCommon.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/JavaScriptCore/assembler/ARMAssembler.cpp b/JavaScriptCore/assembler/ARMAssembler.cpp index 42a6402..86a1c14 100644 --- a/JavaScriptCore/assembler/ARMAssembler.cpp +++ b/JavaScriptCore/assembler/ARMAssembler.cpp @@ -351,8 +351,6 @@ void* ARMAssembler::executableCopy(ExecutablePool* allocator) bkpt(0); char* data = reinterpret_cast<char*>(m_buffer.executableCopy(allocator)); - if (!data) - return 0; for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) { // The last bit is set if the constant must be placed on constant pool. diff --git a/JavaScriptCore/assembler/LinkBuffer.h b/JavaScriptCore/assembler/LinkBuffer.h index 624d1cc..408deb0 100644 --- a/JavaScriptCore/assembler/LinkBuffer.h +++ b/JavaScriptCore/assembler/LinkBuffer.h @@ -62,12 +62,6 @@ class LinkBuffer : public Noncopyable { typedef MacroAssembler::JumpLinkType JumpLinkType; #endif - enum LinkBufferState { - StateInit, - StateChecked, - StateFinalized, - }; - public: // Note: Initialization sequence is significant, since executablePool is a PassRefPtr. // First, executablePool is copied into m_executablePool, then the initialization of @@ -79,7 +73,7 @@ public: , m_code(0) , m_assembler(masm) #ifndef NDEBUG - , m_state(StateInit) + , m_completed(false) #endif { linkCode(linkOffset); @@ -87,18 +81,7 @@ public: ~LinkBuffer() { - ASSERT(m_state == StateFinalized); - } - - // After constructing a link buffer, a client must call allocationSuccessful() to check alloc did not return 0. - bool allocationSuccessful() - { -#ifndef NDEBUG - ASSERT(m_state == StateInit); - m_state = StateChecked; -#endif - - return m_code; + ASSERT(m_completed); } // These methods are used to link or set values at code generation time. @@ -284,8 +267,8 @@ private: void performFinalization() { #ifndef NDEBUG - ASSERT(m_state == StateChecked); - m_state = StateFinalized; + ASSERT(!m_completed); + m_completed = true; #endif ExecutableAllocator::makeExecutable(code(), m_size); @@ -297,7 +280,7 @@ private: void* m_code; MacroAssembler* m_assembler; #ifndef NDEBUG - LinkBufferState m_state; + bool m_completed; #endif }; diff --git a/JavaScriptCore/assembler/MIPSAssembler.h b/JavaScriptCore/assembler/MIPSAssembler.h index a19c7a6..bc77f8d 100644 --- a/JavaScriptCore/assembler/MIPSAssembler.h +++ b/JavaScriptCore/assembler/MIPSAssembler.h @@ -287,6 +287,11 @@ public: emitInst(0x00000018 | (rs << OP_SH_RS) | (rt << OP_SH_RT)); } + void div(RegisterID rs, RegisterID rt) + { + emitInst(0x0000001a | (rs << OP_SH_RS) | (rt << OP_SH_RT)); + } + void mfhi(RegisterID rd) { emitInst(0x00000010 | (rd << OP_SH_RD)); @@ -689,8 +694,10 @@ public: void* executableCopy(ExecutablePool* allocator) { void *result = m_buffer.executableCopy(allocator); - if (result) - relocateJumps(m_buffer.data(), result); + if (!result) + return 0; + + relocateJumps(m_buffer.data(), result); return result; } diff --git a/JavaScriptCore/assembler/X86Assembler.h b/JavaScriptCore/assembler/X86Assembler.h index a1fae0c..20d72f5 100644 --- a/JavaScriptCore/assembler/X86Assembler.h +++ b/JavaScriptCore/assembler/X86Assembler.h @@ -1626,7 +1626,9 @@ public: void* executableCopy(ExecutablePool* allocator) { - return m_formatter.executableCopy(allocator); + void* copy = m_formatter.executableCopy(allocator); + ASSERT(copy); + return copy; } private: diff --git a/JavaScriptCore/bytecode/CodeBlock.h b/JavaScriptCore/bytecode/CodeBlock.h index be12254..766ad2a 100644 --- a/JavaScriptCore/bytecode/CodeBlock.h +++ b/JavaScriptCore/bytecode/CodeBlock.h @@ -47,8 +47,8 @@ #include "StructureStubInfo.h" #endif -// Register numbers used in bytecode operations have different meaning accoring to their ranges: -// 0x80000000-0xFFFFFFFF Negative indicies from the CallFrame pointer are entries in the call frame, see RegisterFile.h. +// Register numbers used in bytecode operations have different meaning according to their ranges: +// 0x80000000-0xFFFFFFFF Negative indices from the CallFrame pointer are entries in the call frame, see RegisterFile.h. // 0x00000000-0x3FFFFFFF Forwards indices from the CallFrame pointer are local vars and temporaries with the function's callframe. // 0x40000000-0x7FFFFFFF Positive indices from 0x40000000 specify entries in the constant pool on the CodeBlock. static const int FirstConstantRegisterIndex = 0x40000000; diff --git a/JavaScriptCore/bytecode/StructureStubInfo.h b/JavaScriptCore/bytecode/StructureStubInfo.h index 8578171..8e2c489 100644 --- a/JavaScriptCore/bytecode/StructureStubInfo.h +++ b/JavaScriptCore/bytecode/StructureStubInfo.h @@ -66,7 +66,7 @@ namespace JSC { baseObjectStructure->ref(); } - void initGetByIdProto(Structure* baseObjectStructure, Structure* prototypeStructure, CodeLocationLabel routine) + void initGetByIdProto(Structure* baseObjectStructure, Structure* prototypeStructure) { accessType = access_get_by_id_proto; @@ -75,11 +75,9 @@ namespace JSC { u.getByIdProto.prototypeStructure = prototypeStructure; prototypeStructure->ref(); - - stubRoutine = routine; } - void initGetByIdChain(Structure* baseObjectStructure, StructureChain* chain, CodeLocationLabel routine) + void initGetByIdChain(Structure* baseObjectStructure, StructureChain* chain) { accessType = access_get_by_id_chain; @@ -88,33 +86,27 @@ namespace JSC { u.getByIdChain.chain = chain; chain->ref(); - - stubRoutine = routine; } - void initGetByIdSelfList(PolymorphicAccessStructureList* structureList) + void initGetByIdSelfList(PolymorphicAccessStructureList* structureList, int listSize) { accessType = access_get_by_id_self_list; u.getByIdProtoList.structureList = structureList; - u.getByIdProtoList.listSize = 1; - - stubRoutine = CodeLocationLabel(); + u.getByIdProtoList.listSize = listSize; } - void initGetByIdProtoList(PolymorphicAccessStructureList* structureList) + void initGetByIdProtoList(PolymorphicAccessStructureList* structureList, int listSize) { accessType = access_get_by_id_proto_list; u.getByIdProtoList.structureList = structureList; - u.getByIdProtoList.listSize = 1; - - stubRoutine = CodeLocationLabel(); + u.getByIdProtoList.listSize = listSize; } // PutById* - void initPutByIdTransition(Structure* previousStructure, Structure* structure, StructureChain* chain, CodeLocationLabel routine) + void initPutByIdTransition(Structure* previousStructure, Structure* structure, StructureChain* chain) { accessType = access_put_by_id_transition; @@ -126,8 +118,6 @@ namespace JSC { u.putByIdTransition.chain = chain; chain->ref(); - - stubRoutine = routine; } void initPutByIdReplace(Structure* baseObjectStructure) diff --git a/JavaScriptCore/jit/ExecutableAllocator.cpp b/JavaScriptCore/jit/ExecutableAllocator.cpp index e3525f5..4800613 100644 --- a/JavaScriptCore/jit/ExecutableAllocator.cpp +++ b/JavaScriptCore/jit/ExecutableAllocator.cpp @@ -52,6 +52,8 @@ void ExecutableAllocator::intializePageSize() ExecutablePool::Allocation ExecutablePool::systemAlloc(size_t size) { PageAllocation allocation = PageAllocation::allocate(size, PageAllocation::JSJITCodePages, EXECUTABLE_POOL_WRITABLE, true); + if (!allocation) + CRASH(); return allocation; } diff --git a/JavaScriptCore/jit/ExecutableAllocator.h b/JavaScriptCore/jit/ExecutableAllocator.h index b60d591..576f889 100644 --- a/JavaScriptCore/jit/ExecutableAllocator.h +++ b/JavaScriptCore/jit/ExecutableAllocator.h @@ -107,7 +107,10 @@ public: #endif typedef Vector<Allocation, 2> AllocationList; - static PassRefPtr<ExecutablePool> create(size_t n); + static PassRefPtr<ExecutablePool> create(size_t n) + { + return adoptRef(new ExecutablePool(n)); + } void* alloc(size_t n) { @@ -146,7 +149,7 @@ private: static Allocation systemAlloc(size_t n); static void systemRelease(Allocation& alloc); - ExecutablePool(Allocation&); + ExecutablePool(size_t n); void* poolAllocate(size_t n); @@ -164,11 +167,8 @@ public: { if (!pageSize) intializePageSize(); - if (isValid()) { + if (isValid()) m_smallAllocationPool = ExecutablePool::create(JIT_ALLOCATOR_LARGE_ALLOC_SIZE); - if (!m_smallAllocationPool) - CRASH(); - } #if !ENABLE(INTERPRETER) else CRASH(); @@ -185,7 +185,7 @@ public: return m_smallAllocationPool; // If the request is large, we just provide a unshared allocator - if (n > JIT_ALLOCATOR_LARGE_ALLOC_SIZE) + if (n > JIT_ALLOCATOR_LARGE_ALLOC_SIZE) return ExecutablePool::create(n); // Create a new allocator @@ -308,20 +308,15 @@ private: static void intializePageSize(); }; -inline PassRefPtr<ExecutablePool> ExecutablePool::create(size_t n) - { - Allocation mem = systemAlloc(roundUpAllocationSize(n, JIT_ALLOCATOR_PAGE_SIZE)); - if (!mem) - return 0; - return adoptRef(new ExecutablePool(mem)); - } - -inline ExecutablePool::ExecutablePool(Allocation& mem) +inline ExecutablePool::ExecutablePool(size_t n) { - ASSERT(!!mem); + size_t allocSize = roundUpAllocationSize(n, JIT_ALLOCATOR_PAGE_SIZE); + Allocation mem = systemAlloc(allocSize); m_pools.append(mem); m_freePtr = static_cast<char*>(mem.base()); - m_end = m_freePtr + mem.size(); + if (!m_freePtr) + CRASH(); // Failed to allocate + m_end = m_freePtr + allocSize; } inline void* ExecutablePool::poolAllocate(size_t n) @@ -330,8 +325,8 @@ inline void* ExecutablePool::poolAllocate(size_t n) Allocation result = systemAlloc(allocSize); if (!result.base()) - return 0; // Failed to allocate - + CRASH(); // Failed to allocate + ASSERT(m_end >= m_freePtr); if ((allocSize - n) > static_cast<size_t>(m_end - m_freePtr)) { // Replace allocation pool diff --git a/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp b/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp index f05e919..b34204f 100644 --- a/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp +++ b/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp @@ -360,14 +360,15 @@ private: // Search m_freeList for a suitable sized chunk to allocate memory from. FreeListEntry* entry = m_freeList.search(size, m_freeList.GREATER_EQUAL); - // This is bad news. + // This would be bad news. if (!entry) { // Errk! Lets take a last-ditch desperation attempt at defragmentation... coalesceFreeSpace(); // Did that free up a large enough chunk? entry = m_freeList.search(size, m_freeList.GREATER_EQUAL); + // No?... *BOOM!* if (!entry) - return 0; + CRASH(); } ASSERT(entry->size != m_commonSize); diff --git a/JavaScriptCore/jit/JIT.cpp b/JavaScriptCore/jit/JIT.cpp index cd5944a..4466fbd 100644 --- a/JavaScriptCore/jit/JIT.cpp +++ b/JavaScriptCore/jit/JIT.cpp @@ -509,12 +509,7 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck) ASSERT(m_jmpTable.isEmpty()); - RefPtr<ExecutablePool> executablePool = m_globalData->executableAllocator.poolForSize(m_assembler.size()); - if (!executablePool) - return JITCode(); - LinkBuffer patchBuffer(this, executablePool.release(), m_linkerOffset); - if (!patchBuffer.allocationSuccessful()) - return JITCode(); + LinkBuffer patchBuffer(this, m_globalData->executableAllocator.poolForSize(m_assembler.size()), m_linkerOffset); // Translate vPC offsets into addresses in JIT generated code, for switch tables. for (unsigned i = 0; i < m_switches.size(); ++i) { diff --git a/JavaScriptCore/jit/JIT.h b/JavaScriptCore/jit/JIT.h index 393c771..7c03a47 100644 --- a/JavaScriptCore/jit/JIT.h +++ b/JavaScriptCore/jit/JIT.h @@ -183,38 +183,38 @@ namespace JSC { return JIT(globalData, codeBlock, offsetBase).privateCompile(functionEntryArityCheck); } - static bool compileGetByIdProto(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress) + static void compileGetByIdProto(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress) { JIT jit(globalData, codeBlock); - return jit.privateCompileGetByIdProto(stubInfo, structure, prototypeStructure, ident, slot, cachedOffset, returnAddress, callFrame); + jit.privateCompileGetByIdProto(stubInfo, structure, prototypeStructure, ident, slot, cachedOffset, returnAddress, callFrame); } - static bool compileGetByIdSelfList(JSGlobalData* globalData, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset) + static void compileGetByIdSelfList(JSGlobalData* globalData, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset) { JIT jit(globalData, codeBlock); - return jit.privateCompileGetByIdSelfList(stubInfo, structure, ident, slot, cachedOffset); + jit.privateCompileGetByIdSelfList(stubInfo, polymorphicStructures, currentIndex, structure, ident, slot, cachedOffset); } - static bool compileGetByIdProtoList(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset) + static void compileGetByIdProtoList(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructureList, int currentIndex, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset) { JIT jit(globalData, codeBlock); - return jit.privateCompileGetByIdProtoList(stubInfo, structure, prototypeStructure, ident, slot, cachedOffset, callFrame); + jit.privateCompileGetByIdProtoList(stubInfo, prototypeStructureList, currentIndex, structure, prototypeStructure, ident, slot, cachedOffset, callFrame); } - static bool compileGetByIdChainList(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset) + static void compileGetByIdChainList(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructureList, int currentIndex, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset) { JIT jit(globalData, codeBlock); - return jit.privateCompileGetByIdChainList(stubInfo, structure, chain, count, ident, slot, cachedOffset, callFrame); + jit.privateCompileGetByIdChainList(stubInfo, prototypeStructureList, currentIndex, structure, chain, count, ident, slot, cachedOffset, callFrame); } - static bool compileGetByIdChain(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress) + static void compileGetByIdChain(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress) { JIT jit(globalData, codeBlock); - return jit.privateCompileGetByIdChain(stubInfo, structure, chain, count, ident, slot, cachedOffset, returnAddress, callFrame); + jit.privateCompileGetByIdChain(stubInfo, structure, chain, count, ident, slot, cachedOffset, returnAddress, callFrame); } - static bool compilePutByIdTransition(JSGlobalData* globalData, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct) + static void compilePutByIdTransition(JSGlobalData* globalData, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct) { JIT jit(globalData, codeBlock); - return jit.privateCompilePutByIdTransition(stubInfo, oldStructure, newStructure, cachedOffset, chain, returnAddress, direct); + jit.privateCompilePutByIdTransition(stubInfo, oldStructure, newStructure, cachedOffset, chain, returnAddress, direct); } static void compileCTIMachineTrampolines(JSGlobalData* globalData, RefPtr<ExecutablePool>* executablePool, TrampolineStructure *trampolines) @@ -237,10 +237,10 @@ namespace JSC { static void patchPutByIdReplace(CodeBlock* codeblock, StructureStubInfo*, Structure*, size_t cachedOffset, ReturnAddressPtr returnAddress, bool direct); static void patchMethodCallProto(CodeBlock* codeblock, MethodCallLinkInfo&, JSFunction*, Structure*, JSObject*, ReturnAddressPtr); - static bool compilePatchGetArrayLength(JSGlobalData* globalData, CodeBlock* codeBlock, StructureStubInfo* stubInfo, ReturnAddressPtr returnAddress) + static void compilePatchGetArrayLength(JSGlobalData* globalData, CodeBlock* codeBlock, ReturnAddressPtr returnAddress) { JIT jit(globalData, codeBlock); - return jit.privateCompilePatchGetArrayLength(stubInfo, returnAddress); + return jit.privateCompilePatchGetArrayLength(returnAddress); } static void linkCall(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, CodePtr, CallLinkInfo*, int callerArgCount, JSGlobalData*); @@ -265,17 +265,17 @@ namespace JSC { void privateCompileLinkPass(); void privateCompileSlowCases(); JITCode privateCompile(CodePtr* functionEntryArityCheck); - bool privateCompileGetByIdProto(StructureStubInfo*, Structure*, Structure* prototypeStructure, const Identifier&, const PropertySlot&, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame); - bool privateCompileGetByIdSelfList(StructureStubInfo*, Structure*, const Identifier&, const PropertySlot&, size_t cachedOffset); - bool privateCompileGetByIdProtoList(StructureStubInfo*, Structure*, Structure* prototypeStructure, const Identifier&, const PropertySlot&, size_t cachedOffset, CallFrame* callFrame); - bool privateCompileGetByIdChainList(StructureStubInfo*, Structure*, StructureChain* chain, size_t count, const Identifier&, const PropertySlot&, size_t cachedOffset, CallFrame* callFrame); - bool privateCompileGetByIdChain(StructureStubInfo*, Structure*, StructureChain*, size_t count, const Identifier&, const PropertySlot&, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame); - bool privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure*, Structure*, size_t cachedOffset, StructureChain*, ReturnAddressPtr returnAddress, bool direct); + void privateCompileGetByIdProto(StructureStubInfo*, Structure*, Structure* prototypeStructure, const Identifier&, const PropertySlot&, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame); + void privateCompileGetByIdSelfList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, const Identifier&, const PropertySlot&, size_t cachedOffset); + void privateCompileGetByIdProtoList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, Structure* prototypeStructure, const Identifier&, const PropertySlot&, size_t cachedOffset, CallFrame* callFrame); + void privateCompileGetByIdChainList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, StructureChain* chain, size_t count, const Identifier&, const PropertySlot&, size_t cachedOffset, CallFrame* callFrame); + void privateCompileGetByIdChain(StructureStubInfo*, Structure*, StructureChain*, size_t count, const Identifier&, const PropertySlot&, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame); + void privateCompilePutByIdTransition(StructureStubInfo*, Structure*, Structure*, size_t cachedOffset, StructureChain*, ReturnAddressPtr returnAddress, bool direct); void privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executablePool, JSGlobalData* data, TrampolineStructure *trampolines); Label privateCompileCTINativeCall(JSGlobalData*, bool isConstruct = false); CodePtr privateCompileCTINativeCall(PassRefPtr<ExecutablePool> executablePool, JSGlobalData* data, NativeFunction func); - bool privateCompilePatchGetArrayLength(StructureStubInfo* stubInfo, ReturnAddressPtr returnAddress); + void privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress); void addSlowCase(Jump); void addSlowCase(JumpList); diff --git a/JavaScriptCore/jit/JITArithmetic.cpp b/JavaScriptCore/jit/JITArithmetic.cpp index a9d0bcd..d75f8b5 100644 --- a/JavaScriptCore/jit/JITArithmetic.cpp +++ b/JavaScriptCore/jit/JITArithmetic.cpp @@ -1139,7 +1139,7 @@ void JIT::emitSlow_op_pre_dec(Instruction* currentInstruction, Vector<SlowCaseEn /* ------------------------------ BEGIN: OP_MOD ------------------------------ */ -#if CPU(X86) || CPU(X86_64) +#if CPU(X86) || CPU(X86_64) || CPU(MIPS) void JIT::emit_op_mod(Instruction* currentInstruction) { @@ -1147,21 +1147,34 @@ void JIT::emit_op_mod(Instruction* currentInstruction) unsigned op1 = currentInstruction[2].u.operand; unsigned op2 = currentInstruction[3].u.operand; - emitGetVirtualRegisters(op1, X86Registers::eax, op2, X86Registers::ecx); - emitJumpSlowCaseIfNotImmediateInteger(X86Registers::eax); - emitJumpSlowCaseIfNotImmediateInteger(X86Registers::ecx); +#if CPU(X86) || CPU(X86_64) + // Make sure registers are correct for x86 IDIV instructions. + ASSERT(regT0 == X86Registers::eax); + ASSERT(regT1 == X86Registers::edx); + ASSERT(regT2 == X86Registers::ecx); +#endif + + emitGetVirtualRegisters(op1, regT0, op2, regT2); + emitJumpSlowCaseIfNotImmediateInteger(regT0); + emitJumpSlowCaseIfNotImmediateInteger(regT2); + #if USE(JSVALUE64) - addSlowCase(branchPtr(Equal, X86Registers::ecx, ImmPtr(JSValue::encode(jsNumber(m_globalData, 0))))); + addSlowCase(branchPtr(Equal, regT2, ImmPtr(JSValue::encode(jsNumber(m_globalData, 0))))); m_assembler.cdq(); - m_assembler.idivl_r(X86Registers::ecx); + m_assembler.idivl_r(regT2); #else - emitFastArithDeTagImmediate(X86Registers::eax); - addSlowCase(emitFastArithDeTagImmediateJumpIfZero(X86Registers::ecx)); + emitFastArithDeTagImmediate(regT0); + addSlowCase(emitFastArithDeTagImmediateJumpIfZero(regT2)); +#if CPU(X86) || CPU(X86_64) m_assembler.cdq(); - m_assembler.idivl_r(X86Registers::ecx); - signExtend32ToPtr(X86Registers::edx, X86Registers::edx); + m_assembler.idivl_r(regT2); + signExtend32ToPtr(regT1, regT1); +#elif CPU(MIPS) + m_assembler.div(regT0, regT2); + m_assembler.mfhi(regT1); +#endif #endif - emitFastArithReTagImmediate(X86Registers::edx, X86Registers::eax); + emitFastArithReTagImmediate(regT1, regT0); emitPutVirtualRegister(result); } @@ -1177,18 +1190,18 @@ void JIT::emitSlow_op_mod(Instruction* currentInstruction, Vector<SlowCaseEntry> Jump notImm1 = getSlowCase(iter); Jump notImm2 = getSlowCase(iter); linkSlowCase(iter); - emitFastArithReTagImmediate(X86Registers::eax, X86Registers::eax); - emitFastArithReTagImmediate(X86Registers::ecx, X86Registers::ecx); + emitFastArithReTagImmediate(regT0, regT0); + emitFastArithReTagImmediate(regT2, regT2); notImm1.link(this); notImm2.link(this); #endif JITStubCall stubCall(this, cti_op_mod); - stubCall.addArgument(X86Registers::eax); - stubCall.addArgument(X86Registers::ecx); + stubCall.addArgument(regT0); + stubCall.addArgument(regT2); stubCall.call(result); } -#else // CPU(X86) || CPU(X86_64) +#else // CPU(X86) || CPU(X86_64) || CPU(MIPS) void JIT::emit_op_mod(Instruction* currentInstruction) { diff --git a/JavaScriptCore/jit/JITOpcodes.cpp b/JavaScriptCore/jit/JITOpcodes.cpp index 28ef4ca..2bfba83 100644 --- a/JavaScriptCore/jit/JITOpcodes.cpp +++ b/JavaScriptCore/jit/JITOpcodes.cpp @@ -161,14 +161,7 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable #endif // All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object. - *executablePool = m_globalData->executableAllocator.poolForSize(m_assembler.size()); - // We can't run without the JIT trampolines! - if (!*executablePool) - CRASH(); - LinkBuffer patchBuffer(this, *executablePool, 0); - // We can't run without the JIT trampolines! - if (!patchBuffer.allocationSuccessful()) - CRASH(); + LinkBuffer patchBuffer(this, m_globalData->executableAllocator.poolForSize(m_assembler.size()), 0); #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) patchBuffer.link(string_failureCases1Call, FunctionPtr(cti_op_get_by_id_string_fail)); @@ -183,6 +176,7 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable patchBuffer.link(callCompileConstruct, FunctionPtr(cti_op_construct_jitCompile)); CodeRef finalCode = patchBuffer.finalizeCode(); + *executablePool = finalCode.m_executablePool; trampolines->ctiVirtualCallLink = patchBuffer.trampolineAt(virtualCallLinkBegin); trampolines->ctiVirtualConstructLink = patchBuffer.trampolineAt(virtualConstructLinkBegin); diff --git a/JavaScriptCore/jit/JITOpcodes32_64.cpp b/JavaScriptCore/jit/JITOpcodes32_64.cpp index 939aa8c..035325a 100644 --- a/JavaScriptCore/jit/JITOpcodes32_64.cpp +++ b/JavaScriptCore/jit/JITOpcodes32_64.cpp @@ -159,14 +159,7 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable #endif // All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object. - *executablePool = m_globalData->executableAllocator.poolForSize(m_assembler.size()); - // We can't run without the JIT trampolines! - if (!*executablePool) - CRASH(); - LinkBuffer patchBuffer(this, *executablePool, 0); - // We can't run without the JIT trampolines! - if (!patchBuffer.allocationSuccessful()) - CRASH(); + LinkBuffer patchBuffer(this, m_globalData->executableAllocator.poolForSize(m_assembler.size()), 0); #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) patchBuffer.link(string_failureCases1Call, FunctionPtr(cti_op_get_by_id_string_fail)); @@ -181,6 +174,7 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable patchBuffer.link(callCompileCconstruct, FunctionPtr(cti_op_construct_jitCompile)); CodeRef finalCode = patchBuffer.finalizeCode(); + *executablePool = finalCode.m_executablePool; trampolines->ctiVirtualCall = patchBuffer.trampolineAt(virtualCallBegin); trampolines->ctiVirtualConstruct = patchBuffer.trampolineAt(virtualConstructBegin); @@ -363,9 +357,6 @@ JIT::CodePtr JIT::privateCompileCTINativeCall(PassRefPtr<ExecutablePool> executa // All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object. LinkBuffer patchBuffer(this, executablePool, 0); - // We can't continue if we can't call a function! - if (!patchBuffer.allocationSuccessful()) - CRASH(); patchBuffer.link(nativeCall, FunctionPtr(func)); patchBuffer.finalizeCode(); diff --git a/JavaScriptCore/jit/JITPropertyAccess.cpp b/JavaScriptCore/jit/JITPropertyAccess.cpp index 6b2a2fe..7c129a5 100644 --- a/JavaScriptCore/jit/JITPropertyAccess.cpp +++ b/JavaScriptCore/jit/JITPropertyAccess.cpp @@ -78,9 +78,6 @@ JIT::CodePtr JIT::stringGetByValStubGenerator(JSGlobalData* globalData, Executab jit.ret(); LinkBuffer patchBuffer(&jit, pool, 0); - // We can't run without the JIT trampolines! - if (!patchBuffer.allocationSuccessful()) - CRASH(); return patchBuffer.finalizeCode().m_code; } @@ -601,7 +598,7 @@ void JIT::testPrototype(JSValue prototype, JumpList& failureCases) #endif } -bool JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct) +void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct) { JumpList failureCases; // Check eax is an object of the right Structure. @@ -653,8 +650,6 @@ bool JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure Call failureCall = tailRecursiveCall(); LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); - if (!patchBuffer.allocationSuccessful()) - return false; patchBuffer.link(failureCall, FunctionPtr(direct ? cti_op_put_by_id_direct_fail : cti_op_put_by_id_fail)); @@ -664,10 +659,9 @@ bool JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure } CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum(); + stubInfo->stubRoutine = entryLabel; RepatchBuffer repatchBuffer(m_codeBlock); repatchBuffer.relinkCallerToTrampoline(returnAddress, entryLabel); - stubInfo->initPutByIdTransition(oldStructure, newStructure, chain, entryLabel); - return true; } void JIT::patchGetByIdSelf(CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, ReturnAddressPtr returnAddress) @@ -730,8 +724,10 @@ void JIT::patchPutByIdReplace(CodeBlock* codeBlock, StructureStubInfo* stubInfo, repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetPutByIdPropertyMapOffset), offset); } -bool JIT::privateCompilePatchGetArrayLength(StructureStubInfo* stubInfo, ReturnAddressPtr returnAddress) +void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress) { + StructureStubInfo* stubInfo = &m_codeBlock->getStubInfo(returnAddress); + // Check eax is an array Jump failureCases1 = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr)); @@ -744,8 +740,6 @@ bool JIT::privateCompilePatchGetArrayLength(StructureStubInfo* stubInfo, ReturnA Jump success = jump(); LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); - if (!patchBuffer.allocationSuccessful()) - return false; // Use the patch information to link the failure cases back to the original slow case routine. CodeLocationLabel slowCaseBegin = stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall); @@ -757,6 +751,7 @@ bool JIT::privateCompilePatchGetArrayLength(StructureStubInfo* stubInfo, ReturnA // Track the stub we have created so that it will be deleted later. CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum(); + stubInfo->stubRoutine = entryLabel; // Finally patch the jump to slow case back in the hot path to jump here instead. CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); @@ -765,11 +760,9 @@ bool JIT::privateCompilePatchGetArrayLength(StructureStubInfo* stubInfo, ReturnA // We don't want to patch more than once - in future go to cti_op_put_by_id_generic. repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_array_fail)); - stubInfo->stubRoutine = entryLabel; - return true; } -bool JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame) +void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame) { // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is // referencing the prototype object - let's speculatively load it's table nice and early!) @@ -810,8 +803,6 @@ bool JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset); Jump success = jump(); LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); - if (!patchBuffer.allocationSuccessful()) - return false; // Use the patch information to link the failure cases back to the original slow case routine. CodeLocationLabel slowCaseBegin = stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall); @@ -829,6 +820,7 @@ bool JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str } // Track the stub we have created so that it will be deleted later. CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum(); + stubInfo->stubRoutine = entryLabel; // Finally patch the jump to slow case back in the hot path to jump here instead. CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); @@ -837,15 +829,10 @@ bool JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str // We don't want to patch more than once - in future go to cti_op_put_by_id_generic. repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_proto_list)); - stubInfo->initGetByIdProto(structure, prototypeStructure, entryLabel); - return true; } -bool JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Structure* structure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset) +void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset) { - PolymorphicAccessStructureList* polymorphicStructures = stubInfo->u.getByIdSelfList.structureList; - int currentIndex = stubInfo->u.getByIdSelfList.listSize; - Jump failureCase = checkStructure(regT0, structure); bool needsStubLink = false; if (slot.cachedPropertyType() == PropertySlot::Getter) { @@ -873,8 +860,6 @@ bool JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Structure* Jump success = jump(); LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); - if (!patchBuffer.allocationSuccessful()) - return false; if (needsStubLink) { for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { @@ -902,15 +887,10 @@ bool JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Structure* CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); RepatchBuffer repatchBuffer(m_codeBlock); repatchBuffer.relink(jumpLocation, entryLabel); - stubInfo->u.getByIdSelfList.listSize++; - return true; } -bool JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame) +void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame) { - PolymorphicAccessStructureList* prototypeStructures = stubInfo->u.getByIdProtoList.structureList; - int currentIndex = stubInfo->u.getByIdProtoList.listSize; - // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is // referencing the prototype object - let's speculatively load it's table nice and early!) JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame)); @@ -951,8 +931,6 @@ bool JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Structure* Jump success = jump(); LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); - if (!patchBuffer.allocationSuccessful()) - return false; if (needsStubLink) { for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { @@ -979,15 +957,10 @@ bool JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Structure* CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); RepatchBuffer repatchBuffer(m_codeBlock); repatchBuffer.relink(jumpLocation, entryLabel); - stubInfo->u.getByIdProtoList.listSize++; - return true; } -bool JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame) +void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame) { - PolymorphicAccessStructureList* prototypeStructures = stubInfo->u.getByIdProtoList.structureList; - int currentIndex = stubInfo->u.getByIdProtoList.listSize; - ASSERT(count); JumpList bucketsOfFail; @@ -1027,8 +1000,6 @@ bool JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Structure* Jump success = jump(); LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); - if (!patchBuffer.allocationSuccessful()) - return false; if (needsStubLink) { for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { @@ -1056,11 +1027,9 @@ bool JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Structure* CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); RepatchBuffer repatchBuffer(m_codeBlock); repatchBuffer.relink(jumpLocation, entryLabel); - stubInfo->u.getByIdProtoList.listSize++; - return true; } -bool JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame) +void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame) { ASSERT(count); @@ -1101,8 +1070,6 @@ bool JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str Jump success = jump(); LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); - if (!patchBuffer.allocationSuccessful()) - return false; if (needsStubLink) { for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { @@ -1119,6 +1086,7 @@ bool JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str // Track the stub we have created so that it will be deleted later. CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum(); + stubInfo->stubRoutine = entryLabel; // Finally patch the jump to slow case back in the hot path to jump here instead. CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); @@ -1127,8 +1095,6 @@ bool JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str // We don't want to patch more than once - in future go to cti_op_put_by_id_generic. repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_proto_list)); - stubInfo->initGetByIdChain(structure, chain, entryLabel); - return true; } /* ------------------------------ END: !ENABLE / ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) ------------------------------ */ diff --git a/JavaScriptCore/jit/JITPropertyAccess32_64.cpp b/JavaScriptCore/jit/JITPropertyAccess32_64.cpp index 9239641..31ecfed 100644 --- a/JavaScriptCore/jit/JITPropertyAccess32_64.cpp +++ b/JavaScriptCore/jit/JITPropertyAccess32_64.cpp @@ -296,9 +296,6 @@ JIT::CodePtr JIT::stringGetByValStubGenerator(JSGlobalData* globalData, Executab jit.ret(); LinkBuffer patchBuffer(&jit, pool, 0); - // We can't run without the JIT trampolines! - if (!patchBuffer.allocationSuccessful()) - CRASH(); return patchBuffer.finalizeCode().m_code; } @@ -605,7 +602,7 @@ void JIT::testPrototype(JSValue prototype, JumpList& failureCases) #endif } -bool JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct) +void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct) { // It is assumed that regT0 contains the basePayload and regT1 contains the baseTag. The value can be found on the stack. @@ -657,9 +654,7 @@ bool JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure Call failureCall = tailRecursiveCall(); LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); - if (!patchBuffer.allocationSuccessful()) - return false; - + patchBuffer.link(failureCall, FunctionPtr(direct ? cti_op_put_by_id_direct_fail : cti_op_put_by_id_fail)); if (willNeedStorageRealloc) { @@ -668,10 +663,9 @@ bool JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure } CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum(); + stubInfo->stubRoutine = entryLabel; RepatchBuffer repatchBuffer(m_codeBlock); repatchBuffer.relinkCallerToTrampoline(returnAddress, entryLabel); - stubInfo->initPutByIdTransition(oldStructure, newStructure, chain, entryLabel); - return true; } void JIT::patchGetByIdSelf(CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, ReturnAddressPtr returnAddress) @@ -736,8 +730,10 @@ void JIT::patchPutByIdReplace(CodeBlock* codeBlock, StructureStubInfo* stubInfo, repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetPutByIdPropertyMapOffset2), offset + OBJECT_OFFSETOF(JSValue, u.asBits.tag)); // tag } -bool JIT::privateCompilePatchGetArrayLength(StructureStubInfo* stubInfo, ReturnAddressPtr returnAddress) +void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress) { + StructureStubInfo* stubInfo = &m_codeBlock->getStubInfo(returnAddress); + // regT0 holds a JSCell* // Check for array @@ -753,9 +749,7 @@ bool JIT::privateCompilePatchGetArrayLength(StructureStubInfo* stubInfo, ReturnA Jump success = jump(); LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); - if (!patchBuffer.allocationSuccessful()) - return false; - + // Use the patch information to link the failure cases back to the original slow case routine. CodeLocationLabel slowCaseBegin = stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall); patchBuffer.link(failureCases1, slowCaseBegin); @@ -766,7 +760,8 @@ bool JIT::privateCompilePatchGetArrayLength(StructureStubInfo* stubInfo, ReturnA // Track the stub we have created so that it will be deleted later. CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum(); - + stubInfo->stubRoutine = entryLabel; + // Finally patch the jump to slow case back in the hot path to jump here instead. CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); RepatchBuffer repatchBuffer(m_codeBlock); @@ -774,11 +769,9 @@ bool JIT::privateCompilePatchGetArrayLength(StructureStubInfo* stubInfo, ReturnA // We don't want to patch more than once - in future go to cti_op_put_by_id_generic. repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_array_fail)); - stubInfo->stubRoutine = entryLabel; - return true; } -bool JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame) +void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame) { // regT0 holds a JSCell* @@ -820,9 +813,7 @@ bool JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str Jump success = jump(); LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); - if (!patchBuffer.allocationSuccessful()) - return false; - + // Use the patch information to link the failure cases back to the original slow case routine. CodeLocationLabel slowCaseBegin = stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall); patchBuffer.link(failureCases1, slowCaseBegin); @@ -840,6 +831,7 @@ bool JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str // Track the stub we have created so that it will be deleted later. CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum(); + stubInfo->stubRoutine = entryLabel; // Finally patch the jump to slow case back in the hot path to jump here instead. CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); @@ -848,16 +840,11 @@ bool JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str // We don't want to patch more than once - in future go to cti_op_put_by_id_generic. repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_proto_list)); - stubInfo->initGetByIdProto(structure, prototypeStructure, entryLabel); - return true; } -bool JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Structure* structure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset) +void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset) { - PolymorphicAccessStructureList* polymorphicStructures = stubInfo->u.getByIdSelfList.structureList; - int currentIndex = stubInfo->u.getByIdSelfList.listSize; - // regT0 holds a JSCell* Jump failureCase = checkStructure(regT0, structure); bool needsStubLink = false; @@ -887,9 +874,6 @@ bool JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Structure* Jump success = jump(); LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); - if (!patchBuffer.allocationSuccessful()) - return false; - if (needsStubLink) { for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { if (iter->to) @@ -915,15 +899,10 @@ bool JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Structure* CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); RepatchBuffer repatchBuffer(m_codeBlock); repatchBuffer.relink(jumpLocation, entryLabel); - stubInfo->u.getByIdSelfList.listSize++; - return true; } -bool JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame) +void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame) { - PolymorphicAccessStructureList* prototypeStructures = stubInfo->u.getByIdProtoList.structureList; - int currentIndex = stubInfo->u.getByIdProtoList.listSize; - // regT0 holds a JSCell* // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is @@ -965,9 +944,6 @@ bool JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Structure* Jump success = jump(); LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); - if (!patchBuffer.allocationSuccessful()) - return false; - if (needsStubLink) { for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { if (iter->to) @@ -992,15 +968,10 @@ bool JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Structure* CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); RepatchBuffer repatchBuffer(m_codeBlock); repatchBuffer.relink(jumpLocation, entryLabel); - stubInfo->u.getByIdProtoList.listSize++; - return true; } -bool JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame) +void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame) { - PolymorphicAccessStructureList* prototypeStructures = stubInfo->u.getByIdProtoList.structureList; - int currentIndex = stubInfo->u.getByIdProtoList.listSize; - // regT0 holds a JSCell* ASSERT(count); @@ -1042,9 +1013,6 @@ bool JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Structure* Jump success = jump(); LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); - if (!patchBuffer.allocationSuccessful()) - return false; - if (needsStubLink) { for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { if (iter->to) @@ -1070,11 +1038,9 @@ bool JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Structure* CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); RepatchBuffer repatchBuffer(m_codeBlock); repatchBuffer.relink(jumpLocation, entryLabel); - stubInfo->u.getByIdProtoList.listSize++; - return true; } -bool JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame) +void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame) { // regT0 holds a JSCell* ASSERT(count); @@ -1116,9 +1082,6 @@ bool JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str Jump success = jump(); LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); - if (!patchBuffer.allocationSuccessful()) - return false; - if (needsStubLink) { for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { if (iter->to) @@ -1133,7 +1096,8 @@ bool JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str // Track the stub we have created so that it will be deleted later. CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum(); - + stubInfo->stubRoutine = entryLabel; + // Finally patch the jump to slow case back in the hot path to jump here instead. CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); RepatchBuffer repatchBuffer(m_codeBlock); @@ -1141,8 +1105,6 @@ bool JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str // We don't want to patch more than once - in future go to cti_op_put_by_id_generic. repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_proto_list)); - stubInfo->initGetByIdChain(structure, chain, entryLabel); - return true; } /* ------------------------------ END: !ENABLE / ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) ------------------------------ */ diff --git a/JavaScriptCore/jit/JITStubs.cpp b/JavaScriptCore/jit/JITStubs.cpp index b53e655..e17c7cb 100644 --- a/JavaScriptCore/jit/JITStubs.cpp +++ b/JavaScriptCore/jit/JITStubs.cpp @@ -824,89 +824,111 @@ JITThunks::~JITThunks() #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) -NEVER_INLINE bool JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const PutPropertySlot& slot, StructureStubInfo* stubInfo, bool direct) +NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const PutPropertySlot& slot, StructureStubInfo* stubInfo, bool direct) { // The interpreter checks for recursion here; I do not believe this can occur in CTI. if (!baseValue.isCell()) - return false; + return; // Uncacheable: give up. - if (!slot.isCacheable()) - return false; + if (!slot.isCacheable()) { + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); + return; + } JSCell* baseCell = asCell(baseValue); Structure* structure = baseCell->structure(); - if (structure->isUncacheableDictionary()) - return false; + if (structure->isUncacheableDictionary()) { + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); + return; + } // If baseCell != base, then baseCell must be a proxy for another object. - if (baseCell != slot.base()) - return false; + if (baseCell != slot.base()) { + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); + return; + } // Cache hit: Specialize instruction and ref Structures. // Structure transition, cache transition info if (slot.type() == PutPropertySlot::NewProperty) { - if (structure->isDictionary()) - return false; + if (structure->isDictionary()) { + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); + return; + } // put_by_id_transition checks the prototype chain for setters. normalizePrototypeChain(callFrame, baseCell); StructureChain* prototypeChain = structure->prototypeChain(callFrame); - return JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress, direct); + stubInfo->initPutByIdTransition(structure->previousID(), structure, prototypeChain); + JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress, direct); + return; } + + stubInfo->initPutByIdReplace(structure); JIT::patchPutByIdReplace(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress, direct); - stubInfo->initPutByIdReplace(structure); - return true; } -NEVER_INLINE bool JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo* stubInfo) +NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo* stubInfo) { // FIXME: Write a test that proves we need to check for recursion here just // like the interpreter does, then add a check for recursion. // FIXME: Cache property access for immediates. - if (!baseValue.isCell()) - return false; + if (!baseValue.isCell()) { + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); + return; + } JSGlobalData* globalData = &callFrame->globalData(); - if (isJSArray(globalData, baseValue) && propertyName == callFrame->propertyNames().length) - return JIT::compilePatchGetArrayLength(callFrame->scopeChain()->globalData, codeBlock, stubInfo, returnAddress); + if (isJSArray(globalData, baseValue) && propertyName == callFrame->propertyNames().length) { + JIT::compilePatchGetArrayLength(callFrame->scopeChain()->globalData, codeBlock, returnAddress); + return; + } if (isJSString(globalData, baseValue) && propertyName == callFrame->propertyNames().length) { // The tradeoff of compiling an patched inline string length access routine does not seem // to pay off, so we currently only do this for arrays. ctiPatchCallByReturnAddress(codeBlock, returnAddress, globalData->jitStubs->ctiStringLengthTrampoline()); - return true; + return; } // Uncacheable: give up. - if (!slot.isCacheable()) - return false; + if (!slot.isCacheable()) { + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); + return; + } JSCell* baseCell = asCell(baseValue); Structure* structure = baseCell->structure(); - if (structure->isUncacheableDictionary()) - return false; + if (structure->isUncacheableDictionary()) { + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); + return; + } // Cache hit: Specialize instruction and ref Structures. if (slot.slotBase() == baseValue) { - if (slot.cachedPropertyType() != PropertySlot::Value) - return false; - JIT::patchGetByIdSelf(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress); + // set this up, so derefStructures can do it's job. stubInfo->initGetByIdSelf(structure); - return true; + if (slot.cachedPropertyType() != PropertySlot::Value) + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_self_fail)); + else + JIT::patchGetByIdSelf(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress); + return; } - if (structure->isDictionary()) - return false; + if (structure->isDictionary()) { + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); + return; + } if (slot.slotBase() == structure->prototypeForLookup(callFrame)) { ASSERT(slot.slotBase().isObject()); @@ -920,20 +942,25 @@ NEVER_INLINE bool JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co slotBaseObject->flattenDictionaryObject(); offset = slotBaseObject->structure()->get(propertyName); } + + stubInfo->initGetByIdProto(structure, slotBaseObject->structure()); + ASSERT(!structure->isDictionary()); ASSERT(!slotBaseObject->structure()->isDictionary()); - return JIT::compileGetByIdProto(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, slotBaseObject->structure(), propertyName, slot, offset, returnAddress); + JIT::compileGetByIdProto(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, slotBaseObject->structure(), propertyName, slot, offset, returnAddress); + return; } size_t offset = slot.cachedOffset(); size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset); if (!count) { stubInfo->accessType = access_get_by_id_generic; - return true; + return; } StructureChain* prototypeChain = structure->prototypeChain(callFrame); - return JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, propertyName, slot, offset, returnAddress); + stubInfo->initGetByIdChain(structure, prototypeChain); + JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, propertyName, slot, offset, returnAddress); } #endif // ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) @@ -1386,13 +1413,9 @@ DEFINE_STUB_FUNCTION(void, op_put_by_id) StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); if (!stubInfo->seenOnce()) stubInfo->setSeen(); - else { - JSValue baseValue = stackFrame.args[0].jsValue(); - bool cached = JITThunks::tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, baseValue, slot, stubInfo, false); - if (!cached && baseValue.isCell()) - ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_id_generic)); - } - + else + JITThunks::tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, stackFrame.args[0].jsValue(), slot, stubInfo, false); + CHECK_FOR_EXCEPTION_AT_END(); } @@ -1409,13 +1432,9 @@ DEFINE_STUB_FUNCTION(void, op_put_by_id_direct) StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); if (!stubInfo->seenOnce()) stubInfo->setSeen(); - else { - JSValue baseValue = stackFrame.args[0].jsValue(); - bool cached = JITThunks::tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, baseValue, slot, stubInfo, true); - if (!cached && baseValue.isCell()) - ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_id_direct_generic)); - } - + else + JITThunks::tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, stackFrame.args[0].jsValue(), slot, stubInfo, true); + CHECK_FOR_EXCEPTION_AT_END(); } @@ -1547,11 +1566,8 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id) StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); if (!stubInfo->seenOnce()) stubInfo->setSeen(); - else { - bool cached = JITThunks::tryCacheGetByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, baseValue, ident, slot, stubInfo); - if (!cached) - ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic)); - } + else + JITThunks::tryCacheGetByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, baseValue, ident, slot, stubInfo); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); @@ -1580,28 +1596,57 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_self_fail) ASSERT(slot.slotBase().isObject()); - // If this is a regular self access (not yet upgraded to list), then switch the stubInfo over. - if (stubInfo->accessType == access_get_by_id_self) - stubInfo->initGetByIdSelfList(new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdSelf.baseObjectStructure)); + PolymorphicAccessStructureList* polymorphicStructureList; + int listIndex = 1; - // If there is room in the list, try to add a cached entry. - if (stubInfo->u.getByIdSelfList.listSize < POLYMORPHIC_LIST_CACHE_SIZE) { - bool cached = JIT::compileGetByIdSelfList(callFrame->scopeChain()->globalData, codeBlock, stubInfo, asCell(baseValue)->structure(), ident, slot, slot.cachedOffset()); - if (cached) - return JSValue::encode(result); + if (stubInfo->accessType == access_get_by_id_self) { + ASSERT(!stubInfo->stubRoutine); + polymorphicStructureList = new PolymorphicAccessStructureList(CodeLocationLabel(), stubInfo->u.getByIdSelf.baseObjectStructure); + stubInfo->initGetByIdSelfList(polymorphicStructureList, 1); + } else { + polymorphicStructureList = stubInfo->u.getByIdSelfList.structureList; + listIndex = stubInfo->u.getByIdSelfList.listSize; } - } - ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic)); + if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) { + stubInfo->u.getByIdSelfList.listSize++; + JIT::compileGetByIdSelfList(callFrame->scopeChain()->globalData, codeBlock, stubInfo, polymorphicStructureList, listIndex, asCell(baseValue)->structure(), ident, slot, slot.cachedOffset()); + + if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) + ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic)); + } + } else + ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic)); return JSValue::encode(result); } -static void setupPolymorphicProtoList(StructureStubInfo* stubInfo) -{ - if (stubInfo->accessType == access_get_by_id_proto) - stubInfo->initGetByIdProtoList(new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdProto.baseObjectStructure, stubInfo->u.getByIdProto.prototypeStructure)); - else if (stubInfo->accessType == access_get_by_id_chain) - stubInfo->initGetByIdProtoList(new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdChain.baseObjectStructure, stubInfo->u.getByIdChain.chain)); - ASSERT(stubInfo->accessType == access_get_by_id_proto_list); +static PolymorphicAccessStructureList* getPolymorphicAccessStructureListSlot(StructureStubInfo* stubInfo, int& listIndex) +{ + PolymorphicAccessStructureList* prototypeStructureList = 0; + listIndex = 1; + + switch (stubInfo->accessType) { + case access_get_by_id_proto: + prototypeStructureList = new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdProto.baseObjectStructure, stubInfo->u.getByIdProto.prototypeStructure); + stubInfo->stubRoutine = CodeLocationLabel(); + stubInfo->initGetByIdProtoList(prototypeStructureList, 2); + break; + case access_get_by_id_chain: + prototypeStructureList = new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdChain.baseObjectStructure, stubInfo->u.getByIdChain.chain); + stubInfo->stubRoutine = CodeLocationLabel(); + stubInfo->initGetByIdProtoList(prototypeStructureList, 2); + break; + case access_get_by_id_proto_list: + prototypeStructureList = stubInfo->u.getByIdProtoList.structureList; + listIndex = stubInfo->u.getByIdProtoList.listSize; + if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) + stubInfo->u.getByIdProtoList.listSize++; + break; + default: + ASSERT_NOT_REACHED(); + } + + ASSERT(listIndex <= POLYMORPHIC_LIST_CACHE_SIZE); + return prototypeStructureList; } DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_getter_stub) @@ -1662,36 +1707,40 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list) size_t offset = slot.cachedOffset(); - // Don't mix self & proto/chain accesses in the same list - if (slot.slotBase() != baseValue) { - if (slot.slotBase() == asCell(baseValue)->structure()->prototypeForLookup(callFrame)) { - ASSERT(!asCell(baseValue)->structure()->isDictionary()); - // Since we're accessing a prototype in a loop, it's a good bet that it - // should not be treated as a dictionary. - if (slotBaseObject->structure()->isDictionary()) { - slotBaseObject->flattenDictionaryObject(); - offset = slotBaseObject->structure()->get(propertyName); - } + if (slot.slotBase() == baseValue) + ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); + else if (slot.slotBase() == asCell(baseValue)->structure()->prototypeForLookup(callFrame)) { + ASSERT(!asCell(baseValue)->structure()->isDictionary()); + // Since we're accessing a prototype in a loop, it's a good bet that it + // should not be treated as a dictionary. + if (slotBaseObject->structure()->isDictionary()) { + slotBaseObject->flattenDictionaryObject(); + offset = slotBaseObject->structure()->get(propertyName); + } - setupPolymorphicProtoList(stubInfo); - if (stubInfo->u.getByIdProtoList.listSize < POLYMORPHIC_LIST_CACHE_SIZE) { - bool cached = JIT::compileGetByIdProtoList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, slotBaseObject->structure(), propertyName, slot, offset); - if (cached) - return JSValue::encode(result); - } - } else if (size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset)) { - ASSERT(!asCell(baseValue)->structure()->isDictionary()); - - setupPolymorphicProtoList(stubInfo); - if (stubInfo->u.getByIdProtoList.listSize < POLYMORPHIC_LIST_CACHE_SIZE) { - bool cached = JIT::compileGetByIdChainList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, structure->prototypeChain(callFrame), count, propertyName, slot, offset); - if (cached) - return JSValue::encode(result); - } + int listIndex; + PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex); + if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) { + JIT::compileGetByIdProtoList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, slotBaseObject->structure(), propertyName, slot, offset); + + if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) + ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full)); } - } + } else if (size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset)) { + ASSERT(!asCell(baseValue)->structure()->isDictionary()); + int listIndex; + PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex); + + if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) { + StructureChain* protoChain = structure->prototypeChain(callFrame); + JIT::compileGetByIdChainList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, protoChain, count, propertyName, slot, offset); + + if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) + ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full)); + } + } else + ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); - ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); return JSValue::encode(result); } diff --git a/JavaScriptCore/jit/JITStubs.h b/JavaScriptCore/jit/JITStubs.h index 43f3d19..4e73070 100644 --- a/JavaScriptCore/jit/JITStubs.h +++ b/JavaScriptCore/jit/JITStubs.h @@ -252,8 +252,8 @@ namespace JSC { JITThunks(JSGlobalData*); ~JITThunks(); - static bool tryCacheGetByID(CallFrame*, CodeBlock*, ReturnAddressPtr returnAddress, JSValue baseValue, const Identifier& propertyName, const PropertySlot&, StructureStubInfo* stubInfo); - static bool tryCachePutByID(CallFrame*, CodeBlock*, ReturnAddressPtr returnAddress, JSValue baseValue, const PutPropertySlot&, StructureStubInfo* stubInfo, bool direct); + 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, bool direct); MacroAssemblerCodePtr ctiStringLengthTrampoline() { return m_trampolineStructure.ctiStringLengthTrampoline; } MacroAssemblerCodePtr ctiVirtualCallLink() { return m_trampolineStructure.ctiVirtualCallLink; } diff --git a/JavaScriptCore/jit/SpecializedThunkJIT.h b/JavaScriptCore/jit/SpecializedThunkJIT.h index ba95498..57515fb 100644 --- a/JavaScriptCore/jit/SpecializedThunkJIT.h +++ b/JavaScriptCore/jit/SpecializedThunkJIT.h @@ -130,9 +130,6 @@ namespace JSC { MacroAssemblerCodePtr finalize(MacroAssemblerCodePtr fallback) { LinkBuffer patchBuffer(this, m_pool.get(), 0); - // We can't continue if we can't call a function! - if (!patchBuffer.allocationSuccessful()) - CRASH(); patchBuffer.link(m_failures, CodeLocationLabel(fallback)); return patchBuffer.finalizeCode().m_code; } diff --git a/JavaScriptCore/parser/JSParser.cpp b/JavaScriptCore/parser/JSParser.cpp index 3baceba..6852de1 100644 --- a/JavaScriptCore/parser/JSParser.cpp +++ b/JavaScriptCore/parser/JSParser.cpp @@ -33,6 +33,7 @@ using namespace JSC; #include "NodeInfo.h" #include "ASTBuilder.h" #include <wtf/HashFunctions.h> +#include <wtf/WTFThreadData.h> #include <utility> using namespace std; @@ -220,12 +221,7 @@ JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, SourceProvider* provi , m_nonLHSCount(0) , m_syntaxAlreadyValidated(provider->isValid()) { - m_endAddress = *(globalData->stackGuards); - if (!m_endAddress) { - char sample = 0; - m_endAddress = &sample - kMaxParserStackUsage; - *(globalData->stackGuards) = m_endAddress; - } + m_endAddress = wtfThreadData().approximatedStackStart() - kMaxParserStackUsage; next(); m_lexer->setLastLineNumber(tokenLine()); } diff --git a/JavaScriptCore/parser/Lexer.cpp b/JavaScriptCore/parser/Lexer.cpp index 877e89a..6c4db32 100644 --- a/JavaScriptCore/parser/Lexer.cpp +++ b/JavaScriptCore/parser/Lexer.cpp @@ -535,6 +535,146 @@ ALWAYS_INLINE bool Lexer::parseString(JSTokenData* lvalp) return true; } +ALWAYS_INLINE void Lexer::parseHex(double& returnValue) +{ + // Optimization: most hexadecimal values fit into 4 bytes. + uint32_t hexValue = 0; + int maximumDigits = 7; + + // Shift out the 'x' prefix. + shift(); + + do { + hexValue = (hexValue << 4) + toASCIIHexValue(m_current); + shift(); + --maximumDigits; + } while (isASCIIHexDigit(m_current) && maximumDigits >= 0); + + if (maximumDigits >= 0) { + returnValue = hexValue; + return; + } + + // No more place in the hexValue buffer. + // The values are shifted out and placed into the m_buffer8 vector. + for (int i = 0; i < 8; ++i) { + int digit = hexValue >> 28; + if (digit < 10) + record8(digit + '0'); + else + record8(digit - 10 + 'a'); + hexValue <<= 4; + } + + while (isASCIIHexDigit(m_current)) { + record8(m_current); + shift(); + } + + returnValue = parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 16); +} + +ALWAYS_INLINE bool Lexer::parseOctal(double& returnValue) +{ + // Optimization: most octal values fit into 4 bytes. + uint32_t octalValue = 0; + int maximumDigits = 9; + // Temporary buffer for the digits. Makes easier + // to reconstruct the input characters when needed. + char digits[10]; + + do { + octalValue = octalValue * 8 + (m_current - '0'); + digits[maximumDigits] = m_current; + shift(); + --maximumDigits; + } while (isASCIIOctalDigit(m_current) && maximumDigits >= 0); + + if (!isASCIIDigit(m_current) && maximumDigits >= 0) { + returnValue = octalValue; + return true; + } + + for (int i = 9; i > maximumDigits; --i) + record8(digits[i]); + + while (isASCIIOctalDigit(m_current)) { + record8(m_current); + shift(); + } + + if (isASCIIDigit(m_current)) + return false; + + returnValue = parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 8); + return true; +} + +ALWAYS_INLINE bool Lexer::parseDecimal(double& returnValue) +{ + // Optimization: most decimal values fit into 4 bytes. + uint32_t decimalValue = 0; + + // Since parseOctal may be executed before parseDecimal, + // the m_buffer8 may hold ascii digits. + if (!m_buffer8.size()) { + int maximumDigits = 9; + // Temporary buffer for the digits. Makes easier + // to reconstruct the input characters when needed. + char digits[10]; + + do { + decimalValue = decimalValue * 10 + (m_current - '0'); + digits[maximumDigits] = m_current; + shift(); + --maximumDigits; + } while (isASCIIDigit(m_current) && maximumDigits >= 0); + + if (maximumDigits >= 0 && m_current != '.' && (m_current | 0x20) != 'e') { + returnValue = decimalValue; + return true; + } + + for (int i = 9; i > maximumDigits; --i) + record8(digits[i]); + } + + while (isASCIIDigit(m_current)) { + record8(m_current); + shift(); + } + + return false; +} + +ALWAYS_INLINE void Lexer::parseNumberAfterDecimalPoint() +{ + record8('.'); + while (isASCIIDigit(m_current)) { + record8(m_current); + shift(); + } +} + +ALWAYS_INLINE bool Lexer::parseNumberAfterExponentIndicator() +{ + record8('e'); + shift(); + if (m_current == '+' || m_current == '-') { + record8(m_current); + shift(); + } + + if (!isASCIIDigit(m_current)) + return false; + + do { + record8(m_current); + shift(); + } while (isASCIIDigit(m_current)); + return true; +} + JSTokenType Lexer::lex(JSTokenData* lvalp, JSTokenInfo* llocp, LexType lexType) { ASSERT(!m_error); @@ -750,14 +890,6 @@ start: } token = BITOR; break; - case CharacterDot: - shift(); - if (isASCIIDigit(m_current)) { - record8('.'); - goto inNumberAfterDecimalPoint; - } - token = DOT; - break; case CharacterOpenParen: token = OPENPAREN; shift(); @@ -806,10 +938,50 @@ start: shift(); token = CLOSEBRACE; break; + case CharacterDot: + shift(); + if (!isASCIIDigit(m_current)) { + token = DOT; + break; + } + goto inNumberAfterDecimalPoint; case CharacterZero: - goto startNumberWithZeroDigit; + shift(); + if ((m_current | 0x20) == 'x' && isASCIIHexDigit(peek(1))) { + parseHex(lvalp->doubleValue); + token = NUMBER; + } else { + record8('0'); + if (isASCIIOctalDigit(m_current)) { + if (parseOctal(lvalp->doubleValue)) + token = NUMBER; + } + } + // Fall through into CharacterNumber case CharacterNumber: - goto startNumber; + if (LIKELY(token != NUMBER)) { + if (!parseDecimal(lvalp->doubleValue)) { + if (m_current == '.') { + shift(); +inNumberAfterDecimalPoint: + parseNumberAfterDecimalPoint(); + } + if ((m_current | 0x20) == 'e') + if (!parseNumberAfterExponentIndicator()) + goto returnError; + // Null-terminate string for strtod. + m_buffer8.append('\0'); + lvalp->doubleValue = WTF::strtod(m_buffer8.data(), 0); + } + token = NUMBER; + } + + // No identifiers allowed directly after numeric literal, e.g. "3in" is bad. + if (UNLIKELY(isIdentStart(m_current))) + goto returnError; + m_buffer8.resize(0); + m_delimited = false; + break; case CharacterQuote: if (UNLIKELY(!parseString(lvalp))) goto returnError; @@ -875,143 +1047,8 @@ inMultiLineComment: shift(); } shift(); - m_atLineStart = false; goto start; -startNumberWithZeroDigit: - shift(); - if ((m_current | 0x20) == 'x' && isASCIIHexDigit(peek(1))) { - shift(); - goto inHex; - } - if (m_current == '.') { - record8('0'); - record8('.'); - shift(); - goto inNumberAfterDecimalPoint; - } - if ((m_current | 0x20) == 'e') { - record8('0'); - record8('e'); - shift(); - goto inExponentIndicator; - } - if (isASCIIOctalDigit(m_current)) - goto inOctal; - if (isASCIIDigit(m_current)) - goto startNumber; - lvalp->doubleValue = 0; - goto doneNumeric; - -inNumberAfterDecimalPoint: - while (isASCIIDigit(m_current)) { - record8(m_current); - shift(); - } - if ((m_current | 0x20) == 'e') { - record8('e'); - shift(); - goto inExponentIndicator; - } - goto doneNumber; - -inExponentIndicator: - if (m_current == '+' || m_current == '-') { - record8(m_current); - shift(); - } - if (!isASCIIDigit(m_current)) - goto returnError; - do { - record8(m_current); - shift(); - } while (isASCIIDigit(m_current)); - goto doneNumber; - -inOctal: { - do { - record8(m_current); - shift(); - } while (isASCIIOctalDigit(m_current)); - if (isASCIIDigit(m_current)) - goto startNumber; - - double dval = 0; - - const char* end = m_buffer8.end(); - for (const char* p = m_buffer8.data(); p < end; ++p) { - dval *= 8; - dval += *p - '0'; - } - if (dval >= mantissaOverflowLowerBound) - dval = parseIntOverflow(m_buffer8.data(), end - m_buffer8.data(), 8); - - m_buffer8.resize(0); - - lvalp->doubleValue = dval; - goto doneNumeric; -} - -inHex: { - do { - record8(m_current); - shift(); - } while (isASCIIHexDigit(m_current)); - - double dval = 0; - - const char* end = m_buffer8.end(); - for (const char* p = m_buffer8.data(); p < end; ++p) { - dval *= 16; - dval += toASCIIHexValue(*p); - } - if (dval >= mantissaOverflowLowerBound) - dval = parseIntOverflow(m_buffer8.data(), end - m_buffer8.data(), 16); - - m_buffer8.resize(0); - - lvalp->doubleValue = dval; - goto doneNumeric; -} - -startNumber: - record8(m_current); - shift(); - while (isASCIIDigit(m_current)) { - record8(m_current); - shift(); - } - if (m_current == '.') { - record8('.'); - shift(); - goto inNumberAfterDecimalPoint; - } - if ((m_current | 0x20) == 'e') { - record8('e'); - shift(); - goto inExponentIndicator; - } - - // Fall through into doneNumber. - -doneNumber: - // Null-terminate string for strtod. - m_buffer8.append('\0'); - lvalp->doubleValue = WTF::strtod(m_buffer8.data(), 0); - m_buffer8.resize(0); - - // Fall through into doneNumeric. - -doneNumeric: - // No identifiers allowed directly after numeric literal, e.g. "3in" is bad. - if (UNLIKELY(isIdentStart(m_current))) - goto returnError; - - m_atLineStart = false; - m_delimited = false; - token = NUMBER; - goto returnToken; - doneSemicolon: token = SEMICOLON; m_delimited = true; diff --git a/JavaScriptCore/parser/Lexer.h b/JavaScriptCore/parser/Lexer.h index 3d97cc1..da84a6b 100644 --- a/JavaScriptCore/parser/Lexer.h +++ b/JavaScriptCore/parser/Lexer.h @@ -96,6 +96,11 @@ namespace JSC { ALWAYS_INLINE JSTokenType parseIdentifier(JSTokenData*, LexType); ALWAYS_INLINE bool parseString(JSTokenData* lvalp); + ALWAYS_INLINE void parseHex(double& returnValue); + ALWAYS_INLINE bool parseOctal(double& returnValue); + ALWAYS_INLINE bool parseDecimal(double& returnValue); + ALWAYS_INLINE void parseNumberAfterDecimalPoint(); + ALWAYS_INLINE bool parseNumberAfterExponentIndicator(); static const size_t initialReadBufferCapacity = 32; diff --git a/JavaScriptCore/runtime/ArrayPrototype.cpp b/JavaScriptCore/runtime/ArrayPrototype.cpp index e49ca28..28269ff 100644 --- a/JavaScriptCore/runtime/ArrayPrototype.cpp +++ b/JavaScriptCore/runtime/ArrayPrototype.cpp @@ -146,6 +146,20 @@ static void putProperty(ExecState* exec, JSObject* obj, const Identifier& proper obj->put(exec, propertyName, value, slot); } +static unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int argument, unsigned length, unsigned undefinedValue = 0) +{ + JSValue value = exec->argument(argument); + if (value.isUndefined()) + return undefinedValue; + + double indexDouble = value.toInteger(exec); + if (indexDouble < 0) { + indexDouble += length; + return indexDouble < 0 ? 0 : static_cast<unsigned>(indexDouble); + } + return indexDouble > length ? length : static_cast<unsigned>(indexDouble); +} + EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); @@ -249,8 +263,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec) { - JSValue thisValue = exec->hostThisValue(); - JSObject* thisObj = thisValue.toThisObject(exec); + JSObject* thisObj = exec->hostThisValue().toThisObject(exec); HashSet<JSObject*>& arrayVisitedElements = exec->globalData().arrayVisitedElements; if (arrayVisitedElements.size() >= MaxSmallThreadReentryDepth) { @@ -323,7 +336,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); JSArray* arr = constructEmptyArray(exec); - int n = 0; + unsigned n = 0; JSValue curArg = thisValue.toThisObject(exec); size_t i = 0; size_t argCount = exec->argumentCount(); @@ -389,8 +402,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncReverse(ExecState* exec) { - JSValue thisValue = exec->hostThisValue(); - JSObject* thisObj = thisValue.toThisObject(exec); + JSObject* thisObj = exec->hostThisValue().toThisObject(exec); unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); unsigned middle = length / 2; @@ -414,8 +426,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReverse(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState* exec) { - JSValue thisValue = exec->hostThisValue(); - JSObject* thisObj = thisValue.toThisObject(exec); + JSObject* thisObj = exec->hostThisValue().toThisObject(exec); JSValue result; unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); @@ -442,43 +453,19 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec) { - JSValue thisValue = exec->hostThisValue(); // http://developer.netscape.com/docs/manuals/js/client/jsref/array.htm#1193713 or 15.4.4.10 - - JSObject* thisObj = thisValue.toThisObject(exec); + JSObject* thisObj = exec->hostThisValue().toThisObject(exec); // We return a new array JSArray* resObj = constructEmptyArray(exec); JSValue result = resObj; - double begin = exec->argument(0).toInteger(exec); + unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - if (begin >= 0) { - if (begin > length) - begin = length; - } else { - begin += length; - if (begin < 0) - begin = 0; - } - double end; - if (exec->argument(1).isUndefined()) - end = length; - else { - end = exec->argument(1).toInteger(exec); - if (end < 0) { - end += length; - if (end < 0) - end = 0; - } else { - if (end > length) - end = length; - } - } + unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length); + unsigned end = argumentClampedIndexFromStartOrEnd(exec, 1, length, length); - int n = 0; - int b = static_cast<int>(begin); - int e = static_cast<int>(end); - for (int k = b; k < e; k++, n++) { + unsigned n = 0; + for (unsigned k = begin; k < end; k++, n++) { if (JSValue v = getProperty(exec, thisObj, k)) resObj->put(exec, n, v); } @@ -488,8 +475,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec) { - JSValue thisValue = exec->hostThisValue(); - JSObject* thisObj = thisValue.toThisObject(exec); + JSObject* thisObj = exec->hostThisValue().toThisObject(exec); JSValue function = exec->argument(0); CallData callData; @@ -547,29 +533,26 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec) { - JSValue thisValue = exec->hostThisValue(); - JSObject* thisObj = thisValue.toThisObject(exec); + JSObject* thisObj = exec->hostThisValue().toThisObject(exec); // 15.4.4.12 - // FIXME: Firefox returns an empty array. if (!exec->argumentCount()) - return JSValue::encode(jsUndefined()); + return JSValue::encode(constructEmptyArray(exec)); unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - double relativeBegin = exec->argument(0).toInteger(exec); - unsigned begin; - if (relativeBegin < 0) { - relativeBegin += length; - begin = (relativeBegin < 0) ? 0 : static_cast<unsigned>(relativeBegin); - } else - begin = std::min<unsigned>(static_cast<unsigned>(relativeBegin), length); - - unsigned deleteCount; - if (exec->argumentCount() > 1) - deleteCount = std::min<int>(std::max<int>(exec->argument(1).toUInt32(exec), 0), length - begin); - else - deleteCount = length - begin; + unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length); + + unsigned deleteCount = length - begin; + if (exec->argumentCount() > 1) { + double deleteDouble = exec->argument(1).toInteger(exec); + if (deleteDouble < 0) + deleteCount = 0; + else if (deleteDouble > length - begin) + deleteCount = length - begin; + else + deleteCount = static_cast<unsigned>(deleteDouble); + } JSArray* resObj = new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), deleteCount, CreateCompact); JSValue result = resObj; @@ -616,8 +599,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState* exec) { - JSValue thisValue = exec->hostThisValue(); - JSObject* thisObj = thisValue.toThisObject(exec); + JSObject* thisObj = exec->hostThisValue().toThisObject(exec); // 15.4.4.13 unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); @@ -643,8 +625,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec) { - JSValue thisValue = exec->hostThisValue(); - JSObject* thisObj = thisValue.toThisObject(exec); + JSObject* thisObj = exec->hostThisValue().toThisObject(exec); JSValue function = exec->argument(0); CallData callData; @@ -702,8 +683,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec) { - JSValue thisValue = exec->hostThisValue(); - JSObject* thisObj = thisValue.toThisObject(exec); + JSObject* thisObj = exec->hostThisValue().toThisObject(exec); JSValue function = exec->argument(0); CallData callData; @@ -760,8 +740,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState* exec) { - JSValue thisValue = exec->hostThisValue(); - JSObject* thisObj = thisValue.toThisObject(exec); + JSObject* thisObj = exec->hostThisValue().toThisObject(exec); JSValue function = exec->argument(0); CallData callData; @@ -817,8 +796,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState* exec) { - JSValue thisValue = exec->hostThisValue(); - JSObject* thisObj = thisValue.toThisObject(exec); + JSObject* thisObj = exec->hostThisValue().toThisObject(exec); JSValue function = exec->argument(0); CallData callData; @@ -863,8 +841,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState* exec) { - JSValue thisValue = exec->hostThisValue(); - JSObject* thisObj = thisValue.toThisObject(exec); + JSObject* thisObj = exec->hostThisValue().toThisObject(exec); JSValue function = exec->argument(0); CallData callData; @@ -917,8 +894,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState* exec) { - JSValue thisValue = exec->hostThisValue(); - JSObject* thisObj = thisValue.toThisObject(exec); + JSObject* thisObj = exec->hostThisValue().toThisObject(exec); JSValue function = exec->argument(0); CallData callData; @@ -988,8 +964,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState* exec) { - JSValue thisValue = exec->hostThisValue(); - JSObject* thisObj = thisValue.toThisObject(exec); + JSObject* thisObj = exec->hostThisValue().toThisObject(exec); JSValue function = exec->argument(0); CallData callData; @@ -1058,23 +1033,12 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState* exec) { - JSValue thisValue = exec->hostThisValue(); // JavaScript 1.5 Extension by Mozilla // Documentation: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf + JSObject* thisObj = exec->hostThisValue().toThisObject(exec); - JSObject* thisObj = thisValue.toThisObject(exec); - - unsigned index = 0; - double d = exec->argument(1).toInteger(exec); unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - if (d < 0) - d += length; - if (d > 0) { - if (d > length) - index = length; - else - index = static_cast<unsigned>(d); - } + unsigned index = argumentClampedIndexFromStartOrEnd(exec, 1, length); JSValue searchElement = exec->argument(0); for (; index < length; ++index) { @@ -1090,32 +1054,36 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState* exec) EncodedJSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState* exec) { - JSValue thisValue = exec->hostThisValue(); // JavaScript 1.6 Extension by Mozilla // Documentation: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf - - JSObject* thisObj = thisValue.toThisObject(exec); + JSObject* thisObj = exec->hostThisValue().toThisObject(exec); unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - int index = length - 1; - double d = exec->argument(1).toIntegerPreserveNaN(exec); - - if (d < 0) { - d += length; - if (d < 0) - return JSValue::encode(jsNumber(exec, -1)); + if (!length) + return JSValue::encode(jsNumber(exec, -1)); + + unsigned index = length - 1; + JSValue fromValue = exec->argument(1); + if (!fromValue.isUndefined()) { + double fromDouble = fromValue.toInteger(exec); + if (fromDouble < 0) { + fromDouble += length; + if (fromDouble < 0) + return JSValue::encode(jsNumber(exec, -1)); + } + if (fromDouble < length) + index = static_cast<unsigned>(fromDouble); } - if (d < length) - index = static_cast<int>(d); JSValue searchElement = exec->argument(0); - for (; index >= 0; --index) { + do { + ASSERT(index < length); JSValue e = getProperty(exec, thisObj, index); if (!e) continue; if (JSValue::strictEqual(exec, searchElement, e)) return JSValue::encode(jsNumber(exec, index)); - } + } while (index--); return JSValue::encode(jsNumber(exec, -1)); } diff --git a/JavaScriptCore/runtime/ErrorInstance.cpp b/JavaScriptCore/runtime/ErrorInstance.cpp index be6d0fb..740e20e 100644 --- a/JavaScriptCore/runtime/ErrorInstance.cpp +++ b/JavaScriptCore/runtime/ErrorInstance.cpp @@ -25,9 +25,10 @@ namespace JSC { const ClassInfo ErrorInstance::info = { "Error", 0, 0, 0 }; -ErrorInstance::ErrorInstance(NonNullPassRefPtr<Structure> structure) +ErrorInstance::ErrorInstance(JSGlobalData* globalData, NonNullPassRefPtr<Structure> structure) : JSObject(structure) { + putDirect(globalData->propertyNames->message, jsString(globalData, "")); } ErrorInstance::ErrorInstance(JSGlobalData* globalData, NonNullPassRefPtr<Structure> structure, const UString& message) @@ -44,7 +45,7 @@ ErrorInstance* ErrorInstance::create(JSGlobalData* globalData, NonNullPassRefPtr ErrorInstance* ErrorInstance::create(ExecState* exec, NonNullPassRefPtr<Structure> structure, JSValue message) { if (message.isUndefined()) - return new (exec) ErrorInstance(structure); + return new (exec) ErrorInstance(&exec->globalData(), structure); return new (exec) ErrorInstance(&exec->globalData(), structure, message.toString(exec)); } diff --git a/JavaScriptCore/runtime/ErrorInstance.h b/JavaScriptCore/runtime/ErrorInstance.h index 35edcb0..a49cc3c 100644 --- a/JavaScriptCore/runtime/ErrorInstance.h +++ b/JavaScriptCore/runtime/ErrorInstance.h @@ -35,7 +35,7 @@ namespace JSC { static ErrorInstance* create(ExecState* exec, NonNullPassRefPtr<Structure>, JSValue message); protected: - explicit ErrorInstance(NonNullPassRefPtr<Structure>); + explicit ErrorInstance(JSGlobalData*, NonNullPassRefPtr<Structure>); explicit ErrorInstance(JSGlobalData*, NonNullPassRefPtr<Structure>, const UString&); }; diff --git a/JavaScriptCore/runtime/ErrorPrototype.cpp b/JavaScriptCore/runtime/ErrorPrototype.cpp index 0e14a30..d18e7d8 100644 --- a/JavaScriptCore/runtime/ErrorPrototype.cpp +++ b/JavaScriptCore/runtime/ErrorPrototype.cpp @@ -36,7 +36,7 @@ static EncodedJSValue JSC_HOST_CALL errorProtoFuncToString(ExecState*); // ECMA 15.9.4 ErrorPrototype::ErrorPrototype(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, Structure* prototypeFunctionStructure) - : ErrorInstance(&exec->globalData(), structure, "Unknown error") + : ErrorInstance(&exec->globalData(), structure) { // The constructor will be added later in ErrorConstructor's constructor diff --git a/JavaScriptCore/runtime/ExceptionHelpers.cpp b/JavaScriptCore/runtime/ExceptionHelpers.cpp index 871b2d5..9a6fe5e 100644 --- a/JavaScriptCore/runtime/ExceptionHelpers.cpp +++ b/JavaScriptCore/runtime/ExceptionHelpers.cpp @@ -187,11 +187,6 @@ JSObject* createNotAnObjectError(ExecState* exec, JSNotAnObjectErrorStub* error, return exception; } -JSObject* createOutOfMemoryError(JSGlobalObject* globalObject) -{ - return createError(globalObject, "Out of memory"); -} - JSValue throwOutOfMemoryError(ExecState* exec) { return throwError(exec, createError(exec, "Out of memory")); diff --git a/JavaScriptCore/runtime/ExceptionHelpers.h b/JavaScriptCore/runtime/ExceptionHelpers.h index e4c94fb..3e6de86 100644 --- a/JavaScriptCore/runtime/ExceptionHelpers.h +++ b/JavaScriptCore/runtime/ExceptionHelpers.h @@ -53,7 +53,6 @@ namespace JSC { JSObject* createNotAConstructorError(ExecState*, JSValue, unsigned bytecodeOffset, CodeBlock*); JSValue createNotAFunctionError(ExecState*, JSValue, unsigned bytecodeOffset, CodeBlock*); JSObject* createNotAnObjectError(ExecState*, JSNotAnObjectErrorStub*, unsigned bytecodeOffset, CodeBlock*); - JSObject* createOutOfMemoryError(JSGlobalObject*); JSValue throwOutOfMemoryError(ExecState*); } // namespace JSC diff --git a/JavaScriptCore/runtime/Executable.cpp b/JavaScriptCore/runtime/Executable.cpp index 058a091..41b5f1f 100644 --- a/JavaScriptCore/runtime/Executable.cpp +++ b/JavaScriptCore/runtime/Executable.cpp @@ -116,10 +116,6 @@ JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scope #if ENABLE(JIT) if (exec->globalData().canUseJIT()) { m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_evalCodeBlock.get()); - if (UNLIKELY(!m_jitCodeForCall)) { - m_evalCodeBlock.clear(); - return createOutOfMemoryError(globalObject); - } #if !ENABLE(OPCODE_SAMPLING) if (!BytecodeGenerator::dumpsGeneratedCode()) m_evalCodeBlock->discardBytecode(); @@ -168,10 +164,6 @@ JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* sc #if ENABLE(JIT) if (exec->globalData().canUseJIT()) { m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_programCodeBlock.get()); - if (UNLIKELY(!m_jitCodeForCall)) { - m_programCodeBlock.clear(); - return createOutOfMemoryError(globalObject); - } #if !ENABLE(OPCODE_SAMPLING) if (!BytecodeGenerator::dumpsGeneratedCode()) m_programCodeBlock->discardBytecode(); @@ -213,10 +205,6 @@ JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChain #if ENABLE(JIT) if (exec->globalData().canUseJIT()) { m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_codeBlockForCall.get(), &m_jitCodeForCallWithArityCheck); - if (UNLIKELY(!m_jitCodeForCall)) { - m_codeBlockForCall.clear(); - return createOutOfMemoryError(globalObject); - } #if !ENABLE(OPCODE_SAMPLING) if (!BytecodeGenerator::dumpsGeneratedCode()) m_codeBlockForCall->discardBytecode(); @@ -258,10 +246,6 @@ JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, Scope #if ENABLE(JIT) if (exec->globalData().canUseJIT()) { m_jitCodeForConstruct = JIT::compile(scopeChainNode->globalData, m_codeBlockForConstruct.get(), &m_jitCodeForConstructWithArityCheck); - if (UNLIKELY(!m_jitCodeForConstruct)) { - m_codeBlockForConstruct.clear(); - return createOutOfMemoryError(globalObject); - } #if !ENABLE(OPCODE_SAMPLING) if (!BytecodeGenerator::dumpsGeneratedCode()) m_codeBlockForConstruct->discardBytecode(); @@ -305,15 +289,12 @@ PassOwnPtr<ExceptionInfo> FunctionExecutable::reparseExceptionInfo(JSGlobalData* #if ENABLE(JIT) if (globalData->canUseJIT()) { JITCode newJITCode = JIT::compile(globalData, newCodeBlock.get(), 0, codeBlock->m_isConstructor ? generatedJITCodeForConstruct().start() : generatedJITCodeForCall().start()); - if (!newJITCode) { - globalData->functionCodeBlockBeingReparsed = 0; - return PassOwnPtr<ExceptionInfo>(); - } ASSERT(codeBlock->m_isConstructor ? newJITCode.size() == generatedJITCodeForConstruct().size() : newJITCode.size() == generatedJITCodeForCall().size()); } #endif globalData->functionCodeBlockBeingReparsed = 0; + return newCodeBlock->extractExceptionInfo(); } @@ -338,10 +319,6 @@ PassOwnPtr<ExceptionInfo> EvalExecutable::reparseExceptionInfo(JSGlobalData* glo #if ENABLE(JIT) if (globalData->canUseJIT()) { JITCode newJITCode = JIT::compile(globalData, newCodeBlock.get(), 0, generatedJITCodeForCall().start()); - if (!newJITCode) { - globalData->functionCodeBlockBeingReparsed = 0; - return PassOwnPtr<ExceptionInfo>(); - } ASSERT(newJITCode.size() == generatedJITCodeForCall().size()); } #endif diff --git a/JavaScriptCore/runtime/JSGlobalData.h b/JavaScriptCore/runtime/JSGlobalData.h index 07acb43..43c4bab 100644 --- a/JavaScriptCore/runtime/JSGlobalData.h +++ b/JavaScriptCore/runtime/JSGlobalData.h @@ -227,7 +227,6 @@ namespace JSC { #endif CachedTranscendentalFunction<sin> cachedSin; - WTF::ThreadSpecific<char*> stackGuards; void resetDateCache(); diff --git a/JavaScriptCore/runtime/JSValue.h b/JavaScriptCore/runtime/JSValue.h index af4b0f4..4a6744d 100644 --- a/JavaScriptCore/runtime/JSValue.h +++ b/JavaScriptCore/runtime/JSValue.h @@ -410,7 +410,7 @@ namespace JSC { inline uint32_t JSValue::toUInt32(ExecState* exec) const { if (isUInt32()) - return asInt32(); + return asUInt32(); double val = toNumber(exec); diff --git a/JavaScriptCore/runtime/NumberPrototype.cpp b/JavaScriptCore/runtime/NumberPrototype.cpp index 1a74375..e18553b 100644 --- a/JavaScriptCore/runtime/NumberPrototype.cpp +++ b/JavaScriptCore/runtime/NumberPrototype.cpp @@ -29,6 +29,7 @@ #include "Operations.h" #include "PrototypeFunction.h" #include "StringBuilder.h" +#include "dtoa.h" #include <wtf/Assertions.h> #include <wtf/DecimalNumber.h> #include <wtf/MathExtras.h> diff --git a/JavaScriptCore/runtime/TimeoutChecker.cpp b/JavaScriptCore/runtime/TimeoutChecker.cpp index 2dc1028..04d904d 100644 --- a/JavaScriptCore/runtime/TimeoutChecker.cpp +++ b/JavaScriptCore/runtime/TimeoutChecker.cpp @@ -98,7 +98,10 @@ static inline unsigned getCPUTime() return GETUPTIMEMS(); #else // FIXME: We should return the time the current thread has spent executing. - return currentTime() * 1000; + + // use a relative time from first call in order to avoid an overflow + static double firstTime = currentTime(); + return (currentTime() - firstTime) * 1000; #endif } diff --git a/JavaScriptCore/runtime/UString.cpp b/JavaScriptCore/runtime/UString.cpp index 7362950..17cd9b6 100644 --- a/JavaScriptCore/runtime/UString.cpp +++ b/JavaScriptCore/runtime/UString.cpp @@ -35,10 +35,10 @@ #include <stdlib.h> #include <wtf/ASCIICType.h> #include <wtf/Assertions.h> +#include <wtf/DecimalNumber.h> #include <wtf/MathExtras.h> #include <wtf/StringExtras.h> #include <wtf/Vector.h> -#include <wtf/text/WTFString.h> #include <wtf/unicode/UTF8.h> #if HAVE(STRINGS_H) @@ -199,7 +199,8 @@ UString UString::number(long l) UString UString::number(double d) { NumberToStringBuffer buffer; - return StringImpl::create(buffer, numberToString(d, buffer)); + unsigned length = numberToString(d, buffer); + return UString(buffer, length); } UString UString::substringSharingImpl(unsigned offset, unsigned length) const diff --git a/JavaScriptCore/wtf/Assertions.cpp b/JavaScriptCore/wtf/Assertions.cpp index cadbc91..273e0e0 100644 --- a/JavaScriptCore/wtf/Assertions.cpp +++ b/JavaScriptCore/wtf/Assertions.cpp @@ -35,7 +35,7 @@ #include <CoreFoundation/CFString.h> #endif -#if COMPILER(MSVC) && !OS(WINCE) +#if COMPILER(MSVC) && !OS(WINCE) && !PLATFORM(BREWMP) #ifndef WINVER #define WINVER 0x0500 #endif @@ -50,8 +50,40 @@ #include <winbase.h> #endif +#if PLATFORM(BREWMP) +#include <AEEStdLib.h> +#include <wtf/Vector.h> +#endif + extern "C" { +#if PLATFORM(BREWMP) + +static void printLog(const Vector<char>& buffer) +{ + // Each call to DBGPRINTF generates at most 128 bytes of output on the Windows SDK. + // On Qualcomm chipset targets, DBGPRINTF() comes out the diag port (though this may change). + // The length of each output string is constrained even more than on the Windows SDK. +#if COMPILER(MSVC) + const int printBufferSize = 128; +#else + const int printBufferSize = 32; +#endif + + char printBuffer[printBufferSize + 1]; + printBuffer[printBufferSize] = 0; // to guarantee null termination + + const char* p = buffer.data(); + const char* end = buffer.data() + buffer.size(); + while (p < end) { + strncpy(printBuffer, p, printBufferSize); + DBGPRINTF(printBuffer); + p += printBufferSize; + } +} + +#endif + WTF_ATTRIBUTE_PRINTF(1, 0) static void vprintf_stderr_common(const char* format, va_list args) { @@ -71,6 +103,16 @@ static void vprintf_stderr_common(const char* format, va_list args) CFRelease(str); CFRelease(cfFormat); } else +#elif PLATFORM(BREWMP) + // When str is 0, the return value is the number of bytes needed + // to accept the result including null termination. + int size = vsnprintf(0, 0, format, args); + if (size > 0) { + Vector<char> buffer(size); + vsnprintf(buffer.data(), size, format, args); + printLog(buffer); + } + #elif COMPILER(MSVC) && !defined(WINCEBASIC) if (IsDebuggerPresent()) { size_t size = 1024; diff --git a/JavaScriptCore/wtf/Assertions.h b/JavaScriptCore/wtf/Assertions.h index afeae0c..c4e015d 100644 --- a/JavaScriptCore/wtf/Assertions.h +++ b/JavaScriptCore/wtf/Assertions.h @@ -212,7 +212,14 @@ void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChann #define ASSERT(assertion) ((void)0) #define ASSERT_NOT_REACHED() ((void)0) + +#if COMPILER(INTEL) && !OS(WINDOWS) || COMPILER(RVCT) +template<typename T> +inline void assertUnused(T& x) { (void)x; } +#define ASSERT_UNUSED(variable, assertion) (assertUnused(variable)) +#else #define ASSERT_UNUSED(variable, assertion) ((void)variable) +#endif #else diff --git a/JavaScriptCore/wtf/Complex.h b/JavaScriptCore/wtf/Complex.h index cfd1d20..7da8511 100644 --- a/JavaScriptCore/wtf/Complex.h +++ b/JavaScriptCore/wtf/Complex.h @@ -26,13 +26,13 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef Complex_h -#define Complex_h +#ifndef WTF_Complex_h +#define WTF_Complex_h #include <complex> #include <wtf/MathExtras.h> -namespace WebCore { +namespace WTF { typedef std::complex<double> Complex; @@ -41,6 +41,6 @@ inline Complex complexFromMagnitudePhase(double magnitude, double phase) return Complex(magnitude * cos(phase), magnitude * sin(phase)); } -} // namespace WebCore +} // namespace WTF -#endif // Complex_h +#endif // WTF_Complex_h diff --git a/JavaScriptCore/wtf/DecimalNumber.h b/JavaScriptCore/wtf/DecimalNumber.h index 118c492..3a831b7 100644 --- a/JavaScriptCore/wtf/DecimalNumber.h +++ b/JavaScriptCore/wtf/DecimalNumber.h @@ -40,111 +40,48 @@ class DecimalNumber { public: DecimalNumber(double d) { - bool sign = d < 0; // This (correctly) ignores the sign on -0.0. - init(sign, d); + ASSERT(!isnan(d) && !isinf(d)); + dtoa(m_significand, d, m_sign, m_exponent, m_precision); + + ASSERT(m_precision); + // Zero should always have exponent 0. + ASSERT(m_significand[0] != '0' || !m_exponent); + // No values other than zero should have a leading zero. + ASSERT(m_significand[0] != '0' || m_precision == 1); + // No values other than zero should have trailing zeros. + ASSERT(m_significand[0] == '0' || m_significand[m_precision - 1] != '0'); } - // If our version of dtoa could round to a given number of significant figures then - // we could remove the pre-rounding code from here. We could also do so just by - // calling dtoa and post-rounding, however currently this is slower, since it forces - // dtoa to generate a higher presision result. DecimalNumber(double d, RoundingSignificantFiguresType, unsigned significantFigures) { ASSERT(!isnan(d) && !isinf(d)); - ASSERT(significantFigures && significantFigures <= 21); - - bool sign = d < 0; // This (correctly) ignores the sign on -0.0. - d = fabs(d); // make d positive before going any further. - - int adjust = 0; - if (d) { - // To round a number we align it such that the correct number of digits are - // to the left of the decimal point, then floor/ceil. For example, to round - // 13579 to 3 s.f. we first adjust it to 135.79, use floor/ceil to obtain the - // values 135/136, and then select 136 (since this is closest to 135.79). - // There are currently (exp + 1) digits to the left of the decimal point, - // and we want thsi to be significantFigures, so we're going to adjust the - // exponent by ((exp + 1) - significantFigures). Adjust is effectively - // a count of how many decimal digits to right-shift the number by. - int exp = static_cast<int>(floor(log10(d))); - adjust = (exp + 1) - significantFigures; - - // If the adjust value might be positive or negative - or zero. If zero, then - // nothing to do! - the number is already appropriately aligned. If adjust - // is positive then divide d by 10^adjust. If adjust is negative multiply d - // by 10^-adjust. This is mathematically the same, but avoids two fp divides - // (one inside intPow10, where the power is negative). - if (adjust > 0) - d /= intPow10(adjust); - else if (adjust < 0) - d *= intPow10(-adjust); - - // Try rounding up & rounding down, select whichever is closest (rounding up if equal distance). - double floorOfD = floor(d); - double ceilOfD = floorOfD + 1; - d = (fabs(ceilOfD - d) <= fabs(floorOfD - d)) ? ceilOfD : floorOfD; - - // The number's exponent has been altered - but don't change it back! We can - // just run dtoa on the modified value, and adjust the exponent afterward to - // account for this. - } - - init(sign, d); + dtoaRoundSF(m_significand, d, significantFigures, m_sign, m_exponent, m_precision); - // We alterered the value when rounding it - modify the exponent to adjust for this, - // but don't mess with the exponent of zero. - if (!isZero()) - m_exponent += adjust; + ASSERT(significantFigures && significantFigures <= sizeof(DtoaBuffer)); + while (m_precision < significantFigures) + m_significand[m_precision++] = '0'; - // Make sure the significand does not contain more digits than requested. - roundToPrecision(significantFigures); + ASSERT(m_precision); + // Zero should always have exponent 0. + ASSERT(m_significand[0] != '0' || !m_exponent); } - // If our version of dtoa could round to a given number of decimal places then we - // could remove the pre-rounding code from here. We could also do so just by calling - // dtoa and post-rounding, however currently this is slower, since it forces dtoa to - // generate a higher presision result. DecimalNumber(double d, RoundingDecimalPlacesType, unsigned decimalPlaces) { ASSERT(!isnan(d) && !isinf(d)); - ASSERT(decimalPlaces <= 20); - - bool sign = d < 0; // This (correctly) ignores the sign on -0.0. - d = fabs(d); // Make d positive before going any further. - - ASSERT(d < 1e+21); // We don't currently support rounding to decimal places for values >= 1e+21. - - // Adjust the number by increasing the exponent by decimalPlaces, such - // that we can round to this number of decimal places jsing floor. - if (decimalPlaces) - d *= intPow10(decimalPlaces); - // Try rounding up & rounding down, select whichever is closest (rounding up if equal distance). - double floorOfD = floor(d); - double ceilOfD = floorOfD + 1; - d = (fabs(ceilOfD - d) <= fabs(floorOfD - d)) ? ceilOfD : floorOfD; - // The number's exponent has been altered - but don't change it back! We can - // just run dtoa on the modified value, and adjust the exponent afterward to - // account for this. - - init(sign, d); - - // We rouned the value before calling dtoa, so the result should not be fractional. - ASSERT(m_exponent >= 0); - - // We alterered the value when rounding it - modify the exponent to adjust for this, - // but don't mess with the exponent of zero. - if (!isZero()) - m_exponent -= decimalPlaces; - - // The value was < 1e+21 before we started, should still be. - ASSERT(m_exponent < 21); + dtoaRoundDP(m_significand, d, decimalPlaces, m_sign, m_exponent, m_precision); unsigned significantFigures = 1 + m_exponent + decimalPlaces; - ASSERT(significantFigures && significantFigures <= 41); - roundToPrecision(significantFigures); + ASSERT(significantFigures && significantFigures <= sizeof(DtoaBuffer)); + while (m_precision < significantFigures) + m_significand[m_precision++] = '0'; + + ASSERT(m_precision); + // Zero should always have exponent 0. + ASSERT(m_significand[0] != '0' || !m_exponent); } - unsigned toStringDecimal(NumberToStringBuffer& buffer) + unsigned toStringDecimal(NumberToStringBuffer buffer) { // Should always be at least one digit to add to the string! ASSERT(m_precision); @@ -198,7 +135,7 @@ public: return next - buffer; } - unsigned toStringExponential(NumberToStringBuffer &buffer) + unsigned toStringExponential(NumberToStringBuffer buffer) { // Should always be at least one digit to add to the string! ASSERT(m_precision); @@ -244,75 +181,6 @@ public: unsigned precision() { return m_precision; } private: - void init(bool sign, double d) - { - ASSERT(!isnan(d) && !isinf(d)); - - int decimalPoint; - int signUnused; - char* resultEnd = 0; - WTF::dtoa(m_significand, d, 0, &decimalPoint, &signUnused, &resultEnd); - - m_sign = sign; - m_precision = resultEnd - m_significand; - m_exponent = decimalPoint - 1; - - // No values other than zero should have a leading zero. - ASSERT(m_significand[0] != '0' || m_precision == 1); - // Zero should always have exponent 0. - ASSERT(m_significand[0] != '0' || !m_exponent); - } - - bool isZero() - { - return m_significand[0] == '0'; - } - - // We pre-round the values to dtoa - which leads to it generating faster results. - // But dtoa won't have zero padded the significand to the precision we require, - // and also might have produced too many digits if rounding went wrong somehow. - // Adjust for this. - void roundToPrecision(unsigned significantFigures) - { - ASSERT(significantFigures && significantFigures <= sizeof(DtoaBuffer)); - - // If there are too few of too many digits in the significand then add more, or remove some! - for (unsigned i = m_precision; i < significantFigures; ++i) - m_significand[i] = '0'; - m_precision = significantFigures; - } - - double intPow10(int e) - { - // This function uses the "exponentiation by squaring" algorithm and - // long double to quickly and precisely calculate integer powers of 10.0. - - // This is a handy workaround for <rdar://problem/4494756> - - if (!e) - return 1.0; - - bool negative = e < 0; - unsigned exp = negative ? -e : e; - - long double result = 10.0; - bool foundOne = false; - for (int bit = 31; bit >= 0; bit--) { - if (!foundOne) { - if ((exp >> bit) & 1) - foundOne = true; - } else { - result = result * result; - if ((exp >> bit) & 1) - result = result * 10.0; - } - } - - if (negative) - return static_cast<double>(1.0 / result); - return static_cast<double>(result); - } - bool m_sign; int m_exponent; DtoaBuffer m_significand; diff --git a/JavaScriptCore/wtf/FastMalloc.cpp b/JavaScriptCore/wtf/FastMalloc.cpp index 39cd324..ee6b02c 100644 --- a/JavaScriptCore/wtf/FastMalloc.cpp +++ b/JavaScriptCore/wtf/FastMalloc.cpp @@ -1546,7 +1546,8 @@ void TCMalloc_PageHeap::scavenge() 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)); + size_t length = DLL_Length(&slist->normal); + size_t numSpansToReturn = (i > kMinSpanListsWithSpans) ? length : length / 2; 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); diff --git a/JavaScriptCore/wtf/Forward.h b/JavaScriptCore/wtf/Forward.h index 32435c8..3a9cfa7 100644 --- a/JavaScriptCore/wtf/Forward.h +++ b/JavaScriptCore/wtf/Forward.h @@ -27,6 +27,7 @@ namespace WTF { template<typename T> class ListRefPtr; template<typename T> class OwnArrayPtr; template<typename T> class OwnPtr; + template<typename T> class PassOwnArrayPtr; template<typename T> class PassOwnPtr; template<typename T> class PassRefPtr; template<typename T> class RefPtr; @@ -43,6 +44,7 @@ namespace WTF { using WTF::ListRefPtr; using WTF::OwnArrayPtr; using WTF::OwnPtr; +using WTF::PassOwnArrayPtr; using WTF::PassOwnPtr; using WTF::PassRefPtr; using WTF::RefPtr; diff --git a/JavaScriptCore/wtf/OwnArrayPtr.h b/JavaScriptCore/wtf/OwnArrayPtr.h index d40ea17..ce056b3 100644 --- a/JavaScriptCore/wtf/OwnArrayPtr.h +++ b/JavaScriptCore/wtf/OwnArrayPtr.h @@ -21,74 +21,154 @@ #ifndef WTF_OwnArrayPtr_h #define WTF_OwnArrayPtr_h +#include "Assertions.h" +#include "Noncopyable.h" +#include "OwnArrayPtrCommon.h" #include <algorithm> -#include <wtf/Assertions.h> -#include <wtf/Noncopyable.h> + +// Remove this once we make all WebKit code compatible with stricter rules about OwnArrayPtr. +#define LOOSE_OWN_ARRAY_PTR namespace WTF { - template <typename T> class OwnArrayPtr : public Noncopyable { - public: - explicit OwnArrayPtr(T* ptr = 0) : m_ptr(ptr) { } - ~OwnArrayPtr() { safeDelete(m_ptr); } +template<typename T> class PassOwnArrayPtr; +template<typename T> PassOwnArrayPtr<T> adoptArrayPtr(T*); + +template <typename T> class OwnArrayPtr : public Noncopyable { +public: + typedef T* PtrType; + + OwnArrayPtr() : m_ptr(0) { } - T* get() const { return m_ptr; } - T* release() { T* ptr = m_ptr; m_ptr = 0; return ptr; } + // See comment in PassOwnArrayPtr.h for why this takes a const reference. + template<typename U> OwnArrayPtr(const PassOwnArrayPtr<U>& o); - // FIXME: This should be removed and replaced with PassOwnArrayPtr. - void set(T* ptr) - { - ASSERT(!ptr || m_ptr != ptr); - T* oldPtr = m_ptr; - m_ptr = ptr; - safeDelete(oldPtr); - } + // This copy constructor is used implicitly by gcc when it generates + // transients for assigning a PassOwnArrayPtr<T> object to a stack-allocated + // OwnArrayPtr<T> object. It should never be called explicitly and gcc + // should optimize away the constructor when generating code. + OwnArrayPtr(const OwnArrayPtr<T>&); - void clear(); + ~OwnArrayPtr() { deleteOwnedArrayPtr(m_ptr); } - T& operator*() const { ASSERT(m_ptr); return *m_ptr; } - T* operator->() const { ASSERT(m_ptr); return m_ptr; } + PtrType get() const { return m_ptr; } - T& operator[](std::ptrdiff_t i) const { ASSERT(m_ptr); ASSERT(i >= 0); return m_ptr[i]; } + void clear(); + PassOwnArrayPtr<T> release(); + PtrType leakPtr() WARN_UNUSED_RETURN; - bool operator!() const { return !m_ptr; } + T& operator*() const { ASSERT(m_ptr); return *m_ptr; } + PtrType operator->() const { ASSERT(m_ptr); return m_ptr; } - // This conversion operator allows implicit conversion to bool but not to other integer types. + T& operator[](std::ptrdiff_t i) const { ASSERT(m_ptr); ASSERT(i >= 0); return m_ptr[i]; } + + bool operator!() const { return !m_ptr; } + + // This conversion operator allows implicit conversion to bool but not to other integer types. #if COMPILER(WINSCW) - operator bool() const { return m_ptr; } + operator bool() const { return m_ptr; } #else - typedef T* OwnArrayPtr::*UnspecifiedBoolType; - operator UnspecifiedBoolType() const { return m_ptr ? &OwnArrayPtr::m_ptr : 0; } + typedef T* OwnArrayPtr::*UnspecifiedBoolType; + operator UnspecifiedBoolType() const { return m_ptr ? &OwnArrayPtr::m_ptr : 0; } +#endif + + OwnArrayPtr& operator=(const PassOwnArrayPtr<T>&); + template<typename U> OwnArrayPtr& operator=(const PassOwnArrayPtr<U>&); + + void swap(OwnArrayPtr& o) { std::swap(m_ptr, o.m_ptr); } + +#ifdef LOOSE_OWN_ARRAY_PTR + explicit OwnArrayPtr(PtrType ptr) : m_ptr(ptr) { } + void set(PtrType); +#endif + +private: + PtrType m_ptr; +}; + +template<typename T> template<typename U> inline OwnArrayPtr<T>::OwnArrayPtr(const PassOwnArrayPtr<U>& o) + : m_ptr(o.leakPtr()) +{ +} + +template<typename T> inline void OwnArrayPtr<T>::clear() +{ + PtrType ptr = m_ptr; + m_ptr = 0; + deleteOwnedArrayPtr(ptr); +} + +template<typename T> inline PassOwnArrayPtr<T> OwnArrayPtr<T>::release() +{ + PtrType ptr = m_ptr; + m_ptr = 0; + return adoptArrayPtr(ptr); +} + +template<typename T> inline typename OwnArrayPtr<T>::PtrType OwnArrayPtr<T>::leakPtr() +{ + PtrType ptr = m_ptr; + m_ptr = 0; + return ptr; +} + +#ifdef LOOSE_OWN_ARRAY_PTR +template<typename T> inline void OwnArrayPtr<T>::set(PtrType ptr) +{ + ASSERT(!ptr || m_ptr != ptr); + PtrType oldPtr = m_ptr; + m_ptr = ptr; + deleteOwnedPtr(oldPtr); +} #endif - void swap(OwnArrayPtr& o) { std::swap(m_ptr, o.m_ptr); } - - private: - static void safeDelete(T*); - - T* m_ptr; - }; - - template<typename T> inline void OwnArrayPtr<T>::clear() - { - T* ptr = m_ptr; - m_ptr = 0; - safeDelete(ptr); - } - - template<typename T> inline void OwnArrayPtr<T>::safeDelete(T* ptr) - { - typedef char known[sizeof(T) ? 1 : -1]; - if (sizeof(known)) - delete [] ptr; - } - - template <typename T> inline void swap(OwnArrayPtr<T>& a, OwnArrayPtr<T>& b) { a.swap(b); } - - template <typename T> inline T* getPtr(const OwnArrayPtr<T>& p) - { - return p.get(); - } +template<typename T> inline OwnArrayPtr<T>& OwnArrayPtr<T>::operator=(const PassOwnArrayPtr<T>& o) +{ + PtrType ptr = m_ptr; + m_ptr = o.leakPtr(); + ASSERT(!ptr || m_ptr != ptr); + deleteOwnedArrayPtr(ptr); + return *this; +} + +template<typename T> template<typename U> inline OwnArrayPtr<T>& OwnArrayPtr<T>::operator=(const PassOwnArrayPtr<U>& o) +{ + PtrType ptr = m_ptr; + m_ptr = o.leakPtr(); + ASSERT(!ptr || m_ptr != ptr); + deleteOwnedArrayPtr(ptr); + return *this; +} + +template <typename T> inline void swap(OwnArrayPtr<T>& a, OwnArrayPtr<T>& b) +{ + a.swap(b); +} + +template<typename T, typename U> inline bool operator==(const OwnArrayPtr<T>& a, U* b) +{ + return a.get() == b; +} + +template<typename T, typename U> inline bool operator==(T* a, const OwnArrayPtr<U>& b) +{ + return a == b.get(); +} + +template<typename T, typename U> inline bool operator!=(const OwnArrayPtr<T>& a, U* b) +{ + return a.get() != b; +} + +template<typename T, typename U> inline bool operator!=(T* a, const OwnArrayPtr<U>& b) +{ + return a != b.get(); +} + +template <typename T> inline T* getPtr(const OwnArrayPtr<T>& p) +{ + return p.get(); +} } // namespace WTF diff --git a/JavaScriptCore/wtf/OwnArrayPtrCommon.h b/JavaScriptCore/wtf/OwnArrayPtrCommon.h new file mode 100644 index 0000000..0113aff --- /dev/null +++ b/JavaScriptCore/wtf/OwnArrayPtrCommon.h @@ -0,0 +1,40 @@ +/* + * 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 WTF_OwnArrayPtrCommon_h +#define WTF_OwnArrayPtrCommon_h + +namespace WTF { + +template<typename T> inline void deleteOwnedArrayPtr(T* ptr) +{ + typedef char known[sizeof(T) ? 1 : -1]; + if (sizeof(known)) + delete [] ptr; +} + +} // namespace WTF + +#endif // WTF_OwnArrayPtrCommon_h diff --git a/JavaScriptCore/wtf/PassOwnArrayPtr.h b/JavaScriptCore/wtf/PassOwnArrayPtr.h new file mode 100644 index 0000000..597339c --- /dev/null +++ b/JavaScriptCore/wtf/PassOwnArrayPtr.h @@ -0,0 +1,215 @@ +/* + * 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 WTF_PassOwnArrayPtr_h +#define WTF_PassOwnArrayPtr_h + +#include "Assertions.h" +#include "OwnArrayPtrCommon.h" +#include "TypeTraits.h" + +// Remove this once we make all WebKit code compatible with stricter rules about PassOwnArrayPtr. +#define LOOSE_PASS_OWN_ARRAY_PTR + +namespace WTF { + +template<typename T> class OwnArrayPtr; +template<typename T> class PassOwnArrayPtr; +template<typename T> PassOwnArrayPtr<T> adoptArrayPtr(T*); + +template<typename T> class PassOwnArrayPtr { +public: + typedef T* PtrType; + + PassOwnArrayPtr() : m_ptr(0) { } + + // It somewhat breaks the type system to allow transfer of ownership out of + // a const PassOwnArrayPtr. However, it makes it much easier to work with PassOwnArrayPtr + // temporaries, and we don't have a need to use real const PassOwnArrayPtrs anyway. + PassOwnArrayPtr(const PassOwnArrayPtr& o) : m_ptr(o.leakPtr()) { } + template<typename U> PassOwnArrayPtr(const PassOwnArrayPtr<U>& o) : m_ptr(o.leakPtr()) { } + + ~PassOwnArrayPtr() { deleteOwnedArrayPtr(m_ptr); } + + PtrType get() const { return m_ptr; } + + void clear(); + PtrType leakPtr() const WARN_UNUSED_RETURN; + + T& operator*() const { ASSERT(m_ptr); return *m_ptr; } + PtrType operator->() const { ASSERT(m_ptr); return m_ptr; } + + bool operator!() const { return !m_ptr; } + + // This conversion operator allows implicit conversion to bool but not to other integer types. +#if COMPILER(WINSCW) + operator bool() const { return m_ptr; } +#else + typedef PtrType PassOwnArrayPtr::*UnspecifiedBoolType; + operator UnspecifiedBoolType() const { return m_ptr ? &PassOwnArrayPtr::m_ptr : 0; } +#endif + + PassOwnArrayPtr& operator=(const PassOwnArrayPtr<T>&); + template<typename U> PassOwnArrayPtr& operator=(const PassOwnArrayPtr<U>&); + + template<typename U> friend PassOwnArrayPtr<U> adoptArrayPtr(U*); + +#ifdef LOOSE_PASS_OWN_ARRAY_PTR + PassOwnArrayPtr(PtrType ptr) : m_ptr(ptr) { } + PassOwnArrayPtr& operator=(PtrType); +#endif + +private: +#ifndef LOOSE_PASS_OWN_ARRAY_PTR + explicit PassOwnArrayPtr(PtrType ptr) : m_ptr(ptr) { } +#endif + + mutable PtrType m_ptr; +}; + +template<typename T> inline void PassOwnArrayPtr<T>::clear() +{ + PtrType ptr = m_ptr; + m_ptr = 0; + deleteOwnedArrayPtr(ptr); +} + +template<typename T> inline typename PassOwnArrayPtr<T>::PtrType PassOwnArrayPtr<T>::leakPtr() const +{ + PtrType ptr = m_ptr; + m_ptr = 0; + return ptr; +} + +#ifdef LOOSE_PASS_OWN_ARRAY_PTR +template<typename T> inline PassOwnArrayPtr<T>& PassOwnArrayPtr<T>::operator=(PtrType optr) +{ + PtrType ptr = m_ptr; + m_ptr = optr; + ASSERT(!ptr || m_ptr != ptr); + if (ptr) + deleteOwnedArrayPtr(ptr); + return *this; +} +#endif + +template<typename T> inline PassOwnArrayPtr<T>& PassOwnArrayPtr<T>::operator=(const PassOwnArrayPtr<T>& optr) +{ + PtrType ptr = m_ptr; + m_ptr = optr.leakPtr(); + ASSERT(!ptr || m_ptr != ptr); + if (ptr) + deleteOwnedArrayPtr(ptr); + return *this; +} + +template<typename T> template<typename U> inline PassOwnArrayPtr<T>& PassOwnArrayPtr<T>::operator=(const PassOwnArrayPtr<U>& optr) +{ + PtrType ptr = m_ptr; + m_ptr = optr.leakPtr(); + ASSERT(!ptr || m_ptr != ptr); + if (ptr) + deleteOwnedArrayPtr(ptr); + return *this; +} + +template<typename T, typename U> inline bool operator==(const PassOwnArrayPtr<T>& a, const PassOwnArrayPtr<U>& b) +{ + return a.get() == b.get(); +} + +template<typename T, typename U> inline bool operator==(const PassOwnArrayPtr<T>& a, const OwnArrayPtr<U>& b) +{ + return a.get() == b.get(); +} + +template<typename T, typename U> inline bool operator==(const OwnArrayPtr<T>& a, const PassOwnArrayPtr<U>& b) +{ + return a.get() == b.get(); +} + +template<typename T, typename U> inline bool operator==(const PassOwnArrayPtr<T>& a, U* b) +{ + return a.get() == b; +} + +template<typename T, typename U> inline bool operator==(T* a, const PassOwnArrayPtr<U>& b) +{ + return a == b.get(); +} + +template<typename T, typename U> inline bool operator!=(const PassOwnArrayPtr<T>& a, const PassOwnArrayPtr<U>& b) +{ + return a.get() != b.get(); +} + +template<typename T, typename U> inline bool operator!=(const PassOwnArrayPtr<T>& a, const OwnArrayPtr<U>& b) +{ + return a.get() != b.get(); +} + +template<typename T, typename U> inline bool operator!=(const OwnArrayPtr<T>& a, const PassOwnArrayPtr<U>& b) +{ + return a.get() != b.get(); +} + +template<typename T, typename U> inline bool operator!=(const PassOwnArrayPtr<T>& a, U* b) +{ + return a.get() != b; +} + +template<typename T, typename U> inline bool operator!=(T* a, const PassOwnArrayPtr<U>& b) +{ + return a != b.get(); +} + +template<typename T> inline PassOwnArrayPtr<T> adoptArrayPtr(T* ptr) +{ + return PassOwnArrayPtr<T>(ptr); +} + +template<typename T, typename U> inline PassOwnArrayPtr<T> static_pointer_cast(const PassOwnArrayPtr<U>& p) +{ + return adoptArrayPtr(static_cast<T*>(p.leakPtr())); +} + +template<typename T, typename U> inline PassOwnArrayPtr<T> const_pointer_cast(const PassOwnArrayPtr<U>& p) +{ + return adoptArrayPtr(const_cast<T*>(p.leakPtr())); +} + +template<typename T> inline T* getPtr(const PassOwnArrayPtr<T>& p) +{ + return p.get(); +} + +} // namespace WTF + +using WTF::PassOwnArrayPtr; +using WTF::adoptArrayPtr; +using WTF::const_pointer_cast; +using WTF::static_pointer_cast; + +#endif // WTF_PassOwnArrayPtr_h diff --git a/JavaScriptCore/wtf/Platform.h b/JavaScriptCore/wtf/Platform.h index 727616f..4fc0a64 100644 --- a/JavaScriptCore/wtf/Platform.h +++ b/JavaScriptCore/wtf/Platform.h @@ -520,7 +520,6 @@ /* PLATFORM(SKIA) for Win/Linux, CG/CI for Mac */ #if PLATFORM(CHROMIUM) -#define ENABLE_HISTORY_ALWAYS_ASYNC 1 #if OS(DARWIN) #define WTF_PLATFORM_CG 1 #define WTF_PLATFORM_CI 1 @@ -528,7 +527,6 @@ #define WTF_USE_CORE_TEXT 1 #else #define WTF_PLATFORM_SKIA 1 -#define WTF_USE_GLES2_RENDERING 1 #endif #endif @@ -596,6 +594,7 @@ #endif #define HAVE_READLINE 1 #define HAVE_RUNLOOP_TIMER 1 +#define ENABLE_FULLSCREEN_API 1 #endif /* PLATFORM(MAC) && !PLATFORM(IOS) */ #if PLATFORM(MAC) @@ -617,6 +616,10 @@ #define WTF_PLATFORM_CF 1 #endif +#if OS(DARWIN) && !defined(BUILDING_ON_TIGER) && !PLATFORM(GTK) && !PLATFORM(QT) +#define ENABLE_PURGEABLE_MEMORY 1 +#endif + #if PLATFORM(IOS) #define ENABLE_CONTEXT_MENUS 0 #define ENABLE_DRAG_SUPPORT 0 @@ -858,6 +861,14 @@ #define ENABLE_NETSCAPE_PLUGIN_API 1 #endif +#if !defined(ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE) +#define ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE 0 +#endif + +#if !defined(ENABLE_PURGEABLE_MEMORY) +#define ENABLE_PURGEABLE_MEMORY 0 +#endif + #if !defined(WTF_USE_PLUGIN_HOST_PROCESS) #define WTF_USE_PLUGIN_HOST_PROCESS 0 #endif @@ -917,6 +928,10 @@ #define ENABLE_ON_FIRST_TEXTAREA_FOCUS_SELECT_ALL 0 #endif +#if !defined(ENABLE_FULLSCREEN_API) +#define ENABLE_FULLSCREEN_API 0 +#endif + #if !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64) #if (CPU(X86_64) && (OS(UNIX) || OS(WINDOWS))) \ || (CPU(IA64) && !CPU(IA64_32)) \ @@ -1118,4 +1133,8 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */ #define ENABLE_BRANCH_COMPACTION 1 #endif +#if PLATFORM(GTK) +#include "GtkTypedefs.h" +#endif + #endif /* WTF_Platform_h */ diff --git a/JavaScriptCore/wtf/TCPageMap.h b/JavaScriptCore/wtf/TCPageMap.h index 3f56c24..99bdc40 100644 --- a/JavaScriptCore/wtf/TCPageMap.h +++ b/JavaScriptCore/wtf/TCPageMap.h @@ -72,7 +72,7 @@ class TCMalloc_PageMap1 { // Ensure that the map contains initialized entries "x .. x+n-1". // Returns true if successful, false if we could not allocate memory. - bool Ensure(Number x, size_t n) { + bool Ensure(Number, size_t) { // Nothing to do since flat array was allocate at start return true; } diff --git a/JavaScriptCore/wtf/ThreadSpecific.h b/JavaScriptCore/wtf/ThreadSpecific.h index 893f561..93ed466 100644 --- a/JavaScriptCore/wtf/ThreadSpecific.h +++ b/JavaScriptCore/wtf/ThreadSpecific.h @@ -67,12 +67,17 @@ public: T* operator->(); operator T*(); T& operator*(); - ~ThreadSpecific(); private: #if !USE(PTHREADS) && !PLATFORM(QT) && !PLATFORM(GTK) && OS(WINDOWS) friend void ThreadSpecificThreadExit(); #endif + + // Not implemented. It's technically possible to destroy a thread specific key, but one would need + // to make sure that all values have been destroyed already (usually, that all threads that used it + // have exited). It's unlikely that any user of this call will be in that situation - and having + // a destructor defined can be confusing, given that it has such strong pre-requisites to work correctly. + ~ThreadSpecific(); T* get(); void set(T*); @@ -116,11 +121,6 @@ inline ThreadSpecific<T>::ThreadSpecific() } template<typename T> -inline ThreadSpecific<T>::~ThreadSpecific() -{ -} - -template<typename T> inline T* ThreadSpecific<T>::get() { return m_value; @@ -143,12 +143,6 @@ inline ThreadSpecific<T>::ThreadSpecific() } template<typename T> -inline ThreadSpecific<T>::~ThreadSpecific() -{ - pthread_key_delete(m_key); // Does not invoke destructor functions. -} - -template<typename T> inline T* ThreadSpecific<T>::get() { Data* data = static_cast<Data*>(pthread_getspecific(m_key)); @@ -170,12 +164,6 @@ inline ThreadSpecific<T>::ThreadSpecific() } template<typename T> -inline ThreadSpecific<T>::~ThreadSpecific() -{ - // Does not invoke destructor functions. QThreadStorage will do it -} - -template<typename T> inline T* ThreadSpecific<T>::get() { Data* data = static_cast<Data*>(m_key.localData()); @@ -199,12 +187,6 @@ inline ThreadSpecific<T>::ThreadSpecific() } template<typename T> -inline ThreadSpecific<T>::~ThreadSpecific() -{ - g_static_private_free(&m_key); -} - -template<typename T> inline T* ThreadSpecific<T>::get() { Data* data = static_cast<Data*>(g_static_private_get(&m_key)); diff --git a/JavaScriptCore/wtf/ThreadingPrimitives.h b/JavaScriptCore/wtf/ThreadingPrimitives.h index 66801c0..c11a6cb 100644 --- a/JavaScriptCore/wtf/ThreadingPrimitives.h +++ b/JavaScriptCore/wtf/ThreadingPrimitives.h @@ -45,8 +45,6 @@ #include <pthread.h> #elif PLATFORM(GTK) #include "GOwnPtr.h" -typedef struct _GMutex GMutex; -typedef struct _GCond GCond; #endif #if PLATFORM(QT) diff --git a/JavaScriptCore/wtf/UnusedParam.h b/JavaScriptCore/wtf/UnusedParam.h index 996f5c8..6ff6fd8 100644 --- a/JavaScriptCore/wtf/UnusedParam.h +++ b/JavaScriptCore/wtf/UnusedParam.h @@ -24,6 +24,14 @@ /* don't use this for C++, it should only be used in plain C files or ObjC methods, where leaving off the parameter name is not allowed. */ -#define UNUSED_PARAM(x) (void)x +#include "Platform.h" + +#if COMPILER(INTEL) && !OS(WINDOWS) || COMPILER(RVCT) +template<typename T> +inline void unusedParam(T& x) { (void)x; } +#define UNUSED_PARAM(variable) unusedParam(variable) +#else +#define UNUSED_PARAM(variable) (void)variable +#endif #endif /* WTF_UnusedParam_h */ diff --git a/JavaScriptCore/wtf/Vector3.h b/JavaScriptCore/wtf/Vector3.h index 3c40b61..1850929 100644 --- a/JavaScriptCore/wtf/Vector3.h +++ b/JavaScriptCore/wtf/Vector3.h @@ -26,12 +26,12 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef Vector3_h -#define Vector3_h +#ifndef WTF_Vector3_h +#define WTF_Vector3_h #include <math.h> -namespace WebCore { +namespace WTF { class Vector3 { public: @@ -133,6 +133,6 @@ inline double distance(const Vector3& v1, const Vector3& v2) return (v1 - v2).abs(); } -} // WebCore +} // WTF -#endif // Vector3_h +#endif // WTF_Vector3_h diff --git a/JavaScriptCore/wtf/WTFThreadData.cpp b/JavaScriptCore/wtf/WTFThreadData.cpp index 729b48e..702baed 100644 --- a/JavaScriptCore/wtf/WTFThreadData.cpp +++ b/JavaScriptCore/wtf/WTFThreadData.cpp @@ -43,6 +43,8 @@ WTFThreadData::WTFThreadData() , m_currentIdentifierTable(m_defaultIdentifierTable) #endif { + char sample = 0; + m_approximatedStackStart = &sample; } WTFThreadData::~WTFThreadData() diff --git a/JavaScriptCore/wtf/WTFThreadData.h b/JavaScriptCore/wtf/WTFThreadData.h index c596260..20ffaca 100644 --- a/JavaScriptCore/wtf/WTFThreadData.h +++ b/JavaScriptCore/wtf/WTFThreadData.h @@ -112,6 +112,11 @@ public: } #endif + char* approximatedStackStart() const + { + return m_approximatedStackStart; + } + private: AtomicStringTable* m_atomicStringTable; AtomicStringTableDestructor m_atomicStringTableDestructor; @@ -128,6 +133,8 @@ private: #endif friend WTFThreadData& wtfThreadData(); friend class AtomicStringTable; + + char* m_approximatedStackStart; }; inline WTFThreadData& wtfThreadData() diff --git a/JavaScriptCore/wtf/dtoa.cpp b/JavaScriptCore/wtf/dtoa.cpp index 88e5692..298bb27 100644 --- a/JavaScriptCore/wtf/dtoa.cpp +++ b/JavaScriptCore/wtf/dtoa.cpp @@ -3,7 +3,7 @@ * The author of this software is David M. Gay. * * Copyright (c) 1991, 2000, 2001 by Lucent Technologies. - * Copyright (C) 2002, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2002, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserved. * * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice @@ -18,14 +18,8 @@ * ***************************************************************/ -/* Please send bug reports to - David M. Gay - Bell Laboratories, Room 2C-463 - 600 Mountain Avenue - Murray Hill, NJ 07974-0636 - U.S.A. - dmg@bell-labs.com - */ +/* Please send bug reports to David M. Gay (dmg at acm dot org, + * with " at " changed at "@" and " dot " changed to "."). */ /* On a machine with IEEE extended-precision registers, it is * necessary to specify double-precision (53-bit) rounding precision @@ -50,7 +44,7 @@ * * Modifications: * - * 1. We only require IEEE. + * 1. We only require IEEE double-precision arithmetic (not IEEE double-extended). * 2. We get by with floating-point arithmetic in a case that * Clinger missed -- when we're computing d * 10^n * for a small integer d and the integer n is not too @@ -67,64 +61,13 @@ * for 0 <= k <= 22). */ -/* - * #define IEEE_8087 for IEEE-arithmetic machines where the least - * significant byte has the lowest address. - * #define IEEE_MC68k for IEEE-arithmetic machines where the most - * significant byte has the lowest address. - * #define No_leftright to omit left-right logic in fast floating-point - * computation of dtoa. - * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 - * and Honor_FLT_ROUNDS is not #defined. - * #define Inaccurate_Divide for IEEE-format with correctly rounded - * products but inaccurate quotients, e.g., for Intel i860. - * #define USE_LONG_LONG on machines that have a "long long" - * integer type (of >= 64 bits), and performance testing shows that - * it is faster than 32-bit fallback (which is often not the case - * on 32-bit machines). On such machines, you can #define Just_16 - * to store 16 bits per 32-bit int32_t when doing high-precision integer - * arithmetic. Whether this speeds things up or slows things down - * depends on the machine and the number being converted. - * #define Bad_float_h if your system lacks a float.h or if it does not - * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, - * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. - * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that - * avoids underflows on inputs whose result does not underflow. - * If you #define NO_IEEE_Scale on a machine that uses IEEE-format - * floating-point numbers and flushes underflows to zero rather - * than implementing gradual underflow, then you must also #define - * Sudden_Underflow. - * #define YES_ALIAS to permit aliasing certain double values with - * arrays of ULongs. This leads to slightly better code with - * some compilers and was always used prior to 19990916, but it - * is not strictly legal and can cause trouble with aggressively - * optimizing compilers (e.g., gcc 2.95.1 under -O2). - * #define SET_INEXACT if IEEE arithmetic is being used and extra - * computation should be done to set the inexact flag when the - * result is inexact and avoid setting inexact when the result - * is exact. In this case, dtoa.c must be compiled in - * an environment, perhaps provided by #include "dtoa.c" in a - * suitable wrapper, that defines two functions, - * int get_inexact(void); - * void clear_inexact(void); - * such that get_inexact() returns a nonzero value if the - * inexact bit is already set, and clear_inexact() sets the - * inexact bit to 0. When SET_INEXACT is #defined, strtod - * also does extra computations to set the underflow and overflow - * flags when appropriate (i.e., when the result is tiny and - * inexact or when it is a numeric value rounded to +-infinity). - * #define NO_ERRNO if strtod should not assign errno = ERANGE when - * the result overflows to +-Infinity or underflows to 0. - */ - #include "config.h" #include "dtoa.h" #if HAVE(ERRNO_H) #include <errno.h> -#else -#define NO_ERRNO #endif +#include <float.h> #include <math.h> #include <stdint.h> #include <stdio.h> @@ -132,9 +75,11 @@ #include <string.h> #include <wtf/AlwaysInline.h> #include <wtf/Assertions.h> +#include <wtf/DecimalNumber.h> #include <wtf/FastMalloc.h> #include <wtf/MathExtras.h> #include <wtf/Threading.h> +#include <wtf/UnusedParam.h> #include <wtf/Vector.h> #if COMPILER(MSVC) @@ -143,18 +88,6 @@ #pragma warning(disable: 4554) #endif -#if CPU(BIG_ENDIAN) -#define IEEE_MC68k -#elif CPU(MIDDLE_ENDIAN) -#define IEEE_ARM -#else -#define IEEE_8087 -#endif - -#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(IEEE_ARM) != 1 -Exactly one of IEEE_8087, IEEE_ARM or IEEE_MC68k should be defined. -#endif - namespace WTF { #if ENABLE(JSC_MULTIPLE_THREADS) @@ -166,25 +99,14 @@ typedef union { uint32_t L[2]; } U; -#ifdef YES_ALIAS -#define dval(x) x -#ifdef IEEE_8087 -#define word0(x) ((uint32_t*)&x)[1] -#define word1(x) ((uint32_t*)&x)[0] -#else -#define word0(x) ((uint32_t*)&x)[0] -#define word1(x) ((uint32_t*)&x)[1] -#endif +#if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN) +#define word0(x) (x)->L[0] +#define word1(x) (x)->L[1] #else -#ifdef IEEE_8087 #define word0(x) (x)->L[1] #define word1(x) (x)->L[0] -#else -#define word0(x) (x)->L[0] -#define word1(x) (x)->L[1] #endif #define dval(x) (x)->d -#endif /* The following definition of Storeinc is appropriate for MIPS processors. * An alternative that might be better on some machines is @@ -193,12 +115,12 @@ typedef union { static ALWAYS_INLINE uint32_t* storeInc(uint32_t* p, uint16_t high, uint16_t low) { uint16_t* p16 = reinterpret_cast<uint16_t*>(p); -#if defined(IEEE_8087) || defined(IEEE_ARM) - p16[1] = high; - p16[0] = low; -#else +#if CPU(BIG_ENDIAN) p16[0] = high; p16[1] = low; +#else + p16[1] = high; + p16[0] = low; #endif return p + 1; } @@ -228,51 +150,18 @@ static ALWAYS_INLINE uint32_t* storeInc(uint32_t* p, uint16_t high, uint16_t low #define Quick_max 14 #define Int_max 14 -#if !defined(NO_IEEE_Scale) -#undef Avoid_Underflow -#define Avoid_Underflow -#endif - -#if !defined(Flt_Rounds) -#if defined(FLT_ROUNDS) -#define Flt_Rounds FLT_ROUNDS -#else -#define Flt_Rounds 1 -#endif -#endif /* Flt_Rounds */ - - #define rounded_product(a, b) a *= b #define rounded_quotient(a, b) a /= b #define Big0 (Frac_mask1 | Exp_msk1 * (DBL_MAX_EXP + Bias - 1)) #define Big1 0xffffffff - -// FIXME: we should remove non-Pack_32 mode since it is unused and unmaintained -#ifndef Pack_32 -#define Pack_32 -#endif - #if CPU(PPC64) || CPU(X86_64) // FIXME: should we enable this on all 64-bit CPUs? // 64-bit emulation provided by the compiler is likely to be slower than dtoa own code on 32-bit hardware. #define USE_LONG_LONG #endif -#ifndef USE_LONG_LONG -#ifdef Just_16 -#undef Pack_32 -/* When Pack_32 is not defined, we store 16 bits per 32-bit int32_t. - * This makes some inner loops simpler and sometimes saves work - * during multiplications, but it often seems to make things slightly - * slower. Hence the default is now to store 32 bits per int32_t. - */ -#endif -#endif - -#define Kmax 15 - struct BigInt { BigInt() : sign(0) { } int sign; @@ -282,7 +171,7 @@ struct BigInt { sign = 0; m_words.clear(); } - + size_t size() const { return m_words.size(); @@ -292,7 +181,7 @@ struct BigInt { { m_words.resize(s); } - + uint32_t* words() { return m_words.data(); @@ -302,12 +191,12 @@ struct BigInt { { return m_words.data(); } - + void append(uint32_t w) { m_words.append(w); } - + Vector<uint32_t, 16> m_words; }; @@ -329,17 +218,11 @@ static void multadd(BigInt& b, int m, int a) /* multiply by m and add a */ carry = y >> 32; *x++ = (uint32_t)y & 0xffffffffUL; #else -#ifdef Pack_32 uint32_t xi = *x; uint32_t y = (xi & 0xffff) * m + carry; uint32_t z = (xi >> 16) * m + (y >> 16); carry = z >> 16; *x++ = (z << 16) + (y & 0xffff); -#else - uint32_t y = *x * m + carry; - carry = y >> 16; - *x++ = y & 0xffff; -#endif #endif } while (++i < wds); @@ -349,20 +232,9 @@ static void multadd(BigInt& b, int m, int a) /* multiply by m and add a */ static void s2b(BigInt& b, const char* s, int nd0, int nd, uint32_t y9) { - int k; - int32_t y; - int32_t x = (nd + 8) / 9; - - for (k = 0, y = 1; x > y; y <<= 1, k++) { } -#ifdef Pack_32 b.sign = 0; b.resize(1); b.words()[0] = y9; -#else - b.sign = 0; - b.resize((b->x[1] = y9 >> 16) ? 2 : 1); - b.words()[0] = y9 & 0xffff; -#endif int i = 9; if (9 < nd0) { @@ -440,7 +312,7 @@ static int lo0bits(uint32_t* y) if (!(x & 1)) { k++; x >>= 1; - if (!x & 1) + if (!x) return 32; } *y = x; @@ -479,7 +351,7 @@ static void mult(BigInt& aRef, const BigInt& bRef) a = b; b = tmp; } - + wa = a->size(); wb = b->size(); wc = wa + wb; @@ -507,7 +379,6 @@ static void mult(BigInt& aRef, const BigInt& bRef) } } #else -#ifdef Pack_32 for (; xb < xbe; xb++, xc0++) { if ((y = *xb & 0xffff)) { x = xa; @@ -537,21 +408,6 @@ static void mult(BigInt& aRef, const BigInt& bRef) *xc = z2; } } -#else - for (; xb < xbe; xc0++) { - if ((y = *xb++)) { - x = xa; - xc = xc0; - carry = 0; - do { - z = *x++ * y + *xc + carry; - carry = z >> 16; - *xc++ = z & 0xffff; - } while (x < xae); - *xc = carry; - } - } -#endif #endif for (xc0 = c.words(), xc = xc0 + wc; wc > 0 && !*--xc; --wc) { } c.resize(wc); @@ -562,7 +418,7 @@ struct P5Node : Noncopyable { BigInt val; P5Node* next; }; - + static P5Node* p5s; static int p5sCount; @@ -615,7 +471,7 @@ static ALWAYS_INLINE void pow5mult(BigInt& b, int k) mult(p5->next->val, p5->next->val); ++p5sCount; } - + p5sCountLocal = p5sCount; #if ENABLE(JSC_MULTIPLE_THREADS) s_dtoaP5Mutex->unlock(); @@ -627,11 +483,7 @@ static ALWAYS_INLINE void pow5mult(BigInt& b, int k) static ALWAYS_INLINE void lshift(BigInt& b, int k) { -#ifdef Pack_32 int n = k >> 5; -#else - int n = k >> 4; -#endif int origSize = b.size(); int n1 = n + origSize + 1; @@ -645,7 +497,6 @@ static ALWAYS_INLINE void lshift(BigInt& b, int k) uint32_t* dstStart = b.words(); const uint32_t* src = srcStart + origSize - 1; uint32_t* dst = dstStart + n1 - 1; -#ifdef Pack_32 if (k) { uint32_t hiSubword = 0; int s = 32 - k; @@ -658,19 +509,6 @@ static ALWAYS_INLINE void lshift(BigInt& b, int k) b.resize(origSize + n + !!b.words()[n1 - 1]); } -#else - if (k &= 0xf) { - uint32_t hiSubword = 0; - int s = 16 - k; - for (; src >= srcStart; --src) { - *dst-- = hiSubword | *src >> s; - hiSubword = (*src << k) & 0xffff; - } - *dst = hiSubword; - ASSERT(dst == dstStart + n); - result->wds = b->wds + n + !!result->x[n1 - 1]; - } -#endif else { do { *--dst = *src--; @@ -752,7 +590,6 @@ static ALWAYS_INLINE void diff(BigInt& c, const BigInt& aRef, const BigInt& bRef } #else uint32_t borrow = 0; -#ifdef Pack_32 do { uint32_t y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; @@ -767,18 +604,6 @@ static ALWAYS_INLINE void diff(BigInt& c, const BigInt& aRef, const BigInt& bRef borrow = (z & 0x10000) >> 16; xc = storeInc(xc, z, y); } -#else - do { - uint32_t y = *xa++ - *xb++ - borrow; - borrow = (y & 0x10000) >> 16; - *xc++ = y & 0xffff; - } while (xb < xbe); - while (xa < xae) { - uint32_t y = *xa++ - borrow; - borrow = (y & 0x10000) >> 16; - *xc++ = y & 0xffff; - } -#endif #endif while (!*--xc) wa--; @@ -791,28 +616,8 @@ static double ulp(U *x) U u; L = (word0(x) & Exp_mask) - (P - 1) * Exp_msk1; -#ifndef Avoid_Underflow -#ifndef Sudden_Underflow - if (L > 0) { -#endif -#endif word0(&u) = L; word1(&u) = 0; -#ifndef Avoid_Underflow -#ifndef Sudden_Underflow - } else { - L = -L >> Exp_shift; - if (L < Exp_shift) { - word0(&u) = 0x80000 >> L; - word1(&u) = 0; - } else { - word0(&u) = 0; - L -= Exp_shift; - word1(&u) = L >= 31 ? 1 : 1 << 31 - L; - } - } -#endif -#endif return dval(&u); } @@ -835,7 +640,6 @@ static double b2d(const BigInt& a, int* e) ASSERT(y); k = hi0bits(y); *e = 32 - k; -#ifdef Pack_32 if (k < Ebits) { d0 = Exp_1 | (y >> (Ebits - k)); w = xa > xa0 ? *--xa : 0; @@ -851,22 +655,6 @@ static double b2d(const BigInt& a, int* e) d0 = Exp_1 | y; d1 = z; } -#else - if (k < Ebits + 16) { - z = xa > xa0 ? *--xa : 0; - d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; - w = xa > xa0 ? *--xa : 0; - y = xa > xa0 ? *--xa : 0; - d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; - goto returnD; - } - z = xa > xa0 ? *--xa : 0; - w = xa > xa0 ? *--xa : 0; - k -= Ebits + 16; - d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; - y = xa > xa0 ? *--xa : 0; - d1 = w << k + 16 | y << k; -#endif returnD: #undef d0 #undef d1 @@ -878,104 +666,44 @@ static ALWAYS_INLINE void d2b(BigInt& b, U* d, int* e, int* bits) int de, k; uint32_t* x; uint32_t y, z; -#ifndef Sudden_Underflow int i; -#endif #define d0 word0(d) #define d1 word1(d) b.sign = 0; -#ifdef Pack_32 b.resize(1); -#else - b.resize(2); -#endif x = b.words(); z = d0 & Frac_mask; d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ -#ifdef Sudden_Underflow - de = (int)(d0 >> Exp_shift); -#else if ((de = (int)(d0 >> Exp_shift))) z |= Exp_msk1; -#endif -#ifdef Pack_32 if ((y = d1)) { if ((k = lo0bits(&y))) { x[0] = y | (z << (32 - k)); z >>= k; } else x[0] = y; - if (z) { - b.resize(2); - x[1] = z; - } + if (z) { + b.resize(2); + x[1] = z; + } -#ifndef Sudden_Underflow i = b.size(); -#endif } else { k = lo0bits(&z); x[0] = z; -#ifndef Sudden_Underflow i = 1; -#endif b.resize(1); k += 32; } -#else - if ((y = d1)) { - if ((k = lo0bits(&y))) { - if (k >= 16) { - x[0] = y | z << 32 - k & 0xffff; - x[1] = z >> k - 16 & 0xffff; - x[2] = z >> k; - i = 2; - } else { - x[0] = y & 0xffff; - x[1] = y >> 16 | z << 16 - k & 0xffff; - x[2] = z >> k & 0xffff; - x[3] = z >> k + 16; - i = 3; - } - } else { - x[0] = y & 0xffff; - x[1] = y >> 16; - x[2] = z & 0xffff; - x[3] = z >> 16; - i = 3; - } - } else { - k = lo0bits(&z); - if (k >= 16) { - x[0] = z; - i = 0; - } else { - x[0] = z & 0xffff; - x[1] = z >> 16; - i = 1; - } - k += 32; - } while (!x[i]) - --i; - b->resize(i + 1); -#endif -#ifndef Sudden_Underflow if (de) { -#endif *e = de - Bias - (P - 1) + k; *bits = P - k; -#ifndef Sudden_Underflow } else { *e = de - Bias - (P - 1) + 1 + k; -#ifdef Pack_32 *bits = (32 * i) - hi0bits(x[i - 1]); -#else - *bits = (i + 2) * 16 - hi0bits(x[i]); -#endif } -#endif } #undef d0 #undef d1 @@ -987,11 +715,7 @@ static double ratio(const BigInt& a, const BigInt& b) dval(&da) = b2d(a, &ka); dval(&db) = b2d(b, &kb); -#ifdef Pack_32 k = ka - kb + 32 * (a.size() - b.size()); -#else - k = ka - kb + 16 * (a.size() - b.size()); -#endif if (k > 0) word0(&da) += k * Exp_msk1; else { @@ -1002,19 +726,15 @@ static double ratio(const BigInt& a, const BigInt& b) } static const double tens[] = { - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, - 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, - 1e20, 1e21, 1e22 + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22 }; static const double bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; static const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, -#ifdef Avoid_Underflow - 9007199254740992. * 9007199254740992.e-256 - /* = 2^106 * 1e-53 */ -#else - 1e-256 -#endif + 9007199254740992. * 9007199254740992.e-256 + /* = 2^106 * 1e-256 */ }; /* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */ @@ -1024,20 +744,15 @@ static const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, double strtod(const char* s00, char** se) { -#ifdef Avoid_Underflow int scale; -#endif int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, - e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; + e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; const char *s, *s0, *s1; double aadj, aadj1; U aadj2, adj, rv, rv0; int32_t L; uint32_t y, z; BigInt bb, bb1, bd, bd0, bs, delta; -#ifdef SET_INEXACT - int inexact, oldinexact; -#endif sign = nz0 = nz = 0; dval(&rv) = 0; @@ -1163,14 +878,9 @@ ret0: nd0 = nd; k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; dval(&rv) = y; - if (k > 9) { -#ifdef SET_INEXACT - if (k > DBL_DIG) - oldinexact = get_inexact(); -#endif + if (k > 9) dval(&rv) = tens[k - 9] * dval(&rv) + z; - } - if (nd <= DBL_DIG && Flt_Rounds == 1) { + if (nd <= DBL_DIG) { if (!e) goto ret; if (e > 0) { @@ -1188,24 +898,14 @@ ret0: /* rv = */ rounded_product(dval(&rv), tens[e]); goto ret; } - } -#ifndef Inaccurate_Divide - else if (e >= -Ten_pmax) { + } else if (e >= -Ten_pmax) { /* rv = */ rounded_quotient(dval(&rv), tens[-e]); goto ret; } -#endif } e1 += nd - k; -#ifdef SET_INEXACT - inexact = 1; - if (k <= DBL_DIG) - oldinexact = get_inexact(); -#endif -#ifdef Avoid_Underflow scale = 0; -#endif /* Get starting approximation = rv * 10**e1 */ @@ -1215,17 +915,12 @@ ret0: if (e1 &= ~15) { if (e1 > DBL_MAX_10_EXP) { ovfl: -#ifndef NO_ERRNO +#if HAVE(ERRNO_H) errno = ERANGE; #endif /* Can't trust HUGE_VAL */ word0(&rv) = Exp_mask; word1(&rv) = 0; -#ifdef SET_INEXACT - /* set overflow bit */ - dval(&rv0) = 1e300; - dval(&rv0) *= dval(&rv0); -#endif goto ret; } e1 >>= 4; @@ -1252,50 +947,30 @@ ovfl: if (e1 >>= 4) { if (e1 >= 1 << n_bigtens) goto undfl; -#ifdef Avoid_Underflow if (e1 & Scale_Bit) scale = 2 * P; for (j = 0; e1 > 0; j++, e1 >>= 1) if (e1 & 1) dval(&rv) *= tinytens[j]; if (scale && (j = (2 * P) + 1 - ((word0(&rv) & Exp_mask) >> Exp_shift)) > 0) { - /* scaled rv is denormal; zap j low bits */ + /* scaled rv is denormal; clear j low bits */ if (j >= 32) { word1(&rv) = 0; if (j >= 53) - word0(&rv) = (P + 2) * Exp_msk1; + word0(&rv) = (P + 2) * Exp_msk1; else - word0(&rv) &= 0xffffffff << (j - 32); + word0(&rv) &= 0xffffffff << (j - 32); } else word1(&rv) &= 0xffffffff << j; } -#else - for (j = 0; e1 > 1; j++, e1 >>= 1) - if (e1 & 1) - dval(&rv) *= tinytens[j]; - /* The last multiplication could underflow. */ - dval(&rv0) = dval(&rv); - dval(&rv) *= tinytens[j]; - if (!dval(&rv)) { - dval(&rv) = 2. * dval(&rv0); - dval(&rv) *= tinytens[j]; -#endif if (!dval(&rv)) { undfl: dval(&rv) = 0.; -#ifndef NO_ERRNO +#if HAVE(ERRNO_H) errno = ERANGE; #endif goto ret; } -#ifndef Avoid_Underflow - word0(&rv) = Tiny0; - word1(&rv) = Tiny1; - /* The refinement below will clean - * this approximation up. - */ - } -#endif } } @@ -1322,30 +997,15 @@ undfl: else bd2 -= bbe; bs2 = bb2; -#ifdef Avoid_Underflow j = bbe - scale; i = j + bbbits - 1; /* logb(rv) */ if (i < Emin) /* denormal */ j += P - Emin; else j = P + 1 - bbbits; -#else /*Avoid_Underflow*/ -#ifdef Sudden_Underflow - j = P + 1 - bbbits; -#else /*Sudden_Underflow*/ - j = bbe; - i = j + bbbits - 1; /* logb(rv) */ - if (i < Emin) /* denormal */ - j += P - Emin; - else - j = P + 1 - bbbits; -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow*/ bb2 += j; bd2 += j; -#ifdef Avoid_Underflow bd2 += scale; -#endif i = bb2 < bd2 ? bb2 : bd2; if (i > bs2) i = bs2; @@ -1376,23 +1036,12 @@ undfl: * special case of mantissa a power of two. */ if (dsign || word1(&rv) || word0(&rv) & Bndry_mask -#ifdef Avoid_Underflow || (word0(&rv) & Exp_mask) <= (2 * P + 1) * Exp_msk1 -#else - || (word0(&rv) & Exp_mask) <= Exp_msk1 -#endif ) { -#ifdef SET_INEXACT - if (!delta->words()[0] && delta->size() <= 1) - inexact = 0; -#endif break; } if (!delta.words()[0] && delta.size() <= 1) { /* exact result */ -#ifdef SET_INEXACT - inexact = 0; -#endif break; } lshift(delta, Log2P); @@ -1405,33 +1054,18 @@ undfl: if (dsign) { if ((word0(&rv) & Bndry_mask1) == Bndry_mask1 && word1(&rv) == ( -#ifdef Avoid_Underflow (scale && (y = word0(&rv) & Exp_mask) <= 2 * P * Exp_msk1) ? (0xffffffff & (0xffffffff << (2 * P + 1 - (y >> Exp_shift)))) : -#endif 0xffffffff)) { /*boundary case -- increment exponent*/ word0(&rv) = (word0(&rv) & Exp_mask) + Exp_msk1; word1(&rv) = 0; -#ifdef Avoid_Underflow dsign = 0; -#endif break; } } else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) { dropDown: /* boundary case -- decrement exponent */ -#ifdef Sudden_Underflow /*{{*/ - L = word0(&rv) & Exp_mask; -#ifdef Avoid_Underflow - if (L <= (scale ? (2 * P + 1) * Exp_msk1 : Exp_msk1)) -#else - if (L <= Exp_msk1) -#endif /*Avoid_Underflow*/ - goto undfl; - L -= Exp_msk1; -#else /*Sudden_Underflow}{*/ -#ifdef Avoid_Underflow if (scale) { L = word0(&rv) & Exp_mask; if (L <= (2 * P + 1) * Exp_msk1) { @@ -1443,9 +1077,7 @@ dropDown: goto undfl; } } -#endif /*Avoid_Underflow*/ L = (word0(&rv) & Exp_mask) - Exp_msk1; -#endif /*Sudden_Underflow}}*/ word0(&rv) = L | Bndry_mask1; word1(&rv) = 0xffffffff; break; @@ -1456,24 +1088,18 @@ dropDown: dval(&rv) += ulp(&rv); else { dval(&rv) -= ulp(&rv); -#ifndef Sudden_Underflow if (!dval(&rv)) goto undfl; -#endif } -#ifdef Avoid_Underflow dsign = 1 - dsign; -#endif break; } if ((aadj = ratio(delta, bs)) <= 2.) { if (dsign) aadj = aadj1 = 1.; else if (word1(&rv) || word0(&rv) & Bndry_mask) { -#ifndef Sudden_Underflow if (word1(&rv) == Tiny1 && !word0(&rv)) goto undfl; -#endif aadj = 1.; aadj1 = -1.; } else { @@ -1489,19 +1115,6 @@ dropDown: } else { aadj *= 0.5; aadj1 = dsign ? aadj : -aadj; -#ifdef Check_FLT_ROUNDS - switch (Rounding) { - case 2: /* towards +infinity */ - aadj1 -= 0.5; - break; - case 0: /* towards 0 */ - case 3: /* towards -infinity */ - aadj1 += 0.5; - } -#else - if (!Flt_Rounds) - aadj1 += 0.5; -#endif /*Check_FLT_ROUNDS*/ } y = word0(&rv) & Exp_mask; @@ -1521,7 +1134,6 @@ dropDown: } word0(&rv) += P * Exp_msk1; } else { -#ifdef Avoid_Underflow if (scale && y <= 2 * P * Exp_msk1) { if (aadj <= 0x7fffffff) { if ((z = (uint32_t)aadj) <= 0) @@ -1535,49 +1147,9 @@ dropDown: } adj.d = aadj1 * ulp(&rv); dval(&rv) += adj.d; -#else -#ifdef Sudden_Underflow - if ((word0(&rv) & Exp_mask) <= P * Exp_msk1) { - dval(&rv0) = dval(&rv); - word0(&rv) += P * Exp_msk1; - adj.d = aadj1 * ulp(&rv); - dval(&rv) += adj.d; - if ((word0(&rv) & Exp_mask) <= P * Exp_msk1) { - if (word0(&rv0) == Tiny0 && word1(&rv0) == Tiny1) - goto undfl; - word0(&rv) = Tiny0; - word1(&rv) = Tiny1; - goto cont; - } - word0(&rv) -= P * Exp_msk1; - } else { - adj.d = aadj1 * ulp(&rv); - dval(&rv) += adj.d; - } -#else /*Sudden_Underflow*/ - /* Compute adj so that the IEEE rounding rules will - * correctly round rv + adj in some half-way cases. - * If rv * ulp(rv) is denormalized (i.e., - * y <= (P - 1) * Exp_msk1), we must adjust aadj to avoid - * trouble from bits lost to denormalization; - * example: 1.2e-307 . - */ - if (y <= (P - 1) * Exp_msk1 && aadj > 1.) { - aadj1 = (double)(int)(aadj + 0.5); - if (!dsign) - aadj1 = -aadj1; - } - adj.d = aadj1 * ulp(&rv); - dval(&rv) += adj.d; -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow*/ } z = word0(&rv) & Exp_mask; -#ifndef SET_INEXACT -#ifdef Avoid_Underflow - if (!scale) -#endif - if (y == z) { + if (!scale && y == z) { /* Can we stop now? */ L = (int32_t)aadj; aadj -= L; @@ -1588,39 +1160,19 @@ dropDown: } else if (aadj < .4999999 / FLT_RADIX) break; } -#endif cont: {} } -#ifdef SET_INEXACT - if (inexact) { - if (!oldinexact) { - word0(&rv0) = Exp_1 + (70 << Exp_shift); - word1(&rv0) = 0; - dval(&rv0) += 1.; - } - } else if (!oldinexact) - clear_inexact(); -#endif -#ifdef Avoid_Underflow if (scale) { word0(&rv0) = Exp_1 - 2 * P * Exp_msk1; word1(&rv0) = 0; dval(&rv) *= dval(&rv0); -#ifndef NO_ERRNO +#if HAVE(ERRNO_H) /* try to avoid the bug of testing an 8087 register value */ if (!word0(&rv) && !word1(&rv)) errno = ERANGE; #endif } -#endif /* Avoid_Underflow */ -#ifdef SET_INEXACT - if (inexact && !(word0(&rv) & Exp_mask)) { - /* set underflow bit */ - dval(&rv0) = 1e-300; - dval(&rv0) *= dval(&rv0); - } -#endif ret: if (se) *se = const_cast<char*>(s); @@ -1639,10 +1191,8 @@ static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S) unsigned long long borrow, carry, y, ys; #else uint32_t borrow, carry, y, ys; -#ifdef Pack_32 uint32_t si, z, zs; #endif -#endif ASSERT(b.size() <= 1 || b.words()[b.size() - 1]); ASSERT(S.size() <= 1 || S.words()[S.size() - 1]); @@ -1667,7 +1217,6 @@ static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S) borrow = y >> 32 & (uint32_t)1; *bx++ = (uint32_t)y & 0xffffffffUL; #else -#ifdef Pack_32 si = *sx++; ys = (si & 0xffff) * q + carry; zs = (si >> 16) * q + (ys >> 16); @@ -1677,13 +1226,6 @@ static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S) z = (*bx >> 16) - (zs & 0xffff) - borrow; borrow = (z & 0x10000) >> 16; bx = storeInc(bx, z, y); -#else - ys = *sx++ * q + carry; - carry = ys >> 16; - y = *bx - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - *bx++ = y & 0xffff; -#endif #endif } while (sx <= sxe); if (!*bxe) { @@ -1707,7 +1249,6 @@ static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S) borrow = y >> 32 & (uint32_t)1; *bx++ = (uint32_t)y & 0xffffffffUL; #else -#ifdef Pack_32 si = *sx++; ys = (si & 0xffff) + carry; zs = (si >> 16) + (ys >> 16); @@ -1717,13 +1258,6 @@ static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S) z = (*bx >> 16) - (zs & 0xffff) - borrow; borrow = (z & 0x10000) >> 16; bx = storeInc(bx, z, y); -#else - ys = *sx++ + carry; - carry = ys >> 16; - y = *bx - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - *bx++ = y & 0xffff; -#endif #endif } while (sx <= sxe); bx = b.words(); @@ -1740,7 +1274,7 @@ static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S) /* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. * * Inspired by "How to Print Floating-Point Numbers Accurately" by - * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101]. + * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. * * Modifications: * 1. Rather than iterating, we use a simple numeric overestimate @@ -1769,78 +1303,54 @@ static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S) * "uniformly" distributed input, the probability is * something like 10^(k-15) that we must resort to the int32_t * calculation. + * + * Note: 'leftright' translates to 'generate shortest possible string'. */ - -void dtoa(DtoaBuffer result, double dd, int ndigits, int* decpt, int* sign, char** rve) +template<bool roundingNone, bool roundingSignificantFigures, bool roundingDecimalPlaces, bool leftright> +void dtoa(DtoaBuffer result, double dd, int ndigits, bool& signOut, int& exponentOut, unsigned& precisionOut) { - /* - Arguments ndigits, decpt, sign are similar to those - of ecvt and fcvt; trailing zeros are suppressed from - the returned string. If not null, *rve is set to point - to the end of the return value. If d is +-Infinity or NaN, - then *decpt is set to 9999. + // Exactly one rounding mode must be specified. + ASSERT(roundingNone + roundingSignificantFigures + roundingDecimalPlaces == 1); + // roundingNone only allowed (only sensible?) with leftright set. + ASSERT(!roundingNone || leftright); - */ + ASSERT(!isnan(dd) && !isinf(dd)); int bbits, b2, b5, be, dig, i, ieps, ilim = 0, ilim0, ilim1 = 0, - j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, - spec_case, try_quick; + j, j1, k, k0, k_check, m2, m5, s2, s5, + spec_case; int32_t L; -#ifndef Sudden_Underflow int denorm; uint32_t x; -#endif - BigInt b, b1, delta, mlo, mhi, S; + BigInt b, delta, mlo, mhi, S; U d2, eps, u; double ds; char* s; char* s0; -#ifdef SET_INEXACT - int inexact, oldinexact; -#endif u.d = dd; - if (word0(&u) & Sign_bit) { - /* set sign for everything, including 0's and NaNs */ - *sign = 1; - word0(&u) &= ~Sign_bit; /* clear sign bit */ - } else - *sign = 0; - - if ((word0(&u) & Exp_mask) == Exp_mask) { - /* Infinity or NaN */ - *decpt = 9999; - if (!word1(&u) && !(word0(&u) & 0xfffff)) { - strcpy(result, "Infinity"); - if (rve) - *rve = result + 8; - } else { - strcpy(result, "NaN"); - if (rve) - *rve = result + 3; - } - return; - } + + /* Infinity or NaN */ + ASSERT((word0(&u) & Exp_mask) != Exp_mask); + + // JavaScript toString conversion treats -0 as 0. if (!dval(&u)) { - *decpt = 1; + signOut = false; + exponentOut = 0; + precisionOut = 1; result[0] = '0'; result[1] = '\0'; - if (rve) - *rve = result + 1; return; } -#ifdef SET_INEXACT - try_quick = oldinexact = get_inexact(); - inexact = 1; -#endif + if (word0(&u) & Sign_bit) { + signOut = true; + word0(&u) &= ~Sign_bit; // clear sign bit + } else + signOut = false; d2b(b, &u, &be, &bbits); -#ifdef Sudden_Underflow - i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask >> Exp_shift1)); -#else if ((i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask >> Exp_shift1)))) { -#endif dval(&d2) = dval(&u); word0(&d2) &= Frac_mask1; word0(&d2) |= Exp_11; @@ -1868,7 +1378,6 @@ void dtoa(DtoaBuffer result, double dd, int ndigits, int* decpt, int* sign, char */ i -= Bias; -#ifndef Sudden_Underflow denorm = 0; } else { /* d is denormalized */ @@ -1881,7 +1390,6 @@ void dtoa(DtoaBuffer result, double dd, int ndigits, int* decpt, int* sign, char i -= (Bias + (P - 1) - 1) + 1; denorm = 1; } -#endif ds = (dval(&d2) - 1.5) * 0.289529654602168 + 0.1760912590558 + (i * 0.301029995663981); k = (int)ds; if (ds < 0. && ds != k) @@ -1910,22 +1418,27 @@ void dtoa(DtoaBuffer result, double dd, int ndigits, int* decpt, int* sign, char s5 = 0; } -#ifndef SET_INEXACT -#ifdef Check_FLT_ROUNDS - try_quick = Rounding == 1; -#else - try_quick = 1; -#endif -#endif /*SET_INEXACT*/ + if (roundingNone) { + ilim = ilim1 = -1; + i = 18; + ndigits = 0; + } + if (roundingSignificantFigures) { + if (ndigits <= 0) + ndigits = 1; + ilim = ilim1 = i = ndigits; + } + if (roundingDecimalPlaces) { + i = ndigits + k + 1; + ilim = i; + ilim1 = i - 1; + if (i <= 0) + i = 1; + } - leftright = 1; - ilim = ilim1 = -1; - i = 18; - ndigits = 0; s = s0 = result; - if (ilim >= 0 && ilim <= Quick_max && try_quick) { - + if (ilim >= 0 && ilim <= Quick_max) { /* Try to get by with floating-point arithmetic. */ i = 0; @@ -1978,7 +1491,6 @@ void dtoa(DtoaBuffer result, double dd, int ndigits, int* decpt, int* sign, char goto noDigits; goto fastFailed; } -#ifndef No_leftright if (leftright) { /* Use Steele & White method of only * generating digits needed. @@ -1998,7 +1510,6 @@ void dtoa(DtoaBuffer result, double dd, int ndigits, int* decpt, int* sign, char dval(&u) *= 10.; } } else { -#endif /* Generate ilim digits, then fix them up. */ dval(&eps) *= tens[ilim - 1]; for (i = 1;; i++, dval(&u) *= 10.) { @@ -2017,9 +1528,7 @@ void dtoa(DtoaBuffer result, double dd, int ndigits, int* decpt, int* sign, char break; } } -#ifndef No_leftright } -#endif fastFailed: s = s0; dval(&u) = dval(&d2); @@ -2042,18 +1551,8 @@ fastFailed: for (i = 1;; i++, dval(&u) *= 10.) { L = (int32_t)(dval(&u) / ds); dval(&u) -= L * ds; -#ifdef Check_FLT_ROUNDS - /* If FLT_ROUNDS == 2, L will usually be high by 1 */ - if (dval(&u) < 0) { - L--; - dval(&u) += ds; - } -#endif *s++ = '0' + (int)L; if (!dval(&u)) { -#ifdef SET_INEXACT - inexact = 0; -#endif break; } if (i == ilim) { @@ -2079,11 +1578,7 @@ bumpUp: mhi.clear(); mlo.clear(); if (leftright) { - i = -#ifndef Sudden_Underflow - denorm ? be + (Bias + (P - 1) - 1 + 1) : -#endif - 1 + P - bbits; + i = denorm ? be + (Bias + (P - 1) - 1 + 1) : 1 + P - bbits; b2 += i; s2 += i; i2b(mhi, 1); @@ -2104,7 +1599,7 @@ bumpUp: pow5mult(b, j); } else pow5mult(b, b5); - } + } i2b(S, 1); if (s5 > 0) pow5mult(S, s5); @@ -2112,11 +1607,7 @@ bumpUp: /* Check for special case that d is a normalized power of 2. */ spec_case = 0; - if (!word1(&u) && !(word0(&u) & Bndry_mask) -#ifndef Sudden_Underflow - && word0(&u) & (Exp_mask & ~Exp_msk1) -#endif - ) { + if ((roundingNone || leftright) && (!word1(&u) && !(word0(&u) & Bndry_mask) && word0(&u) & (Exp_mask & ~Exp_msk1))) { /* The special case */ b2 += Log2P; s2 += Log2P; @@ -2130,13 +1621,8 @@ bumpUp: * and for all and pass them and a shift to quorem, so it * can do shifts and ors to compute the numerator for q. */ -#ifdef Pack_32 if ((i = ((s5 ? 32 - hi0bits(S.words()[S.size() - 1]) : 1) + s2) & 0x1f)) i = 32 - i; -#else - if ((i = ((s5 ? 32 - hi0bits(S.words()[S.size() - 1]) : 1) + s2) & 0xf)) - i = 16 - i; -#endif if (i > 4) { i -= 4; b2 += i; @@ -2161,7 +1647,15 @@ bumpUp: ilim = ilim1; } } - + if (ilim <= 0 && roundingDecimalPlaces) { + if (ilim < 0) + goto noDigits; + multadd(S, 5, 0); + // For IEEE-754 unbiased rounding this check should be <=, such that 0.5 would flush to zero. + if (cmp(b, S) < 0) + goto noDigits; + goto oneDigit; + } if (leftright) { if (m2 > 0) lshift(mhi, m2); @@ -2171,10 +1665,8 @@ bumpUp: */ mlo = mhi; - if (spec_case) { - mhi = mlo; + if (spec_case) lshift(mhi, Log2P); - } for (i = 1;;i++) { dig = quorem(b, S) + '0'; @@ -2184,32 +1676,43 @@ bumpUp: j = cmp(b, mlo); diff(delta, S, mhi); j1 = delta.sign ? 1 : cmp(b, delta); +#ifdef DTOA_ROUND_BIASED + if (j < 0 || !j) { +#else + // FIXME: ECMA-262 specifies that equidistant results round away from + // zero, which probably means we shouldn't be on the unbiased code path + // (the (word1(&u) & 1) clause is looking highly suspicious). I haven't + // yet understood this code well enough to make the call, but we should + // probably be enabling DTOA_ROUND_BIASED. I think the interesting corner + // case to understand is probably "Math.pow(0.5, 24).toString()". + // I believe this value is interesting because I think it is precisely + // representable in binary floating point, and its decimal representation + // has a single digit that Steele & White reduction can remove, with the + // value 5 (thus equidistant from the next numbers above and below). + // We produce the correct answer using either codepath, and I don't as + // yet understand why. :-) if (!j1 && !(word1(&u) & 1)) { if (dig == '9') goto round9up; if (j > 0) dig++; -#ifdef SET_INEXACT - else if (!b->x[0] && b->wds <= 1) - inexact = 0; -#endif *s++ = dig; goto ret; } if (j < 0 || (!j && !(word1(&u) & 1))) { - if (!b.words()[0] && b.size() <= 1) { -#ifdef SET_INEXACT - inexact = 0; #endif - goto acceptDig; - } - if (j1 > 0) { + if ((b.words()[0] || b.size() > 1) && (j1 > 0)) { lshift(b, 1); j1 = cmp(b, S); - if ((j1 > 0 || (!j1 && (dig & 1))) && dig++ == '9') - goto round9up; + // For IEEE-754 round-to-even, this check should be (j1 > 0 || (!j1 && (dig & 1))), + // but ECMA-262 specifies that equidistant values (e.g. (.5).toFixed()) should + // be rounded away from zero. + if (j1 >= 0) { + if (dig == '9') + goto round9up; + dig++; + } } -acceptDig: *s++ = dig; goto ret; } @@ -2229,25 +1732,25 @@ round9up: multadd(mlo, 10, 0); multadd(mhi, 10, 0); } - } else + } else { for (i = 1;; i++) { *s++ = dig = quorem(b, S) + '0'; - if (!b.words()[0] && b.size() <= 1) { -#ifdef SET_INEXACT - inexact = 0; -#endif + if (!b.words()[0] && b.size() <= 1) goto ret; - } if (i >= ilim) break; multadd(b, 10, 0); } + } /* Round off last digit */ lshift(b, 1); j = cmp(b, S); - if (j > 0 || (!j && (dig & 1))) { + // For IEEE-754 round-to-even, this check should be (j > 0 || (!j && (dig & 1))), + // but ECMA-262 specifies that equidistant values (e.g. (.5).toFixed()) should + // be rounded away from zero. + if (j >= 0) { roundoff: while (*--s == '9') if (s == s0) { @@ -2262,27 +1765,67 @@ roundoff: } goto ret; noDigits: - k = -1 - ndigits; - goto ret; + exponentOut = 0; + precisionOut = 1; + result[0] = '0'; + result[1] = '\0'; + return; oneDigit: *s++ = '1'; k++; goto ret; ret: -#ifdef SET_INEXACT - if (inexact) { - if (!oldinexact) { - word0(&u) = Exp_1 + (70 << Exp_shift); - word1(&u) = 0; - dval(&u) += 1.; - } - } else if (!oldinexact) - clear_inexact(); -#endif + ASSERT(s > result); *s = 0; - *decpt = k + 1; - if (rve) - *rve = s; + exponentOut = k; + precisionOut = s - result; +} + +void dtoa(DtoaBuffer result, double dd, bool& sign, int& exponent, unsigned& precision) +{ + // flags are roundingNone, leftright. + dtoa<true, false, false, true>(result, dd, 0, sign, exponent, precision); +} + +void dtoaRoundSF(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision) +{ + // flag is roundingSignificantFigures. + dtoa<false, true, false, false>(result, dd, ndigits, sign, exponent, precision); +} + +void dtoaRoundDP(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision) +{ + // flag is roundingDecimalPlaces. + dtoa<false, false, true, false>(result, dd, ndigits, sign, exponent, precision); +} + +static ALWAYS_INLINE void copyAsciiToUTF16(UChar* next, const char* src, unsigned size) +{ + for (unsigned i = 0; i < size; ++i) + *next++ = *src++; +} + +unsigned numberToString(double d, NumberToStringBuffer buffer) +{ + // Handle NaN and Infinity. + if (isnan(d) || isinf(d)) { + if (isnan(d)) { + copyAsciiToUTF16(buffer, "NaN", 3); + return 3; + } + if (d > 0) { + copyAsciiToUTF16(buffer, "Infinity", 8); + return 8; + } + copyAsciiToUTF16(buffer, "-Infinity", 9); + return 9; + } + + // Convert to decimal with rounding. + DecimalNumber number(d); + return number.exponent() >= -6 && number.exponent() < 21 + ? number.toStringDecimal(buffer) + : number.toStringExponential(buffer); } } // namespace WTF diff --git a/JavaScriptCore/wtf/dtoa.h b/JavaScriptCore/wtf/dtoa.h index bf00ccc..7e4fc41 100644 --- a/JavaScriptCore/wtf/dtoa.h +++ b/JavaScriptCore/wtf/dtoa.h @@ -21,11 +21,10 @@ #ifndef WTF_dtoa_h #define WTF_dtoa_h -namespace WTF { -class Mutex; -} +#include <wtf/unicode/Unicode.h> namespace WTF { +class Mutex; extern WTF::Mutex* s_dtoaP5Mutex; @@ -34,10 +33,18 @@ extern WTF::Mutex* s_dtoaP5Mutex; double strtod(const char* s00, char** se); typedef char DtoaBuffer[80]; -void dtoa(DtoaBuffer result, double d, int ndigits, int* decpt, int* sign, char** rve); + +void dtoa(DtoaBuffer result, double dd, bool& sign, int& exponent, unsigned& precision); +void dtoaRoundSF(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision); +void dtoaRoundDP(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision); + +// Size = 80 for sizeof(DtoaBuffer) + some sign bits, decimal point, 'e', exponent digits. +typedef UChar NumberToStringBuffer[96]; +unsigned numberToString(double, NumberToStringBuffer); } // namespace WTF -using WTF::DtoaBuffer; +using WTF::NumberToStringBuffer; +using WTF::numberToString; #endif // WTF_dtoa_h diff --git a/JavaScriptCore/wtf/gobject/GOwnPtr.h b/JavaScriptCore/wtf/gobject/GOwnPtr.h index 731326e..e04ee9d 100644 --- a/JavaScriptCore/wtf/gobject/GOwnPtr.h +++ b/JavaScriptCore/wtf/gobject/GOwnPtr.h @@ -26,15 +26,6 @@ #include <wtf/Assertions.h> #include <wtf/Noncopyable.h> -// Forward delcarations at this point avoid the need to include GLib includes -// in WTF headers. -typedef struct _GError GError; -typedef struct _GList GList; -typedef struct _GCond GCond; -typedef struct _GMutex GMutex; -typedef struct _GPatternSpec GPatternSpec; -typedef struct _GDir GDir; -typedef struct _GFile GFile; extern "C" void g_free(void*); namespace WTF { diff --git a/JavaScriptCore/wtf/gobject/GRefPtr.h b/JavaScriptCore/wtf/gobject/GRefPtr.h index 064c87e..1ca55ce 100644 --- a/JavaScriptCore/wtf/gobject/GRefPtr.h +++ b/JavaScriptCore/wtf/gobject/GRefPtr.h @@ -27,11 +27,8 @@ #include "PlatformRefPtr.h" #include <algorithm> -typedef struct _GHashTable GHashTable; -typedef struct _GVariant GVariant; -typedef void* gpointer; -extern "C" void g_object_unref(gpointer object); -extern "C" gpointer g_object_ref_sink(gpointer object); +extern "C" void g_object_unref(gpointer); +extern "C" gpointer g_object_ref_sink(gpointer); namespace WTF { diff --git a/JavaScriptCore/wtf/gtk/GtkTypedefs.h b/JavaScriptCore/wtf/gtk/GtkTypedefs.h new file mode 100644 index 0000000..ee96f84 --- /dev/null +++ b/JavaScriptCore/wtf/gtk/GtkTypedefs.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2010 Igalia, S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef GtkTypedefs_h +#define GtkTypedefs_h + +/* Vanilla C code does not seem to be able to handle forward-declaration typedefs. */ +#ifdef __cplusplus + +typedef char gchar; +typedef double gdouble; +typedef float gfloat; +typedef int gint; +typedef gint gboolean; +typedef long glong; +typedef short gshort; +typedef unsigned char guchar; +typedef unsigned int guint; +typedef unsigned long gulong; +typedef unsigned short gushort; +typedef void* gpointer; + +typedef struct _cairo_surface cairo_surface_t; +typedef struct _GCond GCond; +typedef struct _GDir GDir; +typedef struct _GdkAtom* GdkAtom; +typedef struct _GdkCursor GdkCursor; +typedef struct _GdkDragContext GdkDragContext; +typedef struct _GdkDrawable GdkDrawable; +typedef struct _GdkEventConfigure GdkEventConfigure; +typedef struct _GdkPixbuf GdkPixbuf; +typedef struct _GError GError; +typedef struct _GFile GFile; +typedef struct _GHashTable GHashTable; +typedef struct _GList GList; +typedef struct _GMutex GMutex; +typedef struct _GPatternSpec GPatternSpec; +typedef struct _GtkAction GtkAction; +typedef struct _GtkAdjustment GtkAdjustment; +typedef struct _GtkBorder GtkBorder; +typedef struct _GtkClipboard GtkClipboard; +typedef struct _GtkContainer GtkContainer; +typedef struct _GtkIconInfo GtkIconInfo; +typedef struct _GtkMenu GtkMenu; +typedef struct _GtkMenuItem GtkMenuItem; +typedef struct _GtkObject GtkObject; +typedef struct _GtkSelectionData GtkSelectionData; +typedef struct _GtkStyle GtkStyle; +typedef struct _GtkTargetList GtkTargetList; +typedef struct _GtkThemeParts GtkThemeParts; +typedef struct _GtkWidget GtkWidget; +typedef struct _GVariant GVariant; +typedef union _GdkEvent GdkEvent; + +#ifdef GTK_API_VERSION_2 +typedef struct _GdkRectangle GdkRectangle; +#else +typedef struct _cairo_rectangle_int cairo_rectangle_int_t; +typedef cairo_rectangle_int_t GdkRectangle; +#endif + +#endif + +#endif /* GtkTypedefs_h */ diff --git a/JavaScriptCore/wtf/text/AtomicString.cpp b/JavaScriptCore/wtf/text/AtomicString.cpp index 6e95292..1981170 100644 --- a/JavaScriptCore/wtf/text/AtomicString.cpp +++ b/JavaScriptCore/wtf/text/AtomicString.cpp @@ -130,7 +130,7 @@ static inline bool equal(StringImpl* string, const UChar* characters, unsigned l // FIXME: perhaps we should have a more abstract macro that indicates when // going 4 bytes at a time is unsafe -#if CPU(ARM) || CPU(SH4) +#if CPU(ARM) || CPU(SH4) || CPU(MIPS) const UChar* stringCharacters = string->characters(); for (unsigned i = 0; i != length; ++i) { if (*stringCharacters++ != *characters++) diff --git a/JavaScriptCore/wtf/text/StringHash.h b/JavaScriptCore/wtf/text/StringHash.h index 8872fb3..bfd05eb 100644 --- a/JavaScriptCore/wtf/text/StringHash.h +++ b/JavaScriptCore/wtf/text/StringHash.h @@ -55,7 +55,7 @@ namespace WTF { // FIXME: perhaps we should have a more abstract macro that indicates when // going 4 bytes at a time is unsafe -#if CPU(ARM) || CPU(SH4) +#if CPU(ARM) || CPU(SH4) || CPU(MIPS) const UChar* aChars = a->characters(); const UChar* bChars = b->characters(); for (unsigned i = 0; i != aLength; ++i) { diff --git a/JavaScriptCore/wtf/text/StringImpl.cpp b/JavaScriptCore/wtf/text/StringImpl.cpp index ab0f009..a667525 100644 --- a/JavaScriptCore/wtf/text/StringImpl.cpp +++ b/JavaScriptCore/wtf/text/StringImpl.cpp @@ -31,6 +31,8 @@ #include <wtf/StdLibExtras.h> #include <wtf/WTFThreadData.h> +using namespace std; + namespace WTF { using namespace Unicode; @@ -776,6 +778,10 @@ PassRefPtr<StringImpl> StringImpl::replace(unsigned position, unsigned lengthToR if (!lengthToReplace && !lengthToInsert) return this; UChar* data; + + if ((length() - lengthToReplace) >= (numeric_limits<unsigned>::max() - lengthToInsert)) + CRASH(); + PassRefPtr<StringImpl> newImpl = createUninitialized(length() - lengthToReplace + lengthToInsert, data); memcpy(data, characters(), position * sizeof(UChar)); @@ -805,9 +811,18 @@ PassRefPtr<StringImpl> StringImpl::replace(UChar pattern, StringImpl* replacemen if (!matchCount) return this; + if (repStrLength && matchCount > numeric_limits<unsigned>::max() / repStrLength) + CRASH(); + + unsigned replaceSize = matchCount * repStrLength; + unsigned newSize = m_length - matchCount; + if (newSize >= (numeric_limits<unsigned>::max() - replaceSize)) + CRASH(); + + newSize += replaceSize; + UChar* data; - PassRefPtr<StringImpl> newImpl = - createUninitialized(m_length - matchCount + (matchCount * repStrLength), data); + PassRefPtr<StringImpl> newImpl = createUninitialized(newSize, data); // Construct the new data size_t srcSegmentEnd; @@ -855,9 +870,17 @@ PassRefPtr<StringImpl> StringImpl::replace(StringImpl* pattern, StringImpl* repl if (!matchCount) return this; + unsigned newSize = m_length - matchCount * patternLength; + if (repStrLength && matchCount > numeric_limits<unsigned>::max() / repStrLength) + CRASH(); + + if (newSize > (numeric_limits<unsigned>::max() - matchCount * repStrLength)) + CRASH(); + + newSize += matchCount * repStrLength; + UChar* data; - PassRefPtr<StringImpl> newImpl = - createUninitialized(m_length + matchCount * (repStrLength - patternLength), data); + PassRefPtr<StringImpl> newImpl = createUninitialized(newSize, data); // Construct the new data size_t srcSegmentEnd; diff --git a/JavaScriptCore/wtf/text/WTFString.cpp b/JavaScriptCore/wtf/text/WTFString.cpp index bbff576..a83dbba 100644 --- a/JavaScriptCore/wtf/text/WTFString.cpp +++ b/JavaScriptCore/wtf/text/WTFString.cpp @@ -25,10 +25,10 @@ #include <limits> #include <stdarg.h> #include <wtf/ASCIICType.h> -#include <wtf/DecimalNumber.h> +#include <wtf/text/CString.h> #include <wtf/StringExtras.h> #include <wtf/Vector.h> -#include <wtf/text/CString.h> +#include <wtf/dtoa.h> #include <wtf/unicode/UTF8.h> #include <wtf/unicode/Unicode.h> @@ -947,49 +947,42 @@ float charactersToFloat(const UChar* data, size_t length, bool* ok) return static_cast<float>(charactersToDouble(data, length, ok)); } -static unsigned copyToString(const char* string, unsigned length, NumberToStringBuffer& buffer) -{ - for (unsigned i = 0; i < length; ++i) - buffer[i] = string[i]; - return length; -} +} // namespace WTF -static NEVER_INLINE unsigned nanOrInfToString(double x, NumberToStringBuffer& buffer) +#ifndef NDEBUG +// For use in the debugger +String* string(const char*); +Vector<char> asciiDebug(StringImpl* impl); +Vector<char> asciiDebug(String& string); + +String* string(const char* s) { - ASSERT(isnan(x) || isinf(x)); - if (isnan(x)) - return copyToString("NaN", 3, buffer); - if (x < 0) - return copyToString("-Infinity", 9, buffer); - return copyToString("Infinity", 8, buffer); + // leaks memory! + return new String(s); } -// toString converts a number to a string without rounding. For values in the range -// 1e-6 <= x < 1e+21 the result is formatted as a decimal, with values outside of -// this range being formatted as an exponential. -unsigned numberToString(double x, NumberToStringBuffer& buffer) +Vector<char> asciiDebug(StringImpl* impl) { - // Handle NaN and Infinity. - if (UNLIKELY(isnan(x) || isinf(x))) - return nanOrInfToString(x, buffer); - - // Convert to decimal, no rounding. - DecimalNumber number(x); + if (!impl) + return asciiDebug(String("[null]").impl()); - // Format as decimal or exponential, depending on the exponent. - return number.exponent() >= -6 && number.exponent() < 21 - ? number.toStringDecimal(buffer) - : number.toStringExponential(buffer); -} + Vector<char> buffer; + unsigned length = impl->length(); + const UChar* characters = impl->characters(); -} // namespace WTF + buffer.resize(length + 1); + for (unsigned i = 0; i < length; ++i) { + UChar ch = characters[i]; + buffer[i] = ch && (ch < 0x20 || ch > 0x7f) ? '?' : ch; + } + buffer[length] = '\0'; -#ifndef NDEBUG -// For use in the debugger - leaks memory -String* string(const char*); + return buffer; +} -String* string(const char* s) +Vector<char> asciiDebug(String& string) { - return new String(s); + return asciiDebug(string.impl()); } + #endif diff --git a/JavaScriptCore/wtf/text/WTFString.h b/JavaScriptCore/wtf/text/WTFString.h index 8a6bab6..fafef12 100644 --- a/JavaScriptCore/wtf/text/WTFString.h +++ b/JavaScriptCore/wtf/text/WTFString.h @@ -52,10 +52,6 @@ class BString; namespace WTF { -// Size = 80 for sizeof(DtoaBuffer) + some sign bits, decimal point, 'e', exponent digits. -typedef UChar NumberToStringBuffer[96]; -unsigned numberToString(double, NumberToStringBuffer&); - class CString; // Declarations of string operations @@ -457,7 +453,4 @@ using WTF::charactersToInt; using WTF::charactersToFloat; using WTF::charactersToDouble; -using WTF::NumberToStringBuffer; -using WTF::numberToString; - #endif diff --git a/JavaScriptCore/wtf/unicode/glib/UnicodeMacrosFromICU.h b/JavaScriptCore/wtf/unicode/glib/UnicodeMacrosFromICU.h index 5d3eca6..1963576 100644 --- a/JavaScriptCore/wtf/unicode/glib/UnicodeMacrosFromICU.h +++ b/JavaScriptCore/wtf/unicode/glib/UnicodeMacrosFromICU.h @@ -27,6 +27,7 @@ // some defines from ICU +#define U_IS_BMP(c) ((UChar32)(c)<=0xffff) #define U16_IS_LEAD(c) (((c)&0xfffffc00)==0xd800) #define U16_IS_TRAIL(c) (((c)&0xfffffc00)==0xdc00) #define U16_SURROGATE_OFFSET ((0xd800<<10UL)+0xdc00-0x10000) diff --git a/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h b/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h index aa203a2..badab66 100644 --- a/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h +++ b/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h @@ -64,7 +64,9 @@ typedef uint16_t UChar; typedef uint32_t UChar32; // some defines from ICU +// FIXME: This should use UnicodeMacrosFromICU.h instead! +#define U_IS_BMP(c) ((UChar32)(c)<=0xffff) #define U16_IS_LEAD(c) (((c)&0xfffffc00)==0xd800) #define U16_IS_TRAIL(c) (((c)&0xfffffc00)==0xdc00) #define U16_SURROGATE_OFFSET ((0xd800<<10UL)+0xdc00-0x10000) diff --git a/JavaScriptCore/wtf/unicode/wince/UnicodeWince.h b/JavaScriptCore/wtf/unicode/wince/UnicodeWince.h index 68da35a..3866568 100644 --- a/JavaScriptCore/wtf/unicode/wince/UnicodeWince.h +++ b/JavaScriptCore/wtf/unicode/wince/UnicodeWince.h @@ -29,7 +29,9 @@ #define TO_MASK(x) (1 << (x)) // some defines from ICU needed one or two places +// FIXME: This should use UnicodeMacrosFromICU.h instead! +#define U_IS_BMP(c) ((UChar32)(c)<=0xffff) #define U16_IS_LEAD(c) (((c) & 0xfffffc00) == 0xd800) #define U16_IS_TRAIL(c) (((c) & 0xfffffc00) == 0xdc00) #define U16_SURROGATE_OFFSET ((0xd800 << 10UL) + 0xdc00 - 0x10000) diff --git a/JavaScriptCore/yarr/RegexJIT.cpp b/JavaScriptCore/yarr/RegexJIT.cpp index 4c21547..7818b52 100644 --- a/JavaScriptCore/yarr/RegexJIT.cpp +++ b/JavaScriptCore/yarr/RegexJIT.cpp @@ -1472,17 +1472,7 @@ public: { generate(); - RefPtr<ExecutablePool> executablePool = globalData->executableAllocator.poolForSize(size()); - if (!executablePool) { - m_shouldFallBack = true; - return; - } - - LinkBuffer patchBuffer(this, executablePool.release(), 0); - if (!patchBuffer.allocationSuccessful()) { - m_shouldFallBack = true; - return; - } + LinkBuffer patchBuffer(this, globalData->executableAllocator.poolForSize(size()), 0); for (unsigned i = 0; i < m_backtrackRecords.size(); ++i) patchBuffer.patch(m_backtrackRecords[i].dataLabel, patchBuffer.locationOf(m_backtrackRecords[i].backtrackLocation)); |