From 2072925f121fe8785dfd046eba24f8d18c59ae75 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Sat, 3 Jul 2010 08:36:33 +0200 Subject: [PATCH] Upgrade V8 to 2.2.21 --- deps/v8/ChangeLog | 15 + deps/v8/benchmarks/README.txt | 12 +- deps/v8/benchmarks/base.js | 40 ++- deps/v8/benchmarks/crypto.js | 2 +- deps/v8/benchmarks/deltablue.js | 8 +- deps/v8/benchmarks/earley-boyer.js | 2 +- deps/v8/benchmarks/raytrace.js | 2 +- deps/v8/benchmarks/regexp.js | 2 +- deps/v8/benchmarks/revisions.html | 13 +- deps/v8/benchmarks/richards.js | 2 +- deps/v8/benchmarks/run.html | 2 +- deps/v8/benchmarks/splay.js | 21 +- deps/v8/src/arm/assembler-arm.cc | 12 + deps/v8/src/arm/assembler-arm.h | 3 + deps/v8/src/arm/codegen-arm.cc | 379 ++++++++++++++++++-- deps/v8/src/arm/codegen-arm.h | 96 +++++ deps/v8/src/arm/constants-arm.cc | 2 +- deps/v8/src/arm/disasm-arm.cc | 5 +- deps/v8/src/arm/ic-arm.cc | 2 +- deps/v8/src/arm/macro-assembler-arm.cc | 75 +++- deps/v8/src/arm/macro-assembler-arm.h | 49 ++- deps/v8/src/arm/simulator-arm.cc | 9 +- deps/v8/src/code-stubs.h | 1 + deps/v8/src/debug-debugger.js | 61 +++- deps/v8/src/handles.cc | 10 + deps/v8/src/handles.h | 6 + deps/v8/src/ia32/codegen-ia32.cc | 16 +- deps/v8/src/json.js | 2 +- deps/v8/src/jsregexp.cc | 18 +- deps/v8/src/objects.cc | 2 +- deps/v8/src/regexp-macro-assembler.cc | 4 +- deps/v8/src/regexp.js | 12 +- deps/v8/src/runtime.cc | 42 ++- deps/v8/src/runtime.js | 12 +- deps/v8/src/type-info.h | 2 +- deps/v8/src/version.cc | 2 +- deps/v8/src/x64/assembler-x64.cc | 6 +- deps/v8/src/x64/codegen-x64.cc | 50 ++- deps/v8/src/x64/disasm-x64.cc | 26 +- deps/v8/src/x64/macro-assembler-x64.cc | 18 +- deps/v8/src/x64/virtual-frame-x64.cc | 2 +- deps/v8/test/cctest/SConscript | 3 +- deps/v8/test/cctest/test-api.cc | 171 ++++++--- deps/v8/test/cctest/test-disasm-arm.cc | 35 ++ deps/v8/test/cctest/test-type-info.cc | 56 +++ deps/v8/test/es5conform/README | 2 +- deps/v8/test/es5conform/es5conform.status | 217 +++++------ deps/v8/test/mjsunit/debug-setbreakpoint.js | 14 +- deps/v8/test/mjsunit/math-sqrt.js | 25 +- deps/v8/test/mjsunit/mod.js | 53 +++ deps/v8/test/mjsunit/regress/regress-753.js | 36 ++ deps/v8/test/mjsunit/to_number_order.js | 86 +++++ deps/v8/test/mozilla/mozilla.status | 52 ++- deps/v8/tools/stats-viewer.py | 38 +- 54 files changed, 1486 insertions(+), 347 deletions(-) create mode 100644 deps/v8/test/cctest/test-type-info.cc create mode 100644 deps/v8/test/mjsunit/mod.js create mode 100644 deps/v8/test/mjsunit/regress/regress-753.js diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index a8c6186e47..8b58faa183 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,3 +1,18 @@ +2010-06-30: Version 2.2.21 + + Fix bug in externalizing some ASCII strings (Chromium issue 47824). + + Update JSON.stringify to floor the space parameter (issue 753). + + Update the Mozilla test expectations to the newest version. + + Update the ES5 Conformance Test expectations to the latest version. + + Update the V8 benchmark suite. + + Provide actual breakpoints locations in response to setBreakpoint + and listBreakpoints requests. + 2010-06-28: Version 2.2.20 Fix bug with for-in on x64 platform (issue 748). diff --git a/deps/v8/benchmarks/README.txt b/deps/v8/benchmarks/README.txt index 8e08159da8..800b4f5185 100644 --- a/deps/v8/benchmarks/README.txt +++ b/deps/v8/benchmarks/README.txt @@ -66,6 +66,12 @@ extensions enabled. Changes from Version 5 to Version 6 =================================== -Removed dead code from the RayTrace benchmark and changed the Splay -benchmark to avoid converting the same numeric key to a string over -and over again. +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. + +Furthermore, the benchmark runner was changed to run the benchmarks +for at least a few times to stabilize the reported numbers on slower +machines. diff --git a/deps/v8/benchmarks/base.js b/deps/v8/benchmarks/base.js index ce308419ed..0388da6844 100644 --- a/deps/v8/benchmarks/base.js +++ b/deps/v8/benchmarks/base.js @@ -198,15 +198,33 @@ BenchmarkSuite.prototype.NotifyError = function(error) { // Runs a single benchmark for at least a second and computes the // average time it takes to run a single iteration. -BenchmarkSuite.prototype.RunSingleBenchmark = function(benchmark) { - var elapsed = 0; - var start = new Date(); - for (var n = 0; elapsed < 1000; n++) { - benchmark.run(); - elapsed = new Date() - start; +BenchmarkSuite.prototype.RunSingleBenchmark = function(benchmark, data) { + function Measure(data) { + var elapsed = 0; + var start = new Date(); + for (var n = 0; elapsed < 1000; n++) { + benchmark.run(); + elapsed = new Date() - start; + } + if (data != null) { + data.runs += n; + data.elapsed += elapsed; + } + } + + if (data == null) { + // Measure the benchmark once for warm up and throw the result + // away. Return a fresh data object. + Measure(null); + return { runs: 0, elapsed: 0 }; + } else { + Measure(data); + // If we've run too few iterations, we continue for another second. + if (data.runs < 32) return data; + var usec = (data.elapsed * 1000) / data.runs; + this.NotifyStep(new BenchmarkResult(benchmark, usec)); + return null; } - var usec = (elapsed * 1000) / n; - this.NotifyStep(new BenchmarkResult(benchmark, usec)); } @@ -220,6 +238,7 @@ BenchmarkSuite.prototype.RunStep = function(runner) { var length = this.benchmarks.length; var index = 0; var suite = this; + var data; // Run the setup, the actual benchmark, and the tear down in three // separate steps to allow the framework to yield between any of the @@ -241,12 +260,13 @@ BenchmarkSuite.prototype.RunStep = function(runner) { function RunNextBenchmark() { try { - suite.RunSingleBenchmark(suite.benchmarks[index]); + data = suite.RunSingleBenchmark(suite.benchmarks[index], data); } catch (e) { suite.NotifyError(e); return null; } - return RunNextTearDown; + // If data is null, we're done with this benchmark. + return (data == null) ? RunNextTearDown : RunNextBenchmark(); } function RunNextTearDown() { diff --git a/deps/v8/benchmarks/crypto.js b/deps/v8/benchmarks/crypto.js index 12b88ef294..7e9829dc22 100644 --- a/deps/v8/benchmarks/crypto.js +++ b/deps/v8/benchmarks/crypto.js @@ -31,7 +31,7 @@ // The code has been adapted for use as a benchmark by Google. -var Crypto = new BenchmarkSuite('Crypto', 203037, [ +var Crypto = new BenchmarkSuite('Crypto', 110465, [ new Benchmark("Encrypt", encrypt), new Benchmark("Decrypt", decrypt) ]); diff --git a/deps/v8/benchmarks/deltablue.js b/deps/v8/benchmarks/deltablue.js index 7e25d2e13f..4af8387a1c 100644 --- a/deps/v8/benchmarks/deltablue.js +++ b/deps/v8/benchmarks/deltablue.js @@ -23,13 +23,13 @@ // more like a JavaScript program. -var DeltaBlue = new BenchmarkSuite('DeltaBlue', 71104, [ +var DeltaBlue = new BenchmarkSuite('DeltaBlue', 30282, [ new Benchmark('DeltaBlue', deltaBlue) ]); /** - * A JavaScript implementation of the DeltaBlue constrain-solving + * A JavaScript implementation of the DeltaBlue constraint-solving * algorithm, as described in: * * "The DeltaBlue Algorithm: An Incremental Constraint Hierarchy Solver" @@ -349,13 +349,13 @@ function BinaryConstraint(var1, var2, strength) { BinaryConstraint.inheritsFrom(Constraint); /** - * Decides if this constratint can be satisfied and which way it + * Decides if this constraint can be satisfied and which way it * should flow based on the relative strength of the variables related, * and record that decision. */ BinaryConstraint.prototype.chooseMethod = function (mark) { if (this.v1.mark == mark) { - this.direction = (this.v1.mark != mark && Strength.stronger(this.strength, this.v2.walkStrength)) + this.direction = (this.v2.mark != mark && Strength.stronger(this.strength, this.v2.walkStrength)) ? Direction.FORWARD : Direction.NONE; } diff --git a/deps/v8/benchmarks/earley-boyer.js b/deps/v8/benchmarks/earley-boyer.js index 3c7f922c4d..b1efe4addd 100644 --- a/deps/v8/benchmarks/earley-boyer.js +++ b/deps/v8/benchmarks/earley-boyer.js @@ -1,7 +1,7 @@ // This file is automatically generated by scheme2js, except for the // benchmark harness code at the beginning and end of the file. -var EarleyBoyer = new BenchmarkSuite('EarleyBoyer', 765819, [ +var EarleyBoyer = new BenchmarkSuite('EarleyBoyer', 280581, [ new Benchmark("Earley", function () { BgL_earleyzd2benchmarkzd2(); }), new Benchmark("Boyer", function () { BgL_nboyerzd2benchmarkzd2(); }) ]); diff --git a/deps/v8/benchmarks/raytrace.js b/deps/v8/benchmarks/raytrace.js index da4d5924aa..eaf61a123b 100644 --- a/deps/v8/benchmarks/raytrace.js +++ b/deps/v8/benchmarks/raytrace.js @@ -8,7 +8,7 @@ // untouched. This file also contains a copy of parts of the Prototype // JavaScript framework which is used by the ray tracer. -var RayTrace = new BenchmarkSuite('RayTrace', 932666, [ +var RayTrace = new BenchmarkSuite('RayTrace', 533115, [ new Benchmark('RayTrace', renderScene) ]); diff --git a/deps/v8/benchmarks/regexp.js b/deps/v8/benchmarks/regexp.js index dce15b8e37..f9f816c7bd 100644 --- a/deps/v8/benchmarks/regexp.js +++ b/deps/v8/benchmarks/regexp.js @@ -35,7 +35,7 @@ // letters in the data are encoded using ROT13 in a way that does not // affect how the regexps match their input. -var RegRxp = new BenchmarkSuite('RegExp', 995230, [ +var RegRxp = new BenchmarkSuite('RegExp', 601250, [ new Benchmark("RegExp", runRegExpBenchmark) ]); diff --git a/deps/v8/benchmarks/revisions.html b/deps/v8/benchmarks/revisions.html index b03aa126d6..1c54f63462 100644 --- a/deps/v8/benchmarks/revisions.html +++ b/deps/v8/benchmarks/revisions.html @@ -22,10 +22,15 @@ the benchmark suite.

Version 6 (link)

-

Removed dead code from the RayTrace benchmark and changed the Splay -benchmark to avoid converting the same numeric key to a string over -and over again. -

+

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.

+ +

Furthermore, the benchmark runner was changed to run the benchmarks +for at least a few times to stabilize the reported numbers on slower +machines.

Version 5 (link)

diff --git a/deps/v8/benchmarks/richards.js b/deps/v8/benchmarks/richards.js index c9368eff91..b5736f7a21 100644 --- a/deps/v8/benchmarks/richards.js +++ b/deps/v8/benchmarks/richards.js @@ -35,7 +35,7 @@ // Martin Richards. -var Richards = new BenchmarkSuite('Richards', 34886, [ +var Richards = new BenchmarkSuite('Richards', 20687, [ new Benchmark("Richards", runRichards) ]); diff --git a/deps/v8/benchmarks/run.html b/deps/v8/benchmarks/run.html index 30036b7843..05bfffee02 100644 --- a/deps/v8/benchmarks/run.html +++ b/deps/v8/benchmarks/run.html @@ -116,7 +116,7 @@ higher scores means better performance: Bigger is better!
  • RegExp
    Regular expression benchmark generated by extracting regular expression operations from 50 of the most popular web pages (1614 lines).
  • -
  • Splay
    Data manipulation benchmark that deals with splay trees and exercises the automatic memory management subsystem (379 lines).
  • +
  • Splay
    Data manipulation benchmark that deals with splay trees and exercises the automatic memory management subsystem (394 lines).
  • diff --git a/deps/v8/benchmarks/splay.js b/deps/v8/benchmarks/splay.js index d8c8f04271..d63ab8b82f 100644 --- a/deps/v8/benchmarks/splay.js +++ b/deps/v8/benchmarks/splay.js @@ -33,7 +33,7 @@ // also has to deal with a lot of changes to the large tree object // graph. -var Splay = new BenchmarkSuite('Splay', 126125, [ +var Splay = new BenchmarkSuite('Splay', 21915, [ new Benchmark("Splay", SplayRun, SplaySetup, SplayTearDown) ]); @@ -230,9 +230,24 @@ SplayTree.prototype.find = function(key) { }; +/** + * @return {SplayTree.Node} Node having the maximum key value. + */ +SplayTree.prototype.findMax = function(opt_startNode) { + if (this.isEmpty()) { + return null; + } + var current = opt_startNode || this.root_; + while (current.right) { + current = current.right; + } + return current; +}; + + /** * @return {SplayTree.Node} Node having the maximum key value that - * is less or equal to the specified key value. + * is less than the specified key value. */ SplayTree.prototype.findGreatestLessThan = function(key) { if (this.isEmpty()) { @@ -243,7 +258,7 @@ SplayTree.prototype.findGreatestLessThan = function(key) { this.splay_(key); // Now the result is either the root node or the greatest node in // the left subtree. - if (this.root_.key <= key) { + if (this.root_.key < key) { return this.root_; } else if (this.root_.left) { return this.findMax(this.root_.left); diff --git a/deps/v8/src/arm/assembler-arm.cc b/deps/v8/src/arm/assembler-arm.cc index f8d98db926..c8170b3d55 100644 --- a/deps/v8/src/arm/assembler-arm.cc +++ b/deps/v8/src/arm/assembler-arm.cc @@ -2112,6 +2112,18 @@ void Assembler::vmrs(Register dst, Condition cond) { } + +void Assembler::vsqrt(const DwVfpRegister dst, + const DwVfpRegister src, + const Condition cond) { + // cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0001 (19-16) | + // Vd(15-12) | 101(11-9) | sz(8)=1 | 11 (7-6) | M(5)=? | 0(4) | Vm(3-0) + ASSERT(CpuFeatures::IsEnabled(VFP3)); + emit(cond | 0xE*B24 | B23 | 0x3*B20 | B16 | + dst.code()*B12 | 0x5*B9 | B8 | 3*B6 | src.code()); +} + + // Pseudo instructions. void Assembler::nop(int type) { // This is mov rx, rx. diff --git a/deps/v8/src/arm/assembler-arm.h b/deps/v8/src/arm/assembler-arm.h index 54b584ae46..8a4173d837 100644 --- a/deps/v8/src/arm/assembler-arm.h +++ b/deps/v8/src/arm/assembler-arm.h @@ -988,6 +988,9 @@ class Assembler : public Malloced { const Condition cond = al); void vmrs(const Register dst, const Condition cond = al); + void vsqrt(const DwVfpRegister dst, + const DwVfpRegister src, + const Condition cond = al); // Pseudo instructions void nop(int type = 0); diff --git a/deps/v8/src/arm/codegen-arm.cc b/deps/v8/src/arm/codegen-arm.cc index b6639ae670..f923c092d1 100644 --- a/deps/v8/src/arm/codegen-arm.cc +++ b/deps/v8/src/arm/codegen-arm.cc @@ -4279,22 +4279,147 @@ void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList* args) { } -// Generates the Math.pow method - currently just calls runtime. +// Generates the Math.pow method. void CodeGenerator::GenerateMathPow(ZoneList* args) { ASSERT(args->length() == 2); Load(args->at(0)); Load(args->at(1)); - frame_->CallRuntime(Runtime::kMath_pow, 2); - frame_->EmitPush(r0); + + if (!CpuFeatures::IsSupported(VFP3)) { + frame_->CallRuntime(Runtime::kMath_pow, 2); + frame_->EmitPush(r0); + } else { + CpuFeatures::Scope scope(VFP3); + JumpTarget runtime, done; + Label not_minus_half, allocate_return; + + Register scratch1 = VirtualFrame::scratch0(); + Register scratch2 = VirtualFrame::scratch1(); + + // Get base and exponent to registers. + Register exponent = frame_->PopToRegister(); + Register base = frame_->PopToRegister(exponent); + + // Set the frame for the runtime jump target. The code below jumps to the + // jump target label so the frame needs to be established before that. + ASSERT(runtime.entry_frame() == NULL); + runtime.set_entry_frame(frame_); + + __ BranchOnSmi(exponent, runtime.entry_label()); + + // Special handling of raising to the power of -0.5 and 0.5. First check + // that the value is a heap number and that the lower bits (which for both + // values are zero). + Register heap_number_map = r6; + __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); + __ ldr(scratch1, FieldMemOperand(exponent, HeapObject::kMapOffset)); + __ ldr(scratch2, FieldMemOperand(exponent, HeapNumber::kMantissaOffset)); + __ cmp(scratch1, heap_number_map); + runtime.Branch(ne); + __ tst(scratch2, scratch2); + runtime.Branch(ne); + + // Load the e + __ ldr(scratch1, FieldMemOperand(exponent, HeapNumber::kExponentOffset)); + + // Compare exponent with -0.5. + __ cmp(scratch1, Operand(0xbfe00000)); + __ b(ne, ¬_minus_half); + + // Get the double value from the base into vfp register d0. + __ ObjectToDoubleVFPRegister(base, d0, + scratch1, scratch2, heap_number_map, s0, + runtime.entry_label(), + AVOID_NANS_AND_INFINITIES); + + // Load 1.0 into d2. + __ mov(scratch2, Operand(0x3ff00000)); + __ mov(scratch1, Operand(0)); + __ vmov(d2, scratch1, scratch2); + + // Calculate the reciprocal of the square root. 1/sqrt(x) = sqrt(1/x). + __ vdiv(d0, d2, d0); + __ vsqrt(d0, d0); + + __ b(&allocate_return); + + __ bind(¬_minus_half); + // Compare exponent with 0.5. + __ cmp(scratch1, Operand(0x3fe00000)); + runtime.Branch(ne); + + // Get the double value from the base into vfp register d0. + __ ObjectToDoubleVFPRegister(base, d0, + scratch1, scratch2, heap_number_map, s0, + runtime.entry_label(), + AVOID_NANS_AND_INFINITIES); + __ vsqrt(d0, d0); + + __ bind(&allocate_return); + __ AllocateHeapNumberWithValue( + base, d0, scratch1, scratch2, heap_number_map, runtime.entry_label()); + done.Jump(); + + runtime.Bind(); + + // Push back the arguments again for the runtime call. + frame_->EmitPush(base); + frame_->EmitPush(exponent); + frame_->CallRuntime(Runtime::kMath_pow, 2); + __ Move(base, r0); + + done.Bind(); + frame_->EmitPush(base); + } } -// Generates the Math.sqrt method - currently just calls runtime. +// Generates the Math.sqrt method. void CodeGenerator::GenerateMathSqrt(ZoneList* args) { ASSERT(args->length() == 1); Load(args->at(0)); - frame_->CallRuntime(Runtime::kMath_sqrt, 1); - frame_->EmitPush(r0); + + if (!CpuFeatures::IsSupported(VFP3)) { + frame_->CallRuntime(Runtime::kMath_sqrt, 1); + frame_->EmitPush(r0); + } else { + CpuFeatures::Scope scope(VFP3); + JumpTarget runtime, done; + + Register scratch1 = VirtualFrame::scratch0(); + Register scratch2 = VirtualFrame::scratch1(); + + // Get the value from the frame. + Register tos = frame_->PopToRegister(); + + // Set the frame for the runtime jump target. The code below jumps to the + // jump target label so the frame needs to be established before that. + ASSERT(runtime.entry_frame() == NULL); + runtime.set_entry_frame(frame_); + + Register heap_number_map = r6; + __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); + + // Get the double value from the heap number into vfp register d0. + __ ObjectToDoubleVFPRegister(tos, d0, + scratch1, scratch2, heap_number_map, s0, + runtime.entry_label()); + + // Calculate the square root of d0 and place result in a heap number object. + __ vsqrt(d0, d0); + __ AllocateHeapNumberWithValue( + tos, d0, scratch1, scratch2, heap_number_map, runtime.entry_label()); + done.Jump(); + + runtime.Bind(); + // Push back the argument again for the runtime call. + frame_->EmitPush(tos); + frame_->CallRuntime(Runtime::kMath_sqrt, 1); + __ Move(tos, r0); + + done.Bind(); + frame_->EmitPush(tos); + } } @@ -6257,7 +6382,6 @@ bool CodeGenerator::HasValidEntryRegisters() { return true; } #undef __ #define __ ACCESS_MASM(masm) - Handle Reference::GetName() { ASSERT(type_ == NAMED); Property* property = expression_->AsProperty(); @@ -6621,7 +6745,7 @@ void ConvertToDoubleStub::Generate(MacroAssembler* masm) { __ bind(¬_special); // Count leading zeros. Uses mantissa for a scratch register on pre-ARM5. // Gets the wrong answer for 0, but we already checked for that case above. - __ CountLeadingZeros(source_, mantissa, zeros_); + __ CountLeadingZeros(zeros_, source_, mantissa); // Compute exponent and or it into the exponent register. // We use mantissa as a scratch register here. Use a fudge factor to // divide the constant 31 + HeapNumber::kExponentBias, 0x41d, into two parts @@ -7350,7 +7474,7 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases( // If we have floating point hardware, inline ADD, SUB, MUL, and DIV, // using registers d7 and d6 for the double values. - if (use_fp_registers) { + if (CpuFeatures::IsSupported(VFP3)) { CpuFeatures::Scope scope(VFP3); __ mov(r7, Operand(rhs, ASR, kSmiTagSize)); __ vmov(s15, r7); @@ -7358,8 +7482,12 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases( __ mov(r7, Operand(lhs, ASR, kSmiTagSize)); __ vmov(s13, r7); __ vcvt_f64_s32(d6, s13); + if (!use_fp_registers) { + __ vmov(r2, r3, d7); + __ vmov(r0, r1, d6); + } } else { - // Write Smi from rhs to r3 and r2 in double format. r3 is scratch. + // Write Smi from rhs to r3 and r2 in double format. r9 is scratch. __ mov(r7, Operand(rhs)); ConvertToDoubleStub stub1(r3, r2, r7, r9); __ push(lr); @@ -7434,12 +7562,15 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases( __ AllocateHeapNumber(r5, r4, r7, heap_number_map, &slow); } - if (use_fp_registers) { + if (CpuFeatures::IsSupported(VFP3)) { CpuFeatures::Scope scope(VFP3); // Convert smi in r0 to double in d7. __ mov(r7, Operand(r0, ASR, kSmiTagSize)); __ vmov(s15, r7); __ vcvt_f64_s32(d7, s15); + if (!use_fp_registers) { + __ vmov(r2, r3, d7); + } } else { // Write Smi from r0 to r3 and r2 in double format. __ mov(r7, Operand(r0)); @@ -7490,12 +7621,15 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases( __ AllocateHeapNumber(r5, r4, r7, heap_number_map, &slow); } - if (use_fp_registers) { + if (CpuFeatures::IsSupported(VFP3)) { CpuFeatures::Scope scope(VFP3); // Convert smi in r1 to double in d6. __ mov(r7, Operand(r1, ASR, kSmiTagSize)); __ vmov(s13, r7); __ vcvt_f64_s32(d6, s13); + if (!use_fp_registers) { + __ vmov(r0, r1, d6); + } } else { // Write Smi from r1 to r1 and r0 in double format. __ mov(r7, Operand(r1)); @@ -7942,6 +8076,173 @@ static void MultiplyByKnownInt2( } +// This uses versions of the sum-of-digits-to-see-if-a-number-is-divisible-by-3 +// trick. See http://en.wikipedia.org/wiki/Divisibility_rule +// Takes the sum of the digits base (mask + 1) repeatedly until we have a +// number from 0 to mask. On exit the 'eq' condition flags are set if the +// answer is exactly the mask. +void IntegerModStub::DigitSum(MacroAssembler* masm, + Register lhs, + int mask, + int shift, + Label* entry) { + ASSERT(mask > 0); + ASSERT(mask <= 0xff); // This ensures we don't need ip to use it. + Label loop; + __ bind(&loop); + __ and_(ip, lhs, Operand(mask)); + __ add(lhs, ip, Operand(lhs, LSR, shift)); + __ bind(entry); + __ cmp(lhs, Operand(mask)); + __ b(gt, &loop); +} + + +void IntegerModStub::DigitSum(MacroAssembler* masm, + Register lhs, + Register scratch, + int mask, + int shift1, + int shift2, + Label* entry) { + ASSERT(mask > 0); + ASSERT(mask <= 0xff); // This ensures we don't need ip to use it. + Label loop; + __ bind(&loop); + __ bic(scratch, lhs, Operand(mask)); + __ and_(ip, lhs, Operand(mask)); + __ add(lhs, ip, Operand(lhs, LSR, shift1)); + __ add(lhs, lhs, Operand(scratch, LSR, shift2)); + __ bind(entry); + __ cmp(lhs, Operand(mask)); + __ b(gt, &loop); +} + + +// Splits the number into two halves (bottom half has shift bits). The top +// half is subtracted from the bottom half. If the result is negative then +// rhs is added. +void IntegerModStub::ModGetInRangeBySubtraction(MacroAssembler* masm, + Register lhs, + int shift, + int rhs) { + int mask = (1 << shift) - 1; + __ and_(ip, lhs, Operand(mask)); + __ sub(lhs, ip, Operand(lhs, LSR, shift), SetCC); + __ add(lhs, lhs, Operand(rhs), LeaveCC, mi); +} + + +void IntegerModStub::ModReduce(MacroAssembler* masm, + Register lhs, + int max, + int denominator) { + int limit = denominator; + while (limit * 2 <= max) limit *= 2; + while (limit >= denominator) { + __ cmp(lhs, Operand(limit)); + __ sub(lhs, lhs, Operand(limit), LeaveCC, ge); + limit >>= 1; + } +} + + +void IntegerModStub::ModAnswer(MacroAssembler* masm, + Register result, + Register shift_distance, + Register mask_bits, + Register sum_of_digits) { + __ add(result, mask_bits, Operand(sum_of_digits, LSL, shift_distance)); + __ Ret(); +} + + +// See comment for class. +void IntegerModStub::Generate(MacroAssembler* masm) { + __ mov(lhs_, Operand(lhs_, LSR, shift_distance_)); + __ bic(odd_number_, odd_number_, Operand(1)); + __ mov(odd_number_, Operand(odd_number_, LSL, 1)); + // We now have (odd_number_ - 1) * 2 in the register. + // Build a switch out of branches instead of data because it avoids + // having to teach the assembler about intra-code-object pointers + // that are not in relative branch instructions. + Label mod3, mod5, mod7, mod9, mod11, mod13, mod15, mod17, mod19; + Label mod21, mod23, mod25; + { Assembler::BlockConstPoolScope block_const_pool(masm); + __ add(pc, pc, Operand(odd_number_)); + // When you read pc it is always 8 ahead, but when you write it you always + // write the actual value. So we put in two nops to take up the slack. + __ nop(); + __ nop(); + __ b(&mod3); + __ b(&mod5); + __ b(&mod7); + __ b(&mod9); + __ b(&mod11); + __ b(&mod13); + __ b(&mod15); + __ b(&mod17); + __ b(&mod19); + __ b(&mod21); + __ b(&mod23); + __ b(&mod25); + } + + // For each denominator we find a multiple that is almost only ones + // when expressed in binary. Then we do the sum-of-digits trick for + // that number. If the multiple is not 1 then we have to do a little + // more work afterwards to get the answer into the 0-denominator-1 + // range. + DigitSum(masm, lhs_, 3, 2, &mod3); // 3 = b11. + __ sub(lhs_, lhs_, Operand(3), LeaveCC, eq); + ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_); + + DigitSum(masm, lhs_, 0xf, 4, &mod5); // 5 * 3 = b1111. + ModGetInRangeBySubtraction(masm, lhs_, 2, 5); + ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_); + + DigitSum(masm, lhs_, 7, 3, &mod7); // 7 = b111. + __ sub(lhs_, lhs_, Operand(7), LeaveCC, eq); + ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_); + + DigitSum(masm, lhs_, 0x3f, 6, &mod9); // 7 * 9 = b111111. + ModGetInRangeBySubtraction(masm, lhs_, 3, 9); + ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_); + + DigitSum(masm, lhs_, r5, 0x3f, 6, 3, &mod11); // 5 * 11 = b110111. + ModReduce(masm, lhs_, 0x3f, 11); + ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_); + + DigitSum(masm, lhs_, r5, 0xff, 8, 5, &mod13); // 19 * 13 = b11110111. + ModReduce(masm, lhs_, 0xff, 13); + ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_); + + DigitSum(masm, lhs_, 0xf, 4, &mod15); // 15 = b1111. + __ sub(lhs_, lhs_, Operand(15), LeaveCC, eq); + ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_); + + DigitSum(masm, lhs_, 0xff, 8, &mod17); // 15 * 17 = b11111111. + ModGetInRangeBySubtraction(masm, lhs_, 4, 17); + ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_); + + DigitSum(masm, lhs_, r5, 0xff, 8, 5, &mod19); // 13 * 19 = b11110111. + ModReduce(masm, lhs_, 0xff, 19); + ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_); + + DigitSum(masm, lhs_, 0x3f, 6, &mod21); // 3 * 21 = b111111. + ModReduce(masm, lhs_, 0x3f, 21); + ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_); + + DigitSum(masm, lhs_, r5, 0xff, 8, 7, &mod23); // 11 * 23 = b11111101. + ModReduce(masm, lhs_, 0xff, 23); + ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_); + + DigitSum(masm, lhs_, r5, 0x7f, 7, 6, &mod25); // 5 * 25 = b1111101. + ModReduce(masm, lhs_, 0x7f, 25); + ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_); +} + + const char* GenericBinaryOpStub::GetName() { if (name_ != NULL) return name_; const int len = 100; @@ -8069,7 +8370,7 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { case Token::MOD: { Label not_smi; if (ShouldGenerateSmiCode() && specialized_on_rhs_) { - Label smi_is_unsuitable; + Label lhs_is_unsuitable; __ BranchOnNotSmi(lhs, ¬_smi); if (IsPowerOf2(constant_rhs_)) { if (op_ == Token::MOD) { @@ -8090,14 +8391,14 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { __ eor(rhs, rhs, Operand(0x80000000u), SetCC); // Next two instructions are conditional on the answer being -0. __ mov(rhs, Operand(Smi::FromInt(constant_rhs_)), LeaveCC, eq); - __ b(eq, &smi_is_unsuitable); + __ b(eq, &lhs_is_unsuitable); // We need to subtract the dividend. Eg. -3 % 4 == -3. __ sub(result, rhs, Operand(Smi::FromInt(constant_rhs_))); } else { ASSERT(op_ == Token::DIV); __ tst(lhs, Operand(0x80000000u | ((constant_rhs_ << kSmiTagSize) - 1))); - __ b(ne, &smi_is_unsuitable); // Go slow on negative or remainder. + __ b(ne, &lhs_is_unsuitable); // Go slow on negative or remainder. int shift = 0; int d = constant_rhs_; while ((d & 1) == 0) { @@ -8110,7 +8411,7 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { } else { // Not a power of 2. __ tst(lhs, Operand(0x80000000u)); - __ b(ne, &smi_is_unsuitable); + __ b(ne, &lhs_is_unsuitable); // Find a fixed point reciprocal of the divisor so we can divide by // multiplying. double divisor = 1.0 / constant_rhs_; @@ -8145,7 +8446,7 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { // (lhs / rhs) where / indicates integer division. if (op_ == Token::DIV) { __ cmp(lhs, Operand(scratch, LSL, required_scratch_shift)); - __ b(ne, &smi_is_unsuitable); // There was a remainder. + __ b(ne, &lhs_is_unsuitable); // There was a remainder. __ mov(result, Operand(scratch2, LSL, kSmiTagSize)); } else { ASSERT(op_ == Token::MOD); @@ -8153,14 +8454,21 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { } } __ Ret(); - __ bind(&smi_is_unsuitable); + __ bind(&lhs_is_unsuitable); } else if (op_ == Token::MOD && runtime_operands_type_ != BinaryOpIC::HEAP_NUMBERS && runtime_operands_type_ != BinaryOpIC::STRINGS) { // Do generate a bit of smi code for modulus even though the default for // modulus is not to do it, but as the ARM processor has no coprocessor - // support for modulus checking for smis makes sense. + // support for modulus checking for smis makes sense. We can handle + // 1 to 25 times any power of 2. This covers over half the numbers from + // 1 to 100 including all of the first 25. (Actually the constants < 10 + // are handled above by reciprocal multiplication. We only get here for + // those cases if the right hand side is not a constant or for cases + // like 192 which is 3*2^6 and ends up in the 3 case in the integer mod + // stub.) Label slow; + Label not_power_of_2; ASSERT(!ShouldGenerateSmiCode()); ASSERT(kSmiTag == 0); // Adjust code below. // Check for two positive smis. @@ -8168,13 +8476,42 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { __ tst(smi_test_reg, Operand(0x80000000u | kSmiTagMask)); __ b(ne, &slow); // Check that rhs is a power of two and not zero. + Register mask_bits = r3; __ sub(scratch, rhs, Operand(1), SetCC); __ b(mi, &slow); - __ tst(rhs, scratch); - __ b(ne, &slow); + __ and_(mask_bits, rhs, Operand(scratch), SetCC); + __ b(ne, ¬_power_of_2); // Calculate power of two modulus. __ and_(result, lhs, Operand(scratch)); __ Ret(); + + __ bind(¬_power_of_2); + __ eor(scratch, scratch, Operand(mask_bits)); + // At least two bits are set in the modulus. The high one(s) are in + // mask_bits and the low one is scratch + 1. + __ and_(mask_bits, scratch, Operand(lhs)); + Register shift_distance = scratch; + scratch = no_reg; + + // The rhs consists of a power of 2 multiplied by some odd number. + // The power-of-2 part we handle by putting the corresponding bits + // from the lhs in the mask_bits register, and the power in the + // shift_distance register. Shift distance is never 0 due to Smi + // tagging. + __ CountLeadingZeros(r4, shift_distance, shift_distance); + __ rsb(shift_distance, r4, Operand(32)); + + // Now we need to find out what the odd number is. The last bit is + // always 1. + Register odd_number = r4; + __ mov(odd_number, Operand(rhs, LSR, shift_distance)); + __ cmp(odd_number, Operand(25)); + __ b(gt, &slow); + + IntegerModStub stub( + result, shift_distance, odd_number, mask_bits, lhs, r5); + __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); // Tail call. + __ bind(&slow); } HandleBinaryOpSlowCases( diff --git a/deps/v8/src/arm/codegen-arm.h b/deps/v8/src/arm/codegen-arm.h index 925d2675e1..2d8a935203 100644 --- a/deps/v8/src/arm/codegen-arm.h +++ b/deps/v8/src/arm/codegen-arm.h @@ -881,6 +881,102 @@ class StringCompareStub: public CodeStub { }; +// This stub can do a fast mod operation without using fp. +// It is tail called from the GenericBinaryOpStub and it always +// returns an answer. It never causes GC so it doesn't need a real frame. +// +// The inputs are always positive Smis. This is never called +// where the denominator is a power of 2. We handle that separately. +// +// If we consider the denominator as an odd number multiplied by a power of 2, +// then: +// * The exponent (power of 2) is in the shift_distance register. +// * The odd number is in the odd_number register. It is always in the range +// of 3 to 25. +// * The bits from the numerator that are to be copied to the answer (there are +// shift_distance of them) are in the mask_bits register. +// * The other bits of the numerator have been shifted down and are in the lhs +// register. +class IntegerModStub : public CodeStub { + public: + IntegerModStub(Register result, + Register shift_distance, + Register odd_number, + Register mask_bits, + Register lhs, + Register scratch) + : result_(result), + shift_distance_(shift_distance), + odd_number_(odd_number), + mask_bits_(mask_bits), + lhs_(lhs), + scratch_(scratch) { + // We don't code these in the minor key, so they should always be the same. + // We don't really want to fix that since this stub is rather large and we + // don't want many copies of it. + ASSERT(shift_distance_.is(r9)); + ASSERT(odd_number_.is(r4)); + ASSERT(mask_bits_.is(r3)); + ASSERT(scratch_.is(r5)); + } + + private: + Register result_; + Register shift_distance_; + Register odd_number_; + Register mask_bits_; + Register lhs_; + Register scratch_; + + // Minor key encoding in 16 bits. + class ResultRegisterBits: public BitField {}; + class LhsRegisterBits: public BitField {}; + + Major MajorKey() { return IntegerMod; } + int MinorKey() { + // Encode the parameters in a unique 16 bit value. + return ResultRegisterBits::encode(result_.code()) + | LhsRegisterBits::encode(lhs_.code()); + } + + void Generate(MacroAssembler* masm); + + const char* GetName() { return "IntegerModStub"; } + + // Utility functions. + void DigitSum(MacroAssembler* masm, + Register lhs, + int mask, + int shift, + Label* entry); + void DigitSum(MacroAssembler* masm, + Register lhs, + Register scratch, + int mask, + int shift1, + int shift2, + Label* entry); + void ModGetInRangeBySubtraction(MacroAssembler* masm, + Register lhs, + int shift, + int rhs); + void ModReduce(MacroAssembler* masm, + Register lhs, + int max, + int denominator); + void ModAnswer(MacroAssembler* masm, + Register result, + Register shift_distance, + Register mask_bits, + Register sum_of_digits); + + +#ifdef DEBUG + void Print() { PrintF("IntegerModStub\n"); } +#endif +}; + + // This stub can convert a signed int32 to a heap number (double). It does // not work for int32s that are in Smi range! No GC occurs during this stub // so you don't have to set up the frame. diff --git a/deps/v8/src/arm/constants-arm.cc b/deps/v8/src/arm/constants-arm.cc index 4e186d1382..002e4c1368 100644 --- a/deps/v8/src/arm/constants-arm.cc +++ b/deps/v8/src/arm/constants-arm.cc @@ -85,7 +85,7 @@ const char* VFPRegisters::names_[kNumVFPRegisters] = { const char* VFPRegisters::Name(int reg, bool is_double) { ASSERT((0 <= reg) && (reg < kNumVFPRegisters)); - return names_[reg + is_double ? kNumVFPSingleRegisters : 0]; + return names_[reg + (is_double ? kNumVFPSingleRegisters : 0)]; } diff --git a/deps/v8/src/arm/disasm-arm.cc b/deps/v8/src/arm/disasm-arm.cc index 400536993a..fb17d45d5a 100644 --- a/deps/v8/src/arm/disasm-arm.cc +++ b/deps/v8/src/arm/disasm-arm.cc @@ -1038,7 +1038,8 @@ void Decoder::DecodeUnconditional(Instr* instr) { // Dd = vmul(Dn, Dm) // Dd = vdiv(Dn, Dm) // vcmp(Dd, Dm) -// VMRS +// vmrs +// Dd = vsqrt(Dm) void Decoder::DecodeTypeVFP(Instr* instr) { ASSERT((instr->TypeField() == 7) && (instr->Bit(24) == 0x0) ); ASSERT(instr->Bits(11, 9) == 0x5); @@ -1056,6 +1057,8 @@ void Decoder::DecodeTypeVFP(Instr* instr) { } else if (((instr->Opc2Field() == 0x4) || (instr->Opc2Field() == 0x5)) && (instr->Opc3Field() & 0x1)) { DecodeVCMP(instr); + } else if (((instr->Opc2Field() == 0x1)) && (instr->Opc3Field() == 0x3)) { + Format(instr, "vsqrt.f64'cond 'Dd, 'Dm"); } else { Unknown(instr); // Not used by V8. } diff --git a/deps/v8/src/arm/ic-arm.cc b/deps/v8/src/arm/ic-arm.cc index 134dfa3952..0af10362f0 100644 --- a/deps/v8/src/arm/ic-arm.cc +++ b/deps/v8/src/arm/ic-arm.cc @@ -1722,7 +1722,7 @@ static void ConvertIntToFloat(MacroAssembler* masm, // Count leading zeros. // Gets the wrong answer for 0, but we already checked for that case above. Register zeros = scratch2; - __ CountLeadingZeros(ival, scratch1, zeros); + __ CountLeadingZeros(zeros, ival, scratch1); // Compute exponent and or it into the exponent register. __ rsb(scratch1, diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc index df7565f135..630e0b80ac 100644 --- a/deps/v8/src/arm/macro-assembler-arm.cc +++ b/deps/v8/src/arm/macro-assembler-arm.cc @@ -1369,6 +1369,56 @@ void MacroAssembler::IntegerToDoubleConversionWithVFP3(Register inReg, } +void MacroAssembler::ObjectToDoubleVFPRegister(Register object, + DwVfpRegister result, + Register scratch1, + Register scratch2, + Register heap_number_map, + SwVfpRegister scratch3, + Label* not_number, + ObjectToDoubleFlags flags) { + Label done; + if ((flags & OBJECT_NOT_SMI) == 0) { + Label not_smi; + BranchOnNotSmi(object, ¬_smi); + // Remove smi tag and convert to double. + mov(scratch1, Operand(object, ASR, kSmiTagSize)); + vmov(scratch3, scratch1); + vcvt_f64_s32(result, scratch3); + b(&done); + bind(¬_smi); + } + // Check for heap number and load double value from it. + ldr(scratch1, FieldMemOperand(object, HeapObject::kMapOffset)); + sub(scratch2, object, Operand(kHeapObjectTag)); + cmp(scratch1, heap_number_map); + b(ne, not_number); + if ((flags & AVOID_NANS_AND_INFINITIES) != 0) { + // If exponent is all ones the number is either a NaN or +/-Infinity. + ldr(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset)); + Sbfx(scratch1, + scratch1, + HeapNumber::kExponentShift, + HeapNumber::kExponentBits); + // All-one value sign extend to -1. + cmp(scratch1, Operand(-1)); + b(eq, not_number); + } + vldr(result, scratch2, HeapNumber::kValueOffset); + bind(&done); +} + + +void MacroAssembler::SmiToDoubleVFPRegister(Register smi, + DwVfpRegister value, + Register scratch1, + SwVfpRegister scratch2) { + mov(scratch1, Operand(smi, ASR, kSmiTagSize)); + vmov(scratch2, scratch1); + vcvt_f64_s32(value, scratch2); +} + + void MacroAssembler::GetLeastBitsFromSmi(Register dst, Register src, int num_least_bits) { @@ -1686,14 +1736,31 @@ void MacroAssembler::AllocateHeapNumber(Register result, } -void MacroAssembler::CountLeadingZeros(Register source, - Register scratch, - Register zeros) { +void MacroAssembler::AllocateHeapNumberWithValue(Register result, + DwVfpRegister value, + Register scratch1, + Register scratch2, + Register heap_number_map, + Label* gc_required) { + AllocateHeapNumber(result, scratch1, scratch2, heap_number_map, gc_required); + sub(scratch1, result, Operand(kHeapObjectTag)); + vstr(value, scratch1, HeapNumber::kValueOffset); +} + + +void MacroAssembler::CountLeadingZeros(Register zeros, // Answer. + Register source, // Input. + Register scratch) { + ASSERT(!zeros.is(source) || !source.is(zeros)); + ASSERT(!zeros.is(scratch)); + ASSERT(!scratch.is(ip)); + ASSERT(!source.is(ip)); + ASSERT(!zeros.is(ip)); #ifdef CAN_USE_ARMV5_INSTRUCTIONS clz(zeros, source); // This instruction is only supported after ARM5. #else mov(zeros, Operand(0)); - mov(scratch, source); + Move(scratch, source); // Top 16. tst(scratch, Operand(0xffff0000)); add(zeros, zeros, Operand(16), LeaveCC, eq); diff --git a/deps/v8/src/arm/macro-assembler-arm.h b/deps/v8/src/arm/macro-assembler-arm.h index e02a6c8a3e..c3f45a632e 100644 --- a/deps/v8/src/arm/macro-assembler-arm.h +++ b/deps/v8/src/arm/macro-assembler-arm.h @@ -67,6 +67,17 @@ enum AllocationFlags { }; +// Flags used for the ObjectToDoubleVFPRegister function. +enum ObjectToDoubleFlags { + // No special flags. + NO_OBJECT_TO_DOUBLE_FLAGS = 0, + // Object is known to be a non smi. + OBJECT_NOT_SMI = 1 << 0, + // Don't load NaNs or infinities, branch to the non number case instead. + AVOID_NANS_AND_INFINITIES = 1 << 1 +}; + + // MacroAssembler implements a collection of frequently used macros. class MacroAssembler: public Assembler { public: @@ -381,6 +392,13 @@ class MacroAssembler: public Assembler { Register scratch2, Register heap_number_map, Label* gc_required); + void AllocateHeapNumberWithValue(Register result, + DwVfpRegister value, + Register scratch1, + Register scratch2, + Register heap_number_map, + Label* gc_required); + // --------------------------------------------------------------------------- // Support functions. @@ -469,12 +487,35 @@ class MacroAssembler: public Assembler { Register outHighReg, Register outLowReg); + // Load the value of a number object into a VFP double register. If the object + // is not a number a jump to the label not_number is performed and the VFP + // double register is unchanged. + void ObjectToDoubleVFPRegister( + Register object, + DwVfpRegister value, + Register scratch1, + Register scratch2, + Register heap_number_map, + SwVfpRegister scratch3, + Label* not_number, + ObjectToDoubleFlags flags = NO_OBJECT_TO_DOUBLE_FLAGS); + + // Load the value of a smi object into a VFP double register. The register + // scratch1 can be the same register as smi in which case smi will hold the + // untagged value afterwards. + void SmiToDoubleVFPRegister(Register smi, + DwVfpRegister value, + Register scratch1, + SwVfpRegister scratch2); + // Count leading zeros in a 32 bit word. On ARM5 and later it uses the clz // instruction. On pre-ARM5 hardware this routine gives the wrong answer - // for 0 (31 instead of 32). - void CountLeadingZeros(Register source, - Register scratch, - Register zeros); + // for 0 (31 instead of 32). Source and scratch can be the same in which case + // the source is clobbered. Source and zeros can also be the same in which + // case scratch should be a different register. + void CountLeadingZeros(Register zeros, + Register source, + Register scratch); // --------------------------------------------------------------------------- // Runtime calls diff --git a/deps/v8/src/arm/simulator-arm.cc b/deps/v8/src/arm/simulator-arm.cc index 77776c2b6d..6240cd4787 100644 --- a/deps/v8/src/arm/simulator-arm.cc +++ b/deps/v8/src/arm/simulator-arm.cc @@ -26,6 +26,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include +#include #include #include "v8.h" @@ -2262,7 +2263,8 @@ static int GlueRegCode(bool last_bit, int vm, int m) { // Dd = vmul(Dn, Dm) // Dd = vdiv(Dn, Dm) // vcmp(Dd, Dm) -// VMRS +// vmrs +// Dd = vsqrt(Dm) void Simulator::DecodeTypeVFP(Instr* instr) { ASSERT((instr->TypeField() == 7) && (instr->Bit(24) == 0x0) ); ASSERT(instr->Bits(11, 9) == 0x5); @@ -2284,6 +2286,11 @@ void Simulator::DecodeTypeVFP(Instr* instr) { } else if (((instr->Opc2Field() == 0x4) || (instr->Opc2Field() == 0x5)) && (instr->Opc3Field() & 0x1)) { DecodeVCMP(instr); + } else if (((instr->Opc2Field() == 0x1)) && (instr->Opc3Field() == 0x3)) { + // vsqrt + double dm_value = get_double_from_d_register(vm); + double dd_value = sqrt(dm_value); + set_d_register_from_double(vd, dd_value); } else { UNREACHABLE(); // Not used by V8. } diff --git a/deps/v8/src/code-stubs.h b/deps/v8/src/code-stubs.h index de2ad56cc6..e5a222fcda 100644 --- a/deps/v8/src/code-stubs.h +++ b/deps/v8/src/code-stubs.h @@ -46,6 +46,7 @@ namespace internal { V(RecordWrite) \ V(ConvertToDouble) \ V(WriteInt32ToHeapNumber) \ + V(IntegerMod) \ V(StackCheck) \ V(FastNewClosure) \ V(FastNewContext) \ diff --git a/deps/v8/src/debug-debugger.js b/deps/v8/src/debug-debugger.js index d5e91cbdd2..c808c87b8e 100644 --- a/deps/v8/src/debug-debugger.js +++ b/deps/v8/src/debug-debugger.js @@ -236,6 +236,7 @@ function ScriptBreakPoint(type, script_id_or_name, opt_line, opt_column, this.active_ = true; this.condition_ = null; this.ignoreCount_ = 0; + this.break_points_ = []; } @@ -289,6 +290,15 @@ ScriptBreakPoint.prototype.column = function() { }; +ScriptBreakPoint.prototype.actual_locations = function() { + var locations = []; + for (var i = 0; i < this.break_points_.length; i++) { + locations.push(this.break_points_[i].actual_location); + } + return locations; +} + + ScriptBreakPoint.prototype.update_positions = function(line, column) { this.line_ = line; this.column_ = column; @@ -334,10 +344,8 @@ ScriptBreakPoint.prototype.setIgnoreCount = function(ignoreCount) { this.ignoreCount_ = ignoreCount; // Set ignore count on all break points created from this script break point. - for (var i = 0; i < break_points.length; i++) { - if (break_points[i].script_break_point() === this) { - break_points[i].setIgnoreCount(ignoreCount); - } + for (var i = 0; i < this.break_points_.length; i++) { + this.break_points_[i].setIgnoreCount(ignoreCount); } }; @@ -379,20 +387,23 @@ ScriptBreakPoint.prototype.set = function (script) { } // Convert the line and column into an absolute position within the script. - var pos = Debug.findScriptSourcePosition(script, this.line(), column); + var position = Debug.findScriptSourcePosition(script, this.line(), column); // If the position is not found in the script (the script might be shorter // than it used to be) just ignore it. - if (pos === null) return; + if (position === null) return; // Create a break point object and set the break point. - break_point = MakeBreakPoint(pos, this.line(), this.column(), this); + break_point = MakeBreakPoint(position, this.line(), this.column(), this); break_point.setIgnoreCount(this.ignoreCount()); - pos = %SetScriptBreakPoint(script, pos, break_point); - if (!IS_UNDEFINED(pos)) { - this.actual_location = script.locationFromPosition(pos); - } - + var actual_position = %SetScriptBreakPoint(script, position, break_point); + if (IS_UNDEFINED(actual_position)) { + actual_position = position; + } + var actual_location = script.locationFromPosition(actual_position, true); + break_point.actual_location = { line: actual_location.line, + column: actual_location.column }; + this.break_points_.push(break_point); return break_point; }; @@ -409,6 +420,7 @@ ScriptBreakPoint.prototype.clear = function () { } } break_points = remaining_break_points; + this.break_points_ = []; }; @@ -554,6 +566,19 @@ Debug.findBreakPoint = function(break_point_number, remove) { } }; +Debug.findBreakPointActualLocations = function(break_point_number) { + for (var i = 0; i < script_break_points.length; i++) { + if (script_break_points[i].number() == break_point_number) { + return script_break_points[i].actual_locations(); + } + } + for (var i = 0; i < break_points.length; i++) { + if (break_points[i].number() == break_point_number) { + return [break_points[i].actual_location]; + } + } + return []; +} Debug.setBreakPoint = function(func, opt_line, opt_column, opt_condition) { if (!IS_FUNCTION(func)) throw new Error('Parameters have wrong types.'); @@ -585,7 +610,12 @@ Debug.setBreakPoint = function(func, opt_line, opt_column, opt_condition) { } else { // Set a break point directly on the function. var break_point = MakeBreakPoint(source_position, opt_line, opt_column); - %SetFunctionBreakPoint(func, source_position, break_point); + var actual_position = + %SetFunctionBreakPoint(func, source_position, break_point); + actual_position += this.sourcePosition(func); + var actual_location = script.locationFromPosition(actual_position, true); + break_point.actual_location = { line: actual_location.line, + column: actual_location.column }; break_point.setCondition(opt_condition); return break_point.number(); } @@ -1482,8 +1512,10 @@ DebugCommandProcessor.prototype.setBreakPointRequest_ = } response.body.line = break_point.line(); response.body.column = break_point.column(); + response.body.actual_locations = break_point.actual_locations(); } else { response.body.type = 'function'; + response.body.actual_locations = [break_point.actual_location]; } }; @@ -1598,7 +1630,8 @@ DebugCommandProcessor.prototype.listBreakpointsRequest_ = function(request, resp hit_count: break_point.hit_count(), active: break_point.active(), condition: break_point.condition(), - ignoreCount: break_point.ignoreCount() + ignoreCount: break_point.ignoreCount(), + actual_locations: break_point.actual_locations() } if (break_point.type() == Debug.ScriptBreakPointType.ScriptId) { diff --git a/deps/v8/src/handles.cc b/deps/v8/src/handles.cc index c90365c31a..f2adab7567 100644 --- a/deps/v8/src/handles.cc +++ b/deps/v8/src/handles.cc @@ -197,7 +197,17 @@ void TransformToFastProperties(Handle object, void FlattenString(Handle string) { CALL_HEAP_FUNCTION_VOID(string->TryFlatten()); +} + + +Handle FlattenGetString(Handle string) { + Handle result; + CALL_AND_RETRY(string->TryFlatten(), + { result = Handle(String::cast(__object__)); + break; }, + return Handle()); ASSERT(string->IsFlat()); + return result; } diff --git a/deps/v8/src/handles.h b/deps/v8/src/handles.h index 96b17a653c..1e14daf9a9 100644 --- a/deps/v8/src/handles.h +++ b/deps/v8/src/handles.h @@ -193,8 +193,14 @@ void NormalizeProperties(Handle object, void NormalizeElements(Handle object); void TransformToFastProperties(Handle object, int unused_property_fields); + +// Flattens a string. void FlattenString(Handle str); +// Flattens a string and returns the underlying external or sequential +// string. +Handle FlattenGetString(Handle str); + Handle SetProperty(Handle object, Handle key, Handle value, diff --git a/deps/v8/src/ia32/codegen-ia32.cc b/deps/v8/src/ia32/codegen-ia32.cc index c0c54426a3..1a847c1681 100644 --- a/deps/v8/src/ia32/codegen-ia32.cc +++ b/deps/v8/src/ia32/codegen-ia32.cc @@ -11686,16 +11686,18 @@ void CompareStub::Generate(MacroAssembler* masm) { __ Set(eax, Immediate(Smi::FromInt(EQUAL))); __ ret(0); } else { - Label return_equal; Label heap_number; - // If it's not a heap number, then return equal. __ cmp(FieldOperand(edx, HeapObject::kMapOffset), Immediate(Factory::heap_number_map())); - __ j(equal, &heap_number); - __ bind(&return_equal); - __ Set(eax, Immediate(Smi::FromInt(EQUAL))); - __ ret(0); - + if (cc_ == equal) { + __ j(equal, &heap_number); + // Identical objects are equal for operators ==, !=, and ===. + __ Set(eax, Immediate(Smi::FromInt(EQUAL))); + __ ret(0); + } else { + // Identical objects must call ToPrimitive for <, <=, >, and >=. + __ j(not_equal, ¬_identical); + } __ bind(&heap_number); // It is a heap number, so return non-equal if it's NaN and equal if // it's not NaN. diff --git a/deps/v8/src/json.js b/deps/v8/src/json.js index e5ee03d31d..cdb10be1aa 100644 --- a/deps/v8/src/json.js +++ b/deps/v8/src/json.js @@ -241,7 +241,7 @@ function JSONStringify(value, replacer, space) { } var gap; if (IS_NUMBER(space)) { - space = $Math.min(space, 10); + space = $Math.min(ToInteger(space), 10); gap = ""; for (var i = 0; i < space; i++) { gap += " "; diff --git a/deps/v8/src/jsregexp.cc b/deps/v8/src/jsregexp.cc index 3e9c5eab9a..9f98782bbc 100644 --- a/deps/v8/src/jsregexp.cc +++ b/deps/v8/src/jsregexp.cc @@ -356,7 +356,16 @@ int RegExpImpl::IrregexpPrepare(Handle regexp, if (!subject->IsFlat()) { FlattenString(subject); } - bool is_ascii = subject->IsAsciiRepresentation(); + // Check the asciiness of the underlying storage. + bool is_ascii; + { + AssertNoAllocation no_gc; + String* sequential_string = *subject; + if (subject->IsConsString()) { + sequential_string = ConsString::cast(*subject)->first(); + } + is_ascii = sequential_string->IsAsciiRepresentation(); + } if (!EnsureCompiledIrregexp(regexp, is_ascii)) { return -1; } @@ -381,6 +390,11 @@ RegExpImpl::IrregexpResult RegExpImpl::IrregexpExecOnce(Handle regexp, ASSERT(index <= subject->length()); ASSERT(subject->IsFlat()); + // A flat ASCII string might have a two-byte first part. + if (subject->IsConsString()) { + subject = Handle(ConsString::cast(*subject)->first()); + } + #ifndef V8_INTERPRETED_REGEXP ASSERT(output.length() >= (IrregexpNumberOfCaptures(*irregexp) + 1) * 2); @@ -407,7 +421,7 @@ RegExpImpl::IrregexpResult RegExpImpl::IrregexpExecOnce(Handle regexp, // If result is RETRY, the string has changed representation, and we // must restart from scratch. // In this case, it means we must make sure we are prepared to handle - // the, potentially, differen subject (the string can switch between + // the, potentially, different subject (the string can switch between // being internal and external, and even between being ASCII and UC16, // but the characters are always the same). IrregexpPrepare(regexp, subject); diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index 5a057e1643..883b28ef42 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -678,7 +678,7 @@ Object* String::SlowTryFlatten(PretenureFlag pretenure) { bool String::MakeExternal(v8::String::ExternalStringResource* resource) { - // Externalizing twice leaks the external resouce, so it's + // Externalizing twice leaks the external resource, so it's // prohibited by the API. ASSERT(!this->IsExternalString()); #ifdef DEBUG diff --git a/deps/v8/src/regexp-macro-assembler.cc b/deps/v8/src/regexp-macro-assembler.cc index fc6594759c..09797ca2a4 100644 --- a/deps/v8/src/regexp-macro-assembler.cc +++ b/deps/v8/src/regexp-macro-assembler.cc @@ -120,8 +120,6 @@ NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Match( int start_offset = previous_index; int end_offset = subject_ptr->length(); - bool is_ascii = subject->IsAsciiRepresentation(); - // The string has been flattened, so it it is a cons string it contains the // full string in the first part. if (StringShape(subject_ptr).IsCons()) { @@ -129,7 +127,7 @@ NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Match( subject_ptr = ConsString::cast(subject_ptr)->first(); } // Ensure that an underlying string has the same ascii-ness. - ASSERT(subject_ptr->IsAsciiRepresentation() == is_ascii); + bool is_ascii = subject_ptr->IsAsciiRepresentation(); ASSERT(subject_ptr->IsExternalString() || subject_ptr->IsSeqString()); // String is now either Sequential or External int char_size_shift = is_ascii ? 0 : 1; diff --git a/deps/v8/src/regexp.js b/deps/v8/src/regexp.js index f0945b3459..58e620d9ab 100644 --- a/deps/v8/src/regexp.js +++ b/deps/v8/src/regexp.js @@ -296,14 +296,14 @@ function RegExpTest(string) { return cache.answer; } - // Remove irrelevant preceeding '.*' in a test regexp. The expression - // checks whether this.source starts with '.*' and that the third + // Remove irrelevant preceeding '.*' in a test regexp. The expression + // checks whether this.source starts with '.*' and that the third // char is not a '?' if (%_StringCharCodeAt(this.source,0) == 46 && // '.' - %_StringCharCodeAt(this.source,1) == 42 && // '*' - %_StringCharCodeAt(this.source,2) != 63) { // '?' + %_StringCharCodeAt(this.source,1) == 42 && // '*' + %_StringCharCodeAt(this.source,2) != 63) { // '?' if (!%_ObjectEquals(regexp_key, this)) { - regexp_key = this; + regexp_key = this; regexp_val = new $RegExp(this.source.substring(2, this.source.length), (this.global ? 'g' : '') + (this.ignoreCase ? 'i' : '') @@ -311,7 +311,7 @@ function RegExpTest(string) { } if (!regexp_val.test(s)) return false; } - + var length = s.length; var i = this.global ? TO_INTEGER(lastIndex) : 0; diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc index 8625053894..22e80b33e0 100644 --- a/deps/v8/src/runtime.cc +++ b/deps/v8/src/runtime.cc @@ -2782,13 +2782,17 @@ int Runtime::StringMatch(Handle sub, // algorithm is unnecessary overhead. if (pattern_length == 1) { AssertNoAllocation no_heap_allocation; // ensure vectors stay valid - if (sub->IsAsciiRepresentation()) { + String* seq_sub = *sub; + if (seq_sub->IsConsString()) { + seq_sub = ConsString::cast(seq_sub)->first(); + } + if (seq_sub->IsAsciiRepresentation()) { uc16 pchar = pat->Get(0); if (pchar > String::kMaxAsciiCharCode) { return -1; } Vector ascii_vector = - sub->ToAsciiVector().SubVector(start_index, subject_length); + seq_sub->ToAsciiVector().SubVector(start_index, subject_length); const void* pos = memchr(ascii_vector.start(), static_cast(pchar), static_cast(ascii_vector.length())); @@ -2798,7 +2802,9 @@ int Runtime::StringMatch(Handle sub, return static_cast(reinterpret_cast(pos) - ascii_vector.start() + start_index); } - return SingleCharIndexOf(sub->ToUC16Vector(), pat->Get(0), start_index); + return SingleCharIndexOf(seq_sub->ToUC16Vector(), + pat->Get(0), + start_index); } if (!pat->IsFlat()) { @@ -2806,19 +2812,29 @@ int Runtime::StringMatch(Handle sub, } AssertNoAllocation no_heap_allocation; // ensure vectors stay valid + // Extract flattened substrings of cons strings before determining asciiness. + String* seq_sub = *sub; + if (seq_sub->IsConsString()) { + seq_sub = ConsString::cast(seq_sub)->first(); + } + String* seq_pat = *pat; + if (seq_pat->IsConsString()) { + seq_pat = ConsString::cast(seq_pat)->first(); + } + // dispatch on type of strings - if (pat->IsAsciiRepresentation()) { - Vector pat_vector = pat->ToAsciiVector(); - if (sub->IsAsciiRepresentation()) { - return StringSearch(sub->ToAsciiVector(), pat_vector, start_index); + if (seq_pat->IsAsciiRepresentation()) { + Vector pat_vector = seq_pat->ToAsciiVector(); + if (seq_sub->IsAsciiRepresentation()) { + return StringSearch(seq_sub->ToAsciiVector(), pat_vector, start_index); } - return StringSearch(sub->ToUC16Vector(), pat_vector, start_index); + return StringSearch(seq_sub->ToUC16Vector(), pat_vector, start_index); } - Vector pat_vector = pat->ToUC16Vector(); - if (sub->IsAsciiRepresentation()) { - return StringSearch(sub->ToAsciiVector(), pat_vector, start_index); + Vector pat_vector = seq_pat->ToUC16Vector(); + if (seq_sub->IsAsciiRepresentation()) { + return StringSearch(seq_sub->ToAsciiVector(), pat_vector, start_index); } - return StringSearch(sub->ToUC16Vector(), pat_vector, start_index); + return StringSearch(seq_sub->ToUC16Vector(), pat_vector, start_index); } @@ -9063,7 +9079,7 @@ static Object* Runtime_SetFunctionBreakPoint(Arguments args) { // Set break point. Debug::SetBreakPoint(shared, break_point_object_arg, &source_position); - return Heap::undefined_value(); + return Smi::FromInt(source_position); } diff --git a/deps/v8/src/runtime.js b/deps/v8/src/runtime.js index 3e4d473c27..ab6e3e9df1 100644 --- a/deps/v8/src/runtime.js +++ b/deps/v8/src/runtime.js @@ -112,7 +112,7 @@ function STRICT_EQUALS(x) { // the result when either (or both) the operands are NaN. function COMPARE(x, ncr) { var left; - + var right; // Fast cases for string, numbers and undefined compares. if (IS_STRING(this)) { if (IS_STRING(x)) return %_StringCompare(this, x); @@ -123,14 +123,18 @@ function COMPARE(x, ncr) { if (IS_UNDEFINED(x)) return ncr; left = this; } else if (IS_UNDEFINED(this)) { + if (!IS_UNDEFINED(x)) { + %ToPrimitive(x, NUMBER_HINT); + } + return ncr; + } else if (IS_UNDEFINED(x)) { + %ToPrimitive(this, NUMBER_HINT); return ncr; } else { - if (IS_UNDEFINED(x)) return ncr; left = %ToPrimitive(this, NUMBER_HINT); } - // Default implementation. - var right = %ToPrimitive(x, NUMBER_HINT); + right = %ToPrimitive(x, NUMBER_HINT); if (IS_STRING(left) && IS_STRING(right)) { return %_StringCompare(left, right); } else { diff --git a/deps/v8/src/type-info.h b/deps/v8/src/type-info.h index 9d20bc19df..91ecab8f5b 100644 --- a/deps/v8/src/type-info.h +++ b/deps/v8/src/type-info.h @@ -79,7 +79,7 @@ class TypeInfo { // Decode compact representation. Very sensitive to enum values below! static TypeInfo ExpandedRepresentation(int three_bit_representation) { - Type t = static_cast(three_bit_representation >= 6 ? + Type t = static_cast(three_bit_representation > 4 ? three_bit_representation + 2 : three_bit_representation); t = (t == kUnknownType) ? t : static_cast(t | kPrimitiveType); diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc index 4cc7e1be49..68c2e7320b 100644 --- a/deps/v8/src/version.cc +++ b/deps/v8/src/version.cc @@ -34,7 +34,7 @@ // cannot be changed without changing the SCons build script. #define MAJOR_VERSION 2 #define MINOR_VERSION 2 -#define BUILD_NUMBER 20 +#define BUILD_NUMBER 21 #define PATCH_LEVEL 0 #define CANDIDATE_VERSION false diff --git a/deps/v8/src/x64/assembler-x64.cc b/deps/v8/src/x64/assembler-x64.cc index 2bb92d7e25..c19e2ba130 100644 --- a/deps/v8/src/x64/assembler-x64.cc +++ b/deps/v8/src/x64/assembler-x64.cc @@ -1563,7 +1563,7 @@ void Assembler::movq(Register dst, Handle value, RelocInfo::Mode mode) { void Assembler::movsxbq(Register dst, const Operand& src) { EnsureSpace ensure_space(this); last_pc_ = pc_; - emit_rex_32(dst, src); + emit_rex_64(dst, src); emit(0x0F); emit(0xBE); emit_operand(dst, src); @@ -1601,7 +1601,7 @@ void Assembler::movsxlq(Register dst, const Operand& src) { void Assembler::movzxbq(Register dst, const Operand& src) { EnsureSpace ensure_space(this); last_pc_ = pc_; - emit_rex_64(dst, src); + emit_optional_rex_32(dst, src); emit(0x0F); emit(0xB6); emit_operand(dst, src); @@ -1621,7 +1621,7 @@ void Assembler::movzxbl(Register dst, const Operand& src) { void Assembler::movzxwq(Register dst, const Operand& src) { EnsureSpace ensure_space(this); last_pc_ = pc_; - emit_rex_64(dst, src); + emit_optional_rex_32(dst, src); emit(0x0F); emit(0xB7); emit_operand(dst, src); diff --git a/deps/v8/src/x64/codegen-x64.cc b/deps/v8/src/x64/codegen-x64.cc index 0c4cd16cee..a6d31be79f 100644 --- a/deps/v8/src/x64/codegen-x64.cc +++ b/deps/v8/src/x64/codegen-x64.cc @@ -856,7 +856,7 @@ void CodeGenerator::CallApplyLazy(Expression* applicand, __ j(equal, &adapted); // No arguments adaptor frame. Copy fixed number of arguments. - __ movq(rax, Immediate(scope()->num_parameters())); + __ Set(rax, scope()->num_parameters()); for (int i = 0; i < scope()->num_parameters(); i++) { __ push(frame_->ParameterAt(i)); } @@ -5342,13 +5342,18 @@ void CodeGenerator::ToBoolean(ControlDestination* dest) { } // Smi => false iff zero. __ SmiCompare(value.reg(), Smi::FromInt(0)); - dest->false_target()->Branch(equal); - Condition is_smi = masm_->CheckSmi(value.reg()); - dest->true_target()->Branch(is_smi); - __ xorpd(xmm0, xmm0); - __ ucomisd(xmm0, FieldOperand(value.reg(), HeapNumber::kValueOffset)); - value.Unuse(); - dest->Split(not_zero); + if (value.is_smi()) { + value.Unuse(); + dest->Split(not_zero); + } else { + dest->false_target()->Branch(equal); + Condition is_smi = masm_->CheckSmi(value.reg()); + dest->true_target()->Branch(is_smi); + __ xorpd(xmm0, xmm0); + __ ucomisd(xmm0, FieldOperand(value.reg(), HeapNumber::kValueOffset)); + value.Unuse(); + dest->Split(not_zero); + } } else { // Fast case checks. // 'false' => false. @@ -8959,23 +8964,32 @@ void CompareStub::Generate(MacroAssembler* masm) { // Test for NaN. Sadly, we can't just compare to Factory::nan_value(), // so we do the second best thing - test it ourselves. // Note: if cc_ != equal, never_nan_nan_ is not used. - __ Set(rax, EQUAL); + // We cannot set rax to EQUAL until just before return because + // rax must be unchanged on jump to not_identical. + if (never_nan_nan_ && (cc_ == equal)) { + __ Set(rax, EQUAL); __ ret(0); } else { Label heap_number; - // If it's not a heap number, then return equal. + // If it's not a heap number, then return equal for (in)equality operator. __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), Factory::heap_number_map()); - __ j(equal, &heap_number); - __ ret(0); + if (cc_ == equal) { + __ j(equal, &heap_number); + __ Set(rax, EQUAL); + __ ret(0); + } else { + // Identical objects must still be converted to primitive for < and >. + __ j(not_equal, ¬_identical); + } __ bind(&heap_number); // It is a heap number, so return equal if it's not NaN. // For NaN, return 1 for every condition except greater and // greater-equal. Return -1 for them, so the comparison yields // false for all conditions except not-equal. - + __ Set(rax, EQUAL); __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); __ ucomisd(xmm0, xmm0); __ setcc(parity_even, rax); @@ -9058,16 +9072,16 @@ void CompareStub::Generate(MacroAssembler* masm) { Label non_number_comparison; Label unordered; FloatingPointHelper::LoadSSE2UnknownOperands(masm, &non_number_comparison); + __ xorl(rax, rax); + __ xorl(rcx, rcx); __ ucomisd(xmm0, xmm1); // Don't base result on EFLAGS when a NaN is involved. __ j(parity_even, &unordered); // Return a result of -1, 0, or 1, based on EFLAGS. - __ movq(rax, Immediate(0)); // equal - __ movq(rcx, Immediate(1)); - __ cmovq(above, rax, rcx); - __ movq(rcx, Immediate(-1)); - __ cmovq(below, rax, rcx); + __ setcc(above, rax); + __ setcc(below, rcx); + __ subq(rax, rcx); __ ret(2 * kPointerSize); // rax, rdx were pushed // If one of the numbers was NaN, then the result is always false. diff --git a/deps/v8/src/x64/disasm-x64.cc b/deps/v8/src/x64/disasm-x64.cc index 002a5ebc7b..06a8c79629 100644 --- a/deps/v8/src/x64/disasm-x64.cc +++ b/deps/v8/src/x64/disasm-x64.cc @@ -468,20 +468,20 @@ int DisassemblerX64::PrintRightOperandHelper( if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) { // index == rsp means no index. Only use sib byte with no index for // rsp and r12 base. - AppendToBuffer("[%s]", (this->*register_name)(base)); + AppendToBuffer("[%s]", NameOfCPURegister(base)); return 2; } else if (base == 5) { // base == rbp means no base register (when mod == 0). int32_t disp = *reinterpret_cast(modrmp + 2); AppendToBuffer("[%s*%d+0x%x]", - (this->*register_name)(index), + NameOfCPURegister(index), 1 << scale, disp); return 6; } else if (index != 4 && base != 5) { // [base+index*scale] AppendToBuffer("[%s+%s*%d]", - (this->*register_name)(base), - (this->*register_name)(index), + NameOfCPURegister(base), + NameOfCPURegister(index), 1 << scale); return 2; } else { @@ -489,7 +489,7 @@ int DisassemblerX64::PrintRightOperandHelper( return 1; } } else { - AppendToBuffer("[%s]", (this->*register_name)(rm)); + AppendToBuffer("[%s]", NameOfCPURegister(rm)); return 1; } break; @@ -503,21 +503,21 @@ int DisassemblerX64::PrintRightOperandHelper( : *reinterpret_cast(modrmp + 2); if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) { if (-disp > 0) { - AppendToBuffer("[%s-0x%x]", (this->*register_name)(base), -disp); + AppendToBuffer("[%s-0x%x]", NameOfCPURegister(base), -disp); } else { - AppendToBuffer("[%s+0x%x]", (this->*register_name)(base), disp); + AppendToBuffer("[%s+0x%x]", NameOfCPURegister(base), disp); } } else { if (-disp > 0) { AppendToBuffer("[%s+%s*%d-0x%x]", - (this->*register_name)(base), - (this->*register_name)(index), + NameOfCPURegister(base), + NameOfCPURegister(index), 1 << scale, -disp); } else { AppendToBuffer("[%s+%s*%d+0x%x]", - (this->*register_name)(base), - (this->*register_name)(index), + NameOfCPURegister(base), + NameOfCPURegister(index), 1 << scale, disp); } @@ -528,9 +528,9 @@ int DisassemblerX64::PrintRightOperandHelper( int disp = (mod == 2) ? *reinterpret_cast(modrmp + 1) : *reinterpret_cast(modrmp + 1); if (-disp > 0) { - AppendToBuffer("[%s-0x%x]", (this->*register_name)(rm), -disp); + AppendToBuffer("[%s-0x%x]", NameOfCPURegister(rm), -disp); } else { - AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp); + AppendToBuffer("[%s+0x%x]", NameOfCPURegister(rm), disp); } return (mod == 2) ? 5 : 2; } diff --git a/deps/v8/src/x64/macro-assembler-x64.cc b/deps/v8/src/x64/macro-assembler-x64.cc index 32cd2dbc13..3b2c789d1b 100644 --- a/deps/v8/src/x64/macro-assembler-x64.cc +++ b/deps/v8/src/x64/macro-assembler-x64.cc @@ -351,7 +351,7 @@ void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) { // arguments passed in because it is constant. At some point we // should remove this need and make the runtime routine entry code // smarter. - movq(rax, Immediate(num_arguments)); + Set(rax, num_arguments); movq(rbx, ExternalReference(f)); CEntryStub ces(f->result_size); CallStub(&ces); @@ -360,7 +360,7 @@ void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) { void MacroAssembler::CallExternalReference(const ExternalReference& ext, int num_arguments) { - movq(rax, Immediate(num_arguments)); + Set(rax, num_arguments); movq(rbx, ext); CEntryStub stub(1); @@ -382,7 +382,7 @@ void MacroAssembler::TailCallExternalReference(const ExternalReference& ext, // arguments passed in because it is constant. At some point we // should remove this need and make the runtime routine entry code // smarter. - movq(rax, Immediate(num_arguments)); + Set(rax, num_arguments); JumpToExternalReference(ext, result_size); } @@ -640,9 +640,9 @@ Condition MacroAssembler::CheckBothSmi(Register first, Register second) { if (first.is(second)) { return CheckSmi(first); } - movl(kScratchRegister, first); - orl(kScratchRegister, second); - testb(kScratchRegister, Immediate(kSmiTagMask)); + ASSERT(kSmiTag == 0 && kHeapObjectTag == 1 && kHeapObjectTagMask == 3); + leal(kScratchRegister, Operand(first, second, times_1, 0)); + testb(kScratchRegister, Immediate(0x03)); return zero; } @@ -1937,7 +1937,7 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, if (expected.immediate() == actual.immediate()) { definitely_matches = true; } else { - movq(rax, Immediate(actual.immediate())); + Set(rax, actual.immediate()); if (expected.immediate() == SharedFunctionInfo::kDontAdaptArgumentsSentinel) { // Don't worry about adapting arguments for built-ins that @@ -1946,7 +1946,7 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, // arguments. definitely_matches = true; } else { - movq(rbx, Immediate(expected.immediate())); + Set(rbx, expected.immediate()); } } } else { @@ -1957,7 +1957,7 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, cmpq(expected.reg(), Immediate(actual.immediate())); j(equal, &invoke); ASSERT(expected.reg().is(rbx)); - movq(rax, Immediate(actual.immediate())); + Set(rax, actual.immediate()); } else if (!expected.reg().is(actual.reg())) { // Both expected and actual are in (different) registers. This // is the case when we invoke functions using call and apply. diff --git a/deps/v8/src/x64/virtual-frame-x64.cc b/deps/v8/src/x64/virtual-frame-x64.cc index f5e17fd18f..3a0b72fc6c 100644 --- a/deps/v8/src/x64/virtual-frame-x64.cc +++ b/deps/v8/src/x64/virtual-frame-x64.cc @@ -1221,7 +1221,7 @@ Result VirtualFrame::CallConstructor(int arg_count) { // call trampolines per different arguments counts encountered. Result num_args = cgen()->allocator()->Allocate(rax); ASSERT(num_args.is_valid()); - __ movq(num_args.reg(), Immediate(arg_count)); + __ Set(num_args.reg(), arg_count); function.Unuse(); num_args.Unuse(); diff --git a/deps/v8/test/cctest/SConscript b/deps/v8/test/cctest/SConscript index 876c104bca..18388c0273 100644 --- a/deps/v8/test/cctest/SConscript +++ b/deps/v8/test/cctest/SConscript @@ -69,8 +69,9 @@ SOURCES = { 'test-sockets.cc', 'test-spaces.cc', 'test-strings.cc', - 'test-threads.cc', 'test-thread-termination.cc', + 'test-threads.cc', + 'test-type-info.cc', 'test-unbound-queue.cc', 'test-utils.cc', 'test-version.cc' diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index 0cf3f7ba41..be5ecba688 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -58,7 +58,7 @@ using ::v8::Function; using ::v8::AccessorInfo; using ::v8::Extension; -namespace i = ::v8::internal; +namespace i = ::i; static void ExpectString(const char* code, const char* expected) { @@ -381,11 +381,11 @@ THREADED_TEST(ScriptUsingStringResource) { CHECK(source->IsExternal()); CHECK_EQ(resource, static_cast(source->GetExternalStringResource())); - v8::internal::Heap::CollectAllGarbage(false); + i::Heap::CollectAllGarbage(false); CHECK_EQ(0, TestResource::dispose_count); } - v8::internal::CompilationCache::Clear(); - v8::internal::Heap::CollectAllGarbage(false); + i::CompilationCache::Clear(); + i::Heap::CollectAllGarbage(false); CHECK_EQ(1, TestResource::dispose_count); } @@ -402,11 +402,11 @@ THREADED_TEST(ScriptUsingAsciiStringResource) { Local value = script->Run(); CHECK(value->IsNumber()); CHECK_EQ(7, value->Int32Value()); - v8::internal::Heap::CollectAllGarbage(false); + i::Heap::CollectAllGarbage(false); CHECK_EQ(0, TestAsciiResource::dispose_count); } - v8::internal::CompilationCache::Clear(); - v8::internal::Heap::CollectAllGarbage(false); + i::CompilationCache::Clear(); + i::Heap::CollectAllGarbage(false); CHECK_EQ(1, TestAsciiResource::dispose_count); } @@ -427,11 +427,11 @@ THREADED_TEST(ScriptMakingExternalString) { Local value = script->Run(); CHECK(value->IsNumber()); CHECK_EQ(7, value->Int32Value()); - v8::internal::Heap::CollectAllGarbage(false); + i::Heap::CollectAllGarbage(false); CHECK_EQ(0, TestResource::dispose_count); } - v8::internal::CompilationCache::Clear(); - v8::internal::Heap::CollectAllGarbage(false); + i::CompilationCache::Clear(); + i::Heap::CollectAllGarbage(false); CHECK_EQ(1, TestResource::dispose_count); } @@ -453,11 +453,11 @@ THREADED_TEST(ScriptMakingExternalAsciiString) { Local value = script->Run(); CHECK(value->IsNumber()); CHECK_EQ(7, value->Int32Value()); - v8::internal::Heap::CollectAllGarbage(false); + i::Heap::CollectAllGarbage(false); CHECK_EQ(0, TestAsciiResource::dispose_count); } - v8::internal::CompilationCache::Clear(); - v8::internal::Heap::CollectAllGarbage(false); + i::CompilationCache::Clear(); + i::Heap::CollectAllGarbage(false); CHECK_EQ(1, TestAsciiResource::dispose_count); } @@ -645,11 +645,11 @@ TEST(ExternalStringWithDisposeHandling) { Local value = script->Run(); CHECK(value->IsNumber()); CHECK_EQ(7, value->Int32Value()); - v8::internal::Heap::CollectAllGarbage(false); + i::Heap::CollectAllGarbage(false); CHECK_EQ(0, TestAsciiResource::dispose_count); } - v8::internal::CompilationCache::Clear(); - v8::internal::Heap::CollectAllGarbage(false); + i::CompilationCache::Clear(); + i::Heap::CollectAllGarbage(false); CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls); CHECK_EQ(0, TestAsciiResource::dispose_count); @@ -666,11 +666,11 @@ TEST(ExternalStringWithDisposeHandling) { Local value = script->Run(); CHECK(value->IsNumber()); CHECK_EQ(7, value->Int32Value()); - v8::internal::Heap::CollectAllGarbage(false); + i::Heap::CollectAllGarbage(false); CHECK_EQ(0, TestAsciiResource::dispose_count); } - v8::internal::CompilationCache::Clear(); - v8::internal::Heap::CollectAllGarbage(false); + i::CompilationCache::Clear(); + i::Heap::CollectAllGarbage(false); CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls); CHECK_EQ(1, TestAsciiResource::dispose_count); } @@ -708,7 +708,7 @@ THREADED_TEST(StringConcat) { CHECK(value->IsNumber()); CHECK_EQ(68, value->Int32Value()); } - v8::internal::CompilationCache::Clear(); + i::CompilationCache::Clear(); i::Heap::CollectAllGarbage(false); i::Heap::CollectAllGarbage(false); } @@ -1881,7 +1881,7 @@ static const char* js_code_causing_out_of_memory = // that come after them so they cannot run in parallel. TEST(OutOfMemory) { // It's not possible to read a snapshot into a heap with different dimensions. - if (v8::internal::Snapshot::IsEnabled()) return; + if (i::Snapshot::IsEnabled()) return; // Set heap limits. static const int K = 1024; v8::ResourceConstraints constraints; @@ -1922,7 +1922,7 @@ v8::Handle ProvokeOutOfMemory(const v8::Arguments& args) { TEST(OutOfMemoryNested) { // It's not possible to read a snapshot into a heap with different dimensions. - if (v8::internal::Snapshot::IsEnabled()) return; + if (i::Snapshot::IsEnabled()) return; // Set heap limits. static const int K = 1024; v8::ResourceConstraints constraints; @@ -1951,7 +1951,7 @@ TEST(OutOfMemoryNested) { TEST(HugeConsStringOutOfMemory) { // It's not possible to read a snapshot into a heap with different dimensions. - if (v8::internal::Snapshot::IsEnabled()) return; + if (i::Snapshot::IsEnabled()) return; v8::HandleScope scope; LocalContext context; // Set heap limits. @@ -6811,7 +6811,7 @@ static v8::Handle InterceptorCallICFastApi(Local name, int* call_count = reinterpret_cast(v8::External::Unwrap(info.Data())); ++(*call_count); if ((*call_count) % 20 == 0) { - v8::internal::Heap::CollectAllGarbage(true); + i::Heap::CollectAllGarbage(true); } return v8::Handle(); } @@ -7620,8 +7620,8 @@ THREADED_TEST(ObjectProtoToString) { bool ApiTestFuzzer::fuzzing_ = false; -v8::internal::Semaphore* ApiTestFuzzer::all_tests_done_= - v8::internal::OS::CreateSemaphore(0); +i::Semaphore* ApiTestFuzzer::all_tests_done_= + i::OS::CreateSemaphore(0); int ApiTestFuzzer::active_tests_; int ApiTestFuzzer::tests_being_run_; int ApiTestFuzzer::current_; @@ -7899,7 +7899,7 @@ THREADED_TEST(LockUnlockLock) { static int GetGlobalObjectsCount() { int count = 0; - v8::internal::HeapIterator it; + i::HeapIterator it; for (i::HeapObject* object = it.next(); object != NULL; object = it.next()) if (object->IsJSGlobalObject()) count++; return count; @@ -7912,11 +7912,11 @@ static int GetSurvivingGlobalObjectsCount() { // the first garbage collection but some of the maps have already // been marked at that point. Therefore some of the maps are not // collected until the second garbage collection. - v8::internal::Heap::CollectAllGarbage(false); - v8::internal::Heap::CollectAllGarbage(false); + i::Heap::CollectAllGarbage(false); + i::Heap::CollectAllGarbage(false); int count = GetGlobalObjectsCount(); #ifdef DEBUG - if (count > 0) v8::internal::Heap::TracePathToGlobal(); + if (count > 0) i::Heap::TracePathToGlobal(); #endif return count; } @@ -10021,7 +10021,7 @@ static void ExternalArrayTestHelper(v8::ExternalArrayType array_type, THREADED_TEST(ExternalByteArray) { - ExternalArrayTestHelper( + ExternalArrayTestHelper( v8::kExternalByteArray, -128, 127); @@ -10029,7 +10029,7 @@ THREADED_TEST(ExternalByteArray) { THREADED_TEST(ExternalUnsignedByteArray) { - ExternalArrayTestHelper( + ExternalArrayTestHelper( v8::kExternalUnsignedByteArray, 0, 255); @@ -10037,7 +10037,7 @@ THREADED_TEST(ExternalUnsignedByteArray) { THREADED_TEST(ExternalShortArray) { - ExternalArrayTestHelper( + ExternalArrayTestHelper( v8::kExternalShortArray, -32768, 32767); @@ -10045,7 +10045,7 @@ THREADED_TEST(ExternalShortArray) { THREADED_TEST(ExternalUnsignedShortArray) { - ExternalArrayTestHelper( + ExternalArrayTestHelper( v8::kExternalUnsignedShortArray, 0, 65535); @@ -10053,7 +10053,7 @@ THREADED_TEST(ExternalUnsignedShortArray) { THREADED_TEST(ExternalIntArray) { - ExternalArrayTestHelper( + ExternalArrayTestHelper( v8::kExternalIntArray, INT_MIN, // -2147483648 INT_MAX); // 2147483647 @@ -10061,7 +10061,7 @@ THREADED_TEST(ExternalIntArray) { THREADED_TEST(ExternalUnsignedIntArray) { - ExternalArrayTestHelper( + ExternalArrayTestHelper( v8::kExternalUnsignedIntArray, 0, UINT_MAX); // 4294967295 @@ -10069,7 +10069,7 @@ THREADED_TEST(ExternalUnsignedIntArray) { THREADED_TEST(ExternalFloatArray) { - ExternalArrayTestHelper( + ExternalArrayTestHelper( v8::kExternalFloatArray, -500, 500); @@ -10547,7 +10547,7 @@ TEST(Regress528) { other_context->Enter(); CompileRun(source_simple); other_context->Exit(); - v8::internal::Heap::CollectAllGarbage(false); + i::Heap::CollectAllGarbage(false); if (GetGlobalObjectsCount() == 1) break; } CHECK_GE(2, gc_count); @@ -10569,7 +10569,7 @@ TEST(Regress528) { other_context->Enter(); CompileRun(source_eval); other_context->Exit(); - v8::internal::Heap::CollectAllGarbage(false); + i::Heap::CollectAllGarbage(false); if (GetGlobalObjectsCount() == 1) break; } CHECK_GE(2, gc_count); @@ -10596,7 +10596,7 @@ TEST(Regress528) { other_context->Enter(); CompileRun(source_exception); other_context->Exit(); - v8::internal::Heap::CollectAllGarbage(false); + i::Heap::CollectAllGarbage(false); if (GetGlobalObjectsCount() == 1) break; } CHECK_GE(2, gc_count); @@ -10859,7 +10859,7 @@ THREADED_TEST(AddToJSFunctionResultCache) { " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;" " return 'PASSED';" "})()"; - v8::internal::Heap::ClearJSFunctionResultCaches(); + i::Heap::ClearJSFunctionResultCaches(); ExpectString(code, "PASSED"); } @@ -10883,7 +10883,7 @@ THREADED_TEST(FillJSFunctionResultCache) { " return 'FAILED: k0CacheSize is too small';" " return 'PASSED';" "})()"; - v8::internal::Heap::ClearJSFunctionResultCaches(); + i::Heap::ClearJSFunctionResultCaches(); ExpectString(code, "PASSED"); } @@ -10908,7 +10908,7 @@ THREADED_TEST(RoundRobinGetFromCache) { " };" " return 'PASSED';" "})()"; - v8::internal::Heap::ClearJSFunctionResultCaches(); + i::Heap::ClearJSFunctionResultCaches(); ExpectString(code, "PASSED"); } @@ -10933,7 +10933,7 @@ THREADED_TEST(ReverseGetFromCache) { " };" " return 'PASSED';" "})()"; - v8::internal::Heap::ClearJSFunctionResultCaches(); + i::Heap::ClearJSFunctionResultCaches(); ExpectString(code, "PASSED"); } @@ -10951,6 +10951,87 @@ THREADED_TEST(TestEviction) { " };" " return 'PASSED';" "})()"; - v8::internal::Heap::ClearJSFunctionResultCaches(); + i::Heap::ClearJSFunctionResultCaches(); ExpectString(code, "PASSED"); } + + +THREADED_TEST(TwoByteStringInAsciiCons) { + // See Chromium issue 47824. + v8::HandleScope scope; + + LocalContext context; + const char* init_code = + "var str1 = 'abelspendabel';" + "var str2 = str1 + str1 + str1;" + "str2;"; + Local result = CompileRun(init_code); + + CHECK(result->IsString()); + i::Handle string = v8::Utils::OpenHandle(String::Cast(*result)); + int length = string->length(); + CHECK(string->IsAsciiRepresentation()); + + FlattenString(string); + i::Handle flat_string = FlattenGetString(string); + + CHECK(string->IsAsciiRepresentation()); + CHECK(flat_string->IsAsciiRepresentation()); + + // Create external resource. + uint16_t* uc16_buffer = new uint16_t[length + 1]; + + i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length); + uc16_buffer[length] = 0; + + TestResource resource(uc16_buffer); + + flat_string->MakeExternal(&resource); + + CHECK(flat_string->IsTwoByteRepresentation()); + + // At this point, we should have a Cons string which is flat and ASCII, + // with a first half that is a two-byte string (although it only contains + // ASCII characters). This is a valid sequence of steps, and it can happen + // in real pages. + + CHECK(string->IsAsciiRepresentation()); + i::ConsString* cons = i::ConsString::cast(*string); + CHECK_EQ(0, cons->second()->length()); + CHECK(cons->first()->IsTwoByteRepresentation()); + + // Check that some string operations work. + + // Atom RegExp. + Local reresult = CompileRun("str2.match(/abel/g).length;"); + CHECK_EQ(6, reresult->Int32Value()); + + // Nonatom RegExp. + reresult = CompileRun("str2.match(/abe./g).length;"); + CHECK_EQ(6, reresult->Int32Value()); + + reresult = CompileRun("str2.search(/bel/g);"); + CHECK_EQ(1, reresult->Int32Value()); + + reresult = CompileRun("str2.search(/be./g);"); + CHECK_EQ(1, reresult->Int32Value()); + + ExpectTrue("/bel/g.test(str2);"); + + ExpectTrue("/be./g.test(str2);"); + + reresult = CompileRun("/bel/g.exec(str2);"); + CHECK(!reresult->IsNull()); + + reresult = CompileRun("/be./g.exec(str2);"); + CHECK(!reresult->IsNull()); + + ExpectString("str2.substring(2, 10);", "elspenda"); + + ExpectString("str2.substring(2, 20);", "elspendabelabelspe"); + + ExpectString("str2.charAt(2);", "e"); + + reresult = CompileRun("str2.charCodeAt(2);"); + CHECK_EQ(static_cast('e'), reresult->Int32Value()); +} diff --git a/deps/v8/test/cctest/test-disasm-arm.cc b/deps/v8/test/cctest/test-disasm-arm.cc index 5903fe650b..18e641d6a3 100644 --- a/deps/v8/test/cctest/test-disasm-arm.cc +++ b/deps/v8/test/cctest/test-disasm-arm.cc @@ -401,3 +401,38 @@ TEST(Type3) { VERIFY_RUN(); } + + +TEST(Vfp) { + SETUP(); + + if (CpuFeatures::IsSupported(VFP3)) { + CpuFeatures::Scope scope(VFP3); + COMPARE(vadd(d0, d1, d2), + "ee310b02 vadd.f64 d0, d1, d2"); + COMPARE(vadd(d3, d4, d5, mi), + "4e343b05 vadd.f64mi d3, d4, d5"); + + COMPARE(vsub(d0, d1, d2), + "ee310b42 vsub.f64 d0, d1, d2"); + COMPARE(vsub(d3, d4, d5, ne), + "1e343b45 vsub.f64ne d3, d4, d5"); + + COMPARE(vmul(d2, d1, d0), + "ee212b00 vmul.f64 d2, d1, d0"); + COMPARE(vmul(d6, d4, d5, cc), + "3e246b05 vmul.f64cc d6, d4, d5"); + + COMPARE(vdiv(d2, d2, d2), + "ee822b02 vdiv.f64 d2, d2, d2"); + COMPARE(vdiv(d6, d7, d7, hi), + "8e876b07 vdiv.f64hi d6, d7, d7"); + + COMPARE(vsqrt(d0, d0), + "eeb10bc0 vsqrt.f64 d0, d0"); + COMPARE(vsqrt(d2, d3, ne), + "1eb12bc3 vsqrt.f64ne d2, d3"); + } + + VERIFY_RUN(); +} diff --git a/deps/v8/test/cctest/test-type-info.cc b/deps/v8/test/cctest/test-type-info.cc new file mode 100644 index 0000000000..59dd83d1f7 --- /dev/null +++ b/deps/v8/test/cctest/test-type-info.cc @@ -0,0 +1,56 @@ +// 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: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#include "cctest.h" +#include "type-info.h" + +namespace v8 { +namespace internal { + +TEST(ThreeBitRepresentation) { + // Numeric types and unknown should fit into the short + // representation. + CHECK(TypeInfo::ExpandedRepresentation( + TypeInfo::Unknown().ThreeBitRepresentation()).IsUnknown()); + CHECK(TypeInfo::ExpandedRepresentation( + TypeInfo::Number().ThreeBitRepresentation()).IsNumber()); + CHECK(TypeInfo::ExpandedRepresentation( + TypeInfo::Integer32().ThreeBitRepresentation()).IsInteger32()); + CHECK(TypeInfo::ExpandedRepresentation( + TypeInfo::Smi().ThreeBitRepresentation()).IsSmi()); + CHECK(TypeInfo::ExpandedRepresentation( + TypeInfo::Double().ThreeBitRepresentation()).IsDouble()); + + // Other types should map to unknown. + CHECK(TypeInfo::ExpandedRepresentation( + TypeInfo::Primitive().ThreeBitRepresentation()).IsUnknown()); + CHECK(TypeInfo::ExpandedRepresentation( + TypeInfo::String().ThreeBitRepresentation()).IsUnknown()); +} + +} } // namespace v8::internal diff --git a/deps/v8/test/es5conform/README b/deps/v8/test/es5conform/README index 9cfc92b4b9..675249e0f1 100644 --- a/deps/v8/test/es5conform/README +++ b/deps/v8/test/es5conform/README @@ -4,7 +4,7 @@ tests from https://es5conform.svn.codeplex.com/svn -in revision 62998 as 'data' in this directory. Using later version +in revision 71525 as 'data' in this directory. Using later version may be possible but the tests are only known to pass (and indeed run) with that revision. diff --git a/deps/v8/test/es5conform/es5conform.status b/deps/v8/test/es5conform/es5conform.status index 9d9dc3cd5f..8e1e941e02 100644 --- a/deps/v8/test/es5conform/es5conform.status +++ b/deps/v8/test/es5conform/es5conform.status @@ -29,91 +29,107 @@ prefix es5conform def UNIMPLEMENTED = PASS || FAIL def FAIL_OK = FAIL, OKAY -chapter07: UNIMPLEMENTED -chapter08: UNIMPLEMENTED -chapter10: UNIMPLEMENTED -chapter11: UNIMPLEMENTED -chapter12: UNIMPLEMENTED -chapter13: UNIMPLEMENTED -chapter14: UNIMPLEMENTED -chapter15/15.1: UNIMPLEMENTED -chapter15/15.2/15.2.3/15.2.3.1: UNIMPLEMENTED +# Non UTF8 characters in test files. +chapter10/10.4/10.4.2/10.4.2-3-c-2-s: FAIL_OK +chapter10/10.4/10.4.2/10.4.2-3-c-1-s: FAIL_OK +chapter10/10.4/10.4.2/10.4.2-2-c-1: FAIL_OK + +# We do not implement the error chekcs specified in the production rules +# of 11.1.5 (Object initializer). +# We are compatible with Safari and Firefox. +chapter11/11.1/11.1.5: UNIMPLEMENTED + +# Delete returns true in eval even when it should return false. +# Please see http://code.google.com/p/v8/issues/detail?id=759 +chapter11/11.4/11.4.1//11.4.1-4.a-5: FAIL +chapter11/11.4/11.4.1//11.4.1-4.a-7: FAIL + + +# We do not have a global object called 'global' as required by tests. +chapter15/15.1: FAIL_OK + +# NOT IMPLEMENTED: seal chapter15/15.2/15.2.3/15.2.3.8: UNIMPLEMENTED +# NOT IMPLEMENTED: freeze chapter15/15.2/15.2.3/15.2.3.9: UNIMPLEMENTED +# NOT IMPLEMENTED: preventExtensions chapter15/15.2/15.2.3/15.2.3.10: UNIMPLEMENTED +# NOT IMPLEMENTED: isSealed chapter15/15.2/15.2.3/15.2.3.11: UNIMPLEMENTED +# NOT IMPLEMENTED: isFrozen chapter15/15.2/15.2.3/15.2.3.12: UNIMPLEMENTED +# NOT IMPLEMENTED: isExtensible chapter15/15.2/15.2.3/15.2.3.13: UNIMPLEMENTED # NOT IMPLEMENTED: seal -chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-20: FAIL_OK +chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-20: UNIMPLEMENTED # NOT IMPLEMENTED: freeze -chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-21: FAIL_OK +chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-21: UNIMPLEMENTED # NOT IMPLEMENTED: preventExtensions -chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-22: FAIL_OK +chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-22: UNIMPLEMENTED # NOT IMPLEMENTED: isSealed -chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-23: FAIL_OK +chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-23: UNIMPLEMENTED # NOT IMPLEMENTED: isFrozen -chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-24: FAIL_OK +chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-24: UNIMPLEMENTED # NOT IMPLEMENTED: isExtensible -chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-25: FAIL_OK +chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-25: UNIMPLEMENTED # NOT IMPLEMENTED: bind -chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-38: FAIL_OK +chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-38: UNIMPLEMENTED -# NaN is writable +# NaN is writable. We are compatible with JSC. chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-178: FAIL_OK -# Infinity is writable +# Infinity is writable. We are compatible with JSC. chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-179: FAIL_OK -# undefined is writable +# undefined is writable. We are compatible with JSC. chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-180: FAIL_OK -# Our Function object has a "arguments" property which is used as a non -# property in in the test +# Our Function object has an "arguments" property which is used as a +# non-property in the test. chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-183: FAIL_OK -# Our Function object has a "caller" property which is used as a non -# property in in the test +# Our Function object has a "caller" property which is used as a +# non-property in in the test. chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-184: FAIL_OK -# Our function object has a name property which is used as a non -# property in the test +# Our function object has a name property which is used as a +# non-property in the test. chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-188: FAIL_OK # NOT IMPLEMENTED: RegExp.prototype.source -chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-212: FAIL_OK +chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-212: UNIMPLEMENTED # NOT IMPLEMENTED: RegExp.prototype.global -chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-213: FAIL_OK +chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-213: UNIMPLEMENTED # NOT IMPLEMENTED: RegExp.prototype.ignoreCase -chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-214: FAIL_OK +chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-214: UNIMPLEMENTED # NOT IMPLEMENTED: RegExp.prototype.multiline -chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-215: FAIL_OK +chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-215: UNIMPLEMENTED # All of the tests below marked SUBSETFAIL (in 15.2.3.4) fail because # the tests assumes that objects can not have more properties # than those described in the spec - but according to spec they can # have additional properties. # All compareArray calls in these tests could be exchanged with a -# isSubsetOfArray call (I will upload a path to the es5conform site) +# isSubsetOfArray call (I will upload a path to the es5conform site). # SUBSETFAIL chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-1: FAIL_OK -# SUBSETFAIL + we do not implement all methods on Object +# SUBSETFAIL + we do not implement all methods on Object. chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-2: FAIL_OK # SUBSETFAIL chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-3: FAIL_OK -# SUBSETFAIL + we do not implement Function.prototype.bind +# SUBSETFAIL + we do not implement Function.prototype.bind. chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-4: FAIL_OK # SUBSETFAIL @@ -134,29 +150,29 @@ chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-9: FAIL_OK # SUBSETFAIL chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-11: FAIL_OK -# We do not implement all methods on RegExp -chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-13: FAIL_OK +# We do not implement all methods on RegExp. +chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-13: FAIL # SUBSETFAIL chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-14: FAIL_OK -# EvalError.prototype does not have message property -chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-15: FAIL_OK +# EvalError.prototype does not have message property. +chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-15: FAIL -# Rangeerror.prototype does not have message property -chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-16: FAIL_OK +# Rangeerror.prototype does not have message property. +chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-16: FAIL -# ReferenceError.prototype does not have message property -chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-17: FAIL_OK +# ReferenceError.prototype does not have message property. +chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-17: FAIL -# SyntaxError.prototype does not have message property -chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-18: FAIL_OK +# SyntaxError.prototype does not have message property. +chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-18: FAIL -# TypeError.prototype does not have message property -chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-19: FAIL_OK +# TypeError.prototype does not have message property. +chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-19: FAIL -# URIError.prototype does not have message property -chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-20: FAIL_OK +# URIError.prototype does not have message property. +chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-20: FAIL # SUBSETFAIL chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-22: FAIL_OK @@ -200,68 +216,65 @@ chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-34: FAIL_OK # SUBSETFAIL chapter15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-35: FAIL_OK +# NOT IMPLEMENTED: bind on Function.prototype. +chapter15/15.3/15.3.4/15.3.4.5/15.3.4.5-0-1: UNIMPLEMENTED -# We fail this because Object.keys returns numbers for element indices -# rather than strings. -#chapter15/15.2/15.2.3/15.2.3.14/15.2.3.14-3-3: FAIL_OK - -chapter15/15.3: UNIMPLEMENTED - -chapter15/15.4/15.4.4/15.4.4.14: UNIMPLEMENTED -chapter15/15.4/15.4.4/15.4.4.15: UNIMPLEMENTED -chapter15/15.4/15.4.4/15.4.4.20: UNIMPLEMENTED -chapter15/15.4/15.4.4/15.4.4.21: UNIMPLEMENTED -chapter15/15.4/15.4.4/15.4.4.22: UNIMPLEMENTED +# Bad test - the spec does not say anything about throwing errors +# on calling Array.prototype.indexOf with undefined as argument. +chapter15/15.4/15.4.4/15.4.4.14/15.4.4.14-1-1: FAIL_OK -# Wrong test - because this is not given as argument to arr.every -# this._15_4_4_16_5_1 evaluates to undefined -chapter15/15.4/15.4.4/15.4.4.16/15.4.4.16-5-1: FAIL_OK +# Bad test - the spec does not say anything about throwing errors +# on calling Array.prototype.indexOf with null as argument. +chapter15/15.4/15.4.4/15.4.4.14/15.4.4.14-1-2: FAIL_OK -# In test case the element is not appended - it is added in the middle of -# the array -chapter15/15.4/15.4.4/15.4.4.16/15.4.4.16-7-1: FAIL_OK - -# We fail because the test assumes that if the reference to array is deleted it -# is not longer traversed -chapter15/15.4/15.4.4/15.4.4.16/15.4.4.16-7-7: FAIL_OK - -# if (val>1) in test should be if (val>2) -chapter15/15.4/15.4.4/15.4.4.16/15.4.4.16-8-10: FAIL_OK - -# Wrong assumption - according to spec some returns a Boolean, not a number -chapter15/15.4/15.4.4/15.4.4.17/15.4.4.17-4-9: FAIL_OK - -# Same as 15.4.4.16-5-1 -chapter15/15.4/15.4.4/15.4.4.17/15.4.4.17-5-1: FAIL_OK - -# Same as 15.4.4.16-7-1 -chapter15/15.4/15.4.4/15.4.4.17/15.4.4.17-7-1: FAIL_OK - -# Same as 15.4.4.16-7-7 -chapter15/15.4/15.4.4/15.4.4.17/15.4.4.17-7-7: FAIL_OK - -# Same as 15.4.4.16-10-8 +# Bad test - the test at the end should be "i === true". chapter15/15.4/15.4.4/15.4.4.17/15.4.4.17-8-10: FAIL_OK -# Same as 15.4.4.16-5-1 -chapter15/15.4/15.4.4/15.4.4.18/15.4.4.18-5-1: FAIL_OK - -# Same as 15.4.4.16-7-7 -chapter15/15.4/15.4.4/15.4.4.18/15.4.4.18-7-6: FAIL_OK - -# Same as 15.4.4.16-5-1 -chapter15/15.4/15.4.4/15.4.4.19/15.4.4.19-5-1: FAIL_OK - -# Same as 15.4.4.16-7-7 -chapter15/15.4/15.4.4/15.4.4.19/15.4.4.19-8-7: FAIL_OK - +# Bad test - according to spec some returns a Boolean, not a number. +chapter15/15.4/15.4.4/15.4.4.17/15.4.4.17-4-9: FAIL_OK -chapter15/15.5: UNIMPLEMENTED -chapter15/15.6: UNIMPLEMENTED -chapter15/15.7: UNIMPLEMENTED -chapter15/15.9: UNIMPLEMENTED -chapter15/15.10: UNIMPLEMENTED -chapter15/15.12: UNIMPLEMENTED +# Bad test - uses unitialized variable a in precondition check. +chapter15/15.4/15.4.4/15.4.4.19/15.4.4.19-9-3: FAIL_OK + +# We do not implement Array mapping functions correctly if array +# entries are added for nonexistent entries smaller than length by +# the callback function. We are compatible with JSC. +# See http://code.google.com/p/v8/issues/detail?id=755 +chapter15/15.4/15.4.4/15.4.4.22/15.4.4.22-9-1: FAIL_OK + +# Bad tests, path in test file is wrong. This will crash the test +# script so we mark it SKIP. +chapter15/15.4/15.4.4/15.4.4.22/15.4.4.22-9-c-ii-4: SKIP +chapter15/15.4/15.4.4/15.4.4.22/15.4.4.22-9-c-ii-4-s: SKIP + +# Bad test - deleting the property on o in callbackfn will +# have no effect on the actual array on which reduceRight is called. +chapter15/15.4/15.4.4/15.4.4.22/15.4.4.22-9-7: FAIL_OK + +# We do not implement trim correctly on null and undefined. +chapter15/15.5/15.5.4/15.5.4.20/15.5.4.20-1-1: FAIL +chapter15/15.5/15.5.4/15.5.4.20/15.5.4.20-1-2: FAIL + +# We do not correctly recognize \uFEFF as whitespace +chapter15/15.5/15.5.4/15.5.4.20/15.5.4.20-4-10: FAIL +chapter15/15.5/15.5.4/15.5.4.20/15.5.4.20-4-18: FAIL +chapter15/15.5/15.5.4/15.5.4.20/15.5.4.20-4-34: FAIL + +# RegExp.prototype is not of type RegExp - we are bug compatible with JSC. +chapter15/15.10/15.10.6/15.10.6: FAIL_OK + +# We do not have the properties of a RegExp instance on RegExp.prototype. +# The spec says we should - but we are currently bug compatible with JSC. +chapter15/15.10/15.10.7/15.10.7.1/15.10.7.1-1: FAIL_OK +chapter15/15.10/15.10.7/15.10.7.1/15.10.7.1-2: FAIL_OK +chapter15/15.10/15.10.7/15.10.7.2/15.10.7.2-1: FAIL_OK +chapter15/15.10/15.10.7/15.10.7.2/15.10.7.2-2: FAIL_OK +chapter15/15.10/15.10.7/15.10.7.3/15.10.7.3-1: FAIL_OK +chapter15/15.10/15.10.7/15.10.7.3/15.10.7.3-2: FAIL_OK +chapter15/15.10/15.10.7/15.10.7.4/15.10.7.4-1: FAIL_OK +chapter15/15.10/15.10.7/15.10.7.4/15.10.7.4-2: FAIL_OK +chapter15/15.10/15.10.7/15.10.7.5/15.10.7.5-1: FAIL_OK +chapter15/15.10/15.10.7/15.10.7.5/15.10.7.5-2: FAIL_OK [ $arch == mips ] diff --git a/deps/v8/test/mjsunit/debug-setbreakpoint.js b/deps/v8/test/mjsunit/debug-setbreakpoint.js index 9661c95a4e..8201d6394a 100644 --- a/deps/v8/test/mjsunit/debug-setbreakpoint.js +++ b/deps/v8/test/mjsunit/debug-setbreakpoint.js @@ -63,6 +63,7 @@ function testArguments(dcp, arguments, success, is_script) { } else { assertFalse(response.success, request + ' -> ' + json_response); } + return response; } function listener(event, exec_state, event_data, data) { @@ -75,7 +76,7 @@ function listener(event, exec_state, event_data, data) { var request = '{' + base_request + '}' var response = safeEval(dcp.processDebugJSONRequest(request)); assertFalse(response.success); - + var mirror; testArguments(dcp, '{}', false); @@ -118,6 +119,12 @@ function listener(event, exec_state, event_data, data) { testArguments(dcp, '{"type":"script","target":"sourceUrlScript","line":0}', true, true); + // Set a break point on a line with the comment, and check that actual position + // is the next line after the comment. + request = '{"type":"scriptId","target":' + g_script_id + ',"line":' + (g_line + 1) + '}'; + response = testArguments(dcp, request, true, false); + assertEquals(g_line + 2, response.body.actual_locations[0].line); + // Indicate that all was processed. listenerComplete = true; } @@ -185,8 +192,3 @@ Debug.setListener(breakListener); sourceUrlFunc(); assertTrue(breakListenerCalled, "Break listener not called on breakpoint set by sourceURL"); - -// Set a break point on a line with the comment, and check that actual position -// is the next line after the comment. -var number = Debug.setScriptBreakPointById(g_script_id, g_line + 1); -assertEquals(g_line + 2, Debug.findBreakPoint(number).actual_location.line); diff --git a/deps/v8/test/mjsunit/math-sqrt.js b/deps/v8/test/mjsunit/math-sqrt.js index ae29b74381..fb00d5ba8a 100644 --- a/deps/v8/test/mjsunit/math-sqrt.js +++ b/deps/v8/test/mjsunit/math-sqrt.js @@ -27,18 +27,23 @@ // Tests the special cases specified by ES 15.8.2.17 +function test(expected_sqrt, value) { + assertEquals(expected_sqrt, Math.sqrt(value)); + if (isFinite(value)) { + assertEquals(expected_sqrt, Math.pow(value, 0.5)); + } +} + // Simple sanity check -assertEquals(2, Math.sqrt(4)); -assertEquals(0.1, Math.sqrt(0.01)); +test(2, 4); +test(0.1, 0.01); // Spec tests -assertEquals(NaN, Math.sqrt(NaN)); -assertEquals(NaN, Math.sqrt(-1)); -assertEquals(+0, Math.sqrt(+0)); -assertEquals(-0, Math.sqrt(-0)); -assertEquals(Infinity, Math.sqrt(Infinity)); +test(NaN, NaN); +test(NaN, -1); +test(+0, +0); +test(-0, -0); +test(Infinity, Infinity); // -Infinity is smaller than 0 so it should return NaN -assertEquals(NaN, Math.sqrt(-Infinity)); - - +test(NaN, -Infinity); diff --git a/deps/v8/test/mjsunit/mod.js b/deps/v8/test/mjsunit/mod.js new file mode 100644 index 0000000000..8ad98fa7ec --- /dev/null +++ b/deps/v8/test/mjsunit/mod.js @@ -0,0 +1,53 @@ +// 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: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +function foo() { + for (var i = 1; i < 100; i++) { + var answer = 1; + for (var j = 1; j < 100; j++) { + if (answer == i) answer = 0; + // Positive case. + print(j + " % " + i + " = " + answer); + m = j % i; + assertEquals(answer, m, j + " % " + i); + m = j % (-i); + assertEquals(answer, m, j + " % -" + i); + // Negative case. + m = (-j) % i; + assertEquals(-answer, m, j + " % " + i); + // Check for negative zero. + if (answer == 0) assertEquals(-Infinity, 1/m); + m = (-j) % (-i); + assertEquals(-answer, m, j + " % -" + i); + // Check for negative zero. + if (answer == 0) assertEquals(-Infinity, 1/m); + answer++; + } + } +} + +foo(); diff --git a/deps/v8/test/mjsunit/regress/regress-753.js b/deps/v8/test/mjsunit/regress/regress-753.js new file mode 100644 index 0000000000..6a6d87bb0e --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-753.js @@ -0,0 +1,36 @@ +// 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: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Test that JSON.stringify correctly truncates floating point numbers. +// This test is based on chapter15/15.12/15.12.3/15.12.3-6-a-2.js in the +// ES5 conformance tests. + +// See: http://code.google.com/p/v8/issues/detail?id=753 + +var obj = {a1: {b1: [1,2,3,4], b2: {c1: 1, c2: 2}},a2: 'a2'}; +assertEquals(JSON.stringify(obj,null, 5.99999), JSON.stringify(obj,null, 5)); + diff --git a/deps/v8/test/mjsunit/to_number_order.js b/deps/v8/test/mjsunit/to_number_order.js index 1329bad2ca..d17e600050 100644 --- a/deps/v8/test/mjsunit/to_number_order.js +++ b/deps/v8/test/mjsunit/to_number_order.js @@ -39,6 +39,14 @@ x = ""; assertEquals(2, Math.max(v,w)); assertEquals("hestfisk", x, "max"); +x = ""; +assertEquals(1, Math.max(v,v)); +assertEquals("hesthest", x, "max_identical"); + +x = ""; +assertEquals(2, Math.min(w,w)); +assertEquals("fiskfisk", x, "max"); + x = ""; assertEquals(Math.atan2(1, 2), Math.atan2(v, w)); // JSC says fiskhest. @@ -122,8 +130,86 @@ x = ""; new Date().setUTCFullYear(year, month, date, hours, minutes, seconds, ms); assertEquals("123", x, "Date.setUTCFullYear"); +x = ""; var a = { valueOf: function() { x += "hest"; return 97; } }; var b = { valueOf: function() { x += "fisk"; return 98; } }; assertEquals("ab", String.fromCharCode(a, b), "String.fromCharCode"); +assertEquals("hestfisk", x, "String.fromCharCode valueOf order"); + + + +// Test whether valueOf is called when comparing identical objects +x = ""; +assertTrue(a < b, "Compare objects a < b"); +assertEquals("hestfisk", x, "Compare objects a < b valueOf order"); + +x = ""; +assertFalse(a < a, "Compare objects a < a"); +// assertEquals("hesthest", x, "Compare objects a < a valueOf order"); + +x = ""; +assertTrue(a == a, "Compare objects a == a"); +assertEquals("", x, "Compare objects a == a valueOf not called"); + +x = ""; +assertFalse(b > b, "Compare objects b > b"); +assertEquals("fiskfisk", x, "Compare objects b > b valueOf order"); + +x = ""; +assertTrue(b >= b, "Compare objects b >= b"); +assertEquals("fiskfisk", x, "Compare objects b >= b valueOf order"); + +x = ""; +assertFalse(a > b, "Compare objects a > b"); +assertEquals("fiskhest", x, "Compare objects a > b valueOf order"); + +x = ""; +assertFalse(a > void(0), "Compare objects a > undefined"); +assertEquals("hest", x, "Compare objects a > undefined valueOf order"); + +x = ""; +assertFalse(void(0) > b, "Compare objects undefined > b"); +assertEquals("fisk", x, "Compare objects undefined > b valueOf order"); + + +function identical_object_comparison() { + x = ""; + assertTrue(a < b, "Compare objects a < b"); + assertEquals("hestfisk", x, "Compare objects a < b valueOf order"); + + x = ""; + assertFalse(a < a, "Compare objects a < a"); + // assertEquals("hesthest", x, "Compare objects a < a valueOf order"); + + x = ""; + assertTrue(a == a, "Compare objects a == a"); + assertEquals("", x, "Compare objects a == a valueOf not called"); + + x = ""; + assertFalse(b > b, "Compare objects b > b"); + assertEquals("fiskfisk", x, "Compare objects b > b valueOf order"); + + x = ""; + assertTrue(b >= b, "Compare objects b >= b"); + assertEquals("fiskfisk", x, "Compare objects b >= b valueOf order"); + + x = ""; + assertFalse(a > b, "Compare objects a > b"); + assertEquals("fiskhest", x, "Compare objects a > b valueOf order"); + + x = ""; + assertFalse(a > void(0), "Compare objects a > undefined"); + assertEquals("hest", x, "Compare objects a > undefined valueOf order"); + + x = ""; + assertFalse(void(0) > b, "Compare objects undefined > b"); + assertEquals("fisk", x, "Compare objects undefined > b valueOf order"); +} + +// Call inside loop to test optimization and possible caching. +for (i = 0; i < 3; ++i) { + identical_object_comparison(); +} + print("ok"); diff --git a/deps/v8/test/mozilla/mozilla.status b/deps/v8/test/mozilla/mozilla.status index b4ec444784..28fc063154 100644 --- a/deps/v8/test/mozilla/mozilla.status +++ b/deps/v8/test/mozilla/mozilla.status @@ -26,13 +26,13 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # This file is up to date with respect to Mozilla's CVS repository as of -# 2008-09-02. If new tests are added to Mozilla's CVS it may need to be +# 2010-06-29. If new tests are added to Mozilla's CVS it may need to be # updated. # To get the mozilla tests: # cd /path/to/checkout/test/mozilla # rm -rf data -# cvs -d :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot co -D 2008-09-02 mozilla/js/tests +# cvs -d :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot co -D 2010-06-29 mozilla/js/tests # mv mozilla/js/tests data # rm -rf mozilla @@ -53,6 +53,10 @@ def FAIL_OK = FAIL, OKAY js1_5/Regress/regress-271716-n: SKIP +# This test uses a unitialized variable. A Bug has been filed: +# https://bugzilla.mozilla.org/show_bug.cgi?id=575575 +js1_5/Array/regress-465980-02: SKIP + # These tests are simply wrong (i.e., they do not test what they intend # to test). # In particular, these two compare numbers to NaN with != in the current @@ -226,6 +230,10 @@ ecma_3/Function/regress-313570: FAIL_OK # toPrecision argument restricted to range 1..21 in JSC/V8 js1_5/Regress/regress-452346: FAIL_OK +ecma_3/Number/15.7.4.7-1: FAIL_OK + +# toExponential argument restricted to range 0..20 in JSC/V8 +ecma_3/Number/15.7.4.6-1: FAIL_OK # Array.prototype.slice with zero arguments return undefined in JSC/V8, # empty array in Spider/TraceMonkey. @@ -234,8 +242,9 @@ js1_5/Array/regress-451483: FAIL_OK #:=== RegExp:=== # To be compatible with JSC we silently ignore flags that do not make -# sense. This test expects us to throw exceptions. +# sense. These tests expects us to throw exceptions. ecma_3/RegExp/regress-57631: FAIL_OK +ecma_3/RegExp/15.10.4.1-6: FAIL_OK # PCRE doesn't allow subpattern nesting deeper than 200, this tests # depth 500. JSC detects the case, and return null from the match, @@ -315,6 +324,11 @@ js1_5/Regress/regress-234389: FAIL_OK js1_5/Regress/regress-320119: FAIL_OK +# We do not recognize a multiline comment as newline character. +# We are compatible with JSC. +ecma_3/LexicalConventions/7.4-01: FAIL_OK + + # No support for toSource(). js1_5/Regress/regress-248444: FAIL_OK js1_5/Regress/regress-313967-01: FAIL_OK @@ -347,6 +361,7 @@ ecma/GlobalObject/15.1.2.7: FAIL_OK # print strings for errors. Non-ECMA behavior. js1_2/function/tostring-2: FAIL_OK js1_2/Objects/toString-001: FAIL_OK +js1_5/LexicalConventions/regress-469940: FAIL_OK js1_5/Exceptions/regress-332472: FAIL_OK js1_5/Regress/regress-173067: FAIL_OK js1_5/Regress/regress-355556: FAIL_OK @@ -386,11 +401,7 @@ js1_5/decompilation/regress-461110: FAIL_OK # Tests that use uneval. Non-ECMA. js1_5/GC/regress-418128: FAIL_OK js1_5/extensions/regress-465276: FAIL_OK - - -# Tests that use __count__. Non-ECMA. -js1_5/extensions/regress-434837-01: FAIL_OK - +js1_5/Error/regress-465377: FAIL_OK # Tests that use the watch method. Non-ECMA. js1_5/extensions/regress-435345-01: FAIL_OK @@ -432,6 +443,7 @@ js1_5/Object/regress-362872-01: FAIL_OK js1_5/Object/regress-362872-02: FAIL_OK js1_5/Regress/regress-361467: FAIL_OK js1_5/Regress/regress-385393-06: FAIL_OK +js1_5/Regress/regress-506567: FAIL_OK # Use special Mozilla getter/setter syntax @@ -484,6 +496,11 @@ js1_2/Array/array_split_1: FAIL_OK # The concat() method is defined in Array.prototype; not Array. js1_5/Array/regress-313153: FAIL_OK +# The join() method is defined on Array.prototype; not Array. +js1_5/Array/regress-474529: FAIL_OK + +# The lastIndexOf() method is defined on Array.prototype, not Array. +ecma_3/Array/15.5.4.8-01: FAIL_OK # Properties fileName, and lineNumber of Error instances are # not supported. Mozilla specific extension. @@ -552,6 +569,10 @@ js1_5/Regress/regress-352604: FAIL_OK js1_5/Regress/regress-417893: FAIL_OK +# Unsupported use of "[]" as function parameter. We match JSC. +js1_5/Regress/regress-416737-01: FAIL_OK +js1_5/Regress/regress-416737-02: FAIL_OK + ##################### FAILING TESTS ##################### @@ -596,6 +617,11 @@ ecma_3/String/15.5.4.11: FAIL # Marked as: Will not fix. V8 throws an acceptable RangeError. js1_5/Expressions/regress-394673: FAIL + +# Bug 762: http://code.google.com/p/v8/issues/detail?id=762 +# We do not correctly handle assignments within "with" +/ecma_3/Statements/12.10-01: FAIL + ##################### MOZILLA EXTENSION TESTS ##################### ecma/extensions/15.1.2.1-1: FAIL_OK @@ -674,6 +700,9 @@ js1_5/extensions/regress-365869: FAIL_OK js1_5/extensions/regress-367630: FAIL_OK js1_5/extensions/regress-367923: FAIL_OK js1_5/extensions/regress-368859: FAIL_OK +js1_5/extensions/regress-369696-01: FAIL_OK +js1_5/extensions/regress-369696-02: FAIL_OK +js1_5/extensions/regress-369696-03: FAIL_OK js1_5/extensions/regress-374589: FAIL_OK js1_5/extensions/regress-375801: FAIL_OK js1_5/extensions/regress-376052: FAIL_OK @@ -693,6 +722,11 @@ js1_5/extensions/regress-420612: FAIL_OK js1_5/extensions/regress-420869-01: FAIL_OK js1_5/extensions/regress-424257: FAIL_OK js1_5/extensions/regress-424683-01: FAIL_OK +js1_5/extensions/regress-429739: FAIL_OK +js1_5/extensions/regress-454142: FAIL_OK +js1_5/extensions/regress-465145: FAIL_OK +js1_5/extensions/regress-469625: FAIL_OK +js1_5/extensions/regress-472787: FAIL_OK js1_5/extensions/regress-44009: FAIL_OK js1_5/extensions/regress-50447-1: FAIL_OK js1_5/extensions/regress-50447: FAIL_OK @@ -771,7 +805,7 @@ js1_5/decompilation/regress-375882: PASS || FAIL js1_5/decompilation/regress-376564: PASS || FAIL js1_5/decompilation/regress-383721: PASS || FAIL js1_5/decompilation/regress-406555: PASS || FAIL - +js1_5/decompilation/regress-460870: PASS || FAIL # These tests take an unreasonable amount of time so we skip them # in fast mode. diff --git a/deps/v8/tools/stats-viewer.py b/deps/v8/tools/stats-viewer.py index 14b214768f..05cb762882 100755 --- a/deps/v8/tools/stats-viewer.py +++ b/deps/v8/tools/stats-viewer.py @@ -34,8 +34,8 @@ The stats viewer reads counters from a binary file and displays them in a window, re-reading and re-displaying with regular intervals. """ - import mmap +import optparse import os import re import struct @@ -60,13 +60,15 @@ CHROME_COUNTERS_FILE_MAGIC_NUMBER = 0x13131313 class StatsViewer(object): """The main class that keeps the data used by the stats viewer.""" - def __init__(self, data_name): + def __init__(self, data_name, name_filter): """Creates a new instance. Args: data_name: the name of the file containing the counters. + name_filter: The regexp filter to apply to counter names. """ self.data_name = data_name + self.name_filter = name_filter # The handle created by mmap.mmap to the counters file. We need # this to clean it up on exit. @@ -224,17 +226,19 @@ class StatsViewer(object): sorted_groups.sort() for counter_name in sorted_groups: counter_objs = groups[counter_name] - name = Tkinter.Label(self.root, width=50, anchor=Tkinter.W, - text=counter_name) - name.grid(row=index, column=0, padx=1, pady=1) + if self.name_filter.match(counter_name): + name = Tkinter.Label(self.root, width=50, anchor=Tkinter.W, + text=counter_name) + name.grid(row=index, column=0, padx=1, pady=1) count = len(counter_objs) for i in xrange(count): counter = counter_objs[i] name = counter.Name() var = Tkinter.StringVar() - value = Tkinter.Label(self.root, width=15, anchor=Tkinter.W, - textvariable=var) - value.grid(row=index, column=(1 + i), padx=1, pady=1) + if self.name_filter.match(name): + value = Tkinter.Label(self.root, width=15, anchor=Tkinter.W, + textvariable=var) + value.grid(row=index, column=(1 + i), padx=1, pady=1) # If we know how to interpret the prefix of this counter then # add an appropriate formatting to the variable @@ -440,17 +444,25 @@ class ChromeCounterCollection(object): self.counter_values_offset + i * self.max_threads * 4) -def Main(data_file): +def Main(data_file, name_filter): """Run the stats counter. Args: data_file: The counters file to monitor. + name_filter: The regexp filter to apply to counter names. """ - StatsViewer(data_file).Run() + StatsViewer(data_file, name_filter).Run() if __name__ == "__main__": - if len(sys.argv) != 2: - print "Usage: stats-viewer.py |" + parser = optparse.OptionParser("usage: %prog [--filter=re] " + "|") + parser.add_option("--filter", + default=".*", + help=("regexp filter for counter names " + "[default: %default]")) + (options, args) = parser.parse_args() + if len(args) != 1: + parser.print_help() sys.exit(1) - Main(sys.argv[1]) + Main(args[0], re.compile(options.filter))