| 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));
|
| +}
|
|
|