diff options
author | machenbach@chromium.org <machenbach@chromium.org> | 2014-09-26 00:05:23 +0000 |
---|---|---|
committer | machenbach@chromium.org <machenbach@chromium.org> | 2014-09-26 00:05:23 +0000 |
commit | 380972948c208da7ea528679db2b75b02f41aba0 (patch) | |
tree | c06efc246d9893141e48f1591f9aeb0900bdefb1 /test | |
parent | 5830436a84f7792f61451af9bccd991d923fe81c (diff) | |
download | v8-380972948c208da7ea528679db2b75b02f41aba0.tar.gz |
Version 3.29.91 (based on bleeding_edge revision r24232)
Performance and stability improvements on all platforms.
git-svn-id: https://v8.googlecode.com/svn/trunk@24233 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
Diffstat (limited to 'test')
-rw-r--r-- | test/cctest/compiler/test-representation-change.cc | 330 | ||||
-rw-r--r-- | test/cctest/compiler/test-run-machops.cc | 46 | ||||
-rw-r--r-- | test/cctest/compiler/test-simplified-lowering.cc | 35 | ||||
-rw-r--r-- | test/cctest/compiler/value-helper.h | 40 | ||||
-rw-r--r-- | test/cctest/test-assembler-ia32.cc | 28 | ||||
-rw-r--r-- | test/cctest/test-disasm-x64.cc | 1 | ||||
-rw-r--r-- | test/cctest/test-func-name-inference.cc | 2 | ||||
-rw-r--r-- | test/cctest/test-serialize.cc | 175 | ||||
-rw-r--r-- | test/cctest/test-types.cc | 300 | ||||
-rw-r--r-- | test/mjsunit/asm/math-fround.js | 38 | ||||
-rw-r--r-- | test/mjsunit/debug-stepin-property-function-call.js | 153 | ||||
-rw-r--r-- | test/mjsunit/regress/regress-416730.js | 24 | ||||
-rw-r--r-- | test/mjsunit/regress/regress-crbug-323936.js | 46 | ||||
-rw-r--r-- | test/mjsunit/regress/regress-crbug-416558.js | 115 |
14 files changed, 1143 insertions, 190 deletions
diff --git a/test/cctest/compiler/test-representation-change.cc b/test/cctest/compiler/test-representation-change.cc index 6c9026b2e..9bf3b371f 100644 --- a/test/cctest/compiler/test-representation-change.cc +++ b/test/cctest/compiler/test-representation-change.cc @@ -7,6 +7,7 @@ #include "src/v8.h" #include "test/cctest/cctest.h" #include "test/cctest/compiler/graph-builder-tester.h" +#include "test/cctest/compiler/value-helper.h" #include "src/compiler/node-matchers.h" #include "src/compiler/representation-change.h" @@ -51,6 +52,24 @@ class RepresentationChangerTester : public HandleAndZoneScope, CHECK_EQ(expected, m.Value()); } + void CheckUint32Constant(Node* n, uint32_t expected) { + Uint32Matcher m(n); + CHECK(m.HasValue()); + CHECK_EQ(static_cast<int>(expected), static_cast<int>(m.Value())); + } + + void CheckFloat64Constant(Node* n, double expected) { + Float64Matcher m(n); + CHECK(m.HasValue()); + CHECK_EQ(expected, m.Value()); + } + + void CheckFloat32Constant(Node* n, float expected) { + CHECK_EQ(IrOpcode::kFloat32Constant, n->opcode()); + float fval = OpParameter<float>(n->op()); + CHECK_EQ(expected, fval); + } + void CheckHeapConstant(Node* n, HeapObject* expected) { HeapObjectMatcher<HeapObject> m(n); CHECK(m.HasValue()); @@ -88,28 +107,8 @@ class RepresentationChangerTester : public HandleAndZoneScope, } // namespace v8::internal::compiler -// TODO(titzer): add kRepFloat32 when fully supported. -static const MachineType all_reps[] = {kRepBit, kRepWord32, kRepWord64, - kRepFloat64, kRepTagged}; - - -// TODO(titzer): lift this to ValueHelper -static const double double_inputs[] = { - 0.0, -0.0, 1.0, -1.0, 0.1, 1.4, -1.7, - 2, 5, 6, 982983, 888, -999.8, 3.1e7, - -2e66, 2.3e124, -12e73, V8_INFINITY, -V8_INFINITY}; - - -static const int32_t int32_inputs[] = { - 0, 1, -1, - 2, 5, 6, - 982983, 888, -999, - 65535, static_cast<int32_t>(0xFFFFFFFF), static_cast<int32_t>(0x80000000)}; - - -static const uint32_t uint32_inputs[] = { - 0, 1, static_cast<uint32_t>(-1), 2, 5, 6, - 982983, 888, static_cast<uint32_t>(-999), 65535, 0xFFFFFFFF, 0x80000000}; +static const MachineType all_reps[] = {kRepBit, kRepWord32, kRepWord64, + kRepFloat32, kRepFloat64, kRepTagged}; TEST(BoolToBit_constant) { @@ -142,24 +141,234 @@ TEST(BitToBool_constant) { TEST(ToTagged_constant) { RepresentationChangerTester r; - for (size_t i = 0; i < arraysize(double_inputs); i++) { - Node* n = r.jsgraph()->Float64Constant(double_inputs[i]); - Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepTagged); - r.CheckNumberConstant(c, double_inputs[i]); + { + FOR_FLOAT64_INPUTS(i) { + Node* n = r.jsgraph()->Float64Constant(*i); + Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepTagged); + r.CheckNumberConstant(c, *i); + } + } + + { + FOR_FLOAT64_INPUTS(i) { + Node* n = r.jsgraph()->Constant(*i); + Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepTagged); + r.CheckNumberConstant(c, *i); + } + } + + { + FOR_FLOAT32_INPUTS(i) { + Node* n = r.jsgraph()->Float32Constant(*i); + Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32, kRepTagged); + r.CheckNumberConstant(c, *i); + } + } + + { + FOR_INT32_INPUTS(i) { + Node* n = r.jsgraph()->Int32Constant(*i); + Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32, + kRepTagged); + r.CheckNumberConstant(c, *i); + } + } + + { + FOR_UINT32_INPUTS(i) { + Node* n = r.jsgraph()->Int32Constant(*i); + Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32, + kRepTagged); + r.CheckNumberConstant(c, *i); + } + } +} + + +TEST(ToFloat64_constant) { + RepresentationChangerTester r; + + { + FOR_FLOAT64_INPUTS(i) { + Node* n = r.jsgraph()->Float64Constant(*i); + Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepFloat64); + CHECK_EQ(n, c); + } + } + + { + FOR_FLOAT64_INPUTS(i) { + Node* n = r.jsgraph()->Constant(*i); + Node* c = r.changer()->GetRepresentationFor(n, kRepTagged, kRepFloat64); + r.CheckFloat64Constant(c, *i); + } + } + + { + FOR_FLOAT32_INPUTS(i) { + Node* n = r.jsgraph()->Float32Constant(*i); + Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32, kRepFloat64); + r.CheckFloat64Constant(c, *i); + } + } + + { + FOR_INT32_INPUTS(i) { + Node* n = r.jsgraph()->Int32Constant(*i); + Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32, + kRepFloat64); + r.CheckFloat64Constant(c, *i); + } + } + + { + FOR_UINT32_INPUTS(i) { + Node* n = r.jsgraph()->Int32Constant(*i); + Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32, + kRepFloat64); + r.CheckFloat64Constant(c, *i); + } + } +} + + +static bool IsFloat32Int32(int32_t val) { + return val >= -(1 << 23) && val <= (1 << 23); +} + + +static bool IsFloat32Uint32(uint32_t val) { return val <= (1 << 23); } + + +TEST(ToFloat32_constant) { + RepresentationChangerTester r; + + { + FOR_FLOAT32_INPUTS(i) { + Node* n = r.jsgraph()->Float32Constant(*i); + Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32, kRepFloat32); + CHECK_EQ(n, c); + } + } + + { + FOR_FLOAT32_INPUTS(i) { + Node* n = r.jsgraph()->Constant(*i); + Node* c = r.changer()->GetRepresentationFor(n, kRepTagged, kRepFloat32); + r.CheckFloat32Constant(c, *i); + } + } + + { + FOR_FLOAT32_INPUTS(i) { + Node* n = r.jsgraph()->Float64Constant(*i); + Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepFloat32); + r.CheckFloat32Constant(c, *i); + } + } + + { + FOR_INT32_INPUTS(i) { + if (!IsFloat32Int32(*i)) continue; + Node* n = r.jsgraph()->Int32Constant(*i); + Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32, + kRepFloat32); + r.CheckFloat32Constant(c, static_cast<float>(*i)); + } + } + + { + FOR_UINT32_INPUTS(i) { + if (!IsFloat32Uint32(*i)) continue; + Node* n = r.jsgraph()->Int32Constant(*i); + Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32, + kRepFloat32); + r.CheckFloat32Constant(c, static_cast<float>(*i)); + } + } +} + + +TEST(ToInt32_constant) { + RepresentationChangerTester r; + + { + FOR_INT32_INPUTS(i) { + Node* n = r.jsgraph()->Int32Constant(*i); + Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32, + kRepWord32); + r.CheckInt32Constant(c, *i); + } } - for (size_t i = 0; i < arraysize(int32_inputs); i++) { - Node* n = r.jsgraph()->Int32Constant(int32_inputs[i]); - Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32, - kRepTagged); - r.CheckNumberConstant(c, static_cast<double>(int32_inputs[i])); + { + FOR_INT32_INPUTS(i) { + if (!IsFloat32Int32(*i)) continue; + Node* n = r.jsgraph()->Float32Constant(static_cast<float>(*i)); + Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32 | kTypeInt32, + kRepWord32); + r.CheckInt32Constant(c, *i); + } } - for (size_t i = 0; i < arraysize(uint32_inputs); i++) { - Node* n = r.jsgraph()->Int32Constant(uint32_inputs[i]); - Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32, - kRepTagged); - r.CheckNumberConstant(c, static_cast<double>(uint32_inputs[i])); + { + FOR_INT32_INPUTS(i) { + Node* n = r.jsgraph()->Float64Constant(*i); + Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64 | kTypeInt32, + kRepWord32); + r.CheckInt32Constant(c, *i); + } + } + + { + FOR_INT32_INPUTS(i) { + Node* n = r.jsgraph()->Constant(*i); + Node* c = r.changer()->GetRepresentationFor(n, kRepTagged | kTypeInt32, + kRepWord32); + r.CheckInt32Constant(c, *i); + } + } +} + + +TEST(ToUint32_constant) { + RepresentationChangerTester r; + + { + FOR_UINT32_INPUTS(i) { + Node* n = r.jsgraph()->Int32Constant(*i); + Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32, + kRepWord32); + r.CheckUint32Constant(c, *i); + } + } + + { + FOR_UINT32_INPUTS(i) { + if (!IsFloat32Uint32(*i)) continue; + Node* n = r.jsgraph()->Float32Constant(static_cast<float>(*i)); + Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32 | kTypeUint32, + kRepWord32); + r.CheckUint32Constant(c, *i); + } + } + + { + FOR_UINT32_INPUTS(i) { + Node* n = r.jsgraph()->Float64Constant(*i); + Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64 | kTypeUint32, + kRepWord32); + r.CheckUint32Constant(c, *i); + } + } + + { + FOR_UINT32_INPUTS(i) { + Node* n = r.jsgraph()->Constant(static_cast<double>(*i)); + Node* c = r.changer()->GetRepresentationFor(n, kRepTagged | kTypeUint32, + kRepWord32); + r.CheckUint32Constant(c, *i); + } } } @@ -177,6 +386,23 @@ static void CheckChange(IrOpcode::Value expected, MachineTypeUnion from, } +static void CheckTwoChanges(IrOpcode::Value expected2, + IrOpcode::Value expected1, MachineTypeUnion from, + MachineTypeUnion to) { + RepresentationChangerTester r; + + Node* n = r.Parameter(); + Node* c1 = r.changer()->GetRepresentationFor(n, from, to); + + CHECK_NE(c1, n); + CHECK_EQ(expected1, c1->opcode()); + Node* c2 = c1->InputAt(0); + CHECK_NE(c2, n); + CHECK_EQ(expected2, c2->opcode()); + CHECK_EQ(n, c2->InputAt(0)); +} + + TEST(SingleChanges) { CheckChange(IrOpcode::kChangeBoolToBit, kRepTagged, kRepBit); CheckChange(IrOpcode::kChangeBitToBool, kRepBit, kRepTagged); @@ -202,6 +428,26 @@ TEST(SingleChanges) { kRepWord32); CheckChange(IrOpcode::kChangeFloat64ToUint32, kRepFloat64 | kTypeUint32, kRepWord32); + + // Int32,Uint32 <-> Float32 require two changes. + CheckTwoChanges(IrOpcode::kChangeInt32ToFloat64, + IrOpcode::kTruncateFloat64ToFloat32, kRepWord32 | kTypeInt32, + kRepFloat32); + CheckTwoChanges(IrOpcode::kChangeUint32ToFloat64, + IrOpcode::kTruncateFloat64ToFloat32, kRepWord32 | kTypeUint32, + kRepFloat32); + CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64, + IrOpcode::kChangeFloat64ToInt32, kRepFloat32 | kTypeInt32, + kRepWord32); + CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64, + IrOpcode::kChangeFloat64ToUint32, kRepFloat32 | kTypeUint32, + kRepWord32); + + // Float32 <-> Tagged require two changes. + CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64, + IrOpcode::kChangeFloat64ToTagged, kRepFloat32, kRepTagged); + CheckTwoChanges(IrOpcode::kChangeTaggedToFloat64, + IrOpcode::kTruncateFloat64ToFloat32, kRepTagged, kRepFloat32); } @@ -215,6 +461,11 @@ TEST(SignednessInWord32) { kRepWord32 | kTypeUint32); CheckChange(IrOpcode::kChangeInt32ToFloat64, kRepWord32, kRepFloat64); CheckChange(IrOpcode::kChangeFloat64ToInt32, kRepFloat64, kRepWord32); + + CheckTwoChanges(IrOpcode::kChangeInt32ToFloat64, + IrOpcode::kTruncateFloat64ToFloat32, kRepWord32, kRepFloat32); + CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64, + IrOpcode::kChangeFloat64ToInt32, kRepFloat32, kRepWord32); } @@ -295,11 +546,4 @@ TEST(TypeErrors) { r.CheckTypeError(all_reps[i] | all_reps[j], kRepTagged); } } - - // TODO(titzer): Float32 representation changes trigger type errors now. - // Enforce current behavior to test all paths through representation changer. - for (size_t i = 0; i < arraysize(all_reps); i++) { - r.CheckTypeError(all_reps[i], kRepFloat32); - r.CheckTypeError(kRepFloat32, all_reps[i]); - } } diff --git a/test/cctest/compiler/test-run-machops.cc b/test/cctest/compiler/test-run-machops.cc index 985e0f8ff..5606126e0 100644 --- a/test/cctest/compiler/test-run-machops.cc +++ b/test/cctest/compiler/test-run-machops.cc @@ -4242,4 +4242,50 @@ TEST(RunTruncateFloat64ToInt32P) { } } + +TEST(RunChangeFloat32ToFloat64) { + double actual = 0.0f; + float expected = 0.0; + RawMachineAssemblerTester<int32_t> m; + m.StoreToPointer( + &actual, kMachFloat64, + m.ChangeFloat32ToFloat64(m.LoadFromPointer(&expected, kMachFloat32))); + m.Return(m.Int32Constant(0)); + FOR_FLOAT32_INPUTS(i) { + expected = *i; + CHECK_EQ(0, m.Call()); + CHECK_EQ(expected, actual); + } +} + + +TEST(RunTruncateFloat64ToFloat32) { + float actual = 0.0f; + double input = 0.0; + RawMachineAssemblerTester<int32_t> m; + m.StoreToPointer( + &actual, kMachFloat32, + m.TruncateFloat64ToFloat32(m.LoadFromPointer(&input, kMachFloat64))); + m.Return(m.Int32Constant(0)); + FOR_FLOAT64_INPUTS(i) { + input = *i; + volatile double expected = DoubleToFloat32(input); + CHECK_EQ(0, m.Call()); + CHECK_EQ(expected, actual); + } +} + + +TEST(RunFloat32Constant) { + FOR_FLOAT32_INPUTS(i) { + float expected = *i; + float actual = *i; + RawMachineAssemblerTester<int32_t> m; + m.StoreToPointer(&actual, kMachFloat32, m.Float32Constant(expected)); + m.Return(m.Int32Constant(0)); + CHECK_EQ(0, m.Call()); + CHECK_EQ(expected, actual); + } +} + #endif // V8_TURBOFAN_TARGET diff --git a/test/cctest/compiler/test-simplified-lowering.cc b/test/cctest/compiler/test-simplified-lowering.cc index 96fb9650e..e67df9bfd 100644 --- a/test/cctest/compiler/test-simplified-lowering.cc +++ b/test/cctest/compiler/test-simplified-lowering.cc @@ -1523,38 +1523,3 @@ TEST(UpdatePhi) { RepresentationOf(OpParameter<MachineType>(phi))); } } - - -// TODO(titzer): this tests current behavior of assuming an implicit -// representation change in loading float32s. Fix when float32 is fully -// supported. -TEST(ImplicitFloat32ToFloat64InLoads) { - TestingGraph t(Type::Any()); - - FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, - Handle<Name>::null(), Type::Any(), kMachFloat32}; - - Node* load = - t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, t.start); - t.Return(load); - t.Lower(); - CHECK_EQ(IrOpcode::kLoad, load->opcode()); - CHECK_EQ(t.p0, load->InputAt(0)); - CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, load, t.ret->InputAt(0)); -} - - -TEST(ImplicitFloat64ToFloat32InStores) { - TestingGraph t(Type::Any(), Type::Signed32()); - FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, - Handle<Name>::null(), Type::Any(), kMachFloat32}; - - Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0, - t.p1, t.start, t.start); - t.Effect(store); - t.Lower(); - - CHECK_EQ(IrOpcode::kStore, store->opcode()); - CHECK_EQ(t.p0, store->InputAt(0)); - CheckChangeOf(IrOpcode::kChangeTaggedToFloat64, t.p1, store->InputAt(2)); -} diff --git a/test/cctest/compiler/value-helper.h b/test/cctest/compiler/value-helper.h index b5da982e8..7d7c11e4f 100644 --- a/test/cctest/compiler/value-helper.h +++ b/test/cctest/compiler/value-helper.h @@ -60,6 +60,45 @@ class ValueHelper { CheckHeapConstant(isolate_->heap()->false_value(), node); } + static std::vector<float> float32_vector() { + static const float kValues[] = { + -std::numeric_limits<float>::infinity(), -2.70497e+38f, -1.4698e+37f, + -1.22813e+35f, -1.20555e+35f, -1.34584e+34f, + -1.0079e+32f, -6.49364e+26f, -3.06077e+25f, + -1.46821e+25f, -1.17658e+23f, -1.9617e+22f, + -2.7357e+20f, -1.48708e+13f, -1.89633e+12f, + -4.66622e+11f, -2.22581e+11f, -1.45381e+10f, + -1.3956e+09f, -1.32951e+09f, -1.30721e+09f, + -1.19756e+09f, -9.26822e+08f, -6.35647e+08f, + -4.00037e+08f, -1.81227e+08f, -5.09256e+07f, + -964300.0f, -192446.0f, -28455.0f, + -27194.0f, -26401.0f, -20575.0f, + -17069.0f, -9167.0f, -960.178f, + -113.0f, -62.0f, -15.0f, + -7.0f, -0.0256635f, -4.60374e-07f, + -3.63759e-10f, -4.30175e-14f, -5.27385e-15f, + -1.48084e-15f, -1.05755e-19f, -3.2995e-21f, + -1.67354e-23f, -1.11885e-23f, -1.78506e-30f, + -5.07594e-31f, -3.65799e-31f, -1.43718e-34f, + -1.27126e-38f, -0.0f, 0.0f, + 1.17549e-38f, 1.56657e-37f, 4.08512e-29f, + 3.31357e-28f, 6.25073e-22f, 4.1723e-13f, + 1.44343e-09f, 5.27004e-08f, 9.48298e-08f, + 5.57888e-07f, 4.89988e-05f, 0.244326f, + 12.4895f, 19.0f, 47.0f, + 106.0f, 538.324f, 564.536f, + 819.124f, 7048.0f, 12611.0f, + 19878.0f, 20309.0f, 797056.0f, + 1.77219e+09f, 1.51116e+11f, 4.18193e+13f, + 3.59167e+16f, 3.38211e+19f, 2.67488e+20f, + 1.78831e+21f, 9.20914e+21f, 8.35654e+23f, + 1.4495e+24f, 5.94015e+25f, 4.43608e+30f, + 2.44502e+33f, 2.61152e+33f, 1.38178e+37f, + 1.71306e+37f, 3.31899e+38f, 3.40282e+38f, + std::numeric_limits<float>::infinity()}; + return std::vector<float>(&kValues[0], &kValues[arraysize(kValues)]); + } + static std::vector<double> float64_vector() { static const double nan = v8::base::OS::nan_value(); static const double values[] = { @@ -117,6 +156,7 @@ class ValueHelper { #define FOR_INT32_INPUTS(var) FOR_INPUTS(int32_t, int32, var) #define FOR_UINT32_INPUTS(var) FOR_INPUTS(uint32_t, uint32, var) +#define FOR_FLOAT32_INPUTS(var) FOR_INPUTS(float, float32, var) #define FOR_FLOAT64_INPUTS(var) FOR_INPUTS(double, float64, var) #define FOR_INT32_SHIFTS(var) for (int32_t var = 0; var < 32; var++) diff --git a/test/cctest/test-assembler-ia32.cc b/test/cctest/test-assembler-ia32.cc index e8c7f951f..d94329739 100644 --- a/test/cctest/test-assembler-ia32.cc +++ b/test/cctest/test-assembler-ia32.cc @@ -170,11 +170,10 @@ TEST(AssemblerIa323) { assm.GetCode(&desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); - // don't print the code - our disassembler can't handle cvttss2si - // instead print bytes - Disassembler::Dump(stdout, - code->instruction_start(), - code->instruction_start() + code->instruction_size()); +#ifdef OBJECT_PRINT + OFStream os(stdout); + code->Print(os); +#endif F3 f = FUNCTION_CAST<F3>(code->entry()); int res = f(static_cast<float>(-3.1415)); ::printf("f() = %d\n", res); @@ -200,11 +199,10 @@ TEST(AssemblerIa324) { assm.GetCode(&desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); - // don't print the code - our disassembler can't handle cvttsd2si - // instead print bytes - Disassembler::Dump(stdout, - code->instruction_start(), - code->instruction_start() + code->instruction_size()); +#ifdef OBJECT_PRINT + OFStream os(stdout); + code->Print(os); +#endif F4 f = FUNCTION_CAST<F4>(code->entry()); int res = f(2.718281828); ::printf("f() = %d\n", res); @@ -261,13 +259,9 @@ TEST(AssemblerIa326) { assm.GetCode(&desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); -#ifdef DEBUG - ::printf("\n---\n"); - // don't print the code - our disassembler can't handle SSE instructions - // instead print bytes - Disassembler::Dump(stdout, - code->instruction_start(), - code->instruction_start() + code->instruction_size()); +#ifdef OBJECT_PRINT + OFStream os(stdout); + code->Print(os); #endif F5 f = FUNCTION_CAST<F5>(code->entry()); double res = f(2.2, 1.1); diff --git a/test/cctest/test-disasm-x64.cc b/test/cctest/test-disasm-x64.cc index e756ce220..d238410fa 100644 --- a/test/cctest/test-disasm-x64.cc +++ b/test/cctest/test-disasm-x64.cc @@ -167,6 +167,7 @@ TEST(DisasmX64) { __ imulq(rdx, Operand(rbx, rcx, times_4, 10000)); __ imulq(rdx, rcx, Immediate(12)); __ imulq(rdx, rcx, Immediate(1000)); + __ imulq(rdx, Operand(rbx, rcx, times_4, 10000), Immediate(1000)); __ incq(rdx); __ incq(Operand(rbx, rcx, times_4, 10000)); diff --git a/test/cctest/test-func-name-inference.cc b/test/cctest/test-func-name-inference.cc index bc503b58c..ceceff63a 100644 --- a/test/cctest/test-func-name-inference.cc +++ b/test/cctest/test-func-name-inference.cc @@ -30,7 +30,7 @@ #include "src/api.h" #include "src/debug.h" -#include "src/runtime.h" +#include "src/runtime/runtime.h" #include "test/cctest/cctest.h" diff --git a/test/cctest/test-serialize.cc b/test/cctest/test-serialize.cc index 94b400e20..ed9419dfe 100644 --- a/test/cctest/test-serialize.cc +++ b/test/cctest/test-serialize.cc @@ -37,7 +37,7 @@ #include "src/heap/spaces.h" #include "src/natives.h" #include "src/objects.h" -#include "src/runtime.h" +#include "src/runtime/runtime.h" #include "src/scopeinfo.h" #include "src/serialize.h" #include "src/snapshot.h" @@ -137,14 +137,10 @@ class FileByteSink : public SnapshotByteSink { virtual int Position() { return ftell(fp_); } - void WriteSpaceUsed( - int new_space_used, - int pointer_space_used, - int data_space_used, - int code_space_used, - int map_space_used, - int cell_space_used, - int property_cell_space_used); + void WriteSpaceUsed(int new_space_used, int pointer_space_used, + int data_space_used, int code_space_used, + int map_space_used, int cell_space_used, + int property_cell_space_used, int lo_space_used); private: FILE* fp_; @@ -152,14 +148,11 @@ class FileByteSink : public SnapshotByteSink { }; -void FileByteSink::WriteSpaceUsed( - int new_space_used, - int pointer_space_used, - int data_space_used, - int code_space_used, - int map_space_used, - int cell_space_used, - int property_cell_space_used) { +void FileByteSink::WriteSpaceUsed(int new_space_used, int pointer_space_used, + int data_space_used, int code_space_used, + int map_space_used, int cell_space_used, + int property_cell_space_used, + int lo_space_used) { int file_name_length = StrLength(file_name_) + 10; Vector<char> name = Vector<char>::New(file_name_length + 1); SNPrintF(name, "%s.size", file_name_); @@ -172,6 +165,7 @@ void FileByteSink::WriteSpaceUsed( fprintf(fp, "map %d\n", map_space_used); fprintf(fp, "cell %d\n", cell_space_used); fprintf(fp, "property cell %d\n", property_cell_space_used); + fprintf(fp, "lo %d\n", lo_space_used); fclose(fp); } @@ -181,14 +175,14 @@ static bool WriteToFile(Isolate* isolate, const char* snapshot_file) { StartupSerializer ser(isolate, &file); ser.Serialize(); - file.WriteSpaceUsed( - ser.CurrentAllocationAddress(NEW_SPACE), - ser.CurrentAllocationAddress(OLD_POINTER_SPACE), - ser.CurrentAllocationAddress(OLD_DATA_SPACE), - ser.CurrentAllocationAddress(CODE_SPACE), - ser.CurrentAllocationAddress(MAP_SPACE), - ser.CurrentAllocationAddress(CELL_SPACE), - ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE)); + file.WriteSpaceUsed(ser.CurrentAllocationAddress(NEW_SPACE), + ser.CurrentAllocationAddress(OLD_POINTER_SPACE), + ser.CurrentAllocationAddress(OLD_DATA_SPACE), + ser.CurrentAllocationAddress(CODE_SPACE), + ser.CurrentAllocationAddress(MAP_SPACE), + ser.CurrentAllocationAddress(CELL_SPACE), + ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE), + ser.CurrentAllocationAddress(LO_SPACE)); return true; } @@ -246,7 +240,7 @@ static void ReserveSpaceForSnapshot(Deserializer* deserializer, FILE* fp = v8::base::OS::FOpen(name.start(), "r"); name.Dispose(); int new_size, pointer_size, data_size, code_size, map_size, cell_size, - property_cell_size; + property_cell_size, lo_size; #ifdef _MSC_VER // Avoid warning about unsafe fscanf from MSVC. // Please note that this is only fine if %c and %s are not being used. @@ -259,6 +253,7 @@ static void ReserveSpaceForSnapshot(Deserializer* deserializer, CHECK_EQ(1, fscanf(fp, "map %d\n", &map_size)); CHECK_EQ(1, fscanf(fp, "cell %d\n", &cell_size)); CHECK_EQ(1, fscanf(fp, "property cell %d\n", &property_cell_size)); + CHECK_EQ(1, fscanf(fp, "lo %d\n", &lo_size)); #ifdef _MSC_VER #undef fscanf #endif @@ -270,6 +265,7 @@ static void ReserveSpaceForSnapshot(Deserializer* deserializer, deserializer->set_reservation(MAP_SPACE, map_size); deserializer->set_reservation(CELL_SPACE, cell_size); deserializer->set_reservation(PROPERTY_CELL_SPACE, property_cell_size); + deserializer->set_reservation(LO_SPACE, lo_size); } @@ -456,7 +452,8 @@ UNINITIALIZED_TEST(PartialSerialization) { p_ser.CurrentAllocationAddress(CODE_SPACE), p_ser.CurrentAllocationAddress(MAP_SPACE), p_ser.CurrentAllocationAddress(CELL_SPACE), - p_ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE)); + p_ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE), + p_ser.CurrentAllocationAddress(LO_SPACE)); startup_sink.WriteSpaceUsed( startup_serializer.CurrentAllocationAddress(NEW_SPACE), @@ -465,7 +462,8 @@ UNINITIALIZED_TEST(PartialSerialization) { startup_serializer.CurrentAllocationAddress(CODE_SPACE), startup_serializer.CurrentAllocationAddress(MAP_SPACE), startup_serializer.CurrentAllocationAddress(CELL_SPACE), - startup_serializer.CurrentAllocationAddress(PROPERTY_CELL_SPACE)); + startup_serializer.CurrentAllocationAddress(PROPERTY_CELL_SPACE), + startup_serializer.CurrentAllocationAddress(LO_SPACE)); startup_name.Dispose(); } v8_isolate->Exit(); @@ -579,7 +577,8 @@ UNINITIALIZED_TEST(ContextSerialization) { p_ser.CurrentAllocationAddress(CODE_SPACE), p_ser.CurrentAllocationAddress(MAP_SPACE), p_ser.CurrentAllocationAddress(CELL_SPACE), - p_ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE)); + p_ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE), + p_ser.CurrentAllocationAddress(LO_SPACE)); startup_sink.WriteSpaceUsed( startup_serializer.CurrentAllocationAddress(NEW_SPACE), @@ -588,7 +587,8 @@ UNINITIALIZED_TEST(ContextSerialization) { startup_serializer.CurrentAllocationAddress(CODE_SPACE), startup_serializer.CurrentAllocationAddress(MAP_SPACE), startup_serializer.CurrentAllocationAddress(CELL_SPACE), - startup_serializer.CurrentAllocationAddress(PROPERTY_CELL_SPACE)); + startup_serializer.CurrentAllocationAddress(PROPERTY_CELL_SPACE), + startup_serializer.CurrentAllocationAddress(LO_SPACE)); startup_name.Dispose(); } v8_isolate->Dispose(); @@ -786,6 +786,121 @@ TEST(SerializeToplevelInternalizedString) { } +Vector<const uint8_t> ConstructSource(Vector<const uint8_t> head, + Vector<const uint8_t> body, + Vector<const uint8_t> tail, int repeats) { + int source_length = head.length() + body.length() * repeats + tail.length(); + uint8_t* source = NewArray<uint8_t>(static_cast<size_t>(source_length)); + CopyChars(source, head.start(), head.length()); + for (int i = 0; i < repeats; i++) { + CopyChars(source + head.length() + i * body.length(), body.start(), + body.length()); + } + CopyChars(source + head.length() + repeats * body.length(), tail.start(), + tail.length()); + return Vector<const uint8_t>(const_cast<const uint8_t*>(source), + source_length); +} + + +TEST(SerializeToplevelLargeCodeObject) { + FLAG_serialize_toplevel = true; + LocalContext context; + Isolate* isolate = CcTest::i_isolate(); + isolate->compilation_cache()->Disable(); // Disable same-isolate code cache. + + v8::HandleScope scope(CcTest::isolate()); + + Vector<const uint8_t> source = + ConstructSource(STATIC_CHAR_VECTOR("var j=1; try { if (j) throw 1;"), + STATIC_CHAR_VECTOR("for(var i=0;i<1;i++)j++;"), + STATIC_CHAR_VECTOR("} catch (e) { j=7; } j"), 10000); + Handle<String> source_str = + isolate->factory()->NewStringFromOneByte(source).ToHandleChecked(); + + Handle<JSObject> global(isolate->context()->global_object()); + ScriptData* cache = NULL; + + Handle<SharedFunctionInfo> orig = Compiler::CompileScript( + source_str, Handle<String>(), 0, 0, false, + Handle<Context>(isolate->native_context()), NULL, &cache, + v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE); + + CHECK(isolate->heap()->InSpace(orig->code(), LO_SPACE)); + + Handle<SharedFunctionInfo> copy; + { + DisallowCompilation no_compile_expected(isolate); + copy = Compiler::CompileScript( + source_str, Handle<String>(), 0, 0, false, + Handle<Context>(isolate->native_context()), NULL, &cache, + v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE); + } + CHECK_NE(*orig, *copy); + + Handle<JSFunction> copy_fun = + isolate->factory()->NewFunctionFromSharedFunctionInfo( + copy, isolate->native_context()); + + Handle<Object> copy_result = + Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked(); + + int result_int; + CHECK(copy_result->ToInt32(&result_int)); + CHECK_EQ(7, result_int); + + delete cache; + source.Dispose(); +} + + +TEST(SerializeToplevelLargeString) { + FLAG_serialize_toplevel = true; + LocalContext context; + Isolate* isolate = CcTest::i_isolate(); + isolate->compilation_cache()->Disable(); // Disable same-isolate code cache. + + v8::HandleScope scope(CcTest::isolate()); + + Vector<const uint8_t> source = ConstructSource( + STATIC_CHAR_VECTOR("var s = \""), STATIC_CHAR_VECTOR("abcdef"), + STATIC_CHAR_VECTOR("\"; s"), 1000000); + Handle<String> source_str = + isolate->factory()->NewStringFromOneByte(source).ToHandleChecked(); + + Handle<JSObject> global(isolate->context()->global_object()); + ScriptData* cache = NULL; + + Handle<SharedFunctionInfo> orig = Compiler::CompileScript( + source_str, Handle<String>(), 0, 0, false, + Handle<Context>(isolate->native_context()), NULL, &cache, + v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE); + + Handle<SharedFunctionInfo> copy; + { + DisallowCompilation no_compile_expected(isolate); + copy = Compiler::CompileScript( + source_str, Handle<String>(), 0, 0, false, + Handle<Context>(isolate->native_context()), NULL, &cache, + v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE); + } + CHECK_NE(*orig, *copy); + + Handle<JSFunction> copy_fun = + isolate->factory()->NewFunctionFromSharedFunctionInfo( + copy, isolate->native_context()); + + Handle<Object> copy_result = + Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked(); + + CHECK_EQ(6 * 1000000, Handle<String>::cast(copy_result)->length()); + CHECK(isolate->heap()->InSpace(HeapObject::cast(*copy_result), LO_SPACE)); + + delete cache; + source.Dispose(); +} + + TEST(SerializeToplevelIsolates) { FLAG_serialize_toplevel = true; diff --git a/test/cctest/test-types.cc b/test/cctest/test-types.cc index 0cd24728c..e9122b1c6 100644 --- a/test/cctest/test-types.cc +++ b/test/cctest/test-types.cc @@ -11,9 +11,23 @@ using namespace v8::internal; + // Testing auxiliaries (breaking the Type abstraction). + + +static bool IsInteger(double x) { + return nearbyint(x) == x && !i::IsMinusZero(x); // Allows for infinities. +} + + +static bool IsInteger(i::Object* x) { + return x->IsNumber() && IsInteger(x->Number()); +} + + typedef uint32_t bitset; + struct ZoneRep { typedef void* Struct; @@ -261,17 +275,28 @@ class Types { TypeHandle Fuzz(int depth = 4) { switch (rng_->NextInt(depth == 0 ? 3 : 20)) { case 0: { // bitset - int n = 0 #define COUNT_BITSET_TYPES(type, value) + 1 - PROPER_BITSET_TYPE_LIST(COUNT_BITSET_TYPES) + int n = 0 PROPER_BITSET_TYPE_LIST(COUNT_BITSET_TYPES); #undef COUNT_BITSET_TYPES - ; - int i = rng_->NextInt(n); - #define PICK_BITSET_TYPE(type, value) \ - if (i-- == 0) return Type::type(region_); - PROPER_BITSET_TYPE_LIST(PICK_BITSET_TYPE) - #undef PICK_BITSET_TYPE - UNREACHABLE(); + // Pick a bunch of named bitsets and return their intersection. + TypeHandle result = Type::Any(region_); + for (int i = 0, m = 1 + rng_->NextInt(3); i < m; ++i) { + int j = rng_->NextInt(n); + #define PICK_BITSET_TYPE(type, value) \ + if (j-- == 0) { \ + TypeHandle tmp = Type::Intersect( \ + result, Type::type(region_), region_); \ + if (tmp->Is(Type::None()) && i != 0) { \ + break; \ + } { \ + result = tmp; \ + continue; \ + } \ + } + PROPER_BITSET_TYPE_LIST(PICK_BITSET_TYPE) + #undef PICK_BITSET_TYPE + } + return result; } case 1: { // class int i = rng_->NextInt(static_cast<int>(maps.size())); @@ -598,11 +623,11 @@ struct Tests : Rep { // Range(min1, max1) = Range(min2, max2) <=> min1 = min2 /\ max1 = max2 for (ValueIterator i1 = T.integers.begin(); i1 != T.integers.end(); ++i1) { - for (ValueIterator j1 = T.integers.begin(); + for (ValueIterator j1 = i1; j1 != T.integers.end(); ++j1) { for (ValueIterator i2 = T.integers.begin(); i2 != T.integers.end(); ++i2) { - for (ValueIterator j2 = T.integers.begin(); + for (ValueIterator j2 = i2; j2 != T.integers.end(); ++j2) { i::Handle<i::Object> min1 = *i1; i::Handle<i::Object> max1 = *j1; @@ -619,6 +644,33 @@ struct Tests : Rep { } } + void Context() { + // Constructor + for (int i = 0; i < 20; ++i) { + TypeHandle type = T.Random(); + TypeHandle context = T.Context(type); + CHECK(context->Iscontext()); + } + + // Attributes + for (int i = 0; i < 20; ++i) { + TypeHandle type = T.Random(); + TypeHandle context = T.Context(type); + CheckEqual(type, context->AsContext()->Outer()); + } + + // Functionality & Injectivity: Context(T1) = Context(T2) iff T1 = T2 + for (int i = 0; i < 20; ++i) { + for (int j = 0; j < 20; ++j) { + TypeHandle type1 = T.Random(); + TypeHandle type2 = T.Random(); + TypeHandle context1 = T.Context(type1); + TypeHandle context2 = T.Context(type2); + CHECK(Equal(context1, context2) == Equal(type1, type2)); + } + } + } + void Array() { // Constructor for (int i = 0; i < 20; ++i) { @@ -803,6 +855,56 @@ struct Tests : Rep { } } + void MinMax() { + // If b is regular numeric bitset, then Range(b->Min(), b->Max())->Is(b). + // TODO(neis): Need to ignore representation for this to be true. + /* + for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { + TypeHandle type = *it; + if (this->IsBitset(type) && type->Is(T.Number) && + !type->Is(T.None) && !type->Is(T.NaN)) { + TypeHandle range = T.Range( + isolate->factory()->NewNumber(type->Min()), + isolate->factory()->NewNumber(type->Max())); + CHECK(range->Is(type)); + } + } + */ + + // If b is regular numeric bitset, then b->Min() and b->Max() are integers. + for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { + TypeHandle type = *it; + if (this->IsBitset(type) && type->Is(T.Number) && + !type->Is(T.None) && !type->Is(T.NaN)) { + CHECK(IsInteger(type->Min()) && IsInteger(type->Max())); + } + } + + // If b1 and b2 are regular numeric bitsets with b1->Is(b2), then + // b1->Min() >= b2->Min() and b1->Max() <= b2->Max(). + for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { + for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { + TypeHandle type1 = *it1; + TypeHandle type2 = *it2; + if (this->IsBitset(type1) && type1->Is(type2) && type2->Is(T.Number) && + !type1->Is(T.NaN) && !type2->Is(T.NaN)) { + CHECK(type1->Min() >= type2->Min()); + CHECK(type1->Max() <= type2->Max()); + } + } + } + + // Lub(Range(x,y))->Min() <= x and y <= Lub(Range(x,y))->Max() + for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { + TypeHandle type = *it; + if (type->IsRange()) { + TypeHandle lub = Rep::BitsetType::New( + Rep::BitsetType::Lub(type), T.region()); + CHECK(lub->Min() <= type->Min() && type->Max() <= lub->Max()); + } + } + } + void BitsetGlb() { // Lower: (T->BitsetGlb())->Is(T) for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { @@ -871,7 +973,7 @@ struct Tests : Rep { } } - void Is() { + void Is1() { // Least Element (Bottom): None->Is(T) for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { TypeHandle type = *it; @@ -923,6 +1025,26 @@ struct Tests : Rep { } } + // (In-)Compatibilities. + for (TypeIterator i = T.types.begin(); i != T.types.end(); ++i) { + for (TypeIterator j = T.types.begin(); j != T.types.end(); ++j) { + TypeHandle type1 = *i; + TypeHandle type2 = *j; + CHECK(!type1->Is(type2) || this->IsBitset(type2) || + this->IsUnion(type2) || this->IsUnion(type1) || + (type1->IsClass() && type2->IsClass()) || + (type1->IsConstant() && type2->IsConstant()) || + (type1->IsConstant() && type2->IsRange()) || + (type1->IsRange() && type2->IsRange()) || + (type1->IsContext() && type2->IsContext()) || + (type1->IsArray() && type2->IsArray()) || + (type1->IsFunction() && type2->IsFunction()) || + type1->Equals(T.None)); + } + } + } + + void Is2() { // Class(M1)->Is(Class(M2)) iff M1 = M2 for (MapIterator mt1 = T.maps.begin(); mt1 != T.maps.end(); ++mt1) { for (MapIterator mt2 = T.maps.begin(); mt2 != T.maps.end(); ++mt2) { @@ -934,26 +1056,14 @@ struct Tests : Rep { } } - // Constant(V1)->Is(Constant(V2)) iff V1 = V2 - for (ValueIterator vt1 = T.values.begin(); vt1 != T.values.end(); ++vt1) { - for (ValueIterator vt2 = T.values.begin(); vt2 != T.values.end(); ++vt2) { - Handle<i::Object> value1 = *vt1; - Handle<i::Object> value2 = *vt2; - TypeHandle const_type1 = T.Constant(value1); - TypeHandle const_type2 = T.Constant(value2); - CHECK(const_type1->Is(const_type2) == (*value1 == *value2)); - } - } - - // Range(min1, max1)->Is(Range(min2, max2)) iff - // min1 >= min2 /\ max1 <= max2 + // Range(X1, Y1)->Is(Range(X2, Y2)) iff X1 >= X2 /\ Y1 <= Y2 for (ValueIterator i1 = T.integers.begin(); i1 != T.integers.end(); ++i1) { - for (ValueIterator j1 = T.integers.begin(); + for (ValueIterator j1 = i1; j1 != T.integers.end(); ++j1) { for (ValueIterator i2 = T.integers.begin(); i2 != T.integers.end(); ++i2) { - for (ValueIterator j2 = T.integers.begin(); + for (ValueIterator j2 = i2; j2 != T.integers.end(); ++j2) { i::Handle<i::Object> min1 = *i1; i::Handle<i::Object> max1 = *j1; @@ -964,13 +1074,24 @@ struct Tests : Rep { TypeHandle type1 = T.Range(min1, max1); TypeHandle type2 = T.Range(min2, max2); CHECK(type1->Is(type2) == - (min2->Number() <= min1->Number() && + (min1->Number() >= min2->Number() && max1->Number() <= max2->Number())); } } } } + // Constant(V1)->Is(Constant(V2)) iff V1 = V2 + for (ValueIterator vt1 = T.values.begin(); vt1 != T.values.end(); ++vt1) { + for (ValueIterator vt2 = T.values.begin(); vt2 != T.values.end(); ++vt2) { + Handle<i::Object> value1 = *vt1; + Handle<i::Object> value2 = *vt2; + TypeHandle const_type1 = T.Constant(value1); + TypeHandle const_type2 = T.Constant(value2); + CHECK(const_type1->Is(const_type2) == (*value1 == *value2)); + } + } + // Context(T1)->Is(Context(T2)) iff T1 = T2 for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { @@ -1007,25 +1128,45 @@ struct Tests : Rep { } } - // (In-)Compatibilities. - for (TypeIterator i = T.types.begin(); i != T.types.end(); ++i) { - for (TypeIterator j = T.types.begin(); j != T.types.end(); ++j) { - TypeHandle type1 = *i; - TypeHandle type2 = *j; - CHECK(!type1->Is(type2) || this->IsBitset(type2) || - this->IsUnion(type2) || this->IsUnion(type1) || - (type1->IsClass() && type2->IsClass()) || - (type1->IsConstant() && type2->IsConstant()) || - (type1->IsConstant() && type2->IsRange()) || - (type1->IsRange() && type2->IsRange()) || - (type1->IsContext() && type2->IsContext()) || - (type1->IsArray() && type2->IsArray()) || - (type1->IsFunction() && type2->IsFunction()) || - type1->Equals(T.None)); + + // Range-specific subtyping + + // If IsInteger(v) then Constant(v)->Is(Range(v, v)). + for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { + TypeHandle type = *it; + if (type->IsConstant() && IsInteger(*type->AsConstant()->Value())) { + CHECK(type->Is( + T.Range(type->AsConstant()->Value(), type->AsConstant()->Value()))); } } - // Basic types + // If Constant(x)->Is(Range(min,max)) then IsInteger(v) and min <= x <= max. + for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { + for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { + TypeHandle type1 = *it1; + TypeHandle type2 = *it2; + if (type1->IsConstant() && type2->IsRange() && type1->Is(type2)) { + double x = type1->AsConstant()->Value()->Number(); + double min = type2->AsRange()->Min()->Number(); + double max = type2->AsRange()->Max()->Number(); + CHECK(IsInteger(x) && min <= x && x <= max); + } + } + } + + // Lub(Range(x,y))->Is(T.Union(T.Integral32, T.OtherNumber)) + for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { + TypeHandle type = *it; + if (type->IsRange()) { + TypeHandle lub = Rep::BitsetType::New( + Rep::BitsetType::Lub(type), T.region()); + CHECK(lub->Is(T.Union(T.Integral32, T.OtherNumber))); + } + } + + + // Subtyping between concrete basic types + CheckUnordered(T.Boolean, T.Null); CheckUnordered(T.Undefined, T.Null); CheckUnordered(T.Boolean, T.Undefined); @@ -1054,7 +1195,9 @@ struct Tests : Rep { CheckUnordered(T.Object, T.Proxy); CheckUnordered(T.Array, T.Function); - // Structural types + + // Subtyping between concrete structural types + CheckSub(T.ObjectClass, T.Object); CheckSub(T.ArrayClass, T.Object); CheckSub(T.ArrayClass, T.Array); @@ -1443,7 +1586,9 @@ struct Tests : Rep { } // Associativity: Union(T1, Union(T2, T3)) = Union(Union(T1, T2), T3) - // This does NOT hold! + // This does NOT hold! For example: + // (Unsigned32 \/ Range(0,5)) \/ Range(-5,0) = Unsigned32 \/ Range(-5,0) + // Unsigned32 \/ (Range(0,5) \/ Range(-5,0)) = Unsigned32 \/ Range(-5,5) /* for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { @@ -1483,7 +1628,9 @@ struct Tests : Rep { } // Monotonicity: T1->Is(T2) implies Union(T1, T3)->Is(Union(T2, T3)) - // This does NOT hold. + // This does NOT hold. For example: + // Range(-5,-1) <= Signed32 + // Range(-5,-1) \/ Range(1,5) = Range(-5,5) </= Signed32 \/ Range(1,5) /* for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { @@ -1502,8 +1649,10 @@ struct Tests : Rep { void Union2() { // Monotonicity: T1->Is(T3) and T2->Is(T3) implies Union(T1, T2)->Is(T3) - // This does NOT hold. TODO(neis): Could fix this by splitting - // OtherNumber into a negative and a positive part. + // This does NOT hold. For example: + // Range(-2^33, -2^33) <= OtherNumber + // Range(2^33, 2^33) <= OtherNumber + // Range(-2^33, 2^33) </= OtherNumber /* for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { @@ -1523,7 +1672,7 @@ struct Tests : Rep { // Monotonicity: T1->Is(T2) or T1->Is(T3) implies T1->Is(Union(T2, T3)) for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) { + for (TypeIterator it3 = it2; it3 != T.types.end(); ++it3) { TypeHandle type1 = *it1; TypeHandle type2 = *it2; TypeHandle type3 = *it3; @@ -1685,7 +1834,11 @@ struct Tests : Rep { // Associativity: // Intersect(T1, Intersect(T2, T3)) = Intersect(Intersect(T1, T2), T3) - // This does NOT hold. + // This does NOT hold. For example: + // (Class(..stringy1..) /\ Class(..stringy2..)) /\ Constant(..string..) = + // None + // Class(..stringy1..) /\ (Class(..stringy2..) /\ Constant(..string..)) = + // Constant(..string..) /* for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { @@ -1704,7 +1857,11 @@ struct Tests : Rep { */ // Join: Intersect(T1, T2)->Is(T1) and Intersect(T1, T2)->Is(T2) - // This does NOT hold. Not even the disjunction. + // This does NOT hold. For example: + // Class(..stringy..) /\ Constant(..string..) = Constant(..string..) + // Currently, not even the disjunction holds: + // Class(Internal/TaggedPtr) /\ (Any/Untagged \/ Context(..)) = + // Class(Internal/TaggedPtr) \/ Context(..) /* for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { @@ -1728,7 +1885,10 @@ struct Tests : Rep { } // Monotonicity: T1->Is(T2) implies Intersect(T1, T3)->Is(Intersect(T2, T3)) - // This does NOT hold. + // This does NOT hold. For example: + // Class(OtherObject/TaggedPtr) <= Any/TaggedPtr + // Class(OtherObject/TaggedPtr) /\ Any/UntaggedInt1 = Class(..) + // Any/TaggedPtr /\ Any/UntaggedInt1 = None /* for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { @@ -1745,7 +1905,10 @@ struct Tests : Rep { */ // Monotonicity: T1->Is(T3) or T2->Is(T3) implies Intersect(T1, T2)->Is(T3) - // This does NOT hold. + // This does NOT hold. For example: + // Class(..stringy..) <= Class(..stringy..) + // Class(..stringy..) /\ Constant(..string..) = Constant(..string..) + // Constant(..string..) </= Class(..stringy..) /* for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { @@ -1762,8 +1925,6 @@ struct Tests : Rep { */ // Monotonicity: T1->Is(T2) and T1->Is(T3) implies T1->Is(Intersect(T2, T3)) - // This does NOT hold. - /* for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) { @@ -1776,7 +1937,6 @@ struct Tests : Rep { } } } - */ // Bitset-class CheckEqual(T.Intersect(T.ObjectClass, T.Object), T.ObjectClass); @@ -1880,7 +2040,11 @@ struct Tests : Rep { void Distributivity() { // Union(T1, Intersect(T2, T3)) = Intersect(Union(T1, T2), Union(T1, T3)) - // This does NOT hold. + // This does NOT hold. For example: + // Untagged \/ (Untagged /\ Class(../Tagged)) = Untagged \/ Class(../Tagged) + // (Untagged \/ Untagged) /\ (Untagged \/ Class(../Tagged)) = + // Untagged /\ (Untagged \/ Class(../Tagged)) = Untagged + // because Untagged <= Untagged \/ Class(../Tagged) /* for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { @@ -1900,7 +2064,10 @@ struct Tests : Rep { */ // Intersect(T1, Union(T2, T3)) = Union(Intersect(T1, T2), Intersect(T1,T3)) - // This does NOT hold. + // This does NOT hold. For example: + // Untagged /\ (Untagged \/ Class(../Tagged)) = Untagged + // (Untagged /\ Untagged) \/ (Untagged /\ Class(../Tagged)) = + // Untagged \/ Class(../Tagged) /* for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { @@ -2026,10 +2193,17 @@ TEST(BitsetLub) { } -TEST(Is) { +TEST(Is1) { CcTest::InitializeVM(); - ZoneTests().Is(); - HeapTests().Is(); + ZoneTests().Is1(); + HeapTests().Is1(); +} + + +TEST(Is2) { + CcTest::InitializeVM(); + ZoneTests().Is2(); + HeapTests().Is2(); } @@ -2098,13 +2272,11 @@ TEST(Intersect) { } -/* TEST(Distributivity) { CcTest::InitializeVM(); ZoneTests().Distributivity(); HeapTests().Distributivity(); } -*/ TEST(Convert) { diff --git a/test/mjsunit/asm/math-fround.js b/test/mjsunit/asm/math-fround.js new file mode 100644 index 000000000..b1d37e904 --- /dev/null +++ b/test/mjsunit/asm/math-fround.js @@ -0,0 +1,38 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +function Module(stdlib) { + "use asm"; + + var fround = stdlib.Math.fround; + + // f: double -> float + function f(a) { + a = +a; + return fround(a); + } + + return { f: f }; +} + +var f = Module({ Math: Math }).f; + +assertTrue(isNaN(f(NaN))); +assertTrue(isNaN(f(undefined))); +assertTrue(isNaN(f(function() {}))); + +assertEquals("Infinity", String(1/f(0))); +assertEquals("-Infinity", String(1/f(-0))); +assertEquals("Infinity", String(f(Infinity))); +assertEquals("-Infinity", String(f(-Infinity))); +assertEquals("Infinity", String(f(1E200))); +assertEquals("-Infinity", String(f(-1E200))); +assertEquals("Infinity", String(1/f(1E-300))); +assertEquals("-Infinity", String(1/f(-1E-300))); + +assertEquals(0, f(0)); +assertEquals(1, f(1)); +assertEquals(1.5, f(1.5)); +assertEquals(1.3370000123977661, f(1.337)); +assertEquals(-4.300000190734863, f(-4.3)); diff --git a/test/mjsunit/debug-stepin-property-function-call.js b/test/mjsunit/debug-stepin-property-function-call.js new file mode 100644 index 000000000..081fb24fb --- /dev/null +++ b/test/mjsunit/debug-stepin-property-function-call.js @@ -0,0 +1,153 @@ +// Copyright 2014 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. + +// Flags: --expose-debug-as debug --nocrankshaft +// Get the Debug object exposed from the debug context global object. +Debug = debug.Debug + +var exception = null; +var state = 1; + +// Simple debug event handler which first time will cause 'step in' action +// to get into g.call and than check that execution is stopped inside +// function 'g'. +function listener(event, exec_state, event_data, data) { + try { + if (event == Debug.DebugEvent.Break) { + if (state == 1) { + exec_state.prepareStep(Debug.StepAction.StepIn, 3); + state = 2; + } else if (state == 2) { + assertTrue(event_data.sourceLineText().indexOf("Expected to step") > 0, + "source line: \"" + event_data.sourceLineText() + "\""); + state = 3; + } + } + } catch(e) { + print("Exception: " + e); + exception = e; + } +}; + +// Add the debug event listener. +Debug.setListener(listener); + +var count = 0; +var obj = { + fun: function() { + ++count; + return count; // Expected to step + } +}; +obj.fun2 = obj.fun; + +function testCall_Dots() { + debugger; + obj.fun(); +} + +function testCall_Quotes() { + debugger; + obj["fun"](); +} + +function testCall_Call() { + debugger; + obj.fun.call(obj); +} + +function testCall_Apply() { + debugger; + obj.fun.apply(obj); +} + +function testCall_Variable() { + var functionName = "fun"; + debugger; + obj[functionName](); +} + +function testCall_Fun2() { + debugger; + obj.fun2(); +} + +function testCall_InternStrings() { + var cache = { "fun": "fun" }; + var functionName = "fu" + "n"; + debugger; + obj[cache[functionName]](); +} + +function testCall_ViaFunRef() { + var functionName = "fu" + "n"; + var funRef = obj[functionName]; + debugger; + funRef(); +} + +// bug 2888 +function testCall_RuntimeVariable1() { + var functionName = "fu" + "n"; + debugger; + obj[functionName](); +} + +// bug 2888 +function testCall_RuntimeVariable2() { + var functionName = "un".replace(/u/, "fu"); + debugger; + obj[functionName](); +} + +// bug 2888 +function testCall_RuntimeVariable3() { + var expr = "fu" + "n"; + const functionName = expr; + assertEquals("fun", functionName); + debugger; + obj[functionName](); +} + +var functionsCalled = 0; +for (var n in this) { + if (n.substr(0, 4) != 'test' || typeof this[n] !== "function") { + continue; + } + state = 1; + print("Running " + n + "..."); + this[n](); + ++functionsCalled; + assertNull(exception, n); + assertEquals(3, state, n); + assertEquals(functionsCalled, count, n); +} + +assertEquals(11, functionsCalled); + +// Get rid of the debug event listener. +Debug.setListener(null); diff --git a/test/mjsunit/regress/regress-416730.js b/test/mjsunit/regress/regress-416730.js new file mode 100644 index 000000000..8d7f207fd --- /dev/null +++ b/test/mjsunit/regress/regress-416730.js @@ -0,0 +1,24 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +var d = {x: undefined, y: undefined}; + +function Crash(left, right) { + var c = { + x: right.x - left.x, + y: right.y - left.y + }; + return c.x * c.y; +} + +var a = {x: 0.5, y: 0}; +var b = {x: 1, y: 0}; + +for (var i = 0; i < 3; i++) Crash(a, b); +%OptimizeFunctionOnNextCall(Crash); +Crash(a, b); + +Crash({x: 0, y: 0.5}, b); diff --git a/test/mjsunit/regress/regress-crbug-323936.js b/test/mjsunit/regress/regress-crbug-323936.js new file mode 100644 index 000000000..d896eadcc --- /dev/null +++ b/test/mjsunit/regress/regress-crbug-323936.js @@ -0,0 +1,46 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --expose-debug-as debug + +Debug = debug.Debug; + +var step = 0; +var exception = null; + +function listener(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + try { + if (step == 0) { + assertEquals("error", exec_state.frame(0).evaluate("e").value()); + exec_state.frame(0).evaluate("e = 'foo'"); + exec_state.frame(0).evaluate("x = 'modified'"); + } else { + assertEquals("argument", exec_state.frame(0).evaluate("e").value()); + exec_state.frame(0).evaluate("e = 'bar'"); + } + step++; + } catch (e) { + print(e + e.stack); + exception = e; + } +} + +Debug.setListener(listener); + +function f(e, x) { + try { + throw "error"; + } catch(e) { + debugger; + assertEquals("foo", e); + } + debugger; + assertEquals("bar", e); + assertEquals("modified", x); +} + +f("argument") +assertNull(exception); +assertEquals(2, step); diff --git a/test/mjsunit/regress/regress-crbug-416558.js b/test/mjsunit/regress/regress-crbug-416558.js new file mode 100644 index 000000000..375ad406e --- /dev/null +++ b/test/mjsunit/regress/regress-crbug-416558.js @@ -0,0 +1,115 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +(function() { + function store(x) { x[0] = 0; } + store([]); + var c = /x/; + store(c); + function get_hole() { + var b = /x/; + store(b); + return b[1]; + } + assertEquals(undefined, get_hole()); + assertEquals(undefined, get_hole()); +})(); + +(function() { + function store(x) { x[0] = 0; } + store([]); + var c = new Date(); + store(c); + function get_hole() { + var b = new Date(); + store(b); + return b[1]; + } + assertEquals(undefined, get_hole()); + assertEquals(undefined, get_hole()); +})(); + +(function() { + function store(x) { x[0] = 0; } + store([]); + var c = new Number(1); + store(c); + function get_hole() { + var b = new Number(1); + store(b); + return b[1]; + } + assertEquals(undefined, get_hole()); + assertEquals(undefined, get_hole()); +})(); + +(function() { + function store(x) { x[0] = 0; } + store([]); + var c = new Boolean(); + store(c); + function get_hole() { + var b = new Boolean(); + store(b); + return b[1]; + } + assertEquals(undefined, get_hole()); + assertEquals(undefined, get_hole()); +})(); + +(function() { + function store(x) { x[0] = 0; } + store([]); + var c = new Map(); + store(c); + function get_hole() { + var b = new Map(); + store(b); + return b[1]; + } + assertEquals(undefined, get_hole()); + assertEquals(undefined, get_hole()); +})(); + +(function() { + function store(x) { x[0] = 0; } + store([]); + var c = new Set(); + store(c); + function get_hole() { + var b = new Set(); + store(b); + return b[1]; + } + assertEquals(undefined, get_hole()); + assertEquals(undefined, get_hole()); +})(); + +(function() { + function store(x) { x[0] = 0; } + store([]); + var c = new WeakMap(); + store(c); + function get_hole() { + var b = new WeakMap(); + store(b); + return b[1]; + } + assertEquals(undefined, get_hole()); + assertEquals(undefined, get_hole()); +})(); + +(function() { + function store(x) { x[0] = 0; } + store([]); + var c = new WeakSet(); + store(c); + function get_hole() { + var b = new WeakSet(); + store(b); + return b[1]; + } + assertEquals(undefined, get_hole()); + assertEquals(undefined, get_hole()); +})(); |