From e8b154fd68f9b33be40a3590e58347f353835f5c Mon Sep 17 00:00:00 2001 From: Steve Block Date: Fri, 27 Aug 2010 11:02:25 +0100 Subject: Merge WebKit at r66079 : Initial merge by git Change-Id: Ie2e1440fb9d487d24e52c247342c076fecaecac7 --- JavaScriptCore/ChangeLog | 345 +++++++++++++++++ JavaScriptCore/GNUmakefile.am | 1 + JavaScriptCore/JavaScriptCore.exp | 3 +- .../JavaScriptCore/JavaScriptCore.def | 3 +- .../JavaScriptCore.xcodeproj/project.pbxproj | 5 + JavaScriptCore/assembler/ARMAssembler.h | 12 + JavaScriptCore/assembler/MacroAssemblerARM.h | 16 +- JavaScriptCore/interpreter/Interpreter.cpp | 2 +- JavaScriptCore/jit/JITStubs.cpp | 10 +- JavaScriptCore/jit/ThunkGenerators.cpp | 14 +- JavaScriptCore/runtime/JSArray.cpp | 9 +- JavaScriptCore/runtime/JSGlobalData.cpp | 1 - JavaScriptCore/runtime/JSGlobalData.h | 2 - JavaScriptCore/runtime/JSGlobalObject.cpp | 1 - JavaScriptCore/runtime/JSGlobalObject.h | 10 +- JavaScriptCore/runtime/JSValue.cpp | 14 +- JavaScriptCore/runtime/JSValue.h | 36 +- JavaScriptCore/runtime/MathObject.cpp | 2 +- JavaScriptCore/runtime/NumberPrototype.cpp | 416 ++++++--------------- JavaScriptCore/runtime/RegExp.cpp | 31 +- JavaScriptCore/runtime/RegExp.h | 3 - JavaScriptCore/runtime/StringBuilder.h | 9 +- JavaScriptCore/runtime/StringPrototype.cpp | 5 +- JavaScriptCore/runtime/UString.cpp | 10 +- JavaScriptCore/wscript | 13 +- JavaScriptCore/wtf/DecimalNumber.h | 328 ++++++++++++++++ JavaScriptCore/wtf/ListHashSet.h | 3 +- JavaScriptCore/wtf/PageReservation.h | 4 +- JavaScriptCore/wtf/PlatformRefPtr.h | 193 ++++++++++ JavaScriptCore/wtf/dtoa.cpp | 79 ---- JavaScriptCore/wtf/dtoa.h | 6 - JavaScriptCore/wtf/gobject/GRefPtr.cpp | 25 +- JavaScriptCore/wtf/gobject/GRefPtr.h | 160 +------- JavaScriptCore/wtf/text/WTFString.cpp | 39 +- JavaScriptCore/wtf/text/WTFString.h | 7 + 35 files changed, 1192 insertions(+), 625 deletions(-) create mode 100644 JavaScriptCore/wtf/DecimalNumber.h create mode 100644 JavaScriptCore/wtf/PlatformRefPtr.h (limited to 'JavaScriptCore') diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog index 1c7f689..fd23733 100644 --- a/JavaScriptCore/ChangeLog +++ b/JavaScriptCore/ChangeLog @@ -1,3 +1,348 @@ +2010-08-25 Kwang Yul Seo + + Reviewed by Kevin Ollivier. + + [BREWMP] Add build system + https://bugs.webkit.org/show_bug.cgi?id=44645 + + Make waf script portable so that we can add more ports. + + * wscript: + +2010-08-25 Michael Saboff + + Reviewed by Sam Weinig. + + Remove the single entry regular expression cache introduced as part of + the fix for https://bugs.webkit.org/show_bug.cgi?id=41238. + The performance problem in Dromaeo that initiated that bug is no + longer present. Dromaeo has been modified so that the regular + expression tests are somewhat random and don't benefit from a + single entry cache. + + * runtime/RegExp.cpp: + (JSC::RegExp::RegExp): + (JSC::RegExp::match): + * runtime/RegExp.h: + +2010-08-25 Martin Robinson + + Reviewed by Gustavo Noronha Silva. + + Cairo and EFL port shouldn't depend on glib. + https://bugs.webkit.org/show_bug.cgi?id=44354 + + Replace GRefPtr with PlatformRefPtr. Keep GLib specific bits in + GRefPtr.h. + + * GNUmakefile.am: Add PlatformRefPtr.h to the source list. + * wtf/PlatformRefPtr.h: Migrated from GRefPtr.h. + (WTF::PlatformRefPtr::PlatformRefPtr): Ditto. + (WTF::PlatformRefPtr::~PlatformRefPtr): Ditto. + (WTF::PlatformRefPtr::clear): Ditto. + (WTF::PlatformRefPtr::get): Ditto. + (WTF::PlatformRefPtr::operator*): Ditto. + (WTF::PlatformRefPtr::operator->): Ditto. + (WTF::PlatformRefPtr::operator!): Ditto. + (WTF::PlatformRefPtr::operator UnspecifiedBoolType): Ditto. + (WTF::PlatformRefPtr::hashTableDeletedValue): Ditto. + (WTF::::operator): Ditto. + (WTF::::swap): Ditto. + (WTF::swap): Ditto. + (WTF::operator==): Ditto. + (WTF::operator!=): Ditto. + (WTF::static_pointer_cast): Ditto. + (WTF::const_pointer_cast): Ditto. + (WTF::getPtr): Ditto. + (WTF::adoptPlatformRef): Ditto. + * wtf/gobject/GRefPtr.cpp: Changes to reflect new names. + (WTF::refPlatformPtr): + (WTF::derefPlatformPtr): + * wtf/gobject/GRefPtr.h: Ditto. + (WTF::refPlatformPtr): + (WTF::derefPlatformPtr): + +2010-08-25 Xan Lopez + + Reviewed by Alexey Proskuryakov. + + Remove dead code in JSGlobalObject + https://bugs.webkit.org/show_bug.cgi?id=44615 + + The recursion data member in the JSGlobalObject and its getter + plus inc/dec methods seems to be unused, remove them. + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + * runtime/JSGlobalObject.h: + +2010-08-25 Michael Saboff + + Reviewed by Geoffrey Garen. + + Changed the initial and subsequent allocation of vector storage to + Array()s. The changes are to limit sparse arrays to 100000 entries + and fixed the sparse map to vector storage conversion to use the + minimum amount of memory needed to store the current number of entries. + These changes address https://bugs.webkit.org/show_bug.cgi?id=43707 + + * runtime/JSArray.cpp: + (JSC::JSArray::putSlowCase): + (JSC::JSArray::getNewVectorLength): + +2010-08-16 Gabor Loki + + Reviewed by Gavin Barraclough. + + Avoid increasing required alignment of target type warning + https://bugs.webkit.org/show_bug.cgi?id=43963 + + Fix platform independent alignment warnings. + + * wtf/ListHashSet.h: + (WTF::ListHashSetNodeAllocator::pool): + +2010-08-19 Gabor Loki + + Reviewed by Gavin Barraclough. + + Enable truncated floating point feature on ARM + https://bugs.webkit.org/show_bug.cgi?id=44233 + + Enable truncated floating point feature with the help of VCVTR.S32.F64 + instruction. If VCVTR.S32.F64 can't fit the result into a 32-bit + integer/register, it saturates at INT_MAX or INT_MIN. Testing this + looks quicker than testing FPSCR for exception. + + Inspired by Jacob Bramley's patch from JaegerMonkey + + * assembler/ARMAssembler.h: + (JSC::ARMAssembler::): + (JSC::ARMAssembler::cmn_r): + (JSC::ARMAssembler::vcvtr_s32_f64_r): + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::supportsFloatingPointTruncate): + (JSC::MacroAssemblerARM::branchTruncateDoubleToInt32): + +2010-08-24 Gavin Barraclough + + Windows build fix. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + +2010-08-24 Gavin Barraclough + + Windows build fix. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * wtf/DecimalNumber.h: + (WTF::DecimalNumber::intPow10): + * wtf/dtoa.cpp: + * wtf/dtoa.h: + +2010-08-23 Gavin Barraclough + + Reviewed by Oliver Hunt. + + https://bugs.webkit.org/show_bug.cgi?id=44487 + + Number.toExponential/toFixed/toPrecision all contain a spaghetti of duplicated + code & unnecessary complexity. Add a new DecimalNumber class to encapsulate + double to string conversion, share the implementations of rounding & + decimal-fraction/exponential formatting. + + * JavaScriptCore.exp: + Update exports. + + * runtime/NumberPrototype.cpp: + (JSC::toThisNumber): + (JSC::getIntegerArgumentInRange): + Helper methods used in implementing toExponential/toFixed/toString. + (JSC::numberProtoFuncToExponential): + (JSC::numberProtoFuncToFixed): + (JSC::numberProtoFuncToPrecision): + Reimplemented using new DecimalNumber class. + + * runtime/UString.cpp: + (JSC::UString::number): + Updated to call numberToString. + + * wtf/DecimalNumber.h: Added. + (WTF::): + (WTF::DecimalNumber::DecimalNumber): + (WTF::DecimalNumber::toStringDecimal): + (WTF::DecimalNumber::toStringExponential): + (WTF::DecimalNumber::sign): + (WTF::DecimalNumber::exponent): + (WTF::DecimalNumber::significand): + (WTF::DecimalNumber::precision): + (WTF::DecimalNumber::init): + (WTF::DecimalNumber::isZero): + (WTF::DecimalNumber::roundToPrecision): + New class to perform double to string conversion. + Has three constructors, which allow conversion with no rounding, + rounding to significant-figures, or rounding to decimal-places, + and two methods for formatting strings, either using decimal + fraction or exponential encoding. Internal implementation uses + pre-rounding of the values before calling dtoa rather than + relying on dtoa to correctly round, which does not produce + fully accurate results. Hopefully we can address this in the + near future. + + * wtf/dtoa.cpp: + (WTF::intPow10): + * wtf/dtoa.h: + intPow10 is used internally by DecimalNumber. + + * wtf/text/WTFString.cpp: + (WTF::copyToString): + (WTF::nanOrInfToString): + Used internally in numberToString for NaN/Infinity handling. + (WTF::numberToString): + Added new method to convert doubles to strings. + + * wtf/text/WTFString.h: + Added declaration for numberToString. This is here because + we should switch over to using this for all double to string + conversion in WebCore (see section 2.4.4.3 of the HTML5 spec). + +2010-08-24 Oliver Hunt + + Reviewed by Geoff Garen. + + Don't seed the JS random number generator from time() + https://bugs.webkit.org/show_bug.cgi?id=41868 + + + Switch to using the secure random number generator to + seed the fast random generator, and make the generator + be per global object. + + * runtime/JSGlobalData.cpp: + (JSC::JSGlobalData::JSGlobalData): + * runtime/JSGlobalData.h: + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::JSGlobalObjectData::JSGlobalObjectData): + (JSC::JSGlobalObject::weakRandomNumber): + * runtime/MathObject.cpp: + (JSC::mathProtoFuncRandom): + +2010-08-24 Oliver Hunt + + Reviewed by Beth Dakin. + + Make overflow guards in UString::utf8 explicit + https://bugs.webkit.org/show_bug.cgi?id=44540 + + Add an explicit overflow check prior to allocating our buffer, + rather than implicitly relying on the guard in convertUTF16ToUTF8. + + * runtime/UString.cpp: + (JSC::UString::utf8): + +2010-08-24 Yael Aharon + + Reviewed by Simon Hausmann. + + [Symbian] Fix commit/decommit of system memory using RChunk + + Swap accidentially reversed start and m_base values for determining the + offset within the RChunk. + + * wtf/PageReservation.h: + (WTF::PageReservation::systemCommit): + (WTF::PageReservation::systemDecommit): + +2010-08-23 Patrick Gansterer + + Rubber-stamped by Gabor Loki. + + [WINCE] Buildfix for GeneratedJITStubs after r64818 + https://bugs.webkit.org/show_bug.cgi?id=44469 + + Use " THUNK_RETURN_ADDRESS_OFFSET" instead of "#offset#". + + * jit/JITStubs.cpp: + +2010-08-23 Oliver Hunt + + Reviewed by Darin Adler. + + [REGRESSION] Interpreter incorrectly excludes prototype chain when validating put_by_id_transition + https://bugs.webkit.org/show_bug.cgi?id=44240 + + + Fix an error I introduced when cleaning up the interpreter side of the logic + to prevent setters being called in object initialisers. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + +2010-08-23 Michael Saboff + + Reviewed by Oliver Hunt. + + Fixed case where a single character search string in a string.replace() + did not properly handle back reference replacement. The fix is to + check for a '$' as part of the check to see if we can execute the + single character replace optimization. + https://bugs.webkit.org/show_bug.cgi?id=44067 + + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncReplace): + +2010-08-23 Oliver Hunt + + Reviewed by Gavin Barraclough. + + JSON.stringify is much slower than Firefox on particular pathological input + https://bugs.webkit.org/show_bug.cgi?id=44456 + + Make StringBuilder::reserveCapacity reserve additional space so we don't end up + repeatedly copying the entire result string. + + * runtime/StringBuilder.h: + (JSC::StringBuilder::append): + (JSC::StringBuilder::reserveCapacity): + +2010-08-23 Jian Li + + Reviewed by Darin Fisher. + + Handle blob resource. + https://bugs.webkit.org/show_bug.cgi?id=43941 + + * JavaScriptCore.exp: Add an export that is neede by BlobResourceHandle. + +2010-08-19 Andreas Kling + + Reviewed by Geoffrey Garen. + + JSC: Move the static_cast into to(U)Int32 fast case + https://bugs.webkit.org/show_bug.cgi?id=44037 + + Do the static_cast<(u)int32_t> inline to avoid the function call overhead + for easily converted values (within (u)int32_t range.) + + * runtime/JSValue.cpp: + (JSC::toInt32SlowCase): + (JSC::toUInt32SlowCase): + * runtime/JSValue.h: + (JSC::JSValue::toInt32): + (JSC::JSValue::toUInt32): + +2010-08-18 Andreas Kling + + Reviewed by Geoffrey Garen. + + REGRESSION(r58469): Math.pow() always returns double-backed JSValue which is extremely slow as array subscript + https://bugs.webkit.org/show_bug.cgi?id=43742 + + Add codegen for pow() to return Int32 values when possible. + + * jit/ThunkGenerators.cpp: + (JSC::powThunkGenerator): + 2010-08-18 Gabor Loki Reviewed by Gavin Barraclough. diff --git a/JavaScriptCore/GNUmakefile.am b/JavaScriptCore/GNUmakefile.am index fae85e1..ecd7ffe 100644 --- a/JavaScriptCore/GNUmakefile.am +++ b/JavaScriptCore/GNUmakefile.am @@ -469,6 +469,7 @@ javascriptcore_sources += \ JavaScriptCore/wtf/PassOwnPtr.h \ JavaScriptCore/wtf/PassRefPtr.h \ JavaScriptCore/wtf/Platform.h \ + JavaScriptCore/wtf/PlatformRefPtr.h \ JavaScriptCore/wtf/PossiblyNull.h \ JavaScriptCore/wtf/RandomNumber.cpp \ JavaScriptCore/wtf/RandomNumber.h \ diff --git a/JavaScriptCore/JavaScriptCore.exp b/JavaScriptCore/JavaScriptCore.exp index 5cfa1c2..4542730 100644 --- a/JavaScriptCore/JavaScriptCore.exp +++ b/JavaScriptCore/JavaScriptCore.exp @@ -377,6 +377,7 @@ __ZN3WTF13currentThreadEv __ZN3WTF13tryFastCallocEmm __ZN3WTF13tryFastMallocEm __ZN3WTF14fastMallocSizeEPKv +__ZN3WTF14numberToStringEdRA96_t __ZN3WTF15ThreadCondition4waitERNS_5MutexE __ZN3WTF15ThreadCondition6signalEv __ZN3WTF15ThreadCondition9broadcastEv @@ -411,7 +412,6 @@ __ZN3WTF23dayInMonthFromDayInYearEib __ZN3WTF23waitForThreadCompletionEjPPv __ZN3WTF27releaseFastMallocFreeMemoryEv __ZN3WTF28setMainThreadCallbacksPausedEb -__ZN3WTF32doubleToStringInJavaScriptFormatEdPcPj __ZN3WTF36lockAtomicallyInitializedStaticMutexEv __ZN3WTF37parseDateFromNullTerminatedCharactersEPKc __ZN3WTF38unlockAtomicallyInitializedStaticMutexEv @@ -534,6 +534,7 @@ __ZNK3JSC9HashTable11deleteTableEv __ZNK3WTF12AtomicString5lowerEv __ZNK3WTF6String11toIntStrictEPbi __ZNK3WTF6String12toUIntStrictEPbi +__ZNK3WTF6String13toInt64StrictEPbi __ZNK3WTF6String14threadsafeCopyEv __ZNK3WTF6String15stripWhiteSpaceEv __ZNK3WTF6String16removeCharactersEPFbtE diff --git a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def index 934688f..eac99b9 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def +++ b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def @@ -126,7 +126,7 @@ EXPORTS ?detach@Debugger@JSC@@UAEXPAVJSGlobalObject@2@@Z ?detachThread@WTF@@YAXI@Z ?didTimeOut@TimeoutChecker@JSC@@QAE_NPAVExecState@2@@Z - ?doubleToStringInJavaScriptFormat@WTF@@YAXNQADPAI@Z + ?dtoa@WTF@@YAXQADNHPAH1PAPAD@Z ?dumpSampleData@JSGlobalData@JSC@@QAEXPAVExecState@2@@Z ?empty@StringImpl@WTF@@SAPAV12@XZ ?enumerable@PropertyDescriptor@JSC@@QBE_NXZ @@ -149,6 +149,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 ?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.xcodeproj/project.pbxproj b/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj index 511a7a0..e11672c 100644 --- a/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj +++ b/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj @@ -200,6 +200,7 @@ 8626BECF11928E3900782FAB /* StringStatics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8626BECE11928E3900782FAB /* StringStatics.cpp */; }; 8627E5EB11F1281900A313B5 /* PageAllocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8627E5E911F1281900A313B5 /* PageAllocation.cpp */; }; 8627E5EC11F1281900A313B5 /* PageAllocation.h in Headers */ = {isa = PBXBuildFile; fileRef = 8627E5EA11F1281900A313B5 /* PageAllocation.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 862AF4B612239C7B0024E5B8 /* DecimalNumber.h in Headers */ = {isa = PBXBuildFile; fileRef = 862AF4B512239C7B0024E5B8 /* DecimalNumber.h */; }; 863B23E00FC6118900703AA4 /* MacroAssemblerCodeRef.h in Headers */ = {isa = PBXBuildFile; fileRef = 863B23DF0FC60E6200703AA4 /* MacroAssemblerCodeRef.h */; settings = {ATTRIBUTES = (Private, ); }; }; 86565742115BE3DA00291F40 /* CString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86565740115BE3DA00291F40 /* CString.cpp */; }; 86565743115BE3DA00291F40 /* CString.h in Headers */ = {isa = PBXBuildFile; fileRef = 86565741115BE3DA00291F40 /* CString.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -785,6 +786,7 @@ 8626BECE11928E3900782FAB /* StringStatics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StringStatics.cpp; path = text/StringStatics.cpp; sourceTree = ""; }; 8627E5E911F1281900A313B5 /* PageAllocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PageAllocation.cpp; sourceTree = ""; }; 8627E5EA11F1281900A313B5 /* PageAllocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PageAllocation.h; sourceTree = ""; }; + 862AF4B512239C7B0024E5B8 /* DecimalNumber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DecimalNumber.h; sourceTree = ""; }; 863B23DF0FC60E6200703AA4 /* MacroAssemblerCodeRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroAssemblerCodeRef.h; sourceTree = ""; }; 86565740115BE3DA00291F40 /* CString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CString.cpp; path = text/CString.cpp; sourceTree = ""; }; 86565741115BE3DA00291F40 /* CString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CString.h; path = text/CString.h; sourceTree = ""; }; @@ -1438,6 +1440,7 @@ 180B9AF00F16C569009BDBC5 /* CurrentTime.h */, 41359CF40FDD89CB00206180 /* DateMath.cpp */, 41359CF50FDD89CB00206180 /* DateMath.h */, + 862AF4B512239C7B0024E5B8 /* DecimalNumber.h */, 5186111D0CC824830081412B /* Deque.h */, 938C4F6B0CA06BCE00D9310A /* DisallowCType.h */, 651F6412039D5B5F0078395C /* dtoa.cpp */, @@ -2233,6 +2236,7 @@ DDE82AD81209D955005C1756 /* GCHandle.h in Headers */, 86F38859121130CA007A7CE3 /* AtomicStringHash.h in Headers */, 86B6DA0212132B9A000D316F /* StringConcatenate.h in Headers */, + 862AF4B612239C7B0024E5B8 /* DecimalNumber.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2326,6 +2330,7 @@ isa = PBXProject; buildConfigurationList = 149C277108902AFE008A9EFC /* Build configuration list for PBXProject "JavaScriptCore" */; compatibilityVersion = "Xcode 2.4"; + developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( English, diff --git a/JavaScriptCore/assembler/ARMAssembler.h b/JavaScriptCore/assembler/ARMAssembler.h index da128e7..dfa726a 100644 --- a/JavaScriptCore/assembler/ARMAssembler.h +++ b/JavaScriptCore/assembler/ARMAssembler.h @@ -161,6 +161,7 @@ namespace JSC { VMOV_ARM = 0x0e100a10, VCVT_F64_S32 = 0x0eb80bc0, VCVT_S32_F64 = 0x0ebd0b40, + VCVTR_S32_F64 = 0x0ebd0bc0, VMRS_APSR = 0x0ef1fa10, #if WTF_ARM_ARCH_AT_LEAST(5) CLZ = 0x016f0f10, @@ -371,6 +372,11 @@ namespace JSC { emitInst(static_cast(cc) | CMP | SET_CC, 0, rn, op2); } + void cmn_r(int rn, ARMWord op2, Condition cc = AL) + { + emitInst(static_cast(cc) | CMN | SET_CC, 0, rn, op2); + } + void orr_r(int rd, int rn, ARMWord op2, Condition cc = AL) { emitInst(static_cast(cc) | ORR, rd, rn, op2); @@ -578,6 +584,12 @@ namespace JSC { emitDoublePrecisionInst(static_cast(cc) | VCVT_S32_F64, (sd >> 1), 0, dm); } + void vcvtr_s32_f64_r(int sd, int dm, Condition cc = AL) + { + ASSERT(!(sd & 0x1)); // sd must be divisible by 2 + emitDoublePrecisionInst(static_cast(cc) | VCVTR_S32_F64, (sd >> 1), 0, dm); + } + void vmrs_apsr(Condition cc = AL) { m_buffer.putInt(static_cast(cc) | VMRS_APSR); diff --git a/JavaScriptCore/assembler/MacroAssemblerARM.h b/JavaScriptCore/assembler/MacroAssemblerARM.h index 48ddf24..5de8b34 100644 --- a/JavaScriptCore/assembler/MacroAssemblerARM.h +++ b/JavaScriptCore/assembler/MacroAssemblerARM.h @@ -769,7 +769,7 @@ public: bool supportsFloatingPointTruncate() const { - return false; + return s_isVFPPresent; } bool supportsFloatingPointSqrt() const @@ -878,13 +878,17 @@ public: // Truncates 'src' to an integer, and places the resulting 'dest'. // If the result is not representable as a 32 bit value, branch. // May also branch for some values that are representable in 32 bits - // (specifically, in this case, INT_MIN). + // (specifically, in this case, INT_MIN and INT_MAX). Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest) { - UNUSED_PARAM(src); - UNUSED_PARAM(dest); - ASSERT_NOT_REACHED(); - return jump(); + m_assembler.vcvtr_s32_f64_r(ARMRegisters::SD0 << 1, src); + // If VCVTR.S32.F64 can't fit the result into a 32-bit + // integer, it saturates at INT_MAX or INT_MIN. Testing this is + // probably quicker than testing FPSCR for exception. + m_assembler.vmov_arm_r(dest, ARMRegisters::SD0 << 1); + m_assembler.sub_r(ARMRegisters::S0, dest, ARMAssembler::getOp2(0x80000000)); + m_assembler.cmn_r(ARMRegisters::S0, ARMAssembler::getOp2(1), ARMCondition(NotEqual)); + return Jump(m_assembler.jmp(ARMCondition(Equal))); } // Convert 'src' to an integer, and places the resulting 'dest'. diff --git a/JavaScriptCore/interpreter/Interpreter.cpp b/JavaScriptCore/interpreter/Interpreter.cpp index b1049ad..d43eb57 100644 --- a/JavaScriptCore/interpreter/Interpreter.cpp +++ b/JavaScriptCore/interpreter/Interpreter.cpp @@ -2952,7 +2952,7 @@ skip_id_custom_self: JSObject* baseObject = asObject(baseCell); int direct = vPC[8].u.operand; - if (direct) { + if (!direct) { RefPtr* it = vPC[6].u.structureChain->head(); JSValue proto = baseObject->structure()->prototypeForLookup(callFrame); diff --git a/JavaScriptCore/jit/JITStubs.cpp b/JavaScriptCore/jit/JITStubs.cpp index f1808d5..b53e655 100644 --- a/JavaScriptCore/jit/JITStubs.cpp +++ b/JavaScriptCore/jit/JITStubs.cpp @@ -1164,13 +1164,13 @@ MSVC_BEGIN() MSVC_BEGIN(ctiTrampoline PROC) MSVC_BEGIN( stmdb sp!, {r1-r3}) MSVC_BEGIN( stmdb sp!, {r4-r8, lr}) -MSVC_BEGIN( sub sp, sp, ##offset#+4) +MSVC_BEGIN( sub sp, sp, # THUNK_RETURN_ADDRESS_OFFSET + 4) MSVC_BEGIN( mov r4, r2) MSVC_BEGIN( mov r5, #512) MSVC_BEGIN( ; r0 contains the code) MSVC_BEGIN( mov lr, pc) MSVC_BEGIN( bx r0) -MSVC_BEGIN( add sp, sp, ##offset#+4) +MSVC_BEGIN( add sp, sp, # THUNK_RETURN_ADDRESS_OFFSET + 4) MSVC_BEGIN( ldmia sp!, {r4-r8, lr}) MSVC_BEGIN( add sp, sp, #12) MSVC_BEGIN( bx lr) @@ -1181,7 +1181,7 @@ MSVC_BEGIN( mov r0, sp) MSVC_BEGIN( mov lr, pc) MSVC_BEGIN( bl cti_vm_throw) MSVC_BEGIN(ctiOpThrowNotCaught) -MSVC_BEGIN( add sp, sp, ##offset#+4) +MSVC_BEGIN( add sp, sp, # THUNK_RETURN_ADDRESS_OFFSET + 4) MSVC_BEGIN( ldmia sp!, {r4-r8, lr}) MSVC_BEGIN( add sp, sp, #12) MSVC_BEGIN( bx lr) @@ -1191,9 +1191,9 @@ MSVC_BEGIN() MSVC( EXPORT cti_#op#) MSVC( IMPORT JITStubThunked_#op#) MSVC(cti_#op# PROC) -MSVC( str lr, [sp, ##offset#]) +MSVC( str lr, [sp, # THUNK_RETURN_ADDRESS_OFFSET]) MSVC( bl JITStubThunked_#op#) -MSVC( ldr lr, [sp, ##offset#]) +MSVC( ldr lr, [sp, # THUNK_RETURN_ADDRESS_OFFSET]) MSVC( bx lr) MSVC(cti_#op# ENDP) MSVC() diff --git a/JavaScriptCore/jit/ThunkGenerators.cpp b/JavaScriptCore/jit/ThunkGenerators.cpp index 20857cb..4c7a354 100644 --- a/JavaScriptCore/jit/ThunkGenerators.cpp +++ b/JavaScriptCore/jit/ThunkGenerators.cpp @@ -134,7 +134,14 @@ MacroAssemblerCodePtr powThunkGenerator(JSGlobalData* globalData, ExecutablePool jit.branchTest32(MacroAssembler::NonZero, SpecializedThunkJIT::regT0).linkTo(startLoop, &jit); exponentIsZero.link(&jit); - jit.returnDouble(SpecializedThunkJIT::fpRegT1); + + { + SpecializedThunkJIT::JumpList doubleResult; + jit.branchConvertDoubleToInt32(SpecializedThunkJIT::fpRegT1, SpecializedThunkJIT::regT0, doubleResult, SpecializedThunkJIT::fpRegT0); + jit.returnInt32(SpecializedThunkJIT::regT0); + doubleResult.link(&jit); + jit.returnDouble(SpecializedThunkJIT::fpRegT1); + } if (jit.supportsFloatingPointSqrt()) { nonIntExponent.link(&jit); @@ -144,6 +151,11 @@ MacroAssemblerCodePtr powThunkGenerator(JSGlobalData* globalData, ExecutablePool jit.appendFailure(jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, SpecializedThunkJIT::fpRegT2, SpecializedThunkJIT::fpRegT3)); jit.sqrtDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT0); jit.divDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1); + + SpecializedThunkJIT::JumpList doubleResult; + jit.branchConvertDoubleToInt32(SpecializedThunkJIT::fpRegT1, SpecializedThunkJIT::regT0, doubleResult, SpecializedThunkJIT::fpRegT0); + jit.returnInt32(SpecializedThunkJIT::regT0); + doubleResult.link(&jit); jit.returnDouble(SpecializedThunkJIT::fpRegT1); } else jit.appendFailure(nonIntExponent); diff --git a/JavaScriptCore/runtime/JSArray.cpp b/JavaScriptCore/runtime/JSArray.cpp index 9c3570b..55aa327 100644 --- a/JavaScriptCore/runtime/JSArray.cpp +++ b/JavaScriptCore/runtime/JSArray.cpp @@ -421,9 +421,10 @@ NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValue valu if (i >= MIN_SPARSE_ARRAY_INDEX) newNumValuesInVector -= map->contains(i); if (isDenseEnoughForVector(newVectorLength, newNumValuesInVector)) { + unsigned needLength = max(i + 1, storage->m_length); unsigned proposedNewNumValuesInVector = newNumValuesInVector; // If newVectorLength is already the maximum - MAX_STORAGE_VECTOR_LENGTH - then do not attempt to grow any further. - while (newVectorLength < MAX_STORAGE_VECTOR_LENGTH) { + while ((newVectorLength < needLength) && (newVectorLength < MAX_STORAGE_VECTOR_LENGTH)) { unsigned proposedNewVectorLength = getNewVectorLength(newVectorLength + 1); for (unsigned j = max(newVectorLength, MIN_SPARSE_ARRAY_INDEX); j < proposedNewVectorLength; ++j) proposedNewNumValuesInVector += map->contains(j); @@ -553,10 +554,10 @@ ALWAYS_INLINE unsigned JSArray::getNewVectorLength(unsigned desiredLength) ASSERT(desiredLength <= MAX_STORAGE_VECTOR_LENGTH); unsigned increasedLength; - unsigned length = m_storage->m_length; + unsigned maxInitLength = min(m_storage->m_length, 100000U); - if (desiredLength < length) - increasedLength = length; + if (desiredLength < maxInitLength) + increasedLength = maxInitLength; else if (!m_vectorLength) increasedLength = max(desiredLength, lastArraySize); else { diff --git a/JavaScriptCore/runtime/JSGlobalData.cpp b/JavaScriptCore/runtime/JSGlobalData.cpp index ca8605b..97f9be5 100644 --- a/JavaScriptCore/runtime/JSGlobalData.cpp +++ b/JavaScriptCore/runtime/JSGlobalData.cpp @@ -143,7 +143,6 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread , firstStringifierToMark(0) , markStack(jsArrayVPtr) , cachedUTCOffset(NaN) - , weakRandom(static_cast(currentTime())) , maxReentryDepth(threadStackType == ThreadStackTypeSmall ? MaxSmallThreadReentryDepth : MaxLargeThreadReentryDepth) , m_regExpCache(new RegExpCache(this)) #ifndef NDEBUG diff --git a/JavaScriptCore/runtime/JSGlobalData.h b/JavaScriptCore/runtime/JSGlobalData.h index 1928f77..07acb43 100644 --- a/JavaScriptCore/runtime/JSGlobalData.h +++ b/JavaScriptCore/runtime/JSGlobalData.h @@ -213,8 +213,6 @@ namespace JSC { UString cachedDateString; double cachedDateStringValue; - - WeakRandom weakRandom; int maxReentryDepth; diff --git a/JavaScriptCore/runtime/JSGlobalObject.cpp b/JavaScriptCore/runtime/JSGlobalObject.cpp index c317e13..89c042a 100644 --- a/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -141,7 +141,6 @@ void JSGlobalObject::init(JSObject* thisValue) } else headObject = d()->next = d()->prev = this; - d()->recursion = 0; d()->debugger = 0; d()->profileGroup = 0; diff --git a/JavaScriptCore/runtime/JSGlobalObject.h b/JavaScriptCore/runtime/JSGlobalObject.h index e57b737..f5d2fb0 100644 --- a/JavaScriptCore/runtime/JSGlobalObject.h +++ b/JavaScriptCore/runtime/JSGlobalObject.h @@ -31,6 +31,7 @@ #include "StringPrototype.h" #include #include +#include namespace JSC { @@ -92,6 +93,7 @@ namespace JSC { , datePrototype(0) , regExpPrototype(0) , methodCallDummy(0) + , weakRandom(static_cast(randomNumber() * (std::numeric_limits::max() + 1.0))) { } @@ -107,8 +109,6 @@ namespace JSC { ScopeChain globalScopeChain; Register globalCallFrame[RegisterFile::CallFrameHeaderSize]; - int recursion; - RegExpConstructor* regExpConstructor; ErrorConstructor* errorConstructor; NativeErrorConstructor* evalErrorConstructor; @@ -156,6 +156,7 @@ namespace JSC { HashSet codeBlocks; WeakMapSet weakMaps; + WeakRandom weakRandom; }; public: @@ -254,10 +255,6 @@ namespace JSC { virtual bool supportsProfiling() const { return false; } - int recursion() { return d()->recursion; } - void incRecursion() { ++d()->recursion; } - void decRecursion() { --d()->recursion; } - ScopeChain& globalScopeChain() { return d()->globalScopeChain; } virtual bool isGlobalObject() const { return true; } @@ -295,6 +292,7 @@ namespace JSC { d()->weakMaps.remove(map); } + double weakRandomNumber() { return d()->weakRandom.get(); } protected: static const unsigned AnonymousSlotCount = JSVariableObject::AnonymousSlotCount + 1; diff --git a/JavaScriptCore/runtime/JSValue.cpp b/JavaScriptCore/runtime/JSValue.cpp index e752d3f..6db6954 100644 --- a/JavaScriptCore/runtime/JSValue.cpp +++ b/JavaScriptCore/runtime/JSValue.cpp @@ -137,16 +137,13 @@ char* JSValue::description() int32_t toInt32SlowCase(double d, bool& ok) { - ok = true; - - if (d >= -D32 / 2 && d < D32 / 2) - return static_cast(d); - if (isnan(d) || isinf(d)) { ok = false; return 0; } + ok = true; + double d32 = fmod(trunc(d), D32); if (d32 >= D32 / 2) d32 -= D32; @@ -157,16 +154,13 @@ int32_t toInt32SlowCase(double d, bool& ok) uint32_t toUInt32SlowCase(double d, bool& ok) { - ok = true; - - if (d >= 0.0 && d < D32) - return static_cast(d); - if (isnan(d) || isinf(d)) { ok = false; return 0; } + ok = true; + double d32 = fmod(trunc(d), D32); if (d32 < 0) d32 += D32; diff --git a/JavaScriptCore/runtime/JSValue.h b/JavaScriptCore/runtime/JSValue.h index 3c6bc09..af4b0f4 100644 --- a/JavaScriptCore/runtime/JSValue.h +++ b/JavaScriptCore/runtime/JSValue.h @@ -397,16 +397,28 @@ namespace JSC { { if (isInt32()) return asInt32(); + + double val = toNumber(exec); + + if (val >= -2147483648.0 && val < 2147483648.0) + return static_cast(val); + bool ignored; - return toInt32SlowCase(toNumber(exec), ignored); + return toInt32SlowCase(val, ignored); } inline uint32_t JSValue::toUInt32(ExecState* exec) const { if (isUInt32()) return asInt32(); + + double val = toNumber(exec); + + if (val >= 0.0 && val < 4294967296.0) + return static_cast(val); + bool ignored; - return toUInt32SlowCase(toNumber(exec), ignored); + return toUInt32SlowCase(val, ignored); } inline int32_t JSValue::toInt32(ExecState* exec, bool& ok) const @@ -415,7 +427,15 @@ namespace JSC { ok = true; return asInt32(); } - return toInt32SlowCase(toNumber(exec), ok); + + double val = toNumber(exec); + + if (val >= -2147483648.0 && val < 2147483648.0) { + ok = true; + return static_cast(val); + } + + return toInt32SlowCase(val, ok); } inline uint32_t JSValue::toUInt32(ExecState* exec, bool& ok) const @@ -424,7 +444,15 @@ namespace JSC { ok = true; return asInt32(); } - return toUInt32SlowCase(toNumber(exec), ok); + + double val = toNumber(exec); + + if (val >= 0.0 && val < 4294967296.0) { + ok = true; + return static_cast(val); + } + + return toUInt32SlowCase(val, ok); } #if USE(JSVALUE32_64) diff --git a/JavaScriptCore/runtime/MathObject.cpp b/JavaScriptCore/runtime/MathObject.cpp index cfbaab2..5648264 100644 --- a/JavaScriptCore/runtime/MathObject.cpp +++ b/JavaScriptCore/runtime/MathObject.cpp @@ -211,7 +211,7 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncPow(ExecState* exec) EncodedJSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState* exec) { - return JSValue::encode(jsDoubleNumber(exec, exec->globalData().weakRandom.get())); + return JSValue::encode(jsDoubleNumber(exec, exec->lexicalGlobalObject()->weakRandomNumber())); } EncodedJSValue JSC_HOST_CALL mathProtoFuncRound(ExecState* exec) diff --git a/JavaScriptCore/runtime/NumberPrototype.cpp b/JavaScriptCore/runtime/NumberPrototype.cpp index 80b7ce0..1a74375 100644 --- a/JavaScriptCore/runtime/NumberPrototype.cpp +++ b/JavaScriptCore/runtime/NumberPrototype.cpp @@ -29,8 +29,8 @@ #include "Operations.h" #include "PrototypeFunction.h" #include "StringBuilder.h" -#include "dtoa.h" #include +#include #include #include @@ -66,75 +66,140 @@ NumberPrototype::NumberPrototype(ExecState* exec, JSGlobalObject* globalObject, // ECMA 15.7.4.2 - 15.7.4.7 -static UString integerPartNoExp(double d) +static ALWAYS_INLINE bool toThisNumber(JSValue thisValue, double &x) { - int decimalPoint; - int sign; - char result[80]; - WTF::dtoa(result, d, 0, &decimalPoint, &sign, NULL); - bool resultIsInfOrNan = (decimalPoint == 9999); - size_t length = strlen(result); - - StringBuilder builder; - builder.append(sign ? "-" : ""); - if (resultIsInfOrNan) - builder.append((const char*)result); - else if (decimalPoint <= 0) - builder.append("0"); - else { - Vector buf(decimalPoint + 1); - - if (static_cast(length) <= decimalPoint) { - ASSERT(decimalPoint < 1024); - memcpy(buf.data(), result, length); - memset(buf.data() + length, '0', decimalPoint - length); - } else - strncpy(buf.data(), result, decimalPoint); - buf[decimalPoint] = '\0'; - - builder.append((const char*)(buf.data())); + JSValue v = thisValue.getJSNumber(); + if (UNLIKELY(!v)) + return false; + x = v.uncheckedGetNumber(); + return true; +} + +static ALWAYS_INLINE bool getIntegerArgumentInRange(ExecState* exec, int low, int high, int& result, bool& isUndefined) +{ + result = 0; + isUndefined = false; + + JSValue argument0 = exec->argument(0); + if (argument0.isUndefined()) { + isUndefined = true; + return true; } - return builder.build(); + double asDouble = argument0.toInteger(exec); + if (asDouble < low || asDouble > high) + return false; + + result = static_cast(asDouble); + return true; } -static UString charSequence(char c, int count) +// toExponential converts a number to a string, always formatting as an expoential. +// This method takes an optional argument specifying a number of *decimal places* +// to round the significand to (or, put another way, this method optionally rounds +// to argument-plus-one significant figures). +EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState* exec) { - Vector buf(count + 1, c); - buf[count] = '\0'; + // Get x (the double value of this, which should be a Number). + double x; + if (!toThisNumber(exec->hostThisValue(), x)) + return throwVMTypeError(exec); + + // Get the argument. + int decimalPlacesInExponent; + bool isUndefined; + if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlacesInExponent, isUndefined)) + return throwVMError(exec, createRangeError(exec, "toExponential() argument must be between 0 and 20")); - return UString(buf.data()); + // Handle NaN and Infinity. + if (isnan(x) || isinf(x)) + return JSValue::encode(jsString(exec, UString::number(x))); + + // Round if the argument is not undefined, always format as exponential. + NumberToStringBuffer buffer; + unsigned length = isUndefined + ? DecimalNumber(x).toStringExponential(buffer) + : DecimalNumber(x, RoundingSignificantFigures, decimalPlacesInExponent + 1).toStringExponential(buffer); + + return JSValue::encode(jsString(exec, UString(buffer, length))); } -static double intPow10(int e) +// toFixed converts a number to a string, always formatting as an a decimal fraction. +// This method takes an argument specifying a number of decimal places to round the +// significand to. However when converting large values (1e+21 and above) this +// method will instead fallback to calling ToString. +EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec) { - // 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 - - if (e == 0) - 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; - } - } + // Get x (the double value of this, which should be a Number). + JSValue thisValue = exec->hostThisValue(); + JSValue v = thisValue.getJSNumber(); + if (!v) + return throwVMTypeError(exec); + double x = v.uncheckedGetNumber(); + + // Get the argument. + int decimalPlaces; + bool isUndefined; // This is ignored; undefined treated as 0. + if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlaces, isUndefined)) + return throwVMError(exec, createRangeError(exec, "toFixed() argument must be between 0 and 20")); + + // 15.7.4.5.7 states "If x >= 10^21, then let m = ToString(x)" + // This also covers Ininity, and structure the check so that NaN + // values are also handled by numberToString + if (!(fabs(x) < 1e+21)) + return JSValue::encode(jsString(exec, UString::number(x))); + + // The check above will return false for NaN or Infinity, these will be + // handled by numberToString. + ASSERT(!isnan(x) && !isinf(x)); + + // Convert to decimal with rounding, and format as decimal. + NumberToStringBuffer buffer; + unsigned length = DecimalNumber(x, RoundingDecimalPlaces, decimalPlaces).toStringDecimal(buffer); + return JSValue::encode(jsString(exec, UString(buffer, length))); +} - if (negative) - return static_cast(1.0 / result); - return static_cast(result); +// toPrecision converts a number to a string, takeing an argument specifying a +// number of significant figures to round the significand to. For positive +// exponent, all values that can be represented using a decimal fraction will +// be, e.g. when rounding to 3 s.f. any value up to 999 will be formated as a +// decimal, whilst 1000 is converted to the exponential representation 1.00e+3. +// For negative exponents values >= 1e-6 are formated as decimal fractions, +// with smaller values converted to exponential representation. +EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec) +{ + // Get x (the double value of this, which should be a Number). + JSValue thisValue = exec->hostThisValue(); + JSValue v = thisValue.getJSNumber(); + if (!v) + return throwVMTypeError(exec); + double x = v.uncheckedGetNumber(); + + // Get the argument. + int significantFigures; + bool isUndefined; + if (!getIntegerArgumentInRange(exec, 1, 21, significantFigures, isUndefined)) + return throwVMError(exec, createRangeError(exec, "toPrecision() argument must be between 1 and 21")); + + // To precision called with no argument is treated as ToString. + if (isUndefined) + return JSValue::encode(jsString(exec, UString::number(x))); + + // Handle NaN and Infinity. + if (isnan(x) || isinf(x)) + return JSValue::encode(jsString(exec, UString::number(x))); + + // Convert to decimal with rounding. + DecimalNumber number(x, RoundingSignificantFigures, significantFigures); + // If number is in the range 1e-6 <= x < pow(10, significantFigures) then format + // as decimal. Otherwise, format the number as an exponential. Decimal format + // demands a minimum of (exponent + 1) digits to represent a number, for example + // 1234 (1.234e+3) requires 4 digits. (See ECMA-262 15.7.4.7.10.c) + NumberToStringBuffer buffer; + unsigned length = number.exponent() >= -6 && number.exponent() < significantFigures + ? number.toStringDecimal(buffer) + : number.toStringExponential(buffer); + return JSValue::encode(jsString(exec, UString(buffer, length))); } EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec) @@ -243,237 +308,4 @@ EncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState* exec) return JSValue::encode(v); } -EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec) -{ - JSValue thisValue = exec->hostThisValue(); - JSValue v = thisValue.getJSNumber(); - if (!v) - return throwVMTypeError(exec); - - JSValue fractionDigits = exec->argument(0); - double df = fractionDigits.toInteger(exec); - if (!(df >= 0 && df <= 20)) - return throwVMError(exec, createRangeError(exec, "toFixed() digits argument must be between 0 and 20")); - int f = static_cast(df); - - double x = v.uncheckedGetNumber(); - if (isnan(x)) - return JSValue::encode(jsNontrivialString(exec, "NaN")); - - UString s; - if (x < 0) { - s = "-"; - x = -x; - } else { - s = ""; - if (x == -0.0) - x = 0; - } - - if (x >= pow(10.0, 21.0)) - return JSValue::encode(jsString(exec, makeString(s, UString::number(x)))); - - const double tenToTheF = pow(10.0, f); - double n = floor(x * tenToTheF); - if (fabs(n / tenToTheF - x) >= fabs((n + 1) / tenToTheF - x)) - n++; - - UString m = integerPartNoExp(n); - - int k = m.length(); - if (k <= f) { - StringBuilder z; - for (int i = 0; i < f + 1 - k; i++) - z.append('0'); - z.append(m); - m = z.build(); - k = f + 1; - ASSERT(k == static_cast(m.length())); - } - int kMinusf = k - f; - - if (kMinusf < static_cast(m.length())) - return JSValue::encode(jsString(exec, makeString(s, m.substringSharingImpl(0, kMinusf), ".", m.substringSharingImpl(kMinusf)))); - return JSValue::encode(jsString(exec, makeString(s, m.substringSharingImpl(0, kMinusf)))); -} - -static void fractionalPartToString(char* buf, int& i, const char* result, int resultLength, int fractionalDigits) -{ - if (fractionalDigits <= 0) - return; - - int fDigitsInResult = static_cast(resultLength) - 1; - buf[i++] = '.'; - if (fDigitsInResult > 0) { - if (fractionalDigits < fDigitsInResult) { - strncpy(buf + i, result + 1, fractionalDigits); - i += fractionalDigits; - } else { - ASSERT(i + resultLength - 1 < 80); - memcpy(buf + i, result + 1, resultLength - 1); - i += static_cast(resultLength) - 1; - } - } - - for (int j = 0; j < fractionalDigits - fDigitsInResult; j++) - buf[i++] = '0'; -} - -static void exponentialPartToString(char* buf, int& i, int decimalPoint) -{ - buf[i++] = 'e'; - // decimalPoint can't be more than 3 digits decimal given the - // nature of float representation - int exponential = decimalPoint - 1; - buf[i++] = (exponential >= 0) ? '+' : '-'; - if (exponential < 0) - exponential *= -1; - if (exponential >= 100) - buf[i++] = static_cast('0' + exponential / 100); - if (exponential >= 10) - buf[i++] = static_cast('0' + (exponential % 100) / 10); - buf[i++] = static_cast('0' + exponential % 10); -} - -EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState* exec) -{ - JSValue thisValue = exec->hostThisValue(); - JSValue v = thisValue.getJSNumber(); - if (!v) - return throwVMTypeError(exec); - - double x = v.uncheckedGetNumber(); - - if (isnan(x) || isinf(x)) - return JSValue::encode(jsString(exec, UString::number(x))); - - JSValue fractionalDigitsValue = exec->argument(0); - double df = fractionalDigitsValue.toInteger(exec); - if (!(df >= 0 && df <= 20)) - return throwVMError(exec, createRangeError(exec, "toExponential() argument must between 0 and 20")); - int fractionalDigits = static_cast(df); - bool includeAllDigits = fractionalDigitsValue.isUndefined(); - - int decimalAdjust = 0; - if (x && !includeAllDigits) { - double logx = floor(log10(fabs(x))); - x /= pow(10.0, logx); - const double tenToTheF = pow(10.0, fractionalDigits); - double fx = floor(x * tenToTheF) / tenToTheF; - double cx = ceil(x * tenToTheF) / tenToTheF; - - if (fabs(fx - x) < fabs(cx - x)) - x = fx; - else - x = cx; - - decimalAdjust = static_cast(logx); - } - - if (isnan(x)) - return JSValue::encode(jsNontrivialString(exec, "NaN")); - - if (x == -0.0) // (-0.0).toExponential() should print as 0 instead of -0 - x = 0; - - int decimalPoint; - int sign; - char result[80]; - WTF::dtoa(result, x, 0, &decimalPoint, &sign, NULL); - size_t resultLength = strlen(result); - decimalPoint += decimalAdjust; - - int i = 0; - char buf[80]; // digit + '.' + fractionDigits (max 20) + 'e' + sign + exponent (max?) - if (sign) - buf[i++] = '-'; - - // ? 9999 is the magical "result is Inf or NaN" value. what's 999?? - if (decimalPoint == 999) { - ASSERT(i + resultLength < 80); - memcpy(buf + i, result, resultLength); - buf[i + resultLength] = '\0'; - } else { - buf[i++] = result[0]; - - if (includeAllDigits) - fractionalDigits = static_cast(resultLength) - 1; - - fractionalPartToString(buf, i, result, resultLength, fractionalDigits); - exponentialPartToString(buf, i, decimalPoint); - buf[i++] = '\0'; - } - ASSERT(i <= 80); - - return JSValue::encode(jsString(exec, buf)); -} - -EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec) -{ - JSValue thisValue = exec->hostThisValue(); - JSValue v = thisValue.getJSNumber(); - if (!v) - return throwVMTypeError(exec); - - double doublePrecision = exec->argument(0).toIntegerPreserveNaN(exec); - double x = v.uncheckedGetNumber(); - if (exec->argument(0).isUndefined() || isnan(x) || isinf(x)) - return JSValue::encode(jsString(exec, v.toString(exec))); - - UString s; - if (x < 0) { - s = "-"; - x = -x; - } else - s = ""; - - if (!(doublePrecision >= 1 && doublePrecision <= 21)) // true for NaN - return throwVMError(exec, createRangeError(exec, "toPrecision() argument must be between 1 and 21")); - int precision = static_cast(doublePrecision); - - int e = 0; - UString m; - if (x) { - e = static_cast(log10(x)); - double tens = intPow10(e - precision + 1); - double n = floor(x / tens); - if (n < intPow10(precision - 1)) { - e = e - 1; - tens = intPow10(e - precision + 1); - n = floor(x / tens); - } - - if (fabs((n + 1.0) * tens - x) <= fabs(n * tens - x)) - ++n; - // maintain n < 10^(precision) - if (n >= intPow10(precision)) { - n /= 10.0; - e += 1; - } - ASSERT(intPow10(precision - 1) <= n); - ASSERT(n < intPow10(precision)); - - m = integerPartNoExp(n); - if (e < -6 || e >= precision) { - if (m.length() > 1) - m = makeString(m.substringSharingImpl(0, 1), ".", m.substringSharingImpl(1)); - if (e >= 0) - return JSValue::encode(jsMakeNontrivialString(exec, s, m, "e+", UString::number(e))); - return JSValue::encode(jsMakeNontrivialString(exec, s, m, "e-", UString::number(-e))); - } - } else { - m = charSequence('0', precision); - e = 0; - } - - if (e == precision - 1) - return JSValue::encode(jsString(exec, makeString(s, m))); - if (e >= 0) { - if (e + 1 < static_cast(m.length())) - return JSValue::encode(jsString(exec, makeString(s, m.substringSharingImpl(0, e + 1), ".", m.substringSharingImpl(e + 1)))); - return JSValue::encode(jsString(exec, makeString(s, m))); - } - return JSValue::encode(jsMakeNontrivialString(exec, s, "0.", charSequence('0', -(e + 1)), m)); -} - } // namespace JSC diff --git a/JavaScriptCore/runtime/RegExp.cpp b/JavaScriptCore/runtime/RegExp.cpp index 2b844c1..5ad9f3f 100644 --- a/JavaScriptCore/runtime/RegExp.cpp +++ b/JavaScriptCore/runtime/RegExp.cpp @@ -51,7 +51,6 @@ inline RegExp::RegExp(JSGlobalData* globalData, const UString& pattern, const US , m_flagBits(0) , m_constructionError(0) , m_numSubpatterns(0) - , m_lastMatchStart(-1) { // NOTE: The global flag is handled on a case-by-case basis by functions like // String::match and RegExpObject::match. @@ -96,24 +95,8 @@ int RegExp::match(const UString& s, int startOffset, Vector* ovector) if (ovector) ovector->resize(0); - if (static_cast(startOffset) > s.length() || s.isNull()) { - m_lastMatchString = UString(); - m_lastMatchStart = -1; - m_lastOVector.shrink(0); + if (static_cast(startOffset) > s.length() || s.isNull()) return -1; - } - - // Perform check to see if this match call is the same as the last match invocation - // and if it is return the prior result. - if ((startOffset == m_lastMatchStart) && (s.impl() == m_lastMatchString.impl())) { - if (ovector) - *ovector = m_lastOVector; - - if (m_lastOVector.isEmpty()) - return -1; - - return m_lastOVector.at(0); - } #if ENABLE(YARR_JIT) if (!!m_regExpJITCode) { @@ -151,21 +134,9 @@ int RegExp::match(const UString& s, int startOffset, Vector* ovector) ovector->clear(); } - m_lastMatchString = s; - m_lastMatchStart = startOffset; - - if (ovector) - m_lastOVector = *ovector; - else - m_lastOVector = nonReturnedOvector; - return result; } - m_lastMatchString = UString(); - m_lastMatchStart = -1; - m_lastOVector.shrink(0); - return -1; } diff --git a/JavaScriptCore/runtime/RegExp.h b/JavaScriptCore/runtime/RegExp.h index 8ea44e3..aadad6b 100644 --- a/JavaScriptCore/runtime/RegExp.h +++ b/JavaScriptCore/runtime/RegExp.h @@ -65,9 +65,6 @@ namespace JSC { int m_flagBits; const char* m_constructionError; unsigned m_numSubpatterns; - UString m_lastMatchString; - int m_lastMatchStart; - Vector m_lastOVector; #if ENABLE(YARR_JIT) Yarr::RegexCodeBlock m_regExpJITCode; diff --git a/JavaScriptCore/runtime/StringBuilder.h b/JavaScriptCore/runtime/StringBuilder.h index a26b94c..27aa57f 100644 --- a/JavaScriptCore/runtime/StringBuilder.h +++ b/JavaScriptCore/runtime/StringBuilder.h @@ -44,7 +44,7 @@ public: void append(const char* str, size_t len) { - buffer.reserveCapacity(buffer.size() + len); + reserveCapacity(buffer.size() + len); for (size_t i = 0; i < len; i++) buffer.append(static_cast(str[i])); } @@ -60,7 +60,12 @@ public: } bool isEmpty() { return buffer.isEmpty(); } - void reserveCapacity(size_t newCapacity) { buffer.reserveCapacity(newCapacity); } + void reserveCapacity(size_t newCapacity) + { + if (newCapacity < buffer.capacity()) + return; + buffer.reserveCapacity(std::max(newCapacity, buffer.capacity() + buffer.capacity() / 4 + 1)); + } void resize(size_t size) { buffer.resize(size); } size_t size() const { return buffer.size(); } diff --git a/JavaScriptCore/runtime/StringPrototype.cpp b/JavaScriptCore/runtime/StringPrototype.cpp index cfbb3be..91e9b06 100644 --- a/JavaScriptCore/runtime/StringPrototype.cpp +++ b/JavaScriptCore/runtime/StringPrototype.cpp @@ -425,9 +425,10 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec) // Not a regular expression, so treat the pattern as a string. UString patternString = pattern.toString(exec); - if (patternString.length() == 1 && callType == CallTypeNone) + // Special case for single character patterns without back reference replacement + if (patternString.length() == 1 && callType == CallTypeNone && replacementString.find('$', 0) == notFound) return JSValue::encode(sourceVal->replaceCharacter(exec, patternString[0], replacementString)); - + const UString& source = sourceVal->value(exec); size_t matchPos = source.find(patternString); diff --git a/JavaScriptCore/runtime/UString.cpp b/JavaScriptCore/runtime/UString.cpp index ac3acfd..7362950 100644 --- a/JavaScriptCore/runtime/UString.cpp +++ b/JavaScriptCore/runtime/UString.cpp @@ -26,7 +26,6 @@ #include "JSGlobalObjectFunctions.h" #include "Collector.h" -#include "dtoa.h" #include "Identifier.h" #include "Operations.h" #include @@ -39,6 +38,7 @@ #include #include #include +#include #include #if HAVE(STRINGS_H) @@ -198,10 +198,8 @@ UString UString::number(long l) UString UString::number(double d) { - DtoaBuffer buffer; - unsigned length; - doubleToStringInJavaScriptFormat(d, buffer, &length); - return UString(buffer, length); + NumberToStringBuffer buffer; + return StringImpl::create(buffer, numberToString(d, buffer)); } UString UString::substringSharingImpl(unsigned offset, unsigned length) const @@ -334,6 +332,8 @@ CString UString::utf8(bool strict) const // * We could allocate a CStringBuffer with an appropriate size to // have a good chance of being able to write the string into the // buffer without reallocing (say, 1.5 x length). + if (length > numeric_limits::max() / 3) + return CString(); Vector bufferVector(length * 3); char* buffer = bufferVector.data(); diff --git a/JavaScriptCore/wscript b/JavaScriptCore/wscript index e50b18d..d85364c 100644 --- a/JavaScriptCore/wscript +++ b/JavaScriptCore/wscript @@ -36,12 +36,13 @@ sources = [] jscore_excludes.extend(get_excludes(jscore_dir, ['*None.cpp'])) -if building_on_win32: - jscore_excludes += ['MarkStackPosix.cpp', 'ThreadingPthreads.cpp'] - sources += ['runtime/MarkStackWin.cpp'] -else: - jscore_excludes.append('JSStringRefBSTR.cpp') - jscore_excludes.extend(get_excludes(jscore_dir, ['*Win.cpp'])) +if build_port == "wx": + if building_on_win32: + jscore_excludes += ['MarkStackPosix.cpp', 'ThreadingPthreads.cpp'] + sources += ['runtime/MarkStackWin.cpp'] + else: + jscore_excludes.append('JSStringRefBSTR.cpp') + jscore_excludes.extend(get_excludes(jscore_dir, ['*Win.cpp'])) def build(bld): import Options diff --git a/JavaScriptCore/wtf/DecimalNumber.h b/JavaScriptCore/wtf/DecimalNumber.h new file mode 100644 index 0000000..118c492 --- /dev/null +++ b/JavaScriptCore/wtf/DecimalNumber.h @@ -0,0 +1,328 @@ +/* + * 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 DecimalNumber_h +#define DecimalNumber_h + +#include +#include +#include +#include + +namespace WTF { + +enum RoundingSignificantFiguresType { RoundingSignificantFigures }; +enum RoundingDecimalPlacesType { RoundingDecimalPlaces }; + +class DecimalNumber { +public: + DecimalNumber(double d) + { + bool sign = d < 0; // This (correctly) ignores the sign on -0.0. + init(sign, d); + } + + // 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(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); + + // 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; + + // Make sure the significand does not contain more digits than requested. + roundToPrecision(significantFigures); + } + + // 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); + + unsigned significantFigures = 1 + m_exponent + decimalPlaces; + ASSERT(significantFigures && significantFigures <= 41); + roundToPrecision(significantFigures); + } + + unsigned toStringDecimal(NumberToStringBuffer& buffer) + { + // Should always be at least one digit to add to the string! + ASSERT(m_precision); + UChar* next = buffer; + + // if the exponent is negative the number decimal representation is of the form: + // []0.[] + if (m_exponent < 0) { + unsigned zeros = -m_exponent - 1; + + if (m_sign) + *next++ = '-'; + *next++ = '0'; + *next++ = '.'; + for (unsigned i = 0; i < zeros; ++i) + *next++ = '0'; + for (unsigned i = 0; i < m_precision; ++i) + *next++ = m_significand[i]; + + return next - buffer; + } + + unsigned digitsBeforeDecimalPoint = m_exponent + 1; + + // If the precision is <= than the number of digits to get up to the decimal + // point, then there is no fractional part, number is of the form: + // [][] + if (m_precision <= digitsBeforeDecimalPoint) { + if (m_sign) + *next++ = '-'; + for (unsigned i = 0; i < m_precision; ++i) + *next++ = m_significand[i]; + for (unsigned i = 0; i < (digitsBeforeDecimalPoint - m_precision); ++i) + *next++ = '0'; + + return next - buffer; + } + + // If we get here, number starts before the decimal point, and ends after it, + // as such is of the form: + // []. + + if (m_sign) + *next++ = '-'; + for (unsigned i = 0; i < digitsBeforeDecimalPoint; ++i) + *next++ = m_significand[i]; + *next++ = '.'; + for (unsigned i = digitsBeforeDecimalPoint; i < m_precision; ++i) + *next++ = m_significand[i]; + + return next - buffer; + } + + unsigned toStringExponential(NumberToStringBuffer &buffer) + { + // Should always be at least one digit to add to the string! + ASSERT(m_precision); + + UChar* next = buffer; + + // Add the sign + if (m_sign) + *next++ = '-'; + + // Add the significand + *next++ = m_significand[0]; + if (m_precision > 1) { + *next++ = '.'; + for (unsigned i = 1; i < m_precision; ++i) + *next++ = m_significand[i]; + } + + // Add "e+" or "e-" + *next++ = 'e'; + int exponent; + if (m_exponent >= 0) { + *next++ = '+'; + exponent = m_exponent; + } else { + *next++ = '-'; + exponent = -m_exponent; + } + + // Add the exponent + if (exponent >= 100) + *next++ = '0' + exponent / 100; + if (exponent >= 10) + *next++ = '0' + (exponent % 100) / 10; + *next++ = '0' + exponent % 10; + + return next - buffer; + } + + bool sign() { return m_sign; } + int exponent() { return m_exponent; } + const char* significand() { return m_significand; } // significand contains precision characters, is not null-terminated. + 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 + + 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(1.0 / result); + return static_cast(result); + } + + bool m_sign; + int m_exponent; + DtoaBuffer m_significand; + unsigned m_precision; +}; + +} // namespace WTF + +using WTF::DecimalNumber; +using WTF::RoundingSignificantFigures; +using WTF::RoundingDecimalPlaces; + +#endif // DecimalNumber_h diff --git a/JavaScriptCore/wtf/ListHashSet.h b/JavaScriptCore/wtf/ListHashSet.h index 09355ad..e14ac45 100644 --- a/JavaScriptCore/wtf/ListHashSet.h +++ b/JavaScriptCore/wtf/ListHashSet.h @@ -24,6 +24,7 @@ #include "Assertions.h" #include "HashSet.h" #include "OwnPtr.h" +#include "StdLibExtras.h" namespace WTF { @@ -171,7 +172,7 @@ namespace WTF { } private: - Node* pool() { return reinterpret_cast(m_pool.pool); } + Node* pool() { return reinterpret_cast_ptr(m_pool.pool); } Node* pastPool() { return pool() + m_poolSize; } bool inPool(Node* node) diff --git a/JavaScriptCore/wtf/PageReservation.h b/JavaScriptCore/wtf/PageReservation.h index 906b5a4..cfc7cd9 100644 --- a/JavaScriptCore/wtf/PageReservation.h +++ b/JavaScriptCore/wtf/PageReservation.h @@ -226,14 +226,14 @@ inline PageReservation PageReservation::systemReserve(size_t size, Usage usage, inline bool PageReservation::systemCommit(void* start, size_t size) { - intptr_t offset = reinterpret_cast(m_base) - reinterpret_cast(start); + intptr_t offset = reinterpret_cast(start) - reinterpret_cast(m_base); m_chunk->Commit(offset, size); return true; } inline void PageReservation::systemDecommit(void* start, size_t size) { - intptr_t offset = reinterpret_cast(m_base) - reinterpret_cast(start); + intptr_t offset = reinterpret_cast(start) - reinterpret_cast(m_base); m_chunk->Decommit(offset, size); } diff --git a/JavaScriptCore/wtf/PlatformRefPtr.h b/JavaScriptCore/wtf/PlatformRefPtr.h new file mode 100644 index 0000000..2d05ac9 --- /dev/null +++ b/JavaScriptCore/wtf/PlatformRefPtr.h @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Collabora Ltd. + * Copyright (C) 2009 Martin Robinson + * + * 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 PlatformRefPtr_h +#define PlatformRefPtr_h + +#include "AlwaysInline.h" +#include + +namespace WTF { + +enum PlatformRefPtrAdoptType { PlatformRefPtrAdopt }; +template inline T* refPlatformPtr(T*); +template inline void derefPlatformPtr(T*); +template class PlatformRefPtr; +template PlatformRefPtr adoptPlatformRef(T*); + +template class PlatformRefPtr { +public: + PlatformRefPtr() : m_ptr(0) { } + + PlatformRefPtr(T* ptr) + : m_ptr(ptr) + { + if (ptr) + refPlatformPtr(ptr); + } + + PlatformRefPtr(const PlatformRefPtr& o) + : m_ptr(o.m_ptr) + { + if (T* ptr = m_ptr) + refPlatformPtr(ptr); + } + + template PlatformRefPtr(const PlatformRefPtr& o) + : m_ptr(o.get()) + { + if (T* ptr = m_ptr) + refPlatformPtr(ptr); + } + + ~PlatformRefPtr() + { + if (T* ptr = m_ptr) + derefPlatformPtr(ptr); + } + + void clear() + { + T* ptr = m_ptr; + m_ptr = 0; + if (ptr) + derefPlatformPtr(ptr); + } + + T* get() const { return m_ptr; } + T& operator*() const { return *m_ptr; } + ALWAYS_INLINE T* operator->() const { return m_ptr; } + + bool operator!() const { return !m_ptr; } + + // This conversion operator allows implicit conversion to bool but not to other integer types. + typedef T* PlatformRefPtr::*UnspecifiedBoolType; + operator UnspecifiedBoolType() const { return m_ptr ? &PlatformRefPtr::m_ptr : 0; } + + PlatformRefPtr& operator=(const PlatformRefPtr&); + PlatformRefPtr& operator=(T*); + template PlatformRefPtr& operator=(const PlatformRefPtr&); + + void swap(PlatformRefPtr&); + friend PlatformRefPtr adoptPlatformRef(T*); + +private: + static T* hashTableDeletedValue() { return reinterpret_cast(-1); } + // Adopting constructor. + PlatformRefPtr(T* ptr, PlatformRefPtrAdoptType) : m_ptr(ptr) {} + + T* m_ptr; +}; + +template inline PlatformRefPtr& PlatformRefPtr::operator=(const PlatformRefPtr& o) +{ + T* optr = o.get(); + if (optr) + refPlatformPtr(optr); + T* ptr = m_ptr; + m_ptr = optr; + if (ptr) + derefPlatformPtr(ptr); + return *this; +} + +template inline PlatformRefPtr& PlatformRefPtr::operator=(T* optr) +{ + T* ptr = m_ptr; + if (optr) + refPlatformPtr(optr); + m_ptr = optr; + if (ptr) + derefPlatformPtr(ptr); + return *this; +} + +template inline void PlatformRefPtr::swap(PlatformRefPtr& o) +{ + std::swap(m_ptr, o.m_ptr); +} + +template inline void swap(PlatformRefPtr& a, PlatformRefPtr& b) +{ + a.swap(b); +} + +template inline bool operator==(const PlatformRefPtr& a, const PlatformRefPtr& b) +{ + return a.get() == b.get(); +} + +template inline bool operator==(const PlatformRefPtr& a, U* b) +{ + return a.get() == b; +} + +template inline bool operator==(T* a, const PlatformRefPtr& b) +{ + return a == b.get(); +} + +template inline bool operator!=(const PlatformRefPtr& a, const PlatformRefPtr& b) +{ + return a.get() != b.get(); +} + +template inline bool operator!=(const PlatformRefPtr& a, U* b) +{ + return a.get() != b; +} + +template inline bool operator!=(T* a, const PlatformRefPtr& b) +{ + return a != b.get(); +} + +template inline PlatformRefPtr static_pointer_cast(const PlatformRefPtr& p) +{ + return PlatformRefPtr(static_cast(p.get())); +} + +template inline PlatformRefPtr const_pointer_cast(const PlatformRefPtr& p) +{ + return PlatformRefPtr(const_cast(p.get())); +} + +template inline T* getPtr(const PlatformRefPtr& p) +{ + return p.get(); +} + +template PlatformRefPtr adoptPlatformRef(T* p) +{ + return PlatformRefPtr(p, PlatformRefPtrAdopt); +} + +} // namespace WTF + +using WTF::PlatformRefPtr; +using WTF::refPlatformPtr; +using WTF::derefPlatformPtr; +using WTF::adoptPlatformRef; +using WTF::static_pointer_cast; +using WTF::const_pointer_cast; + +#endif // PlatformRefPtr_h diff --git a/JavaScriptCore/wtf/dtoa.cpp b/JavaScriptCore/wtf/dtoa.cpp index f7e19bf..88e5692 100644 --- a/JavaScriptCore/wtf/dtoa.cpp +++ b/JavaScriptCore/wtf/dtoa.cpp @@ -2285,83 +2285,4 @@ ret: *rve = s; } -static ALWAYS_INLINE void append(char*& next, const char* src, unsigned size) -{ - for (unsigned i = 0; i < size; ++i) - *next++ = *src++; -} - -void doubleToStringInJavaScriptFormat(double d, DtoaBuffer buffer, unsigned* resultLength) -{ - ASSERT(buffer); - - // avoid ever printing -NaN, in JS conceptually there is only one NaN value - if (isnan(d)) { - append(buffer, "NaN", 3); - if (resultLength) - *resultLength = 3; - return; - } - // -0 -> "0" - if (!d) { - buffer[0] = '0'; - if (resultLength) - *resultLength = 1; - return; - } - - int decimalPoint; - int sign; - - DtoaBuffer result; - char* resultEnd = 0; - WTF::dtoa(result, d, 0, &decimalPoint, &sign, &resultEnd); - int length = resultEnd - result; - - char* next = buffer; - if (sign) - *next++ = '-'; - - if (decimalPoint <= 0 && decimalPoint > -6) { - *next++ = '0'; - *next++ = '.'; - for (int j = decimalPoint; j < 0; j++) - *next++ = '0'; - append(next, result, length); - } else if (decimalPoint <= 21 && decimalPoint > 0) { - if (length <= decimalPoint) { - append(next, result, length); - for (int j = 0; j < decimalPoint - length; j++) - *next++ = '0'; - } else { - append(next, result, decimalPoint); - *next++ = '.'; - append(next, result + decimalPoint, length - decimalPoint); - } - } else if (result[0] < '0' || result[0] > '9') - append(next, result, length); - else { - *next++ = result[0]; - if (length > 1) { - *next++ = '.'; - append(next, result + 1, length - 1); - } - - *next++ = 'e'; - *next++ = (decimalPoint >= 0) ? '+' : '-'; - // decimalPoint can't be more than 3 digits decimal given the - // nature of float representation - int exponential = decimalPoint - 1; - if (exponential < 0) - exponential = -exponential; - if (exponential >= 100) - *next++ = static_cast('0' + exponential / 100); - if (exponential >= 10) - *next++ = static_cast('0' + (exponential % 100) / 10); - *next++ = static_cast('0' + exponential % 10); - } - if (resultLength) - *resultLength = next - buffer; -} - } // namespace WTF diff --git a/JavaScriptCore/wtf/dtoa.h b/JavaScriptCore/wtf/dtoa.h index e0938ff..bf00ccc 100644 --- a/JavaScriptCore/wtf/dtoa.h +++ b/JavaScriptCore/wtf/dtoa.h @@ -36,14 +36,8 @@ 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); -// dtoa() for ECMA-262 'ToString Applied to the Number Type.' -// The *resultLength will have the length of the resultant string in bufer. -// The resultant string isn't terminated by 0. -void doubleToStringInJavaScriptFormat(double, DtoaBuffer, unsigned* resultLength); - } // namespace WTF using WTF::DtoaBuffer; -using WTF::doubleToStringInJavaScriptFormat; #endif // WTF_dtoa_h diff --git a/JavaScriptCore/wtf/gobject/GRefPtr.cpp b/JavaScriptCore/wtf/gobject/GRefPtr.cpp index 9d16cb5..c16024c 100644 --- a/JavaScriptCore/wtf/gobject/GRefPtr.cpp +++ b/JavaScriptCore/wtf/gobject/GRefPtr.cpp @@ -23,30 +23,47 @@ namespace WTF { -template <> GHashTable* refGPtr(GHashTable* ptr) +template <> GHashTable* refPlatformPtr(GHashTable* ptr) { if (ptr) g_hash_table_ref(ptr); return ptr; } -template <> void derefGPtr(GHashTable* ptr) +template <> void derefPlatformPtr(GHashTable* ptr) { g_hash_table_unref(ptr); } #if GLIB_CHECK_VERSION(2, 24, 0) -template <> GVariant* refGPtr(GVariant* ptr) +template <> GVariant* refPlatformPtr(GVariant* ptr) { if (ptr) g_variant_ref(ptr); return ptr; } -template <> void derefGPtr(GVariant* ptr) +template <> void derefPlatformPtr(GVariant* ptr) { g_variant_unref(ptr); } + +#else + +// We do this so that we can avoid including the glib.h header in GRefPtr.h. +typedef struct _GVariant { + bool fake; +} GVariant; + +template <> GVariant* refPlatformPtr(GVariant* ptr) +{ + return ptr; +} + +template <> void derefPlatformPtr(GVariant* ptr) +{ +} + #endif } // namespace WTF diff --git a/JavaScriptCore/wtf/gobject/GRefPtr.h b/JavaScriptCore/wtf/gobject/GRefPtr.h index 9a07d93..064c87e 100644 --- a/JavaScriptCore/wtf/gobject/GRefPtr.h +++ b/JavaScriptCore/wtf/gobject/GRefPtr.h @@ -24,157 +24,30 @@ #define WTF_GRefPtr_h #include "AlwaysInline.h" +#include "PlatformRefPtr.h" #include -#include -namespace WTF { - -enum GRefPtrAdoptType { GRefPtrAdopt }; -template inline T* refGPtr(T*); -template inline void derefGPtr(T*); -template class GRefPtr; -template GRefPtr adoptGRef(T*); -template <> GHashTable* refGPtr(GHashTable* ptr); -template <> void derefGPtr(GHashTable* ptr); - -#if GLIB_CHECK_VERSION(2, 24, 0) -template <> GVariant* refGPtr(GVariant* ptr); -template <> void derefGPtr(GVariant* ptr); -#endif - -template class GRefPtr { -public: - GRefPtr() : m_ptr(0) { } - GRefPtr(T* ptr) : m_ptr(ptr) { if (ptr) refGPtr(ptr); } - GRefPtr(const GRefPtr& o) : m_ptr(o.m_ptr) { if (T* ptr = m_ptr) refGPtr(ptr); } - template GRefPtr(const GRefPtr& o) : m_ptr(o.get()) { if (T* ptr = m_ptr) refGPtr(ptr); } - - ~GRefPtr() { if (T* ptr = m_ptr) derefGPtr(ptr); } - - void clear() - { - T* ptr = m_ptr; - m_ptr = 0; - if (ptr) - derefGPtr(ptr); - } - - T* get() const { return m_ptr; } - T& operator*() const { return *m_ptr; } - ALWAYS_INLINE T* operator->() const { return m_ptr; } - - bool operator!() const { return !m_ptr; } +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); - // This conversion operator allows implicit conversion to bool but not to other integer types. - typedef T* GRefPtr::*UnspecifiedBoolType; - operator UnspecifiedBoolType() const { return m_ptr ? &GRefPtr::m_ptr : 0; } - - GRefPtr& operator=(const GRefPtr&); - GRefPtr& operator=(T*); - template GRefPtr& operator=(const GRefPtr&); - - void swap(GRefPtr&); - friend GRefPtr adoptGRef(T*); - -private: - static T* hashTableDeletedValue() { return reinterpret_cast(-1); } - // Adopting constructor. - GRefPtr(T* ptr, GRefPtrAdoptType) : m_ptr(ptr) {} - - T* m_ptr; -}; - -template inline GRefPtr& GRefPtr::operator=(const GRefPtr& o) -{ - T* optr = o.get(); - if (optr) - refGPtr(optr); - T* ptr = m_ptr; - m_ptr = optr; - if (ptr) - derefGPtr(ptr); - return *this; -} - -template inline GRefPtr& GRefPtr::operator=(T* optr) -{ - T* ptr = m_ptr; - if (optr) - refGPtr(optr); - m_ptr = optr; - if (ptr) - derefGPtr(ptr); - return *this; -} - -template inline void GRefPtr::swap(GRefPtr& o) -{ - std::swap(m_ptr, o.m_ptr); -} - -template inline void swap(GRefPtr& a, GRefPtr& b) -{ - a.swap(b); -} - -template inline bool operator==(const GRefPtr& a, const GRefPtr& b) -{ - return a.get() == b.get(); -} - -template inline bool operator==(const GRefPtr& a, U* b) -{ - return a.get() == b; -} - -template inline bool operator==(T* a, const GRefPtr& b) -{ - return a == b.get(); -} - -template inline bool operator!=(const GRefPtr& a, const GRefPtr& b) -{ - return a.get() != b.get(); -} - -template inline bool operator!=(const GRefPtr& a, U* b) -{ - return a.get() != b; -} - -template inline bool operator!=(T* a, const GRefPtr& b) -{ - return a != b.get(); -} - -template inline GRefPtr static_pointer_cast(const GRefPtr& p) -{ - return GRefPtr(static_cast(p.get())); -} - -template inline GRefPtr const_pointer_cast(const GRefPtr& p) -{ - return GRefPtr(const_cast(p.get())); -} +namespace WTF { -template inline T* getPtr(const GRefPtr& p) -{ - return p.get(); -} +template <> GHashTable* refPlatformPtr(GHashTable* ptr); +template <> void derefPlatformPtr(GHashTable* ptr); +template <> GVariant* refPlatformPtr(GVariant* ptr); +template <> void derefPlatformPtr(GVariant* ptr); -template GRefPtr adoptGRef(T* p) -{ - return GRefPtr(p, GRefPtrAdopt); -} - -template inline T* refGPtr(T* ptr) +template inline T* refPlatformPtr(T* ptr) { if (ptr) g_object_ref_sink(ptr); return ptr; } -template inline void derefGPtr(T* ptr) +template inline void derefPlatformPtr(T* ptr) { if (ptr) g_object_unref(ptr); @@ -182,11 +55,4 @@ template inline void derefGPtr(T* ptr) } // namespace WTF -using WTF::GRefPtr; -using WTF::refGPtr; -using WTF::derefGPtr; -using WTF::adoptGRef; -using WTF::static_pointer_cast; -using WTF::const_pointer_cast; - #endif // WTF_GRefPtr_h diff --git a/JavaScriptCore/wtf/text/WTFString.cpp b/JavaScriptCore/wtf/text/WTFString.cpp index 7d44d21..bbff576 100644 --- a/JavaScriptCore/wtf/text/WTFString.cpp +++ b/JavaScriptCore/wtf/text/WTFString.cpp @@ -25,10 +25,10 @@ #include #include #include -#include +#include #include #include -#include +#include #include #include @@ -947,6 +947,41 @@ float charactersToFloat(const UChar* data, size_t length, bool* ok) return static_cast(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; +} + +static NEVER_INLINE unsigned nanOrInfToString(double x, NumberToStringBuffer& buffer) +{ + 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); +} + +// 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) +{ + // Handle NaN and Infinity. + if (UNLIKELY(isnan(x) || isinf(x))) + return nanOrInfToString(x, buffer); + + // Convert to decimal, no rounding. + DecimalNumber number(x); + + // Format as decimal or exponential, depending on the exponent. + return number.exponent() >= -6 && number.exponent() < 21 + ? number.toStringDecimal(buffer) + : number.toStringExponential(buffer); +} + } // namespace WTF #ifndef NDEBUG diff --git a/JavaScriptCore/wtf/text/WTFString.h b/JavaScriptCore/wtf/text/WTFString.h index fafef12..8a6bab6 100644 --- a/JavaScriptCore/wtf/text/WTFString.h +++ b/JavaScriptCore/wtf/text/WTFString.h @@ -52,6 +52,10 @@ 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 @@ -453,4 +457,7 @@ using WTF::charactersToInt; using WTF::charactersToFloat; using WTF::charactersToDouble; +using WTF::NumberToStringBuffer; +using WTF::numberToString; + #endif -- cgit v1.1