Index: test/cctest/compiler/test-simplified-lowering.cc |
diff --git a/test/cctest/compiler/test-simplified-lowering.cc b/test/cctest/compiler/test-simplified-lowering.cc |
index bcf1531ca86ba357faac2de18177b16516a798cb..0d841d964370fad956b4a30bd319a07dc706f27f 100644 |
--- a/test/cctest/compiler/test-simplified-lowering.cc |
+++ b/test/cctest/compiler/test-simplified-lowering.cc |
@@ -142,12 +142,13 @@ TEST(RunLoadMap) { |
t.LowerAllNodes(); |
- if (!Pipeline::SupportedTarget()) return; |
- |
- Handle<JSObject> src = TestObject(); |
- Handle<Map> src_map(src->map()); |
- Object* result = t.Call(*src); |
- CHECK_EQ(*src_map, result); |
+ if (Pipeline::SupportedTarget()) { |
+ t.GenerateCode(); |
+ Handle<JSObject> src = TestObject(); |
+ Handle<Map> src_map(src->map()); |
+ Object* result = t.Call(*src); // TODO(titzer): raw pointers in call |
+ CHECK_EQ(*src_map, result); |
+ } |
} |
@@ -155,18 +156,19 @@ TEST(RunStoreMap) { |
SimplifiedGraphBuilderTester<int32_t> t(kMachineTagged, kMachineTagged); |
FieldAccess access = ForJSObjectMap(); |
t.StoreField(access, t.Parameter(1), t.Parameter(0)); |
- t.Return(t.Int32Constant(0)); |
+ t.Return(t.jsgraph.TrueConstant()); |
t.LowerAllNodes(); |
- if (!Pipeline::SupportedTarget()) return; |
- |
- Handle<JSObject> src = TestObject(); |
- Handle<Map> src_map(src->map()); |
- Handle<JSObject> dst = TestObject(); |
- CHECK(src->map() != dst->map()); |
- t.Call(*src_map, *dst); |
- CHECK(*src_map == dst->map()); |
+ if (Pipeline::SupportedTarget()) { |
+ t.GenerateCode(); |
+ Handle<JSObject> src = TestObject(); |
+ Handle<Map> src_map(src->map()); |
+ Handle<JSObject> dst = TestObject(); |
+ CHECK(src->map() != dst->map()); |
+ t.Call(*src_map, *dst); // TODO(titzer): raw pointers in call |
+ CHECK(*src_map == dst->map()); |
+ } |
} |
@@ -178,12 +180,13 @@ TEST(RunLoadProperties) { |
t.LowerAllNodes(); |
- if (!Pipeline::SupportedTarget()) return; |
- |
- Handle<JSObject> src = TestObject(); |
- Handle<FixedArray> src_props(src->properties()); |
- Object* result = t.Call(*src); |
- CHECK_EQ(*src_props, result); |
+ if (Pipeline::SupportedTarget()) { |
+ t.GenerateCode(); |
+ Handle<JSObject> src = TestObject(); |
+ Handle<FixedArray> src_props(src->properties()); |
+ Object* result = t.Call(*src); // TODO(titzer): raw pointers in call |
+ CHECK_EQ(*src_props, result); |
+ } |
} |
@@ -196,16 +199,17 @@ TEST(RunLoadStoreMap) { |
t.LowerAllNodes(); |
- if (!Pipeline::SupportedTarget()) return; |
- |
- Handle<JSObject> src = TestObject(); |
- Handle<Map> src_map(src->map()); |
- Handle<JSObject> dst = TestObject(); |
- CHECK(src->map() != dst->map()); |
- Object* result = t.Call(*src, *dst); |
- CHECK(result->IsMap()); |
- CHECK_EQ(*src_map, result); |
- CHECK(*src_map == dst->map()); |
+ if (Pipeline::SupportedTarget()) { |
+ t.GenerateCode(); |
+ Handle<JSObject> src = TestObject(); |
+ Handle<Map> src_map(src->map()); |
+ Handle<JSObject> dst = TestObject(); |
+ CHECK(src->map() != dst->map()); |
+ Object* result = t.Call(*src, *dst); // TODO(titzer): raw pointers in call |
+ CHECK(result->IsMap()); |
+ CHECK_EQ(*src_map, result); |
+ CHECK(*src_map == dst->map()); |
+ } |
} |
@@ -218,101 +222,53 @@ TEST(RunLoadStoreFixedArrayIndex) { |
t.LowerAllNodes(); |
- if (!Pipeline::SupportedTarget()) return; |
- |
- Handle<FixedArray> array = t.factory()->NewFixedArray(2); |
- Handle<JSObject> src = TestObject(); |
- Handle<JSObject> dst = TestObject(); |
- array->set(0, *src); |
- array->set(1, *dst); |
- Object* result = t.Call(*array); |
- CHECK_EQ(*src, result); |
- CHECK_EQ(*src, array->get(0)); |
- CHECK_EQ(*src, array->get(1)); |
+ if (Pipeline::SupportedTarget()) { |
+ t.GenerateCode(); |
+ Handle<FixedArray> array = t.factory()->NewFixedArray(2); |
+ Handle<JSObject> src = TestObject(); |
+ Handle<JSObject> dst = TestObject(); |
+ array->set(0, *src); |
+ array->set(1, *dst); |
+ Object* result = t.Call(*array); |
+ CHECK_EQ(*src, result); |
+ CHECK_EQ(*src, array->get(0)); |
+ CHECK_EQ(*src, array->get(1)); |
+ } |
} |
TEST(RunLoadStoreArrayBuffer) { |
- SimplifiedGraphBuilderTester<int32_t> t(kMachineTagged); |
+ SimplifiedGraphBuilderTester<Object*> t(kMachineTagged); |
const int index = 12; |
- FieldAccess access = ForArrayBufferBackingStore(); |
- Node* backing_store = t.LoadField(access, t.Parameter(0)); |
ElementAccess buffer_access = ForBackingStoreElement(kMachineWord8); |
+ Node* backing_store = |
+ t.LoadField(ForArrayBufferBackingStore(), t.Parameter(0)); |
Node* load = |
t.LoadElement(buffer_access, backing_store, t.Int32Constant(index)); |
t.StoreElement(buffer_access, backing_store, t.Int32Constant(index + 1), |
load); |
- t.Return(load); |
- |
- t.LowerAllNodes(); |
- |
- if (!Pipeline::SupportedTarget()) return; |
- |
- Handle<JSArrayBuffer> array = t.factory()->NewJSArrayBuffer(); |
- const int array_length = 2 * index; |
- Runtime::SetupArrayBufferAllocatingData(t.isolate(), array, array_length); |
- uint8_t* data = reinterpret_cast<uint8_t*>(array->backing_store()); |
- for (int i = 0; i < array_length; i++) { |
- data[i] = i; |
- } |
- int32_t result = t.Call(*array); |
- CHECK_EQ(index, result); |
- for (int i = 0; i < array_length; i++) { |
- uint8_t expected = i; |
- if (i == (index + 1)) expected = result; |
- CHECK_EQ(data[i], expected); |
- } |
-} |
- |
- |
-TEST(RunCopyFixedArray) { |
- SimplifiedGraphBuilderTester<int32_t> t(kMachineTagged, kMachineTagged); |
- |
- const int kArraySize = 15; |
- Node* one = t.Int32Constant(1); |
- Node* index = t.Int32Constant(0); |
- Node* limit = t.Int32Constant(kArraySize); |
- t.environment()->Push(index); |
- { |
- LoopBuilder loop(&t); |
- loop.BeginLoop(); |
- // Loop exit condition. |
- index = t.environment()->Top(); |
- Node* condition = t.Int32LessThan(index, limit); |
- loop.BreakUnless(condition); |
- // src[index] = dst[index]. |
- index = t.environment()->Pop(); |
- ElementAccess access = ForFixedArrayElement(); |
- Node* src = t.Parameter(0); |
- Node* load = t.LoadElement(access, src, index); |
- Node* dst = t.Parameter(1); |
- t.StoreElement(access, dst, index, load); |
- // index++ |
- index = t.Int32Add(index, one); |
- t.environment()->Push(index); |
- // continue. |
- loop.EndBody(); |
- loop.EndLoop(); |
- } |
- index = t.environment()->Pop(); |
- t.Return(index); |
+ t.Return(t.jsgraph.TrueConstant()); |
t.LowerAllNodes(); |
- if (!Pipeline::SupportedTarget()) return; |
+ if (Pipeline::SupportedTarget()) { |
+ t.GenerateCode(); |
+ Handle<JSArrayBuffer> array = t.factory()->NewJSArrayBuffer(); |
+ const int array_length = 2 * index; |
+ Runtime::SetupArrayBufferAllocatingData(t.isolate(), array, array_length); |
+ uint8_t* data = reinterpret_cast<uint8_t*>(array->backing_store()); |
+ for (int i = 0; i < array_length; i++) { |
+ data[i] = i; |
+ } |
- Handle<FixedArray> src = t.factory()->NewFixedArray(kArraySize); |
- Handle<FixedArray> src_copy = t.factory()->NewFixedArray(kArraySize); |
- Handle<FixedArray> dst = t.factory()->NewFixedArray(kArraySize); |
- for (int i = 0; i < kArraySize; i++) { |
- src->set(i, *TestObject()); |
- src_copy->set(i, src->get(i)); |
- dst->set(i, *TestObject()); |
- CHECK_NE(src_copy->get(i), dst->get(i)); |
- } |
- CHECK_EQ(kArraySize, t.Call(*src, *dst)); |
- for (int i = 0; i < kArraySize; i++) { |
- CHECK_EQ(src_copy->get(i), dst->get(i)); |
+ // TODO(titzer): raw pointers in call |
+ Object* result = t.Call(*array); |
+ CHECK_EQ(t.isolate()->heap()->true_value(), result); |
+ for (int i = 0; i < array_length; i++) { |
+ uint8_t expected = i; |
+ if (i == (index + 1)) expected = index; |
+ CHECK_EQ(data[i], expected); |
+ } |
} |
} |
@@ -425,3 +381,246 @@ TEST(RunStoreElementFromUntaggedBase) { |
} |
} |
} |
+ |
+ |
+// A helper class for accessing fields and elements of various types, on both |
+// tagged and untagged base pointers. Contains both tagged and untagged buffers |
+// for testing direct memory access from generated code. |
+template <typename E> |
+class AccessTester : public HandleAndZoneScope { |
+ public: |
+ bool tagged; |
+ MachineRepresentation rep; |
+ E* original_elements; |
+ int num_elements; |
+ E* untagged_array; |
+ Handle<ByteArray> tagged_array; // TODO(titzer): use FixedArray for tagged. |
+ |
+ AccessTester(bool t, MachineRepresentation r, E* orig, int num) |
+ : tagged(t), |
+ rep(r), |
+ original_elements(orig), |
+ num_elements(num), |
+ untagged_array(static_cast<E*>(malloc(ByteSize()))), |
+ tagged_array(main_isolate()->factory()->NewByteArray(ByteSize())) { |
+ Reinitialize(); |
+ } |
+ |
+ ~AccessTester() { free(untagged_array); } |
+ |
+ size_t ByteSize() { return num_elements * sizeof(E); } |
+ |
+ // Nuke both {untagged_array} and {tagged_array} with {original_elements}. |
+ void Reinitialize() { |
+ memcpy(untagged_array, original_elements, ByteSize()); |
+ CHECK_EQ(ByteSize(), tagged_array->length()); |
+ E* raw = reinterpret_cast<E*>(tagged_array->GetDataStartAddress()); |
+ memcpy(raw, original_elements, ByteSize()); |
+ } |
+ |
+ // Create and run code that copies the element in either {untagged_array} |
+ // or {tagged_array} at index {from_index} to index {to_index}. |
+ void RunCopyElement(int from_index, int to_index) { |
+ // TODO(titzer): test element and field accesses where the base is not |
+ // a constant in the code. |
+ BoundsCheck(from_index); |
+ BoundsCheck(to_index); |
+ ElementAccess access = GetElementAccess(); |
+ |
+ SimplifiedGraphBuilderTester<Object*> t; |
+ Node* ptr = GetBaseNode(&t); |
+ Node* load = t.LoadElement(access, ptr, t.Int32Constant(from_index)); |
+ t.StoreElement(access, ptr, t.Int32Constant(to_index), load); |
+ t.Return(t.jsgraph.TrueConstant()); |
+ t.LowerAllNodes(); |
+ t.GenerateCode(); |
+ |
+ if (Pipeline::SupportedTarget()) { |
+ Object* result = t.Call(); |
+ CHECK_EQ(t.isolate()->heap()->true_value(), result); |
+ } |
+ } |
+ |
+ // Create and run code that copies the field in either {untagged_array} |
+ // or {tagged_array} at index {from_index} to index {to_index}. |
+ void RunCopyField(int from_index, int to_index) { |
+ BoundsCheck(from_index); |
+ BoundsCheck(to_index); |
+ FieldAccess from_access = GetFieldAccess(from_index); |
+ FieldAccess to_access = GetFieldAccess(to_index); |
+ |
+ SimplifiedGraphBuilderTester<Object*> t; |
+ Node* ptr = GetBaseNode(&t); |
+ Node* load = t.LoadField(from_access, ptr); |
+ t.StoreField(to_access, ptr, load); |
+ t.Return(t.jsgraph.TrueConstant()); |
+ t.LowerAllNodes(); |
+ t.GenerateCode(); |
+ |
+ if (Pipeline::SupportedTarget()) { |
+ Object* result = t.Call(); |
+ CHECK_EQ(t.isolate()->heap()->true_value(), result); |
+ } |
+ } |
+ |
+ // Create and run code that copies the elements from {this} to {that}. |
+ void RunCopyElements(AccessTester<E>* that) { |
+ SimplifiedGraphBuilderTester<Object*> t; |
+ |
+ Node* one = t.Int32Constant(1); |
+ Node* index = t.Int32Constant(0); |
+ Node* limit = t.Int32Constant(num_elements); |
+ t.environment()->Push(index); |
+ Node* src = this->GetBaseNode(&t); |
+ Node* dst = that->GetBaseNode(&t); |
+ { |
+ LoopBuilder loop(&t); |
+ loop.BeginLoop(); |
+ // Loop exit condition |
+ index = t.environment()->Top(); |
+ Node* condition = t.Int32LessThan(index, limit); |
+ loop.BreakUnless(condition); |
+ // dst[index] = src[index] |
+ index = t.environment()->Pop(); |
+ Node* load = t.LoadElement(this->GetElementAccess(), src, index); |
+ t.StoreElement(that->GetElementAccess(), dst, index, load); |
+ // index++ |
+ index = t.Int32Add(index, one); |
+ t.environment()->Push(index); |
+ // continue |
+ loop.EndBody(); |
+ loop.EndLoop(); |
+ } |
+ index = t.environment()->Pop(); |
+ t.Return(t.jsgraph.TrueConstant()); |
+ t.LowerAllNodes(); |
+ t.GenerateCode(); |
+ |
+ if (Pipeline::SupportedTarget()) { |
+ Object* result = t.Call(); |
+ CHECK_EQ(t.isolate()->heap()->true_value(), result); |
+ } |
+ } |
+ |
+ E GetElement(int index) { |
+ BoundsCheck(index); |
+ if (tagged) { |
+ E* raw = reinterpret_cast<E*>(tagged_array->GetDataStartAddress()); |
+ return raw[index]; |
+ } else { |
+ return untagged_array[index]; |
+ } |
+ } |
+ |
+ private: |
+ ElementAccess GetElementAccess() { |
+ ElementAccess access = {tagged ? kTaggedBase : kUntaggedBase, |
+ tagged ? FixedArrayBase::kHeaderSize : 0, |
+ Type::Any(), rep}; |
+ return access; |
+ } |
+ |
+ FieldAccess GetFieldAccess(int field) { |
+ int offset = field * sizeof(E); |
+ FieldAccess access = {tagged ? kTaggedBase : kUntaggedBase, |
+ offset + (tagged ? FixedArrayBase::kHeaderSize : 0), |
+ Handle<Name>(), Type::Any(), rep}; |
+ return access; |
+ } |
+ |
+ template <typename T> |
+ Node* GetBaseNode(SimplifiedGraphBuilderTester<T>* t) { |
+ return tagged ? t->HeapConstant(tagged_array) |
+ : t->PointerConstant(untagged_array); |
+ } |
+ |
+ void BoundsCheck(int index) { |
+ CHECK_GE(index, 0); |
+ CHECK_LT(index, num_elements); |
+ CHECK_EQ(ByteSize(), tagged_array->length()); |
+ } |
+}; |
+ |
+ |
+template <typename E> |
+static void RunAccessTest(MachineRepresentation rep, E* original_elements, |
+ size_t num) { |
+ int num_elements = static_cast<int>(num); |
+ |
+ for (int taggedness = 0; taggedness < 2; taggedness++) { |
+ AccessTester<E> a(taggedness == 1, rep, original_elements, num_elements); |
+ for (int field = 0; field < 2; field++) { |
+ for (int i = 0; i < num_elements - 1; i++) { |
+ a.Reinitialize(); |
+ if (field == 0) { |
+ a.RunCopyField(i, i + 1); // Test field read/write. |
+ } else { |
+ a.RunCopyElement(i, i + 1); // Test element read/write. |
+ } |
+ if (Pipeline::SupportedTarget()) { // verify. |
+ for (int j = 0; j < num_elements; j++) { |
+ E expect = |
+ j == (i + 1) ? original_elements[i] : original_elements[j]; |
+ CHECK_EQ(expect, a.GetElement(j)); |
+ } |
+ } |
+ } |
+ } |
+ } |
+ // Test array copy. |
+ for (int tf = 0; tf < 2; tf++) { |
+ for (int tt = 0; tt < 2; tt++) { |
+ AccessTester<E> a(tf == 1, rep, original_elements, num_elements); |
+ AccessTester<E> b(tt == 1, rep, original_elements, num_elements); |
+ a.RunCopyElements(&b); |
+ if (Pipeline::SupportedTarget()) { // verify. |
+ for (int i = 0; i < num_elements; i++) { |
+ CHECK_EQ(a.GetElement(i), b.GetElement(i)); |
+ } |
+ } |
+ } |
+ } |
+} |
+ |
+ |
+TEST(RunAccessTests_uint8) { |
+ uint8_t data[] = {0x07, 0x16, 0x25, 0x34, 0x43, 0x99, |
+ 0xab, 0x78, 0x89, 0x19, 0x2b, 0x38}; |
+ RunAccessTest<uint8_t>(kMachineWord8, data, ARRAY_SIZE(data)); |
+} |
+ |
+ |
+TEST(RunAccessTests_uint16) { |
+ uint16_t data[] = {0x071a, 0x162b, 0x253c, 0x344d, 0x435e, 0x7777}; |
+ RunAccessTest<uint16_t>(kMachineWord16, data, ARRAY_SIZE(data)); |
+} |
+ |
+ |
+TEST(RunAccessTests_int32) { |
+ int32_t data[] = {0xf10733aa, 0xf21644bb, 0xf32555cc, |
+ 0xf43466dd, 0xf54377ee, 0x34455667}; |
+ RunAccessTest<int32_t>(kMachineWord32, data, ARRAY_SIZE(data)); |
+} |
+ |
+ |
+TEST(RunAccessTests_int64) { |
+ if (kPointerSize != 8) return; |
+ int64_t data[] = {0x1011121314151617L, 0x2021222324252627L, |
+ 0x3031323334353637L, 0xa0a1a2a3a4a5a6a7L, |
+ 0xf0f1f2f3f4f5f6f7L}; |
+ RunAccessTest<int64_t>(kMachineWord64, data, ARRAY_SIZE(data)); |
+} |
+ |
+ |
+TEST(RunAccessTests_float64) { |
+ double data[] = {1.25, -1.25, 2.75, 11.0, 11100.8}; |
+ RunAccessTest<double>(kMachineFloat64, data, ARRAY_SIZE(data)); |
+} |
+ |
+ |
+TEST(RunAccessTests_Smi) { |
+ Smi* data[] = {Smi::FromInt(-1), Smi::FromInt(-9), |
+ Smi::FromInt(0), Smi::FromInt(666), |
+ Smi::FromInt(77777), Smi::FromInt(Smi::kMaxValue)}; |
+ RunAccessTest<Smi*>(kMachineTagged, data, ARRAY_SIZE(data)); |
+} |