aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authormachenbach@chromium.org <machenbach@chromium.org>2014-09-26 00:05:23 +0000
committermachenbach@chromium.org <machenbach@chromium.org>2014-09-26 00:05:23 +0000
commit380972948c208da7ea528679db2b75b02f41aba0 (patch)
treec06efc246d9893141e48f1591f9aeb0900bdefb1 /test
parent5830436a84f7792f61451af9bccd991d923fe81c (diff)
downloadv8-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.cc330
-rw-r--r--test/cctest/compiler/test-run-machops.cc46
-rw-r--r--test/cctest/compiler/test-simplified-lowering.cc35
-rw-r--r--test/cctest/compiler/value-helper.h40
-rw-r--r--test/cctest/test-assembler-ia32.cc28
-rw-r--r--test/cctest/test-disasm-x64.cc1
-rw-r--r--test/cctest/test-func-name-inference.cc2
-rw-r--r--test/cctest/test-serialize.cc175
-rw-r--r--test/cctest/test-types.cc300
-rw-r--r--test/mjsunit/asm/math-fround.js38
-rw-r--r--test/mjsunit/debug-stepin-property-function-call.js153
-rw-r--r--test/mjsunit/regress/regress-416730.js24
-rw-r--r--test/mjsunit/regress/regress-crbug-323936.js46
-rw-r--r--test/mjsunit/regress/regress-crbug-416558.js115
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());
+})();