diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index c31f5fc700..7003396123 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,12 +1,25 @@ +2010-09-22: Version 2.4.5 + Changed the RegExp benchmark to exercise the regexp engine on different + inputs by scrambling the input strings. + + Fixed a bug in keyed loads on strings. + + Fixed a bug with loading global function prototypes. + + Fixed a bug with profiling RegExp calls (issue http://crbug.com/55999). + + Performance improvements on all platforms. + + 2010-09-15: Version 2.4.4 - Fix bug with hangs on very large sparse arrays. + Fixed bug with hangs on very large sparse arrays. - Try harder to free up memory when running out of space. + Now tries harder to free up memory when running out of space. - Add heap snapshots to JSON format to API. + Added heap snapshots to JSON format to API. - Recalibrate benchmarks. + Recalibrated benchmarks. 2010-09-13: Version 2.4.3 @@ -42,33 +55,33 @@ 2010-09-01: Version 2.4.0 - Fix bug in Object.freeze and Object.seal when Array.prototype or - Object.prototype is changed (issue 842). + Fixed bug in Object.freeze and Object.seal when Array.prototype or + Object.prototype are changed (issue 842). - Update Array.splice to follow Safari and Firefox when called + Updated Array.splice to follow Safari and Firefox when called with zero arguments. - Fix a missing live register when breaking at keyed loads on ARM. + Fixed a missing live register when breaking at keyed loads on ARM. Performance improvements on all platforms. 2010-08-25: Version 2.3.11 - Fix bug in RegExp related to copy-on-write arrays. + Fixed bug in RegExp related to copy-on-write arrays. - Refactoring of tools/test.py script, including the introduction of + Refactored tools/test.py script, including the introduction of VARIANT_FLAGS that allows specification of sets of flags with which all tests should be run. - Fix a bug in the handling of debug breaks in CallIC. + Fixed a bug in the handling of debug breaks in CallIC. Performance improvements on all platforms. 2010-08-23: Version 2.3.10 - Fix bug in bitops on ARM. + Fixed bug in bitops on ARM. Build fixes for unusual compilers. @@ -79,7 +92,7 @@ 2010-08-18: Version 2.3.9 - Fix compilation for ARMv4 on OpenBSD/FreeBSD. + Fixed compilation for ARMv4 on OpenBSD/FreeBSD. Removed specialized handling of GCC 4.4 (issue 830). @@ -120,7 +133,7 @@ Fixed handling of JSObject::elements in CalculateNetworkSize (issue 822). - Allow compiling with strict aliasing enabled on GCC 4.4 (issue 463). + Allowed compiling with strict aliasing enabled on GCC 4.4 (issue 463). 2010-08-09: Version 2.3.6 @@ -130,7 +143,7 @@ Object.seal and Object.freeze return the modified object (issue 809). - Fix building using GCC 4.4.4. + Fixed building using GCC 4.4.4. 2010-08-04: Version 2.3.5 @@ -139,7 +152,7 @@ dot-notation property access now allows keywords. Also allowed non-identifiers after "get" or "set" in an object initialiser. - Randomize the addresses of allocated executable memory on Windows. + Randomized the addresses of allocated executable memory on Windows. 2010-08-02: Version 2.3.4 @@ -251,15 +264,15 @@ 2010-06-30: Version 2.2.21 - Fix bug in externalizing some ASCII strings (Chromium issue 47824). + Fixed bug in externalizing some ASCII strings (Chromium issue 47824). - Update JSON.stringify to floor the space parameter (issue 753). + Updated JSON.stringify to floor the space parameter (issue 753). - Update the Mozilla test expectations to the newest version. + Updated the Mozilla test expectations to the newest version. - Update the ES5 Conformance Test expectations to the latest version. + Updated the ES5 Conformance Test expectations to the latest version. - Update the V8 benchmark suite. + Updated the V8 benchmark suite. Provide actual breakpoints locations in response to setBreakpoint and listBreakpoints requests. @@ -267,13 +280,13 @@ 2010-06-28: Version 2.2.20 - Fix bug with for-in on x64 platform (issue 748). + Fixed bug with for-in on x64 platform (issue 748). - Fix crash bug on x64 platform (issue 756). + Fixed crash bug on x64 platform (issue 756). - Fix bug in Object.getOwnPropertyNames. (chromium issue 41243). + Fixed bug in Object.getOwnPropertyNames. (chromium issue 41243). - Fix a bug on ARM that caused the result of 1 << x to be + Fixed a bug on ARM that caused the result of 1 << x to be miscalculated for some inputs. Performance improvements on all platforms. @@ -281,7 +294,7 @@ 2010-06-23: Version 2.2.19 - Fix bug that causes the build to break when profillingsupport=off + Fixed bug that causes the build to break when profillingsupport=off (issue 738). Added expose-externalize-string flag for testing extensions. @@ -289,7 +302,7 @@ Resolve linker issues with using V8 as a DLL causing a number of problems with unresolved symbols. - Fix build failure for cctests when ENABLE_DEBUGGER_SUPPORT is not + Fixed build failure for cctests when ENABLE_DEBUGGER_SUPPORT is not defined. Performance improvements on all platforms. @@ -300,11 +313,11 @@ Added API functions to retrieve information on indexed properties managed by the embedding layer. Fixes bug 737. - Make ES5 Object.defineProperty support array elements. Fixes bug 619. + Made ES5 Object.defineProperty support array elements. Fixes bug 619. - Add heap profiling to the API. + Added heap profiling to the API. - Remove old named property query from the API. + Removed old named property query from the API. Incremental performance improvements. @@ -330,12 +343,12 @@ 2010-06-07: Version 2.2.15 - Add an API to control the disposal of external string resources. + Added an API to control the disposal of external string resources. - Add missing initialization of a couple of variables which makes + Added missing initialization of a couple of variables which makes some compilers complaint when compiling with -Werror. - Improve performance on all platforms. + Improved performance on all platforms. 2010-06-02: Version 2.2.14 @@ -349,12 +362,12 @@ 2010-05-31: Version 2.2.13 - Implement Object.getOwnPropertyDescriptor for element indices and + Implemented Object.getOwnPropertyDescriptor for element indices and strings (issue 599). - Fix bug for windows 64 bit C calls from generated code. + Fixed bug for windows 64 bit C calls from generated code. - Add new scons flag unalignedaccesses for arm builds. + Added new scons flag unalignedaccesses for arm builds. Performance improvements on all platforms. @@ -369,7 +382,7 @@ 2010-05-21: Version 2.2.11 - Fix crash bug in liveedit on 64 bit. + Fixed crash bug in liveedit on 64 bit. Use 'full compiler' when debugging is active. This should increase the density of possible break points, making single step more fine @@ -379,11 +392,11 @@ Misc. fixes to the Solaris build. - Add new flags --print-cumulative-gc-stat and --trace-gc-nvp. + Added new flags --print-cumulative-gc-stat and --trace-gc-nvp. - Add filtering of CPU profiles by security context. + Added filtering of CPU profiles by security context. - Fix crash bug on ARM when running without VFP2 or VFP3. + Fixed crash bug on ARM when running without VFP2 or VFP3. Incremental performance improvements in all backends. @@ -395,12 +408,12 @@ 2010-05-10: Version 2.2.9 - Allow Object.create to be called with a function (issue 697). + Allowed Object.create to be called with a function (issue 697). Fixed bug with Date.parse returning a non-NaN value when called on a non date string (issue 696). - Allow unaligned memory accesses on ARM targets that support it (by + Allowed unaligned memory accesses on ARM targets that support it (by Subrato K De of CodeAurora ). C++ API for retrieving JavaScript stack trace information. @@ -554,9 +567,9 @@ 2010-02-23: Version 2.1.2 - Fix a crash bug caused by wrong assert. + Fixed a crash bug caused by wrong assert. - Fix a bug with register names on 64-bit V8 (issue 615). + Fixed a bug with register names on 64-bit V8 (issue 615). Performance improvements on all platforms. @@ -592,13 +605,13 @@ Solaris support by Erich Ocean and Ryan Dahl . - Fix a bug that Math.round() returns incorrect results for huge + Fixed a bug that Math.round() returns incorrect results for huge integers. - Fix enumeration order for objects created from some constructor + Fixed enumeration order for objects created from some constructor functions (isue http://crbug.com/3867). - Fix arithmetic on some integer constants (issue 580). + Fixed arithmetic on some integer constants (issue 580). Numerous performance improvements including porting of previous IA-32 optimizations to x64 and ARM architectures. @@ -737,11 +750,11 @@ X64: Convert smis to holding 32 bits of payload. - Introduce v8::Integer::NewFromUnsigned method. + Introduced v8::Integer::NewFromUnsigned method. - Add missing null check in Context::GetCurrent. + Added missing null check in Context::GetCurrent. - Add trim, trimLeft and trimRight methods to String + Added trim, trimLeft and trimRight methods to String Patch by Jan de Mooij Implement ES5 Array.isArray @@ -749,14 +762,15 @@ Skip access checks for hidden properties. - Add String::Concat(Handle left, Handle right) to the V8 API. + Added String::Concat(Handle left, Handle right) to the + V8 API. - Fix GYP-based builds of V8. + Fixed GYP-based builds of V8. 2009-10-07: Version 1.3.15 - Expand the maximum size of the code space to 512MB for 64-bit mode. + Expanded the maximum size of the code space to 512MB for 64-bit mode. Fixed a crash bug happening when starting profiling (issue http://crbug.com/23768). @@ -768,10 +782,10 @@ located on the object or in the prototype chain skipping any interceptors. - Fix the stack limits setting API to work correctly with threads. The + Fixed the stack limits setting API to work correctly with threads. The stack limit now needs to be set to each thread thich is used with V8. - Remove the high-priority flag from IdleNotification() + Removed the high-priority flag from IdleNotification() Ensure V8 is initialized before locking and unlocking threads. @@ -839,7 +853,7 @@ Implemented missing pieces of debugger infrastructure on ARM. The debugger is now fully functional on ARM. - Make 'hidden' the default visibility for gcc. + Made 'hidden' the default visibility for gcc. 2009-09-09: Version 1.3.10 @@ -894,9 +908,9 @@ 2009-08-21: Version 1.3.6 - Add support for forceful termination of JavaScript execution. + Added support for forceful termination of JavaScript execution. - Add low memory notification to the API. The embedding host can signal + Added low memory notification to the API. The embedding host can signal a low memory situation to V8. Changed the handling of global handles (persistent handles in the API @@ -910,9 +924,9 @@ 2009-08-19: Version 1.3.5 - Optimize initialization of some arrays in the builtins. + Optimized initialization of some arrays in the builtins. - Fix mac-nm script to support filenames with spaces. + Fixed mac-nm script to support filenames with spaces. Support for using the V8 profiler when V8 is embedded in a Windows DLL. @@ -925,7 +939,7 @@ Added API for getting object mirrors. - Make sure that SSE3 instructions are used whenever possible even when + Made sure that SSE3 instructions are used whenever possible even when running off a snapshot generated without using SSE3 instructions. Tweaked the handling of the initial size and growth policy of the heap. @@ -947,20 +961,20 @@ 2009-08-12: Version 1.3.3 - Fix issue 417: incorrect %t placeholder expansion. + Fixed issue 417: incorrect %t placeholder expansion. - Add .gitignore file similar to Chromium's one. + Added .gitignore file similar to Chromium's one. - Fix SConstruct file to build with new logging code for Android. + Fixed SConstruct file to build with new logging code for Android. API: added function to find instance of template in prototype chain. Inlined Object::IsInstanceOf. Land change to notify valgrind when we modify code on x86. - Add api call to determine whether a string can be externalized. + Added api call to determine whether a string can be externalized. - Add a write() command to d8. + Added a write() command to d8. 2009-08-05: Version 1.3.2 @@ -1243,7 +1257,7 @@ Added EcmaScript 5 JSON object. - Fix bug in preemption support on ARM. + Fixed bug in preemption support on ARM. 2009-04-23: Version 1.2.0 diff --git a/deps/v8/benchmarks/README.txt b/deps/v8/benchmarks/README.txt index 800b4f5185..6676f37556 100644 --- a/deps/v8/benchmarks/README.txt +++ b/deps/v8/benchmarks/README.txt @@ -70,7 +70,9 @@ Removed dead code from the RayTrace benchmark and fixed a couple of typos in the DeltaBlue implementation. Changed the Splay benchmark to avoid converting the same numeric key to a string over and over again and to avoid inserting and removing the same element repeatedly thus -increasing pressure on the memory subsystem. +increasing pressure on the memory subsystem. Changed the RegExp +benchmark to exercise the regular expression engine on different +input strings. Furthermore, the benchmark runner was changed to run the benchmarks for at least a few times to stabilize the reported numbers on slower diff --git a/deps/v8/benchmarks/regexp.js b/deps/v8/benchmarks/regexp.js index f76086685c..71b9e6362c 100644 --- a/deps/v8/benchmarks/regexp.js +++ b/deps/v8/benchmarks/regexp.js @@ -1,4 +1,4 @@ -// Copyright 2009 the V8 project authors. All rights reserved. +// Copyright 2010 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -25,21 +25,51 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Automatically generated on 2009-01-30. +// Automatically generated on 2009-01-30. Manually updated on 2010-09-17. // This benchmark is generated by loading 50 of the most popular pages // on the web and logging all regexp operations performed. Each // operation is given a weight that is calculated from an estimate of // the popularity of the pages where it occurs and the number of times -// it is executed while loading each page. Finally the literal +// it is executed while loading each page. Furthermore the literal // letters in the data are encoded using ROT13 in a way that does not -// affect how the regexps match their input. +// affect how the regexps match their input. Finally the strings are +// scrambled to exercise the regexp engine on different input strings. -var RegRxp = new BenchmarkSuite('RegExp', 910985, [ - new Benchmark("RegExp", runRegExpBenchmark) + +var RegExp = new BenchmarkSuite('RegExp', 910985, [ + new Benchmark("RegExp", RegExpRun, RegExpSetup, RegExpTearDown) ]); -function runRegExpBenchmark() { +var regExpBenchmark = null; + +function RegExpSetup() { + regExpBenchmark = new RegExpBenchmark(); + RegExpRun(); // run once to get system initialized +} + +function RegExpRun() { + regExpBenchmark.run(); +} + +function RegExpTearDown() { + regExpBenchmark = null; +} + +// Returns an array of n different variants of the input string str. +// The variants are computed by randomly rotating one random +// character. +function computeInputVariants(str, n) { + var variants = [ str ]; + for (var i = 1; i < n; i++) { + var pos = Math.floor(Math.random() * str.length); + var chr = String.fromCharCode((str.charCodeAt(pos) + Math.floor(Math.random() * 128)) % 128); + variants[i] = str.substring(0, pos) + chr + str.substring(pos + 1, str.length); + } + return variants; +} + +function RegExpBenchmark() { var re0 = /^ba/; var re1 = /(((\w+):\/\/)([^\/:]*)(:(\d+))?)?([^#?]*)(\?([^#]*))?(#(.*))?/; var re2 = /^\s*|\s*$/g; @@ -59,77 +89,105 @@ function runRegExpBenchmark() { var re14 = /\s+/g; var re15 = /^\s*(\S*(\s+\S+)*)\s*$/; var re16 = /(-[a-z])/i; + + var s0 = computeInputVariants('pyvpx', 6511); + var s1 = computeInputVariants('uggc://jjj.snprobbx.pbz/ybtva.cuc', 1844); + var s2 = computeInputVariants('QBZPbageby_cynprubyqre', 739); + var s3 = computeInputVariants('uggc://jjj.snprobbx.pbz/', 598); + var s4 = computeInputVariants('uggc://jjj.snprobbx.pbz/fepu.cuc', 454); + var s5 = computeInputVariants('qqqq, ZZZ q, llll', 352); + var s6 = computeInputVariants('vachggrkg QBZPbageby_cynprubyqre', 312); + var s7 = computeInputVariants('/ZlFcnprUbzrcntr/Vaqrk-FvgrUbzr,10000000', 282); + var s8 = computeInputVariants('vachggrkg', 177); + var s9 = computeInputVariants('528.9', 170); + var s10 = computeInputVariants('528', 170); + var s11 = computeInputVariants('VCPhygher=ra-HF', 156); + var s12 = computeInputVariants('CersreerqPhygher=ra-HF', 156); + var s13 = computeInputVariants('xrlcerff', 144); + var s14 = computeInputVariants('521', 139); + var s15 = computeInputVariants(str0, 139); + var s16 = computeInputVariants('qvi .so_zrah', 137); + var s17 = computeInputVariants('qvi.so_zrah', 137); + var s18 = computeInputVariants('uvqqra_ryrz', 117); + var s19 = computeInputVariants('sevraqfgre_naba=nvq%3Qn6ss9p85n868ro9s059pn854735956o3%26ers%3Q%26df%3Q%26vpgl%3QHF', 95); + var s20 = computeInputVariants('uggc://ubzr.zlfcnpr.pbz/vaqrk.psz', 93); + var s21 = computeInputVariants(str1, 92); + var s22 = computeInputVariants('svefg', 85); + var s23 = computeInputVariants('uggc://cebsvyr.zlfcnpr.pbz/vaqrk.psz', 85); + var s24 = computeInputVariants('ynfg', 85); + var s25 = computeInputVariants('qvfcynl', 85); + function runBlock0() { for (var i = 0; i < 6511; i++) { - re0.exec('pyvpx'); + re0.exec(s0[i]); } for (var i = 0; i < 1844; i++) { - re1.exec('uggc://jjj.snprobbx.pbz/ybtva.cuc'); + re1.exec(s1[i]); } for (var i = 0; i < 739; i++) { - 'QBZPbageby_cynprubyqre'.replace(re2, ''); + s2[i].replace(re2, ''); } for (var i = 0; i < 598; i++) { - re1.exec('uggc://jjj.snprobbx.pbz/'); + re1.exec(s3[i]); } for (var i = 0; i < 454; i++) { - re1.exec('uggc://jjj.snprobbx.pbz/fepu.cuc'); + re1.exec(s4[i]); } for (var i = 0; i < 352; i++) { - /qqqq|qqq|qq|q|ZZZZ|ZZZ|ZZ|Z|llll|ll|l|uu|u|UU|U|zz|z|ff|f|gg|g|sss|ss|s|mmm|mm|m/g.exec('qqqq, ZZZ q, llll'); + /qqqq|qqq|qq|q|ZZZZ|ZZZ|ZZ|Z|llll|ll|l|uu|u|UU|U|zz|z|ff|f|gg|g|sss|ss|s|mmm|mm|m/g.exec(s5[i]); } for (var i = 0; i < 312; i++) { - re3.exec('vachggrkg QBZPbageby_cynprubyqre'); + re3.exec(s6[i]); } for (var i = 0; i < 282; i++) { - re4.exec('/ZlFcnprUbzrcntr/Vaqrk-FvgrUbzr,10000000'); + re4.exec(s7[i]); } for (var i = 0; i < 177; i++) { - 'vachggrkg'.replace(re5, ''); + s8[i].replace(re5, ''); } for (var i = 0; i < 170; i++) { - '528.9'.replace(re6, ''); - re7.exec('528'); + s9[i].replace(re6, ''); + re7.exec(s10[i]); } for (var i = 0; i < 156; i++) { - re8.exec('VCPhygher=ra-HF'); - re8.exec('CersreerqPhygher=ra-HF'); + re8.exec(s11[i]); + re8.exec(s12[i]); } for (var i = 0; i < 144; i++) { - re0.exec('xrlcerff'); + re0.exec(s13[i]); } for (var i = 0; i < 139; i++) { - '521'.replace(re6, ''); - re7.exec('521'); + s14[i].replace(re6, ''); + re7.exec(s14[i]); re9.exec(''); - /JroXvg\/(\S+)/.exec(str0); + /JroXvg\/(\S+)/.exec(s15[i]); } for (var i = 0; i < 137; i++) { - 'qvi .so_zrah'.replace(re10, ''); - 'qvi .so_zrah'.replace(/\[/g, ''); - 'qvi.so_zrah'.replace(re11, ''); + s16[i].replace(re10, ''); + s16[i].replace(/\[/g, ''); + s17[i].replace(re11, ''); } for (var i = 0; i < 117; i++) { - 'uvqqra_ryrz'.replace(re2, ''); + s18[i].replace(re2, ''); } for (var i = 0; i < 95; i++) { - /(?:^|;)\s*sevraqfgre_ynat=([^;]*)/.exec('sevraqfgre_naba=nvq%3Qn6ss9p85n868ro9s059pn854735956o3%26ers%3Q%26df%3Q%26vpgl%3QHF'); + /(?:^|;)\s*sevraqfgre_ynat=([^;]*)/.exec(s19[i]); } for (var i = 0; i < 93; i++) { - 'uggc://ubzr.zlfcnpr.pbz/vaqrk.psz'.replace(re12, ''); - re13.exec('uggc://ubzr.zlfcnpr.pbz/vaqrk.psz'); + s20[i].replace(re12, ''); + re13.exec(s20[i]); } for (var i = 0; i < 92; i++) { - str1.replace(/([a-zA-Z]|\s)+/, ''); + s21[i].replace(/([a-zA-Z]|\s)+/, ''); } for (var i = 0; i < 85; i++) { - 'svefg'.replace(re14, ''); - 'svefg'.replace(re15, ''); - 'uggc://cebsvyr.zlfcnpr.pbz/vaqrk.psz'.replace(re12, ''); - 'ynfg'.replace(re14, ''); - 'ynfg'.replace(re15, ''); - re16.exec('qvfcynl'); - re13.exec('uggc://cebsvyr.zlfcnpr.pbz/vaqrk.psz'); + s22[i].replace(re14, ''); + s22[i].replace(re15, ''); + s23[i].replace(re12, ''); + s24[i].replace(re14, ''); + s24[i].replace(re15, ''); + re16.exec(s25[i]); + re13.exec(s23[i]); } } var re17 = /(^|[^\\])\"\\\/Qngr\((-?[0-9]+)\)\\\/\"/g; @@ -145,64 +203,98 @@ function runRegExpBenchmark() { var str7 = ';;jvaqbj.IjPurpxZbhfrCbfvgvbaNQ_VQ=shapgvba(r){vs(!r)ine r=jvaqbj.rirag;ine c=-1;vs(d1)c=d1.EbyybssCnary;ine bo=IjTrgBow("IjCnayNQ_VQ_"+c);vs(bo&&bo.fglyr.ivfvovyvgl=="ivfvoyr"){ine fns=IjFns?8:0;ine pheK=r.pyvragK+IjBOFpe("U")+fns,pheL=r.pyvragL+IjBOFpe("I")+fns;ine y=IjBOEC(NQ_VQ,bo,"Y"),g=IjBOEC(NQ_VQ,bo,"G");ine e=y+d1.Cnaryf[c].Jvqgu,o=g+d1.Cnaryf[c].Urvtug;vs((pheKe)||(pheLo)){vs(jvaqbj.IjBaEbyybssNQ_VQ)IjBaEbyybssNQ_VQ(c);ryfr IjPybfrNq(NQ_VQ,c,gehr,"");}ryfr erghea;}IjPnapryZbhfrYvfgrareNQ_VQ();};;jvaqbj.IjFrgEbyybssCnaryNQ_VQ=shapgvba(c){ine z="zbhfrzbir",q=qbphzrag,s=IjPurpxZbhfrCbfvgvbaNQ_VQ;c=IjTc(NQ_VQ,c);vs(d1&&d1.EbyybssCnary>-1)IjPnapryZbhfrYvfgrareNQ_VQ();vs(d1)d1.EbyybssCnary=c;gel{vs(q.nqqRiragYvfgrare)q.nqqRiragYvfgrare(z,s,snyfr);ryfr vs(q.nggnpuRirag)q.nggnpuRirag("ba"+z,s);}pngpu(r){}};;jvaqbj.IjPnapryZbhfrYvfgrareNQ_VQ=shapgvba(){ine z="zbhfrzbir",q=qbphzrag,s=IjPurpxZbhfrCbfvgvbaNQ_VQ;vs(d1)d1.EbyybssCnary=-1;gel{vs(q.erzbirRiragYvfgrare)q.erzbirRiragYvfgrare(z,s,snyfr);ryfr vs(q.qrgnpuRirag)q.qrgnpuRirag("ba"+z,s);}pngpu(r){}};;d1.IjTc=d2(n,c){ine nq=d1;vs(vfAnA(c)){sbe(ine v=0;v0){vs(nq.FzV.yratgu>0)nq.FzV+="/";nq.FzV+=vh[v];nq.FtZ[nq.FtZ.yratgu]=snyfr;}}};;d1.IjYvzvg0=d2(n,f){ine nq=d1,vh=f.fcyvg("/");sbe(ine v=0;v0){vs(nq.OvC.yratgu>0)nq.OvC+="/";nq.OvC+=vh[v];}}};;d1.IjRVST=d2(n,c){jvaqbj["IjCnayNQ_VQ_"+c+"_Bow"]=IjTrgBow("IjCnayNQ_VQ_"+c+"_Bow");vs(jvaqbj["IjCnayNQ_VQ_"+c+"_Bow"]==ahyy)frgGvzrbhg("IjRVST(NQ_VQ,"+c+")",d1.rvsg);};;d1.IjNavzSHC=d2(n,c){ine nq=d1;vs(c>nq.Cnaryf.yratgu)erghea;ine cna=nq.Cnaryf[c],nn=gehr,on=gehr,yn=gehr,en=gehr,cn=nq.Cnaryf[0],sf=nq.ShF,j=cn.Jvqgu,u=cn.Urvtug;vs(j=="100%"){j=sf;en=snyfr;yn=snyfr;}vs(u=="100%"){u=sf;nn=snyfr;on=snyfr;}vs(cn.YnY=="Y")yn=snyfr;vs(cn.YnY=="E")en=snyfr;vs(cn.GnY=="G")nn=snyfr;vs(cn.GnY=="O")on=snyfr;ine k=0,l=0;fjvgpu(nq.NshP%8){pnfr 0:oernx;pnfr 1:vs(nn)l=-sf;oernx;pnfr 2:k=j-sf;oernx;pnfr 3:vs(en)k=j;oernx;pnfr 4:k=j-sf;l=u-sf;oernx;pnfr 5:k=j-sf;vs(on)l=u;oernx;pnfr 6:l=u-sf;oernx;pnfr 7:vs(yn)k=-sf;l=u-sf;oernx;}vs(nq.NshP++ 0)||(nethzragf.yratgu==3&&bG>0))){pyrneGvzrbhg(cay.UgU);cay.UgU=frgGvzrbhg(cay.UvqrNpgvba,(nethzragf.yratgu==3?bG:cay.UvqrGvzrbhgInyhr));}};;d1.IjErfrgGvzrbhg=d2(n,c,bG){c=IjTc(n,c);IjPnapryGvzrbhg(n,c);riny("IjFgnegGvzrbhg(NQ_VQ,c"+(nethzragf.yratgu==3?",bG":"")+")");};;d1.IjErfrgNyyGvzrbhgf=d2(n){sbe(ine c=0;c'.replace(re55, ''); ''.replace(re55, ''); - str1.replace(/^.*\s+(\S+\s+\S+$)/, ''); + s21[i].replace(/^.*\s+(\S+\s+\S+$)/, ''); 'tzk%2Subzrcntr%2Sfgneg%2Sqr%2S'.replace(re30, ''); 'tzk'.replace(re30, ''); 'uggc://${ubfg}${cngu}/${dz}'.replace(/(\$\{ubfg\})|(\$ubfg\b)/g, ''); @@ -549,61 +671,70 @@ function runRegExpBenchmark() { var re62 = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/; var str34 = '${1}://${2}${3}${4}${5}'; var str35 = ' O=6gnyg0g4znrrn&o=3&f=gc; Q=_lyu=K3bQZGSxnT4lZzD3OS9GNmV3ZGLkAQxRpTyxNmRlZmRmAmNkAQLRqTImqNZjOUEgpTjQnJ5xMKtgoN--; SCF=qy'; + var s83 = computeInputVariants(str27, 11); + var s84 = computeInputVariants(str28, 11); + var s85 = computeInputVariants(str29, 11); + var s86 = computeInputVariants(str30, 11); + var s87 = computeInputVariants(str31, 11); + var s88 = computeInputVariants(str32, 11); + var s89 = computeInputVariants(str33, 11); + var s90 = computeInputVariants(str34, 11); + function runBlock6() { for (var i = 0; i < 11; i++) { - str27.replace(/##yv0##/gi, ''); - str27.replace(re57, ''); - str28.replace(re58, ''); - str29.replace(re59, ''); - str30.replace(/##\/o##/gi, ''); - str30.replace(/##\/v##/gi, ''); - str30.replace(/##\/h##/gi, ''); - str30.replace(/##o##/gi, ''); - str30.replace(/##oe##/gi, ''); - str30.replace(/##v##/gi, ''); - str30.replace(/##h##/gi, ''); - str31.replace(/##n##/gi, ''); - str32.replace(/##\/n##/gi, ''); - str33.replace(/#~#argjbexybtb#~#/g, ''); - / Zbovyr\//.exec(str0); - /##yv1##/gi.exec(str27); - /##yv10##/gi.exec(str28); - /##yv11##/gi.exec(str28); - /##yv12##/gi.exec(str28); - /##yv13##/gi.exec(str28); - /##yv14##/gi.exec(str28); - /##yv15##/gi.exec(str28); - re58.exec(str28); - /##yv17##/gi.exec(str29); - /##yv18##/gi.exec(str29); - re59.exec(str29); - /##yv2##/gi.exec(str27); - /##yv20##/gi.exec(str30); - /##yv21##/gi.exec(str30); - /##yv22##/gi.exec(str30); - /##yv23##/gi.exec(str30); - /##yv3##/gi.exec(str27); - re57.exec(str27); - /##yv5##/gi.exec(str28); - /##yv6##/gi.exec(str28); - /##yv7##/gi.exec(str28); - /##yv8##/gi.exec(str28); - /##yv9##/gi.exec(str28); + s83[i].replace(/##yv0##/gi, ''); + s83[i].replace(re57, ''); + s84[i].replace(re58, ''); + s85[i].replace(re59, ''); + s86[i].replace(/##\/o##/gi, ''); + s86[i].replace(/##\/v##/gi, ''); + s86[i].replace(/##\/h##/gi, ''); + s86[i].replace(/##o##/gi, ''); + s86[i].replace(/##oe##/gi, ''); + s86[i].replace(/##v##/gi, ''); + s86[i].replace(/##h##/gi, ''); + s87[i].replace(/##n##/gi, ''); + s88[i].replace(/##\/n##/gi, ''); + s89[i].replace(/#~#argjbexybtb#~#/g, ''); + / Zbovyr\//.exec(s15[i]); + /##yv1##/gi.exec(s83[i]); + /##yv10##/gi.exec(s84[i]); + /##yv11##/gi.exec(s84[i]); + /##yv12##/gi.exec(s84[i]); + /##yv13##/gi.exec(s84[i]); + /##yv14##/gi.exec(s84[i]); + /##yv15##/gi.exec(s84[i]); + re58.exec(s84[i]); + /##yv17##/gi.exec(s85[i]); + /##yv18##/gi.exec(s85[i]); + re59.exec(s85[i]); + /##yv2##/gi.exec(s83[i]); + /##yv20##/gi.exec(s86[i]); + /##yv21##/gi.exec(s86[i]); + /##yv22##/gi.exec(s86[i]); + /##yv23##/gi.exec(s86[i]); + /##yv3##/gi.exec(s83[i]); + re57.exec(s83[i]); + /##yv5##/gi.exec(s84[i]); + /##yv6##/gi.exec(s84[i]); + /##yv7##/gi.exec(s84[i]); + /##yv8##/gi.exec(s84[i]); + /##yv9##/gi.exec(s84[i]); re8.exec('473qq1rs0n2r70q9qo1pq48n021s9468ron90nps048p4p29'); re8.exec('SbeprqRkcvengvba=633669325184628362'); re8.exec('FrffvbaQQS2=473qq1rs0n2r70q9qo1pq48n021s9468ron90nps048p4p29'); - /AbxvnA[^\/]*/.exec(str0); + /AbxvnA[^\/]*/.exec(s15[i]); } for (var i = 0; i < 10; i++) { ' bss'.replace(/(?:^|\s+)bss(?:\s+|$)/g, ''); - str34.replace(/(\$\{0\})|(\$0\b)/g, ''); - str34.replace(/(\$\{1\})|(\$1\b)/g, ''); - str34.replace(/(\$\{pbzcyrgr\})|(\$pbzcyrgr\b)/g, ''); - str34.replace(/(\$\{sentzrag\})|(\$sentzrag\b)/g, ''); - str34.replace(/(\$\{ubfgcbeg\})|(\$ubfgcbeg\b)/g, ''); - str34.replace(re56, ''); - str34.replace(/(\$\{cebgbpby\})|(\$cebgbpby\b)/g, ''); - str34.replace(/(\$\{dhrel\})|(\$dhrel\b)/g, ''); + s90[i].replace(/(\$\{0\})|(\$0\b)/g, ''); + s90[i].replace(/(\$\{1\})|(\$1\b)/g, ''); + s90[i].replace(/(\$\{pbzcyrgr\})|(\$pbzcyrgr\b)/g, ''); + s90[i].replace(/(\$\{sentzrag\})|(\$sentzrag\b)/g, ''); + s90[i].replace(/(\$\{ubfgcbeg\})|(\$ubfgcbeg\b)/g, ''); + s90[i].replace(re56, ''); + s90[i].replace(/(\$\{cebgbpby\})|(\$cebgbpby\b)/g, ''); + s90[i].replace(/(\$\{dhrel\})|(\$dhrel\b)/g, ''); 'nqfvmr'.replace(re29, ''); 'nqfvmr'.replace(re30, ''); 'uggc://${2}${3}${4}${5}'.replace(/(\$\{2\})|(\$2\b)/g, ''); @@ -629,7 +760,7 @@ function runRegExpBenchmark() { re9.exec('zrqvgobk'); re9.exec('hsgy'); re9.exec('lhv-h'); - /Fnsnev|Xbadhrebe|XUGZY/gi.exec(str0); + /Fnsnev|Xbadhrebe|XUGZY/gi.exec(s15[i]); re61.exec('uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/onfr.wf'); re62.exec('#Ybtva_rznvy'); } @@ -640,6 +771,9 @@ function runRegExpBenchmark() { var str38 = 'uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_zlfcnpr-ubzrcntr_wf&qg=1231364057761&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231364057761&punaary=svz_zlfcnpr_ubzrcntr_abgybttrqva%2Psvz_zlfcnpr_aba_HTP%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Ssevraqf.zlfcnpr.pbz%2Svaqrk.psz&nq_glcr=grkg&rvq=6083027&rn=0&sez=0&tn_ivq=1667363813.1231364061&tn_fvq=1231364061&tn_uvq=1917563877&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22'; var str39 = 'ZFPhygher=VC=74.125.75.20&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669321699093060&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q'; var str40 = 'ZFPhygher=VC=74.125.75.20&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669321699093060&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R='; + var s91 = computeInputVariants(str36, 9); + var s92 = computeInputVariants(str37, 9); + var s93 = computeInputVariants(str38, 9); function runBlock7() { for (var i = 0; i < 9; i++) { '0'.replace(re40, ''); @@ -660,15 +794,15 @@ function runRegExpBenchmark() { for (var i = 0; i < 8; i++) { 'Pybfr {0}'.replace(re63, ''); 'Bcra {0}'.replace(re63, ''); - str36.split(re32); - str37.split(re32); + s91[i].split(re32); + s92[i].split(re32); 'puvyq p1 svefg gnournqref'.replace(re14, ''); 'puvyq p1 svefg gnournqref'.replace(re15, ''); 'uqy_fcb'.replace(re14, ''); 'uqy_fcb'.replace(re15, ''); 'uvag'.replace(re14, ''); 'uvag'.replace(re15, ''); - str38.replace(re33, ''); + s93[i].replace(re33, ''); 'yvfg'.replace(re14, ''); 'yvfg'.replace(re15, ''); 'at_bhgre'.replace(re30, ''); @@ -697,8 +831,8 @@ function runRegExpBenchmark() { re8.exec('__hgzo=144631658.0.10.1231364074'); re8.exec('__hgzm=144631658.1231364074.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)'); re8.exec('p98s8o9q42nr21or1r61pqorn1n002nsss569635984s6qp7'); - re34.exec(str36); - re34.exec(str37); + re34.exec(s91[i]); + re34.exec(s92[i]); } } var re64 = /\b[a-z]/g; @@ -707,7 +841,7 @@ function runRegExpBenchmark() { var str41 = 'uggc://cebsvyr.zlfcnpr.pbz/Zbqhyrf/Nccyvpngvbaf/Cntrf/Pnainf.nfck'; function runBlock8() { for (var i = 0; i < 7; i++) { - str1.match(/\d+/g); + s21[i].match(/\d+/g); 'nsgre'.replace(re64, ''); 'orsber'.replace(re64, ''); 'obggbz'.replace(re64, ''); @@ -741,9 +875,9 @@ function runRegExpBenchmark() { re19.exec('gno6'); re19.exec('gno7'); re19.exec('gno8'); - /NqborNVE\/([^\s]*)/.exec(str0); - /NccyrJroXvg\/([^ ]*)/.exec(str0); - /XUGZY/gi.exec(str0); + /NqborNVE\/([^\s]*)/.exec(s15[i]); + /NccyrJroXvg\/([^ ]*)/.exec(s15[i]); + /XUGZY/gi.exec(s15[i]); /^(?:obql|ugzy)$/i.exec('YV'); re38.exec('ohggba'); re38.exec('vachg'); @@ -774,14 +908,14 @@ function runRegExpBenchmark() { 'freivpr'.replace(re46, ''); 'freivpr'.replace(re47, ''); 'freivpr'.replace(re48, ''); - /((ZFVR\s+([6-9]|\d\d)\.))/.exec(str0); + /((ZFVR\s+([6-9]|\d\d)\.))/.exec(s15[i]); re66.exec(''); re50.exec('fryrpgrq'); re8.exec('8sqq78r9n442851q565599o401385sp3s04r92rnn7o19ssn'); re8.exec('SbeprqRkcvengvba=633669340386893867'); re8.exec('VC=74.125.75.17'); re8.exec('FrffvbaQQS2=8sqq78r9n442851q565599o401385sp3s04r92rnn7o19ssn'); - /Xbadhrebe|Fnsnev|XUGZY/.exec(str0); + /Xbadhrebe|Fnsnev|XUGZY/.exec(s15[i]); re13.exec(str41); re49.exec('unfsbphf'); } @@ -826,12 +960,23 @@ function runRegExpBenchmark() { var str61 = 'uggc://gx2.fgp.f-zfa.pbz/oe/uc/11/ra-hf/pff/v/g.tvs#uggc://gx2.fgo.f-zfa.pbz/v/29/4RQP4969777N048NPS4RRR3PO2S7S.wct'; var str62 = 'uggc://gx2.fgp.f-zfa.pbz/oe/uc/11/ra-hf/pff/v/g.tvs#uggc://gx2.fgo.f-zfa.pbz/v/OQ/63NP9O94NS5OQP1249Q9S1ROP7NS3.wct'; var str63 = 'zbmvyyn/5.0 (jvaqbjf; h; jvaqbjf ag 5.1; ra-hf) nccyrjroxvg/528.9 (xugzy, yvxr trpxb) puebzr/2.0.157.0 fnsnev/528.9'; + var s94 = computeInputVariants(str42, 5); + var s95 = computeInputVariants(str43, 5); + var s96 = computeInputVariants(str44, 5); + var s97 = computeInputVariants(str47, 5); + var s98 = computeInputVariants(str48, 5); + var s99 = computeInputVariants(str49, 5); + var s100 = computeInputVariants(str50, 5); + var s101 = computeInputVariants(str51, 5); + var s102 = computeInputVariants(str52, 5); + var s103 = computeInputVariants(str53, 5); + function runBlock9() { for (var i = 0; i < 5; i++) { - str42.split(re32); - str43.split(re32); + s94[i].split(re32); + s95[i].split(re32); 'svz_zlfcnpr_hfre-ivrj-pbzzragf,svz_zlfcnpr_havgrq-fgngrf'.split(re20); - str44.replace(re33, ''); + s96[i].replace(re33, ''); 'zrah_arj zrah_arj_gbttyr zrah_gbttyr'.replace(re67, ''); 'zrah_byq zrah_byq_gbttyr zrah_gbttyr'.replace(re67, ''); re8.exec('102n9o0o9pq60132qn0337rr867p75953502q2s27s2s5r98'); @@ -855,12 +1000,12 @@ function runRegExpBenchmark() { ' yvfg2'.replace(re15, ''); ' frneputebhc1'.replace(re14, ''); ' frneputebhc1'.replace(re15, ''); - str47.replace(re68, ''); - str47.replace(re18, ''); + s97[i].replace(re68, ''); + s97[i].replace(re18, ''); ''.replace(/&/g, ''); ''.replace(re35, ''); '(..-{0})(\|(\d+)|)'.replace(re63, ''); - str48.replace(re18, ''); + s98[i].replace(re18, ''); '//vzt.jro.qr/vij/FC/${cngu}/${anzr}/${inyhr}?gf=${abj}'.replace(re56, ''); '//vzt.jro.qr/vij/FC/tzk_uc/${anzr}/${inyhr}?gf=${abj}'.replace(/(\$\{anzr\})|(\$anzr\b)/g, ''); 'Jvaqbjf Yvir Ubgznvy{1}'.replace(re69, ''); @@ -872,8 +1017,8 @@ function runRegExpBenchmark() { 'Zncf'.replace(re15, ''); 'Zbq-Vasb-Vasb-WninFpevcgUvag'.replace(re39, ''); 'Arjf'.replace(re15, ''); - str49.split(re32); - str50.split(re32); + s99[i].split(re32); + s100[i].split(re32); 'Ivqrb'.replace(re15, ''); 'Jro'.replace(re15, ''); 'n'.replace(re39, ''); @@ -907,17 +1052,17 @@ function runRegExpBenchmark() { 'uc_fubccvatobk'.replace(re30, ''); 'ugzy%2Rvq'.replace(re29, ''); 'ugzy%2Rvq'.replace(re30, ''); - str51.replace(re33, ''); + s101[i].replace(re33, ''); 'uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/cebgbglcr.wf${4}${5}'.replace(re71, ''); 'uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/cebgbglcr.wf${5}'.replace(re72, ''); - str52.replace(re73, ''); + s102[i].replace(re73, ''); 'uggc://zfacbegny.112.2b7.arg/o/ff/zfacbegnyubzr/1/U.7-cqi-2/f55332979829981?[NDO]&{1}&{2}&[NDR]'.replace(re69, ''); 'vztZFSG'.replace(re14, ''); 'vztZFSG'.replace(re15, ''); 'zfasbbg1 ps'.replace(re14, ''); 'zfasbbg1 ps'.replace(re15, ''); - str53.replace(re14, ''); - str53.replace(re15, ''); + s103[i].replace(re14, ''); + s103[i].replace(re15, ''); 'cnerag puebzr6 fvatyr1 gno fryrpgrq ovaq'.replace(re14, ''); 'cnerag puebzr6 fvatyr1 gno fryrpgrq ovaq'.replace(re15, ''); 'cevznel'.replace(re14, ''); @@ -945,11 +1090,11 @@ function runRegExpBenchmark() { re8.exec('__hgzn=144631658.2770915348920628700.1231367708.1231367708.1231367708.1'); re8.exec('__hgzo=144631658.0.10.1231367708'); re8.exec('__hgzm=144631658.1231367708.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)'); - re34.exec(str49); - re34.exec(str50); - /ZFVR\s+5[.]01/.exec(str0); + re34.exec(s99[i]); + re34.exec(s100[i]); + /ZFVR\s+5[.]01/.exec(s15[i]); /HF(?=;)/i.exec(str56); - re74.exec(str47); + re74.exec(s97[i]); re28.exec('svefg npgvir svefgNpgvir'); re28.exec('ynfg'); /\bp:(..)/i.exec('m:94043|yn:37.4154|yb:-122.0585|p:HF'); @@ -967,15 +1112,15 @@ function runRegExpBenchmark() { re79.exec(str60); re79.exec(str59); /\|p:([a-z]{2})/i.exec('m:94043|yn:37.4154|yb:-122.0585|p:HF|ue:1'); - re80.exec(str47); + re80.exec(s97[i]); re61.exec('cebgbglcr.wf'); - re68.exec(str47); - re81.exec(str47); - re82.exec(str47); - /^Fubpxjnir Synfu (\d)/.exec(str1); - /^Fubpxjnir Synfu (\d+)/.exec(str1); + re68.exec(s97[i]); + re81.exec(s97[i]); + re82.exec(s97[i]); + /^Fubpxjnir Synfu (\d)/.exec(s21[i]); + /^Fubpxjnir Synfu (\d+)/.exec(s21[i]); re83.exec('[bowrpg tybony]'); - re62.exec(str47); + re62.exec(s97[i]); re84.exec(str61); re84.exec(str62); /jroxvg/.exec(str63); @@ -1597,18 +1742,23 @@ function runRegExpBenchmark() { /jvaqbjf/.exec(str63); } } - for (var i = 0; i < 5; i++) { - runBlock0(); - runBlock1(); - runBlock2(); - runBlock3(); - runBlock4(); - runBlock5(); - runBlock6(); - runBlock7(); - runBlock8(); - runBlock9(); - runBlock10(); - runBlock11(); + + function run() { + for (var i = 0; i < 5; i++) { + runBlock0(); + runBlock1(); + runBlock2(); + runBlock3(); + runBlock4(); + runBlock5(); + runBlock6(); + runBlock7(); + runBlock8(); + runBlock9(); + runBlock10(); + runBlock11(); + } } + + this.run = run; } diff --git a/deps/v8/benchmarks/revisions.html b/deps/v8/benchmarks/revisions.html index 1c54f63462..6ff75be1e1 100644 --- a/deps/v8/benchmarks/revisions.html +++ b/deps/v8/benchmarks/revisions.html @@ -26,7 +26,9 @@ the benchmark suite. typos in the DeltaBlue implementation. Changed the Splay benchmark to avoid converting the same numeric key to a string over and over again and to avoid inserting and removing the same element repeatedly thus -increasing pressure on the memory subsystem.

+increasing pressure on the memory subsystem. Changed the RegExp +benchmark to exercise the regular expression engine on different input +strings.

Furthermore, the benchmark runner was changed to run the benchmarks for at least a few times to stabilize the reported numbers on slower diff --git a/deps/v8/benchmarks/run.html b/deps/v8/benchmarks/run.html index 05bfffee02..36d2ad511b 100644 --- a/deps/v8/benchmarks/run.html +++ b/deps/v8/benchmarks/run.html @@ -114,7 +114,7 @@ higher scores means better performance: Bigger is better!

  • RayTrace
    Ray tracer benchmark based on code by Adam Burmister (904 lines).
  • EarleyBoyer
    Classic Scheme benchmarks, translated to JavaScript by Florian Loitsch's Scheme2Js compiler (4684 lines).
  • RegExp
    Regular expression benchmark generated by extracting regular expression operations from 50 of the most popular web pages -(1614 lines). +(1761 lines).
  • Splay
    Data manipulation benchmark that deals with splay trees and exercises the automatic memory management subsystem (394 lines).
  • diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index e09d4c954c..d6ed8aee2f 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -4433,7 +4433,7 @@ double CpuProfileNode::GetSelfSamplesCount() const { unsigned CpuProfileNode::GetCallUid() const { IsDeadCheck("v8::CpuProfileNode::GetCallUid"); - return reinterpret_cast(this)->entry()->call_uid(); + return reinterpret_cast(this)->entry()->GetCallUid(); } diff --git a/deps/v8/src/arm/frames-arm.cc b/deps/v8/src/arm/frames-arm.cc index 47434392df..b0c0990306 100644 --- a/deps/v8/src/arm/frames-arm.cc +++ b/deps/v8/src/arm/frames-arm.cc @@ -37,17 +37,8 @@ namespace v8 { namespace internal { -StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) { - if (fp == 0) return NONE; - // Compute frame type and stack pointer. - Address sp = fp + ExitFrameConstants::kSPOffset; - - // Fill in the state. - state->sp = sp; - state->fp = fp; - state->pc_address = reinterpret_cast(sp - 1 * kPointerSize); - ASSERT(*state->pc_address != NULL); - return EXIT; +Address ExitFrame::ComputeStackPointer(Address fp) { + return fp + ExitFrameConstants::kSPOffset; } diff --git a/deps/v8/src/arm/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc index c776d67cca..f5d121785d 100644 --- a/deps/v8/src/arm/full-codegen-arm.cc +++ b/deps/v8/src/arm/full-codegen-arm.cc @@ -620,7 +620,7 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable, __ pop(r2); // Receiver. Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); - __ Call(ic, RelocInfo::CODE_TARGET); + EmitCallIC(ic, RelocInfo::CODE_TARGET); // Value in r0 is ignored (declarations are statements). } } @@ -956,7 +956,7 @@ void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( slow)); __ mov(r0, Operand(key_literal->handle())); Handle ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); - __ Call(ic, RelocInfo::CODE_TARGET); + EmitCallIC(ic, RelocInfo::CODE_TARGET); __ jmp(done); } } @@ -1022,7 +1022,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( ? RelocInfo::CODE_TARGET : RelocInfo::CODE_TARGET_CONTEXT; Handle ic(Builtins::builtin(Builtins::LoadIC_Initialize)); - __ Call(ic, mode); + EmitCallIC(ic, mode); } @@ -1041,7 +1041,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var, __ ldr(r0, CodeGenerator::GlobalObject()); __ mov(r2, Operand(var->name())); Handle ic(Builtins::builtin(Builtins::LoadIC_Initialize)); - __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); + EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); Apply(context, r0); } else if (slot != NULL && slot->type() == Slot::LOOKUP) { @@ -1100,7 +1100,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var, // Call keyed load IC. It has arguments key and receiver in r0 and r1. Handle ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); - __ Call(ic, RelocInfo::CODE_TARGET); + EmitCallIC(ic, RelocInfo::CODE_TARGET); Apply(context, r0); } } @@ -1189,7 +1189,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ mov(r2, Operand(key->handle())); __ ldr(r1, MemOperand(sp)); Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); - __ Call(ic, RelocInfo::CODE_TARGET); + EmitCallIC(ic, RelocInfo::CODE_TARGET); break; } // Fall through. @@ -1409,7 +1409,7 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { __ mov(r2, Operand(key->handle())); // Call load IC. It has arguments receiver and property name r0 and r2. Handle ic(Builtins::builtin(Builtins::LoadIC_Initialize)); - __ Call(ic, RelocInfo::CODE_TARGET); + EmitCallIC(ic, RelocInfo::CODE_TARGET); } @@ -1417,7 +1417,7 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); // Call keyed load IC. It has arguments key and receiver in r0 and r1. Handle ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); - __ Call(ic, RelocInfo::CODE_TARGET); + EmitCallIC(ic, RelocInfo::CODE_TARGET); } @@ -1475,7 +1475,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) { __ pop(r0); // Restore value. __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); - __ Call(ic, RelocInfo::CODE_TARGET); + EmitCallIC(ic, RelocInfo::CODE_TARGET); break; } case KEYED_PROPERTY: { @@ -1486,7 +1486,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) { __ pop(r2); __ pop(r0); // Restore value. Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); - __ Call(ic, RelocInfo::CODE_TARGET); + EmitCallIC(ic, RelocInfo::CODE_TARGET); break; } } @@ -1509,7 +1509,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, __ mov(r2, Operand(var->name())); __ ldr(r1, CodeGenerator::GlobalObject()); Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); - __ Call(ic, RelocInfo::CODE_TARGET); + EmitCallIC(ic, RelocInfo::CODE_TARGET); } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) { // Perform the assignment for non-const variables and for initialization @@ -1598,7 +1598,7 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { } Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); - __ Call(ic, RelocInfo::CODE_TARGET); + EmitCallIC(ic, RelocInfo::CODE_TARGET); // If the assignment ends an initialization block, revert to fast case. if (expr->ends_initialization_block()) { @@ -1642,7 +1642,7 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { } Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); - __ Call(ic, RelocInfo::CODE_TARGET); + EmitCallIC(ic, RelocInfo::CODE_TARGET); // If the assignment ends an initialization block, revert to fast case. if (expr->ends_initialization_block()) { @@ -1691,7 +1691,7 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr, // Call the IC initialization code. InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; Handle ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop); - __ Call(ic, mode); + EmitCallIC(ic, mode); // Restore context register. __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); Apply(context_, r0); @@ -1715,7 +1715,7 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; Handle ic = CodeGenerator::ComputeKeyedCallInitialize(arg_count, in_loop); - __ Call(ic, mode); + EmitCallIC(ic, mode); // Restore context register. __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); Apply(context_, r0); @@ -1854,7 +1854,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { __ pop(r1); // We do not need to keep the receiver. Handle ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); - __ Call(ic, RelocInfo::CODE_TARGET); + EmitCallIC(ic, RelocInfo::CODE_TARGET); __ ldr(r1, CodeGenerator::GlobalObject()); __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); __ Push(r0, r1); // Function, receiver. @@ -2769,7 +2769,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { __ mov(r2, Operand(expr->name())); Handle ic = CodeGenerator::ComputeCallInitialize(arg_count, NOT_IN_LOOP); - __ Call(ic, RelocInfo::CODE_TARGET); + EmitCallIC(ic, RelocInfo::CODE_TARGET); // Restore context register. __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); } else { @@ -3065,7 +3065,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); __ pop(r1); Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); - __ Call(ic, RelocInfo::CODE_TARGET); + EmitCallIC(ic, RelocInfo::CODE_TARGET); if (expr->is_postfix()) { if (context_ != Expression::kEffect) { ApplyTOS(context_); @@ -3079,7 +3079,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { __ pop(r1); // Key. __ pop(r2); // Receiver. Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); - __ Call(ic, RelocInfo::CODE_TARGET); + EmitCallIC(ic, RelocInfo::CODE_TARGET); if (expr->is_postfix()) { if (context_ != Expression::kEffect) { ApplyTOS(context_); @@ -3102,7 +3102,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr, Location where) { Handle ic(Builtins::builtin(Builtins::LoadIC_Initialize)); // Use a regular load, not a contextual load, to avoid a reference // error. - __ Call(ic, RelocInfo::CODE_TARGET); + EmitCallIC(ic, RelocInfo::CODE_TARGET); if (where == kStack) __ push(r0); } else if (proxy != NULL && proxy->var()->slot() != NULL && @@ -3365,10 +3365,21 @@ void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { } -Register FullCodeGenerator::result_register() { return r0; } +Register FullCodeGenerator::result_register() { + return r0; +} -Register FullCodeGenerator::context_register() { return cp; } +Register FullCodeGenerator::context_register() { + return cp; +} + + +void FullCodeGenerator::EmitCallIC(Handle ic, RelocInfo::Mode mode) { + ASSERT(mode == RelocInfo::CODE_TARGET || + mode == RelocInfo::CODE_TARGET_CONTEXT); + __ Call(ic, mode); +} void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { diff --git a/deps/v8/src/arm/ic-arm.cc b/deps/v8/src/arm/ic-arm.cc index 1a76db2ce3..d5a700cd9f 100644 --- a/deps/v8/src/arm/ic-arm.cc +++ b/deps/v8/src/arm/ic-arm.cc @@ -967,6 +967,14 @@ bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) { } +bool LoadIC::PatchInlinedContextualLoad(Address address, + Object* map, + Object* cell) { + // TODO(): implement this. + return false; +} + + bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) { // Find the end of the inlined code for the store if there is an // inlined version of the store. @@ -1236,7 +1244,6 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) { // -- r1 : receiver // ----------------------------------- Label miss; - Label index_out_of_range; Register receiver = r1; Register index = r0; @@ -1251,7 +1258,7 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) { result, &miss, // When not a string. &miss, // When not a number. - &index_out_of_range, + &miss, // When index out of range. STRING_INDEX_IS_ARRAY_INDEX); char_at_generator.GenerateFast(masm); __ Ret(); @@ -1259,10 +1266,6 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) { ICRuntimeCallHelper call_helper; char_at_generator.GenerateSlow(masm, call_helper); - __ bind(&index_out_of_range); - __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); - __ Ret(); - __ bind(&miss); GenerateMiss(masm); } diff --git a/deps/v8/src/arm/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc index 0da5f64696..070e352e47 100644 --- a/deps/v8/src/arm/stub-cache-arm.cc +++ b/deps/v8/src/arm/stub-cache-arm.cc @@ -266,7 +266,12 @@ void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm, void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( - MacroAssembler* masm, int index, Register prototype) { + MacroAssembler* masm, int index, Register prototype, Label* miss) { + // Check we're still in the same context. + __ ldr(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); + __ Move(ip, Top::global()); + __ cmp(prototype, ip); + __ b(ne, miss); // Get the global function with the given index. JSFunction* function = JSFunction::cast(Top::global_context()->get(index)); // Load its initial map. The global functions all have initial maps. @@ -1434,7 +1439,8 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall( // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(masm(), Context::STRING_FUNCTION_INDEX, - r0); + r0, + &miss); ASSERT(object != holder); CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r1, r3, r4, name, &miss); @@ -1505,7 +1511,8 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object, // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(masm(), Context::STRING_FUNCTION_INDEX, - r0); + r0, + &miss); ASSERT(object != holder); CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r1, r3, r4, name, &miss); @@ -1626,6 +1633,16 @@ Object* CallStubCompiler::CompileStringFromCharCodeCall( } +Object* CallStubCompiler::CompileMathFloorCall(Object* object, + JSObject* holder, + JSGlobalPropertyCell* cell, + JSFunction* function, + String* name) { + // TODO(872): implement this. + return Heap::undefined_value(); +} + + Object* CallStubCompiler::CompileCallConstant(Object* object, JSObject* holder, JSFunction* function, @@ -1705,7 +1722,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, __ b(hs, &miss); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype( - masm(), Context::STRING_FUNCTION_INDEX, r0); + masm(), Context::STRING_FUNCTION_INDEX, r0, &miss); CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, r1, r4, name, &miss); } @@ -1725,7 +1742,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, __ bind(&fast); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype( - masm(), Context::NUMBER_FUNCTION_INDEX, r0); + masm(), Context::NUMBER_FUNCTION_INDEX, r0, &miss); CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, r1, r4, name, &miss); } @@ -1748,7 +1765,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, __ bind(&fast); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype( - masm(), Context::BOOLEAN_FUNCTION_INDEX, r0); + masm(), Context::BOOLEAN_FUNCTION_INDEX, r0, &miss); CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, r1, r4, name, &miss); } @@ -2212,11 +2229,11 @@ Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object, } __ mov(r0, r4); - __ IncrementCounter(&Counters::named_load_global_inline, 1, r1, r3); + __ IncrementCounter(&Counters::named_load_global_stub, 1, r1, r3); __ Ret(); __ bind(&miss); - __ IncrementCounter(&Counters::named_load_global_inline_miss, 1, r1, r3); + __ IncrementCounter(&Counters::named_load_global_stub_miss, 1, r1, r3); GenerateLoadMiss(masm(), Code::LOAD_IC); // Return the generated code. diff --git a/deps/v8/src/bootstrapper.cc b/deps/v8/src/bootstrapper.cc index 6e6c2c639c..1f12502684 100644 --- a/deps/v8/src/bootstrapper.cc +++ b/deps/v8/src/bootstrapper.cc @@ -1344,33 +1344,41 @@ bool Genesis::InstallNatives() { } -static void InstallCustomCallGenerator( - Handle holder_function, - CallStubCompiler::CustomGeneratorOwner owner_flag, - const char* function_name, - int id) { - Handle owner; - if (owner_flag == CallStubCompiler::FUNCTION) { - owner = Handle::cast(holder_function); - } else { - ASSERT(owner_flag == CallStubCompiler::INSTANCE_PROTOTYPE); - owner = Handle( - JSObject::cast(holder_function->instance_prototype())); +static Handle ResolveCustomCallGeneratorHolder( + Handle global_context, + const char* holder_expr) { + Handle global(global_context->global()); + const char* period_pos = strchr(holder_expr, '.'); + if (period_pos == NULL) { + return Handle::cast( + GetProperty(global, Factory::LookupAsciiSymbol(holder_expr))); } + ASSERT_EQ(".prototype", period_pos); + Vector property(holder_expr, + static_cast(period_pos - holder_expr)); + Handle function = Handle::cast( + GetProperty(global, Factory::LookupSymbol(property))); + return Handle(JSObject::cast(function->prototype())); +} + + +static void InstallCustomCallGenerator(Handle holder, + const char* function_name, + int id) { Handle name = Factory::LookupAsciiSymbol(function_name); - Handle function(JSFunction::cast(owner->GetProperty(*name))); + Handle function(JSFunction::cast(holder->GetProperty(*name))); function->shared()->set_function_data(Smi::FromInt(id)); } void Genesis::InstallCustomCallGenerators() { HandleScope scope; -#define INSTALL_CALL_GENERATOR(holder_fun, owner_flag, fun_name, name) \ - { \ - Handle holder(global_context()->holder_fun##_function()); \ - const int id = CallStubCompiler::k##name##CallGenerator; \ - InstallCustomCallGenerator(holder, CallStubCompiler::owner_flag, \ - #fun_name, id); \ +#define INSTALL_CALL_GENERATOR(holder_expr, fun_name, name) \ + { \ + Handle holder = ResolveCustomCallGeneratorHolder( \ + global_context(), #holder_expr); \ + const int id = CallStubCompiler::k##name##CallGenerator; \ + InstallCustomCallGenerator(holder, #fun_name, id); \ } CUSTOM_CALL_IC_GENERATORS(INSTALL_CALL_GENERATOR) #undef INSTALL_CALL_GENERATOR diff --git a/deps/v8/src/conversions.cc b/deps/v8/src/conversions.cc index 90cdc773ea..f15a804ef8 100644 --- a/deps/v8/src/conversions.cc +++ b/deps/v8/src/conversions.cc @@ -956,8 +956,9 @@ static char* CreateExponentialRepresentation(char* decimal_rep, char* DoubleToExponentialCString(double value, int f) { + const int kMaxDigitsAfterPoint = 20; // f might be -1 to signal that f was undefined in JavaScript. - ASSERT(f >= -1 && f <= 20); + ASSERT(f >= -1 && f <= kMaxDigitsAfterPoint); bool negative = false; if (value < 0) { @@ -969,29 +970,60 @@ char* DoubleToExponentialCString(double value, int f) { int decimal_point; int sign; char* decimal_rep = NULL; + bool used_gay_dtoa = false; + // f corresponds to the digits after the point. There is always one digit + // before the point. The number of requested_digits equals hence f + 1. + // And we have to add one character for the null-terminator. + const int kV8DtoaBufferCapacity = kMaxDigitsAfterPoint + 1 + 1; + // Make sure that the buffer is big enough, even if we fall back to the + // shortest representation (which happens when f equals -1). + ASSERT(kBase10MaximalLength <= kMaxDigitsAfterPoint + 1); + char v8_dtoa_buffer[kV8DtoaBufferCapacity]; + int decimal_rep_length; + if (f == -1) { - decimal_rep = dtoa(value, 0, 0, &decimal_point, &sign, NULL); - f = StrLength(decimal_rep) - 1; + if (DoubleToAscii(value, DTOA_SHORTEST, 0, + Vector(v8_dtoa_buffer, kV8DtoaBufferCapacity), + &sign, &decimal_rep_length, &decimal_point)) { + f = decimal_rep_length - 1; + decimal_rep = v8_dtoa_buffer; + } else { + decimal_rep = dtoa(value, 0, 0, &decimal_point, &sign, NULL); + decimal_rep_length = StrLength(decimal_rep); + f = decimal_rep_length - 1; + used_gay_dtoa = true; + } } else { - decimal_rep = dtoa(value, 2, f + 1, &decimal_point, &sign, NULL); + if (DoubleToAscii(value, DTOA_PRECISION, f + 1, + Vector(v8_dtoa_buffer, kV8DtoaBufferCapacity), + &sign, &decimal_rep_length, &decimal_point)) { + decimal_rep = v8_dtoa_buffer; + } else { + decimal_rep = dtoa(value, 2, f + 1, &decimal_point, &sign, NULL); + decimal_rep_length = StrLength(decimal_rep); + used_gay_dtoa = true; + } } - int decimal_rep_length = StrLength(decimal_rep); ASSERT(decimal_rep_length > 0); ASSERT(decimal_rep_length <= f + 1); - USE(decimal_rep_length); int exponent = decimal_point - 1; char* result = CreateExponentialRepresentation(decimal_rep, exponent, negative, f+1); - freedtoa(decimal_rep); + if (used_gay_dtoa) { + freedtoa(decimal_rep); + } return result; } char* DoubleToPrecisionCString(double value, int p) { - ASSERT(p >= 1 && p <= 21); + const int kMinimalDigits = 1; + const int kMaximalDigits = 21; + ASSERT(p >= kMinimalDigits && p <= kMaximalDigits); + USE(kMinimalDigits); bool negative = false; if (value < 0) { @@ -1002,8 +1034,22 @@ char* DoubleToPrecisionCString(double value, int p) { // Find a sufficiently precise decimal representation of n. int decimal_point; int sign; - char* decimal_rep = dtoa(value, 2, p, &decimal_point, &sign, NULL); - int decimal_rep_length = StrLength(decimal_rep); + char* decimal_rep = NULL; + bool used_gay_dtoa = false; + // Add one for the terminating null character. + const int kV8DtoaBufferCapacity = kMaximalDigits + 1; + char v8_dtoa_buffer[kV8DtoaBufferCapacity]; + int decimal_rep_length; + + if (DoubleToAscii(value, DTOA_PRECISION, p, + Vector(v8_dtoa_buffer, kV8DtoaBufferCapacity), + &sign, &decimal_rep_length, &decimal_point)) { + decimal_rep = v8_dtoa_buffer; + } else { + decimal_rep = dtoa(value, 2, p, &decimal_point, &sign, NULL); + decimal_rep_length = StrLength(decimal_rep); + used_gay_dtoa = true; + } ASSERT(decimal_rep_length <= p); int exponent = decimal_point - 1; @@ -1047,7 +1093,9 @@ char* DoubleToPrecisionCString(double value, int p) { result = builder.Finalize(); } - freedtoa(decimal_rep); + if (used_gay_dtoa) { + freedtoa(decimal_rep); + } return result; } diff --git a/deps/v8/src/cpu-profiler-inl.h b/deps/v8/src/cpu-profiler-inl.h index cb7fdd8ff6..5df5893f8a 100644 --- a/deps/v8/src/cpu-profiler-inl.h +++ b/deps/v8/src/cpu-profiler-inl.h @@ -82,14 +82,11 @@ TickSample* ProfilerEventsProcessor::TickSampleEvent() { bool ProfilerEventsProcessor::FilterOutCodeCreateEvent( Logger::LogEventsAndTags tag) { - // In browser mode, leave only callbacks and non-native JS entries. - // We filter out regular expressions as currently we can't tell - // whether they origin from native scripts, so let's not confise people by - // showing them weird regexes they didn't wrote. return FLAG_prof_browser_mode && (tag != Logger::CALLBACK_TAG && tag != Logger::FUNCTION_TAG && tag != Logger::LAZY_COMPILE_TAG + && tag != Logger::REG_EXP_TAG && tag != Logger::SCRIPT_TAG); } diff --git a/deps/v8/src/debug-debugger.js b/deps/v8/src/debug-debugger.js index 0b02e2102a..34eb0f0ec5 100644 --- a/deps/v8/src/debug-debugger.js +++ b/deps/v8/src/debug-debugger.js @@ -45,7 +45,7 @@ Debug.DebugEvent = { Break: 1, ScriptCollected: 6 }; // Types of exceptions that can be broken upon. -Debug.ExceptionBreak = { All : 0, +Debug.ExceptionBreak = { Caught : 0, Uncaught: 1 }; // The different types of steps. @@ -87,7 +87,27 @@ var debugger_flags = { this.value = !!value; %SetDisableBreak(!this.value); } - } + }, + breakOnCaughtException: { + getValue: function() { return Debug.isBreakOnException(); }, + setValue: function(value) { + if (value) { + Debug.setBreakOnException(); + } else { + Debug.clearBreakOnException(); + } + } + }, + breakOnUncaughtException: { + getValue: function() { return Debug.isBreakOnUncaughtException(); }, + setValue: function(value) { + if (value) { + Debug.setBreakOnUncaughtException(); + } else { + Debug.clearBreakOnUncaughtException(); + } + } + }, }; @@ -781,11 +801,15 @@ Debug.clearStepping = function() { } Debug.setBreakOnException = function() { - return %ChangeBreakOnException(Debug.ExceptionBreak.All, true); + return %ChangeBreakOnException(Debug.ExceptionBreak.Caught, true); }; Debug.clearBreakOnException = function() { - return %ChangeBreakOnException(Debug.ExceptionBreak.All, false); + return %ChangeBreakOnException(Debug.ExceptionBreak.Caught, false); +}; + +Debug.isBreakOnException = function() { + return !!%IsBreakOnException(Debug.ExceptionBreak.Caught); }; Debug.setBreakOnUncaughtException = function() { @@ -796,6 +820,10 @@ Debug.clearBreakOnUncaughtException = function() { return %ChangeBreakOnException(Debug.ExceptionBreak.Uncaught, false); }; +Debug.isBreakOnUncaughtException = function() { + return !!%IsBreakOnException(Debug.ExceptionBreak.Uncaught); +}; + Debug.showBreakPoints = function(f, full) { if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.'); var source = full ? this.scriptSource(f) : this.source(f); diff --git a/deps/v8/src/debug.cc b/deps/v8/src/debug.cc index 87780d350c..24b1d31097 100644 --- a/deps/v8/src/debug.cc +++ b/deps/v8/src/debug.cc @@ -1200,6 +1200,15 @@ void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) { } +bool Debug::IsBreakOnException(ExceptionBreakType type) { + if (type == BreakUncaughtException) { + return break_on_uncaught_exception_; + } else { + return break_on_exception_; + } +} + + void Debug::PrepareStep(StepAction step_action, int step_count) { HandleScope scope; ASSERT(Debug::InDebugger()); diff --git a/deps/v8/src/debug.h b/deps/v8/src/debug.h index 8b3b29e636..0d63085f15 100644 --- a/deps/v8/src/debug.h +++ b/deps/v8/src/debug.h @@ -236,6 +236,7 @@ class Debug { static void FloodWithOneShot(Handle shared); static void FloodHandlerWithOneShot(); static void ChangeBreakOnException(ExceptionBreakType type, bool enable); + static bool IsBreakOnException(ExceptionBreakType type); static void PrepareStep(StepAction step_action, int step_count); static void ClearStepping(); static bool StepNextContinue(BreakLocationIterator* break_location_iterator, diff --git a/deps/v8/src/dtoa.cc b/deps/v8/src/dtoa.cc index e3dcbf2d61..f4141eb619 100644 --- a/deps/v8/src/dtoa.cc +++ b/deps/v8/src/dtoa.cc @@ -65,11 +65,12 @@ bool DoubleToAscii(double v, DtoaMode mode, int requested_digits, switch (mode) { case DTOA_SHORTEST: - return FastDtoa(v, buffer, length, point); + return FastDtoa(v, FAST_DTOA_SHORTEST, 0, buffer, length, point); case DTOA_FIXED: return FastFixedDtoa(v, requested_digits, buffer, length, point); - default: - break; + case DTOA_PRECISION: + return FastDtoa(v, FAST_DTOA_PRECISION, requested_digits, + buffer, length, point); } return false; } diff --git a/deps/v8/src/fast-dtoa.cc b/deps/v8/src/fast-dtoa.cc index b4b7be053f..d2a00cc624 100644 --- a/deps/v8/src/fast-dtoa.cc +++ b/deps/v8/src/fast-dtoa.cc @@ -42,8 +42,8 @@ namespace internal { // // A different range might be chosen on a different platform, to optimize digit // generation, but a smaller range requires more powers of ten to be cached. -static const int minimal_target_exponent = -60; -static const int maximal_target_exponent = -32; +static const int kMinimalTargetExponent = -60; +static const int kMaximalTargetExponent = -32; // Adjusts the last digit of the generated number, and screens out generated @@ -61,13 +61,13 @@ static const int maximal_target_exponent = -32; // Output: returns true if the buffer is guaranteed to contain the closest // representable number to the input. // Modifies the generated digits in the buffer to approach (round towards) w. -bool RoundWeed(Vector buffer, - int length, - uint64_t distance_too_high_w, - uint64_t unsafe_interval, - uint64_t rest, - uint64_t ten_kappa, - uint64_t unit) { +static bool RoundWeed(Vector buffer, + int length, + uint64_t distance_too_high_w, + uint64_t unsafe_interval, + uint64_t rest, + uint64_t ten_kappa, + uint64_t unit) { uint64_t small_distance = distance_too_high_w - unit; uint64_t big_distance = distance_too_high_w + unit; // Let w_low = too_high - big_distance, and @@ -75,7 +75,7 @@ bool RoundWeed(Vector buffer, // Note: w_low < w < w_high // // The real w (* unit) must lie somewhere inside the interval - // ]w_low; w_low[ (often written as "(w_low; w_low)") + // ]w_low; w_high[ (often written as "(w_low; w_high)") // Basically the buffer currently contains a number in the unsafe interval // ]too_low; too_high[ with too_low < w < too_high @@ -122,10 +122,10 @@ bool RoundWeed(Vector buffer, // inside the safe interval then we simply do not know and bail out (returning // false). // - // Similarly we have to take into account the imprecision of 'w' when rounding - // the buffer. If we have two potential representations we need to make sure - // that the chosen one is closer to w_low and w_high since v can be anywhere - // between them. + // Similarly we have to take into account the imprecision of 'w' when finding + // the closest representation of 'w'. If we have two potential + // representations, and one is closer to both w_low and w_high, then we know + // it is closer to the actual value v. // // By generating the digits of too_high we got the largest (closest to // too_high) buffer that is still in the unsafe interval. In the case where @@ -139,6 +139,9 @@ bool RoundWeed(Vector buffer, // (buffer{-1} < w_high) && w_high - buffer{-1} > buffer - w_high // Instead of using the buffer directly we use its distance to too_high. // Conceptually rest ~= too_high - buffer + // We need to do the following tests in this order to avoid over- and + // underflows. + ASSERT(rest <= unsafe_interval); while (rest < small_distance && // Negated condition 1 unsafe_interval - rest >= ten_kappa && // Negated condition 2 (rest + ten_kappa < small_distance || // buffer{-1} > w_high @@ -166,6 +169,62 @@ bool RoundWeed(Vector buffer, } +// Rounds the buffer upwards if the result is closer to v by possibly adding +// 1 to the buffer. If the precision of the calculation is not sufficient to +// round correctly, return false. +// The rounding might shift the whole buffer in which case the kappa is +// adjusted. For example "99", kappa = 3 might become "10", kappa = 4. +// +// If 2*rest > ten_kappa then the buffer needs to be round up. +// rest can have an error of +/- 1 unit. This function accounts for the +// imprecision and returns false, if the rounding direction cannot be +// unambiguously determined. +// +// Precondition: rest < ten_kappa. +static bool RoundWeedCounted(Vector buffer, + int length, + uint64_t rest, + uint64_t ten_kappa, + uint64_t unit, + int* kappa) { + ASSERT(rest < ten_kappa); + // The following tests are done in a specific order to avoid overflows. They + // will work correctly with any uint64 values of rest < ten_kappa and unit. + // + // If the unit is too big, then we don't know which way to round. For example + // a unit of 50 means that the real number lies within rest +/- 50. If + // 10^kappa == 40 then there is no way to tell which way to round. + if (unit >= ten_kappa) return false; + // Even if unit is just half the size of 10^kappa we are already completely + // lost. (And after the previous test we know that the expression will not + // over/underflow.) + if (ten_kappa - unit <= unit) return false; + // If 2 * (rest + unit) <= 10^kappa we can safely round down. + if ((ten_kappa - rest > rest) && (ten_kappa - 2 * rest >= 2 * unit)) { + return true; + } + // If 2 * (rest - unit) >= 10^kappa, then we can safely round up. + if ((rest > unit) && (ten_kappa - (rest - unit) <= (rest - unit))) { + // Increment the last digit recursively until we find a non '9' digit. + buffer[length - 1]++; + for (int i = length - 1; i > 0; --i) { + if (buffer[i] != '0' + 10) break; + buffer[i] = '0'; + buffer[i - 1]++; + } + // If the first digit is now '0'+ 10 we had a buffer with all '9's. With the + // exception of the first digit all digits are now '0'. Simply switch the + // first digit to '1' and adjust the kappa. Example: "99" becomes "10" and + // the power (the kappa) is increased. + if (buffer[0] == '0' + 10) { + buffer[0] = '1'; + (*kappa) += 1; + } + return true; + } + return false; +} + static const uint32_t kTen4 = 10000; static const uint32_t kTen5 = 100000; @@ -178,7 +237,7 @@ static const uint32_t kTen9 = 1000000000; // number. We furthermore receive the maximum number of bits 'number' has. // If number_bits == 0 then 0^-1 is returned // The number of bits must be <= 32. -// Precondition: (1 << number_bits) <= number < (1 << (number_bits + 1)). +// Precondition: number < (1 << (number_bits + 1)). static void BiggestPowerTen(uint32_t number, int number_bits, uint32_t* power, @@ -281,18 +340,18 @@ static void BiggestPowerTen(uint32_t number, // Generates the digits of input number w. // w is a floating-point number (DiyFp), consisting of a significand and an -// exponent. Its exponent is bounded by minimal_target_exponent and -// maximal_target_exponent. +// exponent. Its exponent is bounded by kMinimalTargetExponent and +// kMaximalTargetExponent. // Hence -60 <= w.e() <= -32. // // Returns false if it fails, in which case the generated digits in the buffer // should not be used. // Preconditions: // * low, w and high are correct up to 1 ulp (unit in the last place). That -// is, their error must be less that a unit of their last digits. +// is, their error must be less than a unit of their last digits. // * low.e() == w.e() == high.e() // * low < w < high, and taking into account their error: low~ <= high~ -// * minimal_target_exponent <= w.e() <= maximal_target_exponent +// * kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent // Postconditions: returns false if procedure fails. // otherwise: // * buffer is not null-terminated, but len contains the number of digits. @@ -321,15 +380,15 @@ static void BiggestPowerTen(uint32_t number, // represent 'w' we can stop. Everything inside the interval low - high // represents w. However we have to pay attention to low, high and w's // imprecision. -bool DigitGen(DiyFp low, - DiyFp w, - DiyFp high, - Vector buffer, - int* length, - int* kappa) { +static bool DigitGen(DiyFp low, + DiyFp w, + DiyFp high, + Vector buffer, + int* length, + int* kappa) { ASSERT(low.e() == w.e() && w.e() == high.e()); ASSERT(low.f() + 1 <= high.f() - 1); - ASSERT(minimal_target_exponent <= w.e() && w.e() <= maximal_target_exponent); + ASSERT(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent); // low, w and high are imprecise, but by less than one ulp (unit in the last // place). // If we remove (resp. add) 1 ulp from low (resp. high) we are certain that @@ -359,23 +418,23 @@ bool DigitGen(DiyFp low, uint32_t integrals = static_cast(too_high.f() >> -one.e()); // Modulo by one is an and. uint64_t fractionals = too_high.f() & (one.f() - 1); - uint32_t divider; - int divider_exponent; + uint32_t divisor; + int divisor_exponent; BiggestPowerTen(integrals, DiyFp::kSignificandSize - (-one.e()), - ÷r, ÷r_exponent); - *kappa = divider_exponent + 1; + &divisor, &divisor_exponent); + *kappa = divisor_exponent + 1; *length = 0; // Loop invariant: buffer = too_high / 10^kappa (integer division) // The invariant holds for the first iteration: kappa has been initialized - // with the divider exponent + 1. And the divider is the biggest power of ten + // with the divisor exponent + 1. And the divisor is the biggest power of ten // that is smaller than integrals. while (*kappa > 0) { - int digit = integrals / divider; + int digit = integrals / divisor; buffer[*length] = '0' + digit; (*length)++; - integrals %= divider; + integrals %= divisor; (*kappa)--; - // Note that kappa now equals the exponent of the divider and that the + // Note that kappa now equals the exponent of the divisor and that the // invariant thus holds again. uint64_t rest = (static_cast(integrals) << -one.e()) + fractionals; @@ -386,32 +445,24 @@ bool DigitGen(DiyFp low, // that lies within the unsafe interval. return RoundWeed(buffer, *length, DiyFp::Minus(too_high, w).f(), unsafe_interval.f(), rest, - static_cast(divider) << -one.e(), unit); + static_cast(divisor) << -one.e(), unit); } - divider /= 10; + divisor /= 10; } // The integrals have been generated. We are at the point of the decimal // separator. In the following loop we simply multiply the remaining digits by // 10 and divide by one. We just need to pay attention to multiply associated // data (like the interval or 'unit'), too. - // Instead of multiplying by 10 we multiply by 5 (cheaper operation) and - // increase its (imaginary) exponent. At the same time we decrease the - // divider's (one's) exponent and shift its significand. - // Basically, if fractionals was a DiyFp (with fractionals.e == one.e): - // fractionals.f *= 10; - // fractionals.f >>= 1; fractionals.e++; // value remains unchanged. - // one.f >>= 1; one.e++; // value remains unchanged. - // and we have again fractionals.e == one.e which allows us to divide - // fractionals.f() by one.f() - // We simply combine the *= 10 and the >>= 1. + // Note that the multiplication by 10 does not overflow, because w.e >= -60 + // and thus one.e >= -60. + ASSERT(one.e() >= -60); + ASSERT(fractionals < one.f()); + ASSERT(V8_2PART_UINT64_C(0xFFFFFFFF, FFFFFFFF) / 10 >= one.f()); while (true) { - fractionals *= 5; - unit *= 5; - unsafe_interval.set_f(unsafe_interval.f() * 5); - unsafe_interval.set_e(unsafe_interval.e() + 1); // Will be optimized out. - one.set_f(one.f() >> 1); - one.set_e(one.e() + 1); + fractionals *= 10; + unit *= 10; + unsafe_interval.set_f(unsafe_interval.f() * 10); // Integer division by one. int digit = static_cast(fractionals >> -one.e()); buffer[*length] = '0' + digit; @@ -426,6 +477,113 @@ bool DigitGen(DiyFp low, } + +// Generates (at most) requested_digits of input number w. +// w is a floating-point number (DiyFp), consisting of a significand and an +// exponent. Its exponent is bounded by kMinimalTargetExponent and +// kMaximalTargetExponent. +// Hence -60 <= w.e() <= -32. +// +// Returns false if it fails, in which case the generated digits in the buffer +// should not be used. +// Preconditions: +// * w is correct up to 1 ulp (unit in the last place). That +// is, its error must be strictly less than a unit of its last digit. +// * kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent +// +// Postconditions: returns false if procedure fails. +// otherwise: +// * buffer is not null-terminated, but length contains the number of +// digits. +// * the representation in buffer is the most precise representation of +// requested_digits digits. +// * buffer contains at most requested_digits digits of w. If there are less +// than requested_digits digits then some trailing '0's have been removed. +// * kappa is such that +// w = buffer * 10^kappa + eps with |eps| < 10^kappa / 2. +// +// Remark: This procedure takes into account the imprecision of its input +// numbers. If the precision is not enough to guarantee all the postconditions +// then false is returned. This usually happens rarely, but the failure-rate +// increases with higher requested_digits. +static bool DigitGenCounted(DiyFp w, + int requested_digits, + Vector buffer, + int* length, + int* kappa) { + ASSERT(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent); + ASSERT(kMinimalTargetExponent >= -60); + ASSERT(kMaximalTargetExponent <= -32); + // w is assumed to have an error less than 1 unit. Whenever w is scaled we + // also scale its error. + uint64_t w_error = 1; + // We cut the input number into two parts: the integral digits and the + // fractional digits. We don't emit any decimal separator, but adapt kappa + // instead. Example: instead of writing "1.2" we put "12" into the buffer and + // increase kappa by 1. + DiyFp one = DiyFp(static_cast(1) << -w.e(), w.e()); + // Division by one is a shift. + uint32_t integrals = static_cast(w.f() >> -one.e()); + // Modulo by one is an and. + uint64_t fractionals = w.f() & (one.f() - 1); + uint32_t divisor; + int divisor_exponent; + BiggestPowerTen(integrals, DiyFp::kSignificandSize - (-one.e()), + &divisor, &divisor_exponent); + *kappa = divisor_exponent + 1; + *length = 0; + + // Loop invariant: buffer = w / 10^kappa (integer division) + // The invariant holds for the first iteration: kappa has been initialized + // with the divisor exponent + 1. And the divisor is the biggest power of ten + // that is smaller than 'integrals'. + while (*kappa > 0) { + int digit = integrals / divisor; + buffer[*length] = '0' + digit; + (*length)++; + requested_digits--; + integrals %= divisor; + (*kappa)--; + // Note that kappa now equals the exponent of the divisor and that the + // invariant thus holds again. + if (requested_digits == 0) break; + divisor /= 10; + } + + if (requested_digits == 0) { + uint64_t rest = + (static_cast(integrals) << -one.e()) + fractionals; + return RoundWeedCounted(buffer, *length, rest, + static_cast(divisor) << -one.e(), w_error, + kappa); + } + + // The integrals have been generated. We are at the point of the decimal + // separator. In the following loop we simply multiply the remaining digits by + // 10 and divide by one. We just need to pay attention to multiply associated + // data (the 'unit'), too. + // Note that the multiplication by 10 does not overflow, because w.e >= -60 + // and thus one.e >= -60. + ASSERT(one.e() >= -60); + ASSERT(fractionals < one.f()); + ASSERT(V8_2PART_UINT64_C(0xFFFFFFFF, FFFFFFFF) / 10 >= one.f()); + while (requested_digits > 0 && fractionals > w_error) { + fractionals *= 10; + w_error *= 10; + // Integer division by one. + int digit = static_cast(fractionals >> -one.e()); + buffer[*length] = '0' + digit; + (*length)++; + requested_digits--; + fractionals &= one.f() - 1; // Modulo by one. + (*kappa)--; + } + if (requested_digits != 0) return false; + return RoundWeedCounted(buffer, *length, fractionals, one.f(), w_error, + kappa); +} + + // Provides a decimal representation of v. // Returns true if it succeeds, otherwise the result cannot be trusted. // There will be *length digits inside the buffer (not null-terminated). @@ -437,7 +595,10 @@ bool DigitGen(DiyFp low, // The last digit will be closest to the actual v. That is, even if several // digits might correctly yield 'v' when read again, the closest will be // computed. -bool grisu3(double v, Vector buffer, int* length, int* decimal_exponent) { +static bool Grisu3(double v, + Vector buffer, + int* length, + int* decimal_exponent) { DiyFp w = Double(v).AsNormalizedDiyFp(); // boundary_minus and boundary_plus are the boundaries between v and its // closest floating-point neighbors. Any number strictly between @@ -448,12 +609,12 @@ bool grisu3(double v, Vector buffer, int* length, int* decimal_exponent) { ASSERT(boundary_plus.e() == w.e()); DiyFp ten_mk; // Cached power of ten: 10^-k int mk; // -k - GetCachedPower(w.e() + DiyFp::kSignificandSize, minimal_target_exponent, - maximal_target_exponent, &mk, &ten_mk); - ASSERT(minimal_target_exponent <= w.e() + ten_mk.e() + - DiyFp::kSignificandSize && - maximal_target_exponent >= w.e() + ten_mk.e() + - DiyFp::kSignificandSize); + GetCachedPower(w.e() + DiyFp::kSignificandSize, kMinimalTargetExponent, + kMaximalTargetExponent, &mk, &ten_mk); + ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() + + DiyFp::kSignificandSize) && + (kMaximalTargetExponent >= w.e() + ten_mk.e() + + DiyFp::kSignificandSize)); // Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a // 64 bit significand and ten_mk is thus only precise up to 64 bits. @@ -488,17 +649,75 @@ bool grisu3(double v, Vector buffer, int* length, int* decimal_exponent) { } +// The "counted" version of grisu3 (see above) only generates requested_digits +// number of digits. This version does not generate the shortest representation, +// and with enough requested digits 0.1 will at some point print as 0.9999999... +// Grisu3 is too imprecise for real halfway cases (1.5 will not work) and +// therefore the rounding strategy for halfway cases is irrelevant. +static bool Grisu3Counted(double v, + int requested_digits, + Vector buffer, + int* length, + int* decimal_exponent) { + DiyFp w = Double(v).AsNormalizedDiyFp(); + DiyFp ten_mk; // Cached power of ten: 10^-k + int mk; // -k + GetCachedPower(w.e() + DiyFp::kSignificandSize, kMinimalTargetExponent, + kMaximalTargetExponent, &mk, &ten_mk); + ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() + + DiyFp::kSignificandSize) && + (kMaximalTargetExponent >= w.e() + ten_mk.e() + + DiyFp::kSignificandSize)); + // Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a + // 64 bit significand and ten_mk is thus only precise up to 64 bits. + + // The DiyFp::Times procedure rounds its result, and ten_mk is approximated + // too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now + // off by a small amount. + // In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w. + // In other words: let f = scaled_w.f() and e = scaled_w.e(), then + // (f-1) * 2^e < w*10^k < (f+1) * 2^e + DiyFp scaled_w = DiyFp::Times(w, ten_mk); + + // We now have (double) (scaled_w * 10^-mk). + // DigitGen will generate the first requested_digits digits of scaled_w and + // return together with a kappa such that scaled_w ~= buffer * 10^kappa. (It + // will not always be exactly the same since DigitGenCounted only produces a + // limited number of digits.) + int kappa; + bool result = DigitGenCounted(scaled_w, requested_digits, + buffer, length, &kappa); + *decimal_exponent = -mk + kappa; + return result; +} + + bool FastDtoa(double v, + FastDtoaMode mode, + int requested_digits, Vector buffer, int* length, - int* point) { + int* decimal_point) { ASSERT(v > 0); ASSERT(!Double(v).IsSpecial()); - int decimal_exponent; - bool result = grisu3(v, buffer, length, &decimal_exponent); - *point = *length + decimal_exponent; - buffer[*length] = '\0'; + bool result = false; + int decimal_exponent = 0; + switch (mode) { + case FAST_DTOA_SHORTEST: + result = Grisu3(v, buffer, length, &decimal_exponent); + break; + case FAST_DTOA_PRECISION: + result = Grisu3Counted(v, requested_digits, + buffer, length, &decimal_exponent); + break; + default: + UNREACHABLE(); + } + if (result) { + *decimal_point = *length + decimal_exponent; + buffer[*length] = '\0'; + } return result; } diff --git a/deps/v8/src/fast-dtoa.h b/deps/v8/src/fast-dtoa.h index 4403a75029..94c22ecd7c 100644 --- a/deps/v8/src/fast-dtoa.h +++ b/deps/v8/src/fast-dtoa.h @@ -31,27 +31,52 @@ namespace v8 { namespace internal { +enum FastDtoaMode { + // Computes the shortest representation of the given input. The returned + // result will be the most accurate number of this length. Longer + // representations might be more accurate. + FAST_DTOA_SHORTEST, + // Computes a representation where the precision (number of digits) is + // given as input. The precision is independent of the decimal point. + FAST_DTOA_PRECISION +}; + // FastDtoa will produce at most kFastDtoaMaximalLength digits. This does not // include the terminating '\0' character. static const int kFastDtoaMaximalLength = 17; // Provides a decimal representation of v. -// v must be a strictly positive finite double. +// The result should be interpreted as buffer * 10^(point - length). +// +// Precondition: +// * v must be a strictly positive finite double. +// // Returns true if it succeeds, otherwise the result can not be trusted. // There will be *length digits inside the buffer followed by a null terminator. -// If the function returns true then -// v == (double) (buffer * 10^(point - length)). -// The digits in the buffer are the shortest representation possible: no -// 0.099999999999 instead of 0.1. -// The last digit will be closest to the actual v. That is, even if several -// digits might correctly yield 'v' when read again, the buffer will contain the -// one closest to v. -// The variable 'sign' will be '0' if the given number is positive, and '1' -// otherwise. +// If the function returns true and mode equals +// - FAST_DTOA_SHORTEST, then +// the parameter requested_digits is ignored. +// The result satisfies +// v == (double) (buffer * 10^(point - length)). +// The digits in the buffer are the shortest representation possible. E.g. +// if 0.099999999999 and 0.1 represent the same double then "1" is returned +// with point = 0. +// The last digit will be closest to the actual v. That is, even if several +// digits might correctly yield 'v' when read again, the buffer will contain +// the one closest to v. +// - FAST_DTOA_PRECISION, then +// the buffer contains requested_digits digits. +// the difference v - (buffer * 10^(point-length)) is closest to zero for +// all possible representations of requested_digits digits. +// If there are two values that are equally close, then FastDtoa returns +// false. +// For both modes the buffer must be large enough to hold the result. bool FastDtoa(double d, + FastDtoaMode mode, + int requested_digits, Vector buffer, int* length, - int* point); + int* decimal_point); } } // namespace v8::internal diff --git a/deps/v8/src/frames.cc b/deps/v8/src/frames.cc index 76a441b64d..3cdb0157e7 100644 --- a/deps/v8/src/frames.cc +++ b/deps/v8/src/frames.cc @@ -143,8 +143,8 @@ void StackFrameIterator::Reset() { state.pc_address = reinterpret_cast(StandardFrame::ComputePCAddress(fp_)); type = StackFrame::ComputeType(&state); - if (SingletonFor(type) == NULL) return; } + if (SingletonFor(type) == NULL) return; frame_ = SingletonFor(type, &state); } @@ -203,13 +203,24 @@ bool StackTraceFrameIterator::IsValidFrame() { // ------------------------------------------------------------------------- +bool SafeStackFrameIterator::ExitFrameValidator::IsValidFP(Address fp) { + if (!validator_.IsValid(fp)) return false; + Address sp = ExitFrame::ComputeStackPointer(fp); + if (!validator_.IsValid(sp)) return false; + StackFrame::State state; + ExitFrame::FillState(fp, sp, &state); + if (!validator_.IsValid(reinterpret_cast
    (state.pc_address))) { + return false; + } + return *state.pc_address != NULL; +} + + SafeStackFrameIterator::SafeStackFrameIterator( Address fp, Address sp, Address low_bound, Address high_bound) : - maintainer_(), low_bound_(low_bound), high_bound_(high_bound), - is_valid_top_( - IsWithinBounds(low_bound, high_bound, - Top::c_entry_fp(Top::GetCurrentThread())) && - Top::handler(Top::GetCurrentThread()) != NULL), + maintainer_(), + stack_validator_(low_bound, high_bound), + is_valid_top_(IsValidTop(low_bound, high_bound)), is_valid_fp_(IsWithinBounds(low_bound, high_bound, fp)), is_working_iterator_(is_valid_top_ || is_valid_fp_), iteration_done_(!is_working_iterator_), @@ -217,6 +228,14 @@ SafeStackFrameIterator::SafeStackFrameIterator( } +bool SafeStackFrameIterator::IsValidTop(Address low_bound, Address high_bound) { + Address fp = Top::c_entry_fp(Top::GetCurrentThread()); + ExitFrameValidator validator(low_bound, high_bound); + if (!validator.IsValidFP(fp)) return false; + return Top::handler(Top::GetCurrentThread()) != NULL; +} + + void SafeStackFrameIterator::Advance() { ASSERT(is_working_iterator_); ASSERT(!done()); @@ -258,9 +277,8 @@ bool SafeStackFrameIterator::IsValidCaller(StackFrame* frame) { // sure that caller FP address is valid. Address caller_fp = Memory::Address_at( frame->fp() + EntryFrameConstants::kCallerFPOffset); - if (!IsValidStackAddress(caller_fp)) { - return false; - } + ExitFrameValidator validator(stack_validator_); + if (!validator.IsValidFP(caller_fp)) return false; } else if (frame->is_arguments_adaptor()) { // See ArgumentsAdaptorFrame::GetCallerStackPointer. It assumes that // the number of arguments is stored on stack as Smi. We need to check @@ -415,6 +433,22 @@ Address ExitFrame::GetCallerStackPointer() const { } +StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) { + if (fp == 0) return NONE; + Address sp = ComputeStackPointer(fp); + FillState(fp, sp, state); + ASSERT(*state->pc_address != NULL); + return EXIT; +} + + +void ExitFrame::FillState(Address fp, Address sp, State* state) { + state->sp = sp; + state->fp = fp; + state->pc_address = reinterpret_cast(sp - 1 * kPointerSize); +} + + Address StandardFrame::GetExpressionAddress(int n) const { const int offset = StandardFrameConstants::kExpressionsOffset; return fp() + offset - n * kPointerSize; diff --git a/deps/v8/src/frames.h b/deps/v8/src/frames.h index 20111904f5..2d4f338ae0 100644 --- a/deps/v8/src/frames.h +++ b/deps/v8/src/frames.h @@ -67,7 +67,7 @@ class PcToCodeCache : AllStatic { static PcToCodeCacheEntry* GetCacheEntry(Address pc); private: - static const int kPcToCodeCacheSize = 256; + static const int kPcToCodeCacheSize = 1024; static PcToCodeCacheEntry cache_[kPcToCodeCacheSize]; }; @@ -141,6 +141,13 @@ class StackFrame BASE_EMBEDDED { NO_ID = 0 }; + struct State { + State() : sp(NULL), fp(NULL), pc_address(NULL) { } + Address sp; + Address fp; + Address* pc_address; + }; + // Copy constructor; it breaks the connection to host iterator. StackFrame(const StackFrame& original) { this->state_ = original.state_; @@ -201,12 +208,6 @@ class StackFrame BASE_EMBEDDED { int index) const { } protected: - struct State { - Address sp; - Address fp; - Address* pc_address; - }; - explicit StackFrame(StackFrameIterator* iterator) : iterator_(iterator) { } virtual ~StackFrame() { } @@ -318,6 +319,8 @@ class ExitFrame: public StackFrame { // pointer. Used when constructing the first stack frame seen by an // iterator and the frames following entry frames. static Type GetStateForFramePointer(Address fp, State* state); + static Address ComputeStackPointer(Address fp); + static void FillState(Address fp, Address sp, State* state); protected: explicit ExitFrame(StackFrameIterator* iterator) : StackFrame(iterator) { } @@ -443,6 +446,7 @@ class JavaScriptFrame: public StandardFrame { inline Object* function_slot_object() const; friend class StackFrameIterator; + friend class StackTracer; }; @@ -654,12 +658,36 @@ class SafeStackFrameIterator BASE_EMBEDDED { } private: + class StackAddressValidator { + public: + StackAddressValidator(Address low_bound, Address high_bound) + : low_bound_(low_bound), high_bound_(high_bound) { } + bool IsValid(Address addr) const { + return IsWithinBounds(low_bound_, high_bound_, addr); + } + private: + Address low_bound_; + Address high_bound_; + }; + + class ExitFrameValidator { + public: + explicit ExitFrameValidator(const StackAddressValidator& validator) + : validator_(validator) { } + ExitFrameValidator(Address low_bound, Address high_bound) + : validator_(low_bound, high_bound) { } + bool IsValidFP(Address fp); + private: + StackAddressValidator validator_; + }; + bool IsValidStackAddress(Address addr) const { - return IsWithinBounds(low_bound_, high_bound_, addr); + return stack_validator_.IsValid(addr); } bool CanIterateHandles(StackFrame* frame, StackHandler* handler); bool IsValidFrame(StackFrame* frame) const; bool IsValidCaller(StackFrame* frame); + static bool IsValidTop(Address low_bound, Address high_bound); // This is a nasty hack to make sure the active count is incremented // before the constructor for the embedded iterator is invoked. This @@ -674,8 +702,7 @@ class SafeStackFrameIterator BASE_EMBEDDED { ActiveCountMaintainer maintainer_; static int active_count_; - Address low_bound_; - Address high_bound_; + StackAddressValidator stack_validator_; const bool is_valid_top_; const bool is_valid_fp_; const bool is_working_iterator_; diff --git a/deps/v8/src/full-codegen.h b/deps/v8/src/full-codegen.h index 9db233c229..2d60d5b032 100644 --- a/deps/v8/src/full-codegen.h +++ b/deps/v8/src/full-codegen.h @@ -509,6 +509,9 @@ class FullCodeGenerator: public AstVisitor { static Register result_register(); static Register context_register(); + // Helper for calling an IC stub. + void EmitCallIC(Handle ic, RelocInfo::Mode mode); + // Set fields in the stack frame. Offsets are the frame pointer relative // offsets defined in, e.g., StandardFrameConstants. void StoreToFrameField(int frame_offset, Register value); diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc index 650800fa4b..905d06551b 100644 --- a/deps/v8/src/heap.cc +++ b/deps/v8/src/heap.cc @@ -2650,6 +2650,20 @@ Object* Heap::AllocateArgumentsObject(Object* callee, int length) { } +static bool HasDuplicates(DescriptorArray* descriptors) { + int count = descriptors->number_of_descriptors(); + if (count > 1) { + String* prev_key = descriptors->GetKey(0); + for (int i = 1; i != count; i++) { + String* current_key = descriptors->GetKey(i); + if (prev_key == current_key) return true; + prev_key = current_key; + } + } + return false; +} + + Object* Heap::AllocateInitialMap(JSFunction* fun) { ASSERT(!fun->has_initial_map()); @@ -2683,23 +2697,34 @@ Object* Heap::AllocateInitialMap(JSFunction* fun) { if (fun->shared()->CanGenerateInlineConstructor(prototype)) { int count = fun->shared()->this_property_assignments_count(); if (count > in_object_properties) { - count = in_object_properties; - } - Object* descriptors_obj = DescriptorArray::Allocate(count); - if (descriptors_obj->IsFailure()) return descriptors_obj; - DescriptorArray* descriptors = DescriptorArray::cast(descriptors_obj); - for (int i = 0; i < count; i++) { - String* name = fun->shared()->GetThisPropertyAssignmentName(i); - ASSERT(name->IsSymbol()); - FieldDescriptor field(name, i, NONE); - field.SetEnumerationIndex(i); - descriptors->Set(i, &field); + // Inline constructor can only handle inobject properties. + fun->shared()->ForbidInlineConstructor(); + } else { + Object* descriptors_obj = DescriptorArray::Allocate(count); + if (descriptors_obj->IsFailure()) return descriptors_obj; + DescriptorArray* descriptors = DescriptorArray::cast(descriptors_obj); + for (int i = 0; i < count; i++) { + String* name = fun->shared()->GetThisPropertyAssignmentName(i); + ASSERT(name->IsSymbol()); + FieldDescriptor field(name, i, NONE); + field.SetEnumerationIndex(i); + descriptors->Set(i, &field); + } + descriptors->SetNextEnumerationIndex(count); + descriptors->SortUnchecked(); + + // The descriptors may contain duplicates because the compiler does not + // guarantee the uniqueness of property names (it would have required + // quadratic time). Once the descriptors are sorted we can check for + // duplicates in linear time. + if (HasDuplicates(descriptors)) { + fun->shared()->ForbidInlineConstructor(); + } else { + map->set_instance_descriptors(descriptors); + map->set_pre_allocated_property_fields(count); + map->set_unused_property_fields(in_object_properties - count); + } } - descriptors->SetNextEnumerationIndex(count); - descriptors->Sort(); - map->set_instance_descriptors(descriptors); - map->set_pre_allocated_property_fields(count); - map->set_unused_property_fields(in_object_properties - count); } return map; } diff --git a/deps/v8/src/ia32/assembler-ia32.cc b/deps/v8/src/ia32/assembler-ia32.cc index eef307d7ed..e0cb8a1352 100644 --- a/deps/v8/src/ia32/assembler-ia32.cc +++ b/deps/v8/src/ia32/assembler-ia32.cc @@ -2179,6 +2179,16 @@ void Assembler::sqrtsd(XMMRegister dst, XMMRegister src) { } +void Assembler::andpd(XMMRegister dst, XMMRegister src) { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + EMIT(0x66); + EMIT(0x0F); + EMIT(0x54); + emit_sse_operand(dst, src); +} + + void Assembler::ucomisd(XMMRegister dst, XMMRegister src) { ASSERT(CpuFeatures::IsEnabled(SSE2)); EnsureSpace ensure_space(this); @@ -2201,7 +2211,29 @@ void Assembler::movmskpd(Register dst, XMMRegister src) { } -void Assembler::movdqa(const Operand& dst, XMMRegister src ) { +void Assembler::cmpltsd(XMMRegister dst, XMMRegister src) { + ASSERT(CpuFeatures::IsEnabled(SSE2)); + EnsureSpace ensure_space(this); + last_pc_ = pc_; + EMIT(0xF2); + EMIT(0x0F); + EMIT(0xC2); + emit_sse_operand(dst, src); + EMIT(1); // LT == 1 +} + + +void Assembler::movaps(XMMRegister dst, XMMRegister src) { + ASSERT(CpuFeatures::IsEnabled(SSE2)); + EnsureSpace ensure_space(this); + last_pc_ = pc_; + EMIT(0x0F); + EMIT(0x28); + emit_sse_operand(dst, src); +} + + +void Assembler::movdqa(const Operand& dst, XMMRegister src) { ASSERT(CpuFeatures::IsEnabled(SSE2)); EnsureSpace ensure_space(this); last_pc_ = pc_; @@ -2358,6 +2390,19 @@ void Assembler::ptest(XMMRegister dst, XMMRegister src) { emit_sse_operand(dst, src); } + +void Assembler::psllq(XMMRegister reg, int8_t imm8) { + ASSERT(CpuFeatures::IsEnabled(SSE2)); + EnsureSpace ensure_space(this); + last_pc_ = pc_; + EMIT(0x66); + EMIT(0x0F); + EMIT(0x73); + emit_sse_operand(esi, reg); // esi == 6 + EMIT(imm8); +} + + void Assembler::emit_sse_operand(XMMRegister reg, const Operand& adr) { Register ireg = { reg.code() }; emit_operand(ireg, adr); diff --git a/deps/v8/src/ia32/assembler-ia32.h b/deps/v8/src/ia32/assembler-ia32.h index 928f172894..539addd086 100644 --- a/deps/v8/src/ia32/assembler-ia32.h +++ b/deps/v8/src/ia32/assembler-ia32.h @@ -788,9 +788,15 @@ class Assembler : public Malloced { void xorpd(XMMRegister dst, XMMRegister src); void sqrtsd(XMMRegister dst, XMMRegister src); + void andpd(XMMRegister dst, XMMRegister src); + void ucomisd(XMMRegister dst, XMMRegister src); void movmskpd(Register dst, XMMRegister src); + void cmpltsd(XMMRegister dst, XMMRegister src); + + void movaps(XMMRegister dst, XMMRegister src); + void movdqa(XMMRegister dst, const Operand& src); void movdqa(const Operand& dst, XMMRegister src); void movdqu(XMMRegister dst, const Operand& src); @@ -806,6 +812,8 @@ class Assembler : public Malloced { void pxor(XMMRegister dst, XMMRegister src); void ptest(XMMRegister dst, XMMRegister src); + void psllq(XMMRegister reg, int8_t imm8); + // Parallel XMM operations. void movntdqa(XMMRegister src, const Operand& dst); void movntdq(const Operand& dst, XMMRegister src); diff --git a/deps/v8/src/ia32/codegen-ia32.cc b/deps/v8/src/ia32/codegen-ia32.cc index 86f3877c7e..bde2f18449 100644 --- a/deps/v8/src/ia32/codegen-ia32.cc +++ b/deps/v8/src/ia32/codegen-ia32.cc @@ -9144,9 +9144,15 @@ class DeferredReferenceGetNamedValue: public DeferredCode { public: DeferredReferenceGetNamedValue(Register dst, Register receiver, - Handle name) - : dst_(dst), receiver_(receiver), name_(name) { - set_comment("[ DeferredReferenceGetNamedValue"); + Handle name, + bool is_contextual) + : dst_(dst), + receiver_(receiver), + name_(name), + is_contextual_(is_contextual) { + set_comment(is_contextual + ? "[ DeferredReferenceGetNamedValue (contextual)" + : "[ DeferredReferenceGetNamedValue"); } virtual void Generate(); @@ -9158,6 +9164,7 @@ class DeferredReferenceGetNamedValue: public DeferredCode { Register dst_; Register receiver_; Handle name_; + bool is_contextual_; }; @@ -9167,9 +9174,15 @@ void DeferredReferenceGetNamedValue::Generate() { } __ Set(ecx, Immediate(name_)); Handle ic(Builtins::builtin(Builtins::LoadIC_Initialize)); - __ call(ic, RelocInfo::CODE_TARGET); - // The call must be followed by a test eax instruction to indicate - // that the inobject property case was inlined. + RelocInfo::Mode mode = is_contextual_ + ? RelocInfo::CODE_TARGET_CONTEXT + : RelocInfo::CODE_TARGET; + __ call(ic, mode); + // The call must be followed by: + // - a test eax instruction to indicate that the inobject property + // case was inlined. + // - a mov ecx instruction to indicate that the contextual property + // load was inlined. // // Store the delta to the map check instruction here in the test // instruction. Use masm_-> instead of the __ macro since the @@ -9177,8 +9190,13 @@ void DeferredReferenceGetNamedValue::Generate() { int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); // Here we use masm_-> instead of the __ macro because this is the // instruction that gets patched and coverage code gets in the way. - masm_->test(eax, Immediate(-delta_to_patch_site)); - __ IncrementCounter(&Counters::named_load_inline_miss, 1); + if (is_contextual_) { + masm_->mov(ecx, -delta_to_patch_site); + __ IncrementCounter(&Counters::named_load_global_inline_miss, 1); + } else { + masm_->test(eax, Immediate(-delta_to_patch_site)); + __ IncrementCounter(&Counters::named_load_inline_miss, 1); + } if (!dst_.is(eax)) __ mov(dst_, eax); } @@ -9349,12 +9367,17 @@ Result CodeGenerator::EmitNamedLoad(Handle name, bool is_contextual) { #ifdef DEBUG int original_height = frame()->height(); #endif + + bool contextual_load_in_builtin = + is_contextual && + (Bootstrapper::IsActive() || + (!info_->closure().is_null() && info_->closure()->IsBuiltin())); + Result result; - // Do not inline the inobject property case for loads from the global - // object. Also do not inline for unoptimized code. This saves time in - // the code generator. Unoptimized code is toplevel code or code that is - // not in a loop. - if (is_contextual || scope()->is_global_scope() || loop_nesting() == 0) { + // Do not inline in the global code or when not in loop. + if (scope()->is_global_scope() || + loop_nesting() == 0 || + contextual_load_in_builtin) { Comment cmnt(masm(), "[ Load from named Property"); frame()->Push(name); @@ -9367,19 +9390,26 @@ Result CodeGenerator::EmitNamedLoad(Handle name, bool is_contextual) { // instruction here. __ nop(); } else { - // Inline the inobject property case. - Comment cmnt(masm(), "[ Inlined named property load"); + // Inline the property load. + Comment cmnt(masm(), is_contextual + ? "[ Inlined contextual property load" + : "[ Inlined named property load"); Result receiver = frame()->Pop(); receiver.ToRegister(); result = allocator()->Allocate(); ASSERT(result.is_valid()); DeferredReferenceGetNamedValue* deferred = - new DeferredReferenceGetNamedValue(result.reg(), receiver.reg(), name); + new DeferredReferenceGetNamedValue(result.reg(), + receiver.reg(), + name, + is_contextual); - // Check that the receiver is a heap object. - __ test(receiver.reg(), Immediate(kSmiTagMask)); - deferred->Branch(zero); + if (!is_contextual) { + // Check that the receiver is a heap object. + __ test(receiver.reg(), Immediate(kSmiTagMask)); + deferred->Branch(zero); + } __ bind(deferred->patch_site()); // This is the map check instruction that will be patched (so we can't @@ -9391,17 +9421,33 @@ Result CodeGenerator::EmitNamedLoad(Handle name, bool is_contextual) { // which allows the assert below to succeed and patching to work. deferred->Branch(not_equal); - // The delta from the patch label to the load offset must be statically - // known. + // The delta from the patch label to the actual load must be + // statically known. ASSERT(masm()->SizeOfCodeGeneratedSince(deferred->patch_site()) == LoadIC::kOffsetToLoadInstruction); - // The initial (invalid) offset has to be large enough to force a 32-bit - // instruction encoding to allow patching with an arbitrary offset. Use - // kMaxInt (minus kHeapObjectTag). - int offset = kMaxInt; - masm()->mov(result.reg(), FieldOperand(receiver.reg(), offset)); - __ IncrementCounter(&Counters::named_load_inline, 1); + if (is_contextual) { + // Load the (initialy invalid) cell and get its value. + masm()->mov(result.reg(), Factory::null_value()); + if (FLAG_debug_code) { + __ cmp(FieldOperand(result.reg(), HeapObject::kMapOffset), + Factory::global_property_cell_map()); + __ Assert(equal, "Uninitialized inlined contextual load"); + } + __ mov(result.reg(), + FieldOperand(result.reg(), JSGlobalPropertyCell::kValueOffset)); + __ cmp(result.reg(), Factory::the_hole_value()); + deferred->Branch(equal); + __ IncrementCounter(&Counters::named_load_global_inline, 1); + } else { + // The initial (invalid) offset has to be large enough to force a 32-bit + // instruction encoding to allow patching with an arbitrary offset. Use + // kMaxInt (minus kHeapObjectTag). + int offset = kMaxInt; + masm()->mov(result.reg(), FieldOperand(receiver.reg(), offset)); + __ IncrementCounter(&Counters::named_load_inline, 1); + } + deferred->BindExit(); } ASSERT(frame()->height() == original_height - 1); diff --git a/deps/v8/src/ia32/disasm-ia32.cc b/deps/v8/src/ia32/disasm-ia32.cc index 64305ef69e..207648bd80 100644 --- a/deps/v8/src/ia32/disasm-ia32.cc +++ b/deps/v8/src/ia32/disasm-ia32.cc @@ -685,7 +685,8 @@ int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode, case 0xDD: switch (regop) { case 0: mnem = "fld_d"; break; - case 2: mnem = "fstp"; break; + case 1: mnem = "fisttp_d"; break; + case 2: mnem = "fst_d"; break; case 3: mnem = "fstp_d"; break; default: UnimplementedInstruction(); } @@ -957,6 +958,14 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector out_buffer, } else if (f0byte == 0xA2 || f0byte == 0x31) { AppendToBuffer("%s", f0mnem); data += 2; + } else if (f0byte == 0x28) { + data += 2; + int mod, regop, rm; + get_modrm(*data, &mod, ®op, &rm); + AppendToBuffer("movaps %s,%s", + NameOfXMMRegister(regop), + NameOfXMMRegister(rm)); + data++; } else if ((f0byte & 0xF0) == 0x80) { data += JumpConditional(data, branch_hint); } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 || @@ -1156,6 +1165,23 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector out_buffer, NameOfXMMRegister(regop), NameOfXMMRegister(rm)); data++; + } else if (*data == 0x73) { + data++; + int mod, regop, rm; + get_modrm(*data, &mod, ®op, &rm); + int8_t imm8 = static_cast(data[1]); + AppendToBuffer("psllq %s,%d", + NameOfXMMRegister(rm), + static_cast(imm8)); + data += 2; + } else if (*data == 0x54) { + data++; + int mod, regop, rm; + get_modrm(*data, &mod, ®op, &rm); + AppendToBuffer("andpd %s,%s", + NameOfXMMRegister(regop), + NameOfXMMRegister(rm)); + data++; } else { UnimplementedInstruction(); } @@ -1274,6 +1300,23 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector out_buffer, NameOfXMMRegister(rm)); data++; } + } else if (b2 == 0xC2) { + // Intel manual 2A, Table 3-18. + const char* const pseudo_op[] = { + "cmpeqsd", + "cmpltsd", + "cmplesd", + "cmpunordsd", + "cmpneqsd", + "cmpnltsd", + "cmpnlesd", + "cmpordsd" + }; + AppendToBuffer("%s %s,%s", + pseudo_op[data[1]], + NameOfXMMRegister(regop), + NameOfXMMRegister(rm)); + data += 2; } else { if (mod != 0x3) { AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); @@ -1367,7 +1410,7 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector out_buffer, " %s", tmp_buffer_.start()); return instr_len; -} +} // NOLINT (function is too long) //------------------------------------------------------------------------------ diff --git a/deps/v8/src/ia32/frames-ia32.cc b/deps/v8/src/ia32/frames-ia32.cc index 9baf76336b..dd44f0ee5f 100644 --- a/deps/v8/src/ia32/frames-ia32.cc +++ b/deps/v8/src/ia32/frames-ia32.cc @@ -35,16 +35,8 @@ namespace v8 { namespace internal { -StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) { - if (fp == 0) return NONE; - // Compute the stack pointer. - Address sp = Memory::Address_at(fp + ExitFrameConstants::kSPOffset); - // Fill in the state. - state->fp = fp; - state->sp = sp; - state->pc_address = reinterpret_cast(sp - 1 * kPointerSize); - ASSERT(*state->pc_address != NULL); - return EXIT; +Address ExitFrame::ComputeStackPointer(Address fp) { + return Memory::Address_at(fp + ExitFrameConstants::kSPOffset); } diff --git a/deps/v8/src/ia32/full-codegen-ia32.cc b/deps/v8/src/ia32/full-codegen-ia32.cc index 1e65c4b40a..8144f41dd9 100644 --- a/deps/v8/src/ia32/full-codegen-ia32.cc +++ b/deps/v8/src/ia32/full-codegen-ia32.cc @@ -631,10 +631,7 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable, __ pop(edx); Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); - __ call(ic, RelocInfo::CODE_TARGET); - // Absence of a test eax instruction following the call - // indicates that none of the load was inlined. - __ nop(); + EmitCallIC(ic, RelocInfo::CODE_TARGET); } } } @@ -991,8 +988,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) ? RelocInfo::CODE_TARGET : RelocInfo::CODE_TARGET_CONTEXT; - __ call(ic, mode); - __ nop(); // Signal no inlined code. + EmitCallIC(ic, mode); } @@ -1069,7 +1065,7 @@ void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( slow)); __ mov(eax, Immediate(key_literal->handle())); Handle ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); - __ call(ic, RelocInfo::CODE_TARGET); + EmitCallIC(ic, RelocInfo::CODE_TARGET); __ jmp(done); } } @@ -1093,12 +1089,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var, __ mov(eax, CodeGenerator::GlobalObject()); __ mov(ecx, var->name()); Handle ic(Builtins::builtin(Builtins::LoadIC_Initialize)); - __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); - // By emitting a nop we make sure that we do not have a test eax - // instruction after the call it is treated specially by the LoadIC code - // Remember that the assembler may choose to do peephole optimization - // (eg, push/pop elimination). - __ nop(); + EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); Apply(context, eax); } else if (slot != NULL && slot->type() == Slot::LOOKUP) { @@ -1161,10 +1152,8 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var, // Do a keyed property load. Handle ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); - __ call(ic, RelocInfo::CODE_TARGET); - // Notice: We must not have a "test eax, ..." instruction after the - // call. It is treated specially by the LoadIC code. - __ nop(); + EmitCallIC(ic, RelocInfo::CODE_TARGET); + // Drop key and object left on the stack by IC. Apply(context, eax); } @@ -1262,8 +1251,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ mov(ecx, Immediate(key->handle())); __ mov(edx, Operand(esp, 0)); Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); - __ call(ic, RelocInfo::CODE_TARGET); - __ nop(); + EmitCallIC(ic, RelocInfo::CODE_TARGET); break; } // Fall through. @@ -1476,16 +1464,14 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { Literal* key = prop->key()->AsLiteral(); __ mov(ecx, Immediate(key->handle())); Handle ic(Builtins::builtin(Builtins::LoadIC_Initialize)); - __ call(ic, RelocInfo::CODE_TARGET); - __ nop(); + EmitCallIC(ic, RelocInfo::CODE_TARGET); } void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); Handle ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); - __ call(ic, RelocInfo::CODE_TARGET); - __ nop(); + EmitCallIC(ic, RelocInfo::CODE_TARGET); } @@ -1844,8 +1830,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) { __ pop(eax); // Restore value. __ mov(ecx, prop->key()->AsLiteral()->handle()); Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); - __ call(ic, RelocInfo::CODE_TARGET); - __ nop(); // Signal no inlined code. + EmitCallIC(ic, RelocInfo::CODE_TARGET); break; } case KEYED_PROPERTY: { @@ -1856,8 +1841,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) { __ pop(edx); __ pop(eax); // Restore value. Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); - __ call(ic, RelocInfo::CODE_TARGET); - __ nop(); // Signal no inlined code. + EmitCallIC(ic, RelocInfo::CODE_TARGET); break; } } @@ -1880,8 +1864,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, __ mov(ecx, var->name()); __ mov(edx, CodeGenerator::GlobalObject()); Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); - __ call(ic, RelocInfo::CODE_TARGET); - __ nop(); + EmitCallIC(ic, RelocInfo::CODE_TARGET); } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) { // Perform the assignment for non-const variables and for initialization @@ -1965,8 +1948,7 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { __ pop(edx); } Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); - __ call(ic, RelocInfo::CODE_TARGET); - __ nop(); + EmitCallIC(ic, RelocInfo::CODE_TARGET); // If the assignment ends an initialization block, revert to fast case. if (expr->ends_initialization_block()) { @@ -2004,10 +1986,7 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { // Record source code position before IC call. SetSourcePosition(expr->position()); Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); - __ call(ic, RelocInfo::CODE_TARGET); - // This nop signals to the IC that there is no inlined code at the call - // site for it to patch. - __ nop(); + EmitCallIC(ic, RelocInfo::CODE_TARGET); // If the assignment ends an initialization block, revert to fast case. if (expr->ends_initialization_block()) { @@ -2054,7 +2033,7 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr, SetSourcePosition(expr->position()); InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; Handle ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop); - __ call(ic, mode); + EmitCallIC(ic, mode); // Restore context register. __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); Apply(context_, eax); @@ -2077,7 +2056,7 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; Handle ic = CodeGenerator::ComputeKeyedCallInitialize( arg_count, in_loop); - __ call(ic, mode); + EmitCallIC(ic, mode); // Restore context register. __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); Apply(context_, eax); @@ -2201,7 +2180,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { } else { // Call to a keyed property. // For a synthetic property use keyed load IC followed by function call, - // for a regular property use keyed CallIC. + // for a regular property use keyed EmitCallIC. VisitForValue(prop->obj(), kStack); if (prop->is_synthetic()) { VisitForValue(prop->key(), kAccumulator); @@ -2210,11 +2189,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { __ pop(edx); // We do not need to keep the receiver. Handle ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); - __ call(ic, RelocInfo::CODE_TARGET); - // By emitting a nop we make sure that we do not have a "test eax,..." - // instruction after the call as it is treated specially - // by the LoadIC code. - __ nop(); + EmitCallIC(ic, RelocInfo::CODE_TARGET); // Push result (function). __ push(eax); // Push Global receiver. @@ -3142,7 +3117,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { __ Set(ecx, Immediate(expr->name())); InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; Handle ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop); - __ call(ic, RelocInfo::CODE_TARGET); + EmitCallIC(ic, RelocInfo::CODE_TARGET); // Restore context register. __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); } else { @@ -3447,10 +3422,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { __ mov(ecx, prop->key()->AsLiteral()->handle()); __ pop(edx); Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); - __ call(ic, RelocInfo::CODE_TARGET); - // This nop signals to the IC that there is no inlined code at the call - // site for it to patch. - __ nop(); + EmitCallIC(ic, RelocInfo::CODE_TARGET); if (expr->is_postfix()) { if (context_ != Expression::kEffect) { ApplyTOS(context_); @@ -3464,10 +3436,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { __ pop(ecx); __ pop(edx); Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); - __ call(ic, RelocInfo::CODE_TARGET); - // This nop signals to the IC that there is no inlined code at the call - // site for it to patch. - __ nop(); + EmitCallIC(ic, RelocInfo::CODE_TARGET); if (expr->is_postfix()) { // Result is on the stack if (context_ != Expression::kEffect) { @@ -3491,8 +3460,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr, Location where) { Handle ic(Builtins::builtin(Builtins::LoadIC_Initialize)); // Use a regular load, not a contextual load, to avoid a reference // error. - __ call(ic, RelocInfo::CODE_TARGET); - __ nop(); // Signal no inlined code. + EmitCallIC(ic, RelocInfo::CODE_TARGET); if (where == kStack) __ push(eax); } else if (proxy != NULL && proxy->var()->slot() != NULL && @@ -3744,10 +3712,36 @@ void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { } -Register FullCodeGenerator::result_register() { return eax; } +Register FullCodeGenerator::result_register() { + return eax; +} + + +Register FullCodeGenerator::context_register() { + return esi; +} -Register FullCodeGenerator::context_register() { return esi; } +void FullCodeGenerator::EmitCallIC(Handle ic, RelocInfo::Mode mode) { + ASSERT(mode == RelocInfo::CODE_TARGET || + mode == RelocInfo::CODE_TARGET_CONTEXT); + __ call(ic, mode); + + // If we're calling a (keyed) load or store stub, we have to mark + // the call as containing no inlined code so we will not attempt to + // patch it. + switch (ic->kind()) { + case Code::LOAD_IC: + case Code::KEYED_LOAD_IC: + case Code::STORE_IC: + case Code::KEYED_STORE_IC: + __ nop(); // Signals no inlined code. + break; + default: + // Do nothing. + break; + } +} void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { diff --git a/deps/v8/src/ia32/ic-ia32.cc b/deps/v8/src/ia32/ic-ia32.cc index 3d0bd796a0..413c36e922 100644 --- a/deps/v8/src/ia32/ic-ia32.cc +++ b/deps/v8/src/ia32/ic-ia32.cc @@ -692,7 +692,6 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) { // -- esp[0] : return address // ----------------------------------- Label miss; - Label index_out_of_range; Register receiver = edx; Register index = eax; @@ -707,7 +706,7 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) { result, &miss, // When not a string. &miss, // When not a number. - &index_out_of_range, + &miss, // When index out of range. STRING_INDEX_IS_ARRAY_INDEX); char_at_generator.GenerateFast(masm); __ ret(0); @@ -715,10 +714,6 @@ void KeyedLoadIC::GenerateString(MacroAssembler* masm) { ICRuntimeCallHelper call_helper; char_at_generator.GenerateSlow(masm, call_helper); - __ bind(&index_out_of_range); - __ Set(eax, Immediate(Factory::undefined_value())); - __ ret(0); - __ bind(&miss); GenerateMiss(masm); } @@ -1666,6 +1661,38 @@ bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) { } +// One byte opcode for mov ecx,0xXXXXXXXX. +static const byte kMovEcxByte = 0xB9; + +bool LoadIC::PatchInlinedContextualLoad(Address address, + Object* map, + Object* cell) { + // The address of the instruction following the call. + Address mov_instruction_address = + address + Assembler::kCallTargetAddressOffset; + // If the instruction following the call is not a cmp eax, nothing + // was inlined. + if (*mov_instruction_address != kMovEcxByte) return false; + + Address delta_address = mov_instruction_address + 1; + // The delta to the start of the map check instruction. + int delta = *reinterpret_cast(delta_address); + + // The map address is the last 4 bytes of the 7-byte + // operand-immediate compare instruction, so we add 3 to get the + // offset to the last 4 bytes. + Address map_address = mov_instruction_address + delta + 3; + *(reinterpret_cast(map_address)) = map; + + // The cell is in the last 4 bytes of a five byte mov reg, imm32 + // instruction, so we add 1 to get the offset to the last 4 bytes. + Address offset_address = + mov_instruction_address + delta + kOffsetToLoadInstruction + 1; + *reinterpret_cast(offset_address) = cell; + return true; +} + + bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) { // The address of the instruction following the call. Address test_instruction_address = diff --git a/deps/v8/src/ia32/macro-assembler-ia32.cc b/deps/v8/src/ia32/macro-assembler-ia32.cc index 87e25d73db..f8dabd5411 100644 --- a/deps/v8/src/ia32/macro-assembler-ia32.cc +++ b/deps/v8/src/ia32/macro-assembler-ia32.cc @@ -1553,6 +1553,17 @@ void MacroAssembler::ConvertToInt32(Register dst, } +void MacroAssembler::LoadPowerOf2(XMMRegister dst, + Register scratch, + int power) { + ASSERT(is_uintn(power + HeapNumber::kExponentBias, + HeapNumber::kExponentBits)); + mov(scratch, Immediate(power + HeapNumber::kExponentBias)); + movd(dst, Operand(scratch)); + psllq(dst, HeapNumber::kMantissaBits); +} + + void MacroAssembler::JumpIfInstanceTypeIsNotSequentialAscii( Register instance_type, Register scratch, diff --git a/deps/v8/src/ia32/macro-assembler-ia32.h b/deps/v8/src/ia32/macro-assembler-ia32.h index a7534cbd47..aa7caf54aa 100644 --- a/deps/v8/src/ia32/macro-assembler-ia32.h +++ b/deps/v8/src/ia32/macro-assembler-ia32.h @@ -258,6 +258,8 @@ class MacroAssembler: public Assembler { TypeInfo info, Label* on_not_int32); + void LoadPowerOf2(XMMRegister dst, Register scratch, int power); + // Abort execution if argument is not a number. Used in debug code. void AbortIfNotNumber(Register object); diff --git a/deps/v8/src/ia32/stub-cache-ia32.cc b/deps/v8/src/ia32/stub-cache-ia32.cc index 828e71a8fb..672d8c7375 100644 --- a/deps/v8/src/ia32/stub-cache-ia32.cc +++ b/deps/v8/src/ia32/stub-cache-ia32.cc @@ -265,7 +265,11 @@ void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm, void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( - MacroAssembler* masm, int index, Register prototype) { + MacroAssembler* masm, int index, Register prototype, Label* miss) { + // Check we're still in the same context. + __ cmp(Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)), + Top::global()); + __ j(not_equal, miss); // Get the global function with the given index. JSFunction* function = JSFunction::cast(Top::global_context()->get(index)); // Load its initial map. The global functions all have initial maps. @@ -1626,7 +1630,8 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall( // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(masm(), Context::STRING_FUNCTION_INDEX, - eax); + eax, + &miss); ASSERT(object != holder); CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, ebx, edx, edi, name, &miss); @@ -1695,7 +1700,8 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object, // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(masm(), Context::STRING_FUNCTION_INDEX, - eax); + eax, + &miss); ASSERT(object != holder); CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, ebx, edx, edi, name, &miss); @@ -1813,6 +1819,131 @@ Object* CallStubCompiler::CompileStringFromCharCodeCall( } +Object* CallStubCompiler::CompileMathFloorCall(Object* object, + JSObject* holder, + JSGlobalPropertyCell* cell, + JSFunction* function, + String* name) { + // ----------- S t a t e ------------- + // -- ecx : name + // -- esp[0] : return address + // -- esp[(argc - n) * 4] : arg[n] (zero-based) + // -- ... + // -- esp[(argc + 1) * 4] : receiver + // ----------------------------------- + + if (!CpuFeatures::IsSupported(SSE2)) return Heap::undefined_value(); + CpuFeatures::Scope use_sse2(SSE2); + + const int argc = arguments().immediate(); + + // If the object is not a JSObject or we got an unexpected number of + // arguments, bail out to the regular call. + if (!object->IsJSObject() || argc != 1) return Heap::undefined_value(); + + Label miss; + GenerateNameCheck(name, &miss); + + if (cell == NULL) { + __ mov(edx, Operand(esp, 2 * kPointerSize)); + + STATIC_ASSERT(kSmiTag == 0); + __ test(edx, Immediate(kSmiTagMask)); + __ j(zero, &miss); + + CheckPrototypes(JSObject::cast(object), edx, holder, ebx, eax, edi, name, + &miss); + } else { + ASSERT(cell->value() == function); + GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); + GenerateLoadFunctionFromCell(cell, function, &miss); + } + + // Load the (only) argument into eax. + __ mov(eax, Operand(esp, 1 * kPointerSize)); + + // Check if the argument is a smi. + Label smi; + STATIC_ASSERT(kSmiTag == 0); + __ test(eax, Immediate(kSmiTagMask)); + __ j(zero, &smi); + + // Check if the argument is a heap number and load its value into xmm0. + Label slow; + __ CheckMap(eax, Factory::heap_number_map(), &slow, true); + __ movdbl(xmm0, FieldOperand(eax, HeapNumber::kValueOffset)); + + // Check if the argument is strictly positive. Note this also + // discards NaN. + __ xorpd(xmm1, xmm1); + __ ucomisd(xmm0, xmm1); + __ j(below_equal, &slow); + + // Do a truncating conversion. + __ cvttsd2si(eax, Operand(xmm0)); + + // Check if the result fits into a smi. Note this also checks for + // 0x80000000 which signals a failed conversion. + Label wont_fit_into_smi; + __ test(eax, Immediate(0xc0000000)); + __ j(not_zero, &wont_fit_into_smi); + + // Smi tag and return. + __ SmiTag(eax); + __ bind(&smi); + __ ret(2 * kPointerSize); + + // Check if the argument is < 2^kMantissaBits. + Label already_round; + __ bind(&wont_fit_into_smi); + __ LoadPowerOf2(xmm1, ebx, HeapNumber::kMantissaBits); + __ ucomisd(xmm0, xmm1); + __ j(above_equal, &already_round); + + // Save a copy of the argument. + __ movaps(xmm2, xmm0); + + // Compute (argument + 2^kMantissaBits) - 2^kMantissaBits. + __ addsd(xmm0, xmm1); + __ subsd(xmm0, xmm1); + + // Compare the argument and the tentative result to get the right mask: + // if xmm2 < xmm0: + // xmm2 = 1...1 + // else: + // xmm2 = 0...0 + __ cmpltsd(xmm2, xmm0); + + // Subtract 1 if the argument was less than the tentative result. + __ LoadPowerOf2(xmm1, ebx, 0); + __ andpd(xmm1, xmm2); + __ subsd(xmm0, xmm1); + + // Return a new heap number. + __ AllocateHeapNumber(eax, ebx, edx, &slow); + __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); + __ ret(2 * kPointerSize); + + // Return the argument (when it's an already round heap number). + __ bind(&already_round); + __ mov(eax, Operand(esp, 1 * kPointerSize)); + __ ret(2 * kPointerSize); + + // Tail call the full function. We do not have to patch the receiver + // because the function makes no use of it. + __ bind(&slow); + __ InvokeFunction(function, arguments(), JUMP_FUNCTION); + + __ bind(&miss); + // ecx: function name. + Object* obj = GenerateMissBranch(); + if (obj->IsFailure()) return obj; + + // Return the generated code. + return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); +} + + Object* CallStubCompiler::CompileCallConstant(Object* object, JSObject* holder, JSFunction* function, @@ -1894,7 +2025,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, __ j(above_equal, &miss, not_taken); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype( - masm(), Context::STRING_FUNCTION_INDEX, eax); + masm(), Context::STRING_FUNCTION_INDEX, eax, &miss); CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, ebx, edx, edi, name, &miss); } @@ -1914,7 +2045,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, __ bind(&fast); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype( - masm(), Context::NUMBER_FUNCTION_INDEX, eax); + masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss); CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, ebx, edx, edi, name, &miss); } @@ -1935,7 +2066,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, __ bind(&fast); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype( - masm(), Context::BOOLEAN_FUNCTION_INDEX, eax); + masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss); CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, ebx, edx, edi, name, &miss); } @@ -2474,12 +2605,12 @@ Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object, __ Check(not_equal, "DontDelete cells can't contain the hole"); } - __ IncrementCounter(&Counters::named_load_global_inline, 1); + __ IncrementCounter(&Counters::named_load_global_stub, 1); __ mov(eax, ebx); __ ret(0); __ bind(&miss); - __ IncrementCounter(&Counters::named_load_global_inline_miss, 1); + __ IncrementCounter(&Counters::named_load_global_stub_miss, 1); GenerateLoadMiss(masm(), Code::LOAD_IC); // Return the generated code. diff --git a/deps/v8/src/ic.cc b/deps/v8/src/ic.cc index b4a333ec90..5b62a8a09c 100644 --- a/deps/v8/src/ic.cc +++ b/deps/v8/src/ic.cc @@ -299,6 +299,7 @@ void LoadIC::ClearInlinedVersion(Address address) { // present) to guarantee failure by holding an invalid map (the null // value). The offset can be patched to anything. PatchInlinedLoad(address, Heap::null_value(), 0); + PatchInlinedContextualLoad(address, Heap::null_value(), Heap::null_value()); } @@ -720,6 +721,14 @@ Object* KeyedCallIC::LoadFunction(State state, } +#ifdef DEBUG +#define TRACE_IC_NAMED(msg, name) \ + if (FLAG_trace_ic) PrintF(msg, *(name)->ToCString()) +#else +#define TRACE_IC_NAMED(msg, name) +#endif + + Object* LoadIC::Load(State state, Handle object, Handle name) { // If the object is undefined or null it's illegal to try to get any // of its properties; throw a TypeError in that case. @@ -797,15 +806,24 @@ Object* LoadIC::Load(State state, Handle object, Handle name) { LOG(SuspectReadEvent(*name, *object)); } - bool can_be_inlined = + bool can_be_inlined_precheck = FLAG_use_ic && - state == PREMONOMORPHIC && lookup.IsProperty() && lookup.IsCacheable() && lookup.holder() == *object && - lookup.type() == FIELD && !object->IsAccessCheckNeeded(); + bool can_be_inlined = + can_be_inlined_precheck && + state == PREMONOMORPHIC && + lookup.type() == FIELD; + + bool can_be_inlined_contextual = + can_be_inlined_precheck && + state == UNINITIALIZED && + lookup.holder()->IsGlobalObject() && + lookup.type() == NORMAL; + if (can_be_inlined) { Map* map = lookup.holder()->map(); // Property's index in the properties array. If negative we have @@ -816,32 +834,29 @@ Object* LoadIC::Load(State state, Handle object, Handle name) { int offset = map->instance_size() + (index * kPointerSize); if (PatchInlinedLoad(address(), map, offset)) { set_target(megamorphic_stub()); -#ifdef DEBUG - if (FLAG_trace_ic) { - PrintF("[LoadIC : inline patch %s]\n", *name->ToCString()); - } -#endif + TRACE_IC_NAMED("[LoadIC : inline patch %s]\n", name); return lookup.holder()->FastPropertyAt(lookup.GetFieldIndex()); -#ifdef DEBUG } else { - if (FLAG_trace_ic) { - PrintF("[LoadIC : no inline patch %s (patching failed)]\n", - *name->ToCString()); - } + TRACE_IC_NAMED("[LoadIC : no inline patch %s (patching failed)]\n", + name); } } else { - if (FLAG_trace_ic) { - PrintF("[LoadIC : no inline patch %s (not inobject)]\n", - *name->ToCString()); - } + TRACE_IC_NAMED("[LoadIC : no inline patch %s (not inobject)]\n", name); + } + } else if (can_be_inlined_contextual) { + Map* map = lookup.holder()->map(); + JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast( + lookup.holder()->property_dictionary()->ValueAt( + lookup.GetDictionaryEntry())); + if (PatchInlinedContextualLoad(address(), map, cell)) { + set_target(megamorphic_stub()); + TRACE_IC_NAMED("[LoadIC : inline contextual patch %s]\n", name); + ASSERT(cell->value() != Heap::the_hole_value()); + return cell->value(); } } else { if (FLAG_use_ic && state == PREMONOMORPHIC) { - if (FLAG_trace_ic) { - PrintF("[LoadIC : no inline patch %s (not inlinable)]\n", - *name->ToCString()); -#endif - } + TRACE_IC_NAMED("[LoadIC : no inline patch %s (not inlinable)]\n", name); } } diff --git a/deps/v8/src/ic.h b/deps/v8/src/ic.h index 17450cc356..a5fada09f4 100644 --- a/deps/v8/src/ic.h +++ b/deps/v8/src/ic.h @@ -298,6 +298,10 @@ class LoadIC: public IC { static bool PatchInlinedLoad(Address address, Object* map, int index); + static bool PatchInlinedContextualLoad(Address address, + Object* map, + Object* cell); + friend class IC; }; diff --git a/deps/v8/src/log.cc b/deps/v8/src/log.cc index 0bca5ebd86..a9d89a20ea 100644 --- a/deps/v8/src/log.cc +++ b/deps/v8/src/log.cc @@ -171,7 +171,9 @@ void StackTracer::Trace(TickSample* sample) { SafeStackTraceFrameIterator it(sample->fp, sample->sp, sample->sp, js_entry_sp); while (!it.done() && i < TickSample::kMaxFramesCount) { - sample->stack[i++] = reinterpret_cast
    (it.frame()->function()); + sample->stack[i++] = + reinterpret_cast
    (it.frame()->function_slot_object()) - + kHeapObjectTag; it.Advance(); } sample->frames_count = i; diff --git a/deps/v8/src/messages.js b/deps/v8/src/messages.js index f26c3b501d..4f492bc5e7 100644 --- a/deps/v8/src/messages.js +++ b/deps/v8/src/messages.js @@ -684,6 +684,11 @@ CallSite.prototype.getEvalOrigin = function () { return FormatEvalOrigin(script); }; +CallSite.prototype.getScriptNameOrSourceURL = function () { + var script = %FunctionGetScript(this.fun); + return script ? script.nameOrSourceURL() : null; +}; + CallSite.prototype.getFunction = function () { return this.fun; }; @@ -775,7 +780,11 @@ CallSite.prototype.isConstructor = function () { }; function FormatEvalOrigin(script) { - var eval_origin = ""; + var sourceURL = script.nameOrSourceURL(); + if (sourceURL) + return sourceURL; + + var eval_origin = "eval at "; if (script.eval_from_function_name) { eval_origin += script.eval_from_function_name; } else { @@ -786,9 +795,9 @@ function FormatEvalOrigin(script) { if (eval_from_script) { if (eval_from_script.compilation_type == COMPILATION_TYPE_EVAL) { // eval script originated from another eval. - eval_origin += " (eval at " + FormatEvalOrigin(eval_from_script) + ")"; + eval_origin += " (" + FormatEvalOrigin(eval_from_script) + ")"; } else { - // eval script originated from "real" scource. + // eval script originated from "real" source. if (eval_from_script.name) { eval_origin += " (" + eval_from_script.name; var location = eval_from_script.locationFromPosition(script.eval_from_script_position, true); @@ -807,25 +816,30 @@ function FormatEvalOrigin(script) { }; function FormatSourcePosition(frame) { + var fileName; var fileLocation = ""; if (frame.isNative()) { fileLocation = "native"; } else if (frame.isEval()) { - fileLocation = "eval at " + frame.getEvalOrigin(); + fileName = frame.getScriptNameOrSourceURL(); + if (!fileName) + fileLocation = frame.getEvalOrigin(); } else { - var fileName = frame.getFileName(); - if (fileName) { - fileLocation += fileName; - var lineNumber = frame.getLineNumber(); - if (lineNumber != null) { - fileLocation += ":" + lineNumber; - var columnNumber = frame.getColumnNumber(); - if (columnNumber) { - fileLocation += ":" + columnNumber; - } + fileName = frame.getFileName(); + } + + if (fileName) { + fileLocation += fileName; + var lineNumber = frame.getLineNumber(); + if (lineNumber != null) { + fileLocation += ":" + lineNumber; + var columnNumber = frame.getColumnNumber(); + if (columnNumber) { + fileLocation += ":" + columnNumber; } } } + if (!fileLocation) { fileLocation = "unknown source"; } diff --git a/deps/v8/src/mips/frames-mips.cc b/deps/v8/src/mips/frames-mips.cc index 0fce3cdd95..d630562995 100644 --- a/deps/v8/src/mips/frames-mips.cc +++ b/deps/v8/src/mips/frames-mips.cc @@ -52,9 +52,7 @@ StackFrame::Type StackFrame::ComputeType(State* state) { } -StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) { - if (fp == 0) return NONE; - // Compute frame type and stack pointer. +Address ExitFrame::ComputeStackPointer(Address fp) { Address sp = fp + ExitFrameConstants::kSPDisplacement; const int offset = ExitFrameConstants::kCodeOffset; Object* code = Memory::Object_at(fp + offset); @@ -62,11 +60,7 @@ StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) { if (is_debug_exit) { sp -= kNumJSCallerSaved * kPointerSize; } - // Fill in the state. - state->sp = sp; - state->fp = fp; - state->pc_address = reinterpret_cast(sp - 1 * kPointerSize); - return EXIT; + return sp; } diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index ef5185145a..f77800ad1f 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -3825,7 +3825,7 @@ Object* DescriptorArray::RemoveTransitions() { } -void DescriptorArray::Sort() { +void DescriptorArray::SortUnchecked() { // In-place heap sort. int len = number_of_descriptors(); @@ -3875,7 +3875,11 @@ void DescriptorArray::Sort() { parent_index = child_index; } } +} + +void DescriptorArray::Sort() { + SortUnchecked(); SLOW_ASSERT(IsSortedNoDuplicates()); } @@ -5269,6 +5273,13 @@ bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) { } +void SharedFunctionInfo::ForbidInlineConstructor() { + set_compiler_hints(BooleanBit::set(compiler_hints(), + kHasOnlySimpleThisPropertyAssignments, + false)); +} + + void SharedFunctionInfo::SetThisPropertyAssignmentsInfo( bool only_simple_this_property_assignments, FixedArray* assignments) { diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index 7f6538cf9c..1036a5a605 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -1892,6 +1892,11 @@ class DescriptorArray: public FixedArray { MUST_USE_RESULT Object* RemoveTransitions(); // Sort the instance descriptors by the hash codes of their keys. + // Does not check for duplicates. + void SortUnchecked(); + + // Sort the instance descriptors by the hash codes of their keys. + // Checks the result for duplicates. void Sort(); // Search the instance descriptors for given name. @@ -3542,6 +3547,10 @@ class SharedFunctionInfo: public HeapObject { // prototype. bool CanGenerateInlineConstructor(Object* prototype); + // Prevents further attempts to generate inline constructors. + // To be called if generation failed for any reason. + void ForbidInlineConstructor(); + // For functions which only contains this property assignments this provides // access to the names for the properties assigned. DECL_ACCESSORS(this_property_assignments, Object) diff --git a/deps/v8/src/parser.cc b/deps/v8/src/parser.cc index 856c474066..aebcc9ae2c 100644 --- a/deps/v8/src/parser.cc +++ b/deps/v8/src/parser.cc @@ -1001,7 +1001,7 @@ class CompleteParserRecorder: public PartialParserRecorder { Vector > symbol = symbol_entries_.AddBlock(1, literal); entry->key = &symbol[0]; } - symbol_store_.Add(id - 1); + WriteNumber(id - 1); } virtual Vector ExtractData() { @@ -1457,7 +1457,7 @@ Parser::Parser(Handle