blob: 0b23669cf7d04280e551ff36d2b1bb03150fcc84 [file] [log] [blame]
Ben Murdochc5610432016-08-08 18:44:38 +01001// Copyright 2016 the V8 project authors. All rights reserved. Use of this
2// source code is governed by a BSD-style license that can be found in the
3// LICENSE file.
4
5#include <cmath>
6#include <functional>
7#include <limits>
8
9#include "src/base/bits.h"
10#include "src/base/utils/random-number-generator.h"
11#include "src/codegen.h"
12#include "test/cctest/cctest.h"
13#include "test/cctest/compiler/codegen-tester.h"
14#include "test/cctest/compiler/graph-builder-tester.h"
15#include "test/cctest/compiler/value-helper.h"
16
17using namespace v8::internal;
18using namespace v8::internal::compiler;
19
20static void UpdateMemoryReferences(Handle<Code> code, Address old_base,
21 Address new_base, uint32_t old_size,
22 uint32_t new_size) {
23 Isolate* isolate = CcTest::i_isolate();
24 bool modified = false;
25 int mode_mask = RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_REFERENCE) |
26 RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_SIZE_REFERENCE);
27 for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) {
28 RelocInfo::Mode mode = it.rinfo()->rmode();
29 if (RelocInfo::IsWasmMemoryReference(mode) ||
30 RelocInfo::IsWasmMemorySizeReference(mode)) {
31 // Patch addresses with change in memory start address
32 it.rinfo()->update_wasm_memory_reference(old_base, new_base, old_size,
33 new_size);
34 modified = true;
35 }
36 }
37 if (modified) {
38 Assembler::FlushICache(isolate, code->instruction_start(),
39 code->instruction_size());
40 }
41}
42
43template <typename CType>
44static void RunLoadStoreRelocation(MachineType rep) {
45 const int kNumElems = 2;
46 CType buffer[kNumElems];
47 CType new_buffer[kNumElems];
48 byte* raw = reinterpret_cast<byte*>(buffer);
49 byte* new_raw = reinterpret_cast<byte*>(new_buffer);
50 for (size_t i = 0; i < sizeof(buffer); i++) {
51 raw[i] = static_cast<byte>((i + sizeof(CType)) ^ 0xAA);
52 new_raw[i] = static_cast<byte>((i + sizeof(CType)) ^ 0xAA);
53 }
54 int32_t OK = 0x29000;
55 RawMachineAssemblerTester<uint32_t> m;
56 Node* base = m.RelocatableIntPtrConstant(reinterpret_cast<intptr_t>(raw),
57 RelocInfo::WASM_MEMORY_REFERENCE);
58 Node* base1 = m.RelocatableIntPtrConstant(
59 reinterpret_cast<intptr_t>(raw + sizeof(CType)),
60 RelocInfo::WASM_MEMORY_REFERENCE);
61 Node* index = m.Int32Constant(0);
62 Node* load = m.Load(rep, base, index);
63 m.Store(rep.representation(), base1, index, load, kNoWriteBarrier);
64 m.Return(m.Int32Constant(OK));
65 CHECK(buffer[0] != buffer[1]);
66 CHECK_EQ(OK, m.Call());
67 CHECK(buffer[0] == buffer[1]);
68 m.GenerateCode();
69 Handle<Code> code = m.GetCode();
70 UpdateMemoryReferences(code, raw, new_raw, sizeof(buffer),
71 sizeof(new_buffer));
72 CHECK(new_buffer[0] != new_buffer[1]);
73 CHECK_EQ(OK, m.Call());
74 CHECK(new_buffer[0] == new_buffer[1]);
75}
76
77TEST(RunLoadStoreRelocation) {
78 RunLoadStoreRelocation<int8_t>(MachineType::Int8());
79 RunLoadStoreRelocation<uint8_t>(MachineType::Uint8());
80 RunLoadStoreRelocation<int16_t>(MachineType::Int16());
81 RunLoadStoreRelocation<uint16_t>(MachineType::Uint16());
82 RunLoadStoreRelocation<int32_t>(MachineType::Int32());
83 RunLoadStoreRelocation<uint32_t>(MachineType::Uint32());
84 RunLoadStoreRelocation<void*>(MachineType::AnyTagged());
85 RunLoadStoreRelocation<float>(MachineType::Float32());
86 RunLoadStoreRelocation<double>(MachineType::Float64());
87}
88
89template <typename CType>
90static void RunLoadStoreRelocationOffset(MachineType rep) {
91 RawMachineAssemblerTester<int32_t> r(MachineType::Int32());
92 const int kNumElems = 4;
93 CType buffer[kNumElems];
94 CType new_buffer[kNumElems + 1];
95
96 for (int32_t x = 0; x < kNumElems; x++) {
97 int32_t y = kNumElems - x - 1;
98 // initialize the buffer with raw data.
99 byte* raw = reinterpret_cast<byte*>(buffer);
100 for (size_t i = 0; i < sizeof(buffer); i++) {
101 raw[i] = static_cast<byte>((i + sizeof(buffer)) ^ 0xAA);
102 }
103
104 RawMachineAssemblerTester<int32_t> m;
105 int32_t OK = 0x29000 + x;
106 Node* base = m.RelocatableIntPtrConstant(reinterpret_cast<intptr_t>(buffer),
107 RelocInfo::WASM_MEMORY_REFERENCE);
108 Node* index0 = m.IntPtrConstant(x * sizeof(buffer[0]));
109 Node* load = m.Load(rep, base, index0);
110 Node* index1 = m.IntPtrConstant(y * sizeof(buffer[0]));
111 m.Store(rep.representation(), base, index1, load, kNoWriteBarrier);
112 m.Return(m.Int32Constant(OK));
113
114 CHECK(buffer[x] != buffer[y]);
115 CHECK_EQ(OK, m.Call());
116 CHECK(buffer[x] == buffer[y]);
117 m.GenerateCode();
118
119 // Initialize new buffer and set old_buffer to 0
120 byte* new_raw = reinterpret_cast<byte*>(new_buffer);
121 for (size_t i = 0; i < sizeof(buffer); i++) {
122 raw[i] = 0;
123 new_raw[i] = static_cast<byte>((i + sizeof(buffer)) ^ 0xAA);
124 }
125
126 // Perform relocation on generated code
127 Handle<Code> code = m.GetCode();
128 UpdateMemoryReferences(code, raw, new_raw, sizeof(buffer),
129 sizeof(new_buffer));
130
131 CHECK(new_buffer[x] != new_buffer[y]);
132 CHECK_EQ(OK, m.Call());
133 CHECK(new_buffer[x] == new_buffer[y]);
134 }
135}
136
137TEST(RunLoadStoreRelocationOffset) {
138 RunLoadStoreRelocationOffset<int8_t>(MachineType::Int8());
139 RunLoadStoreRelocationOffset<uint8_t>(MachineType::Uint8());
140 RunLoadStoreRelocationOffset<int16_t>(MachineType::Int16());
141 RunLoadStoreRelocationOffset<uint16_t>(MachineType::Uint16());
142 RunLoadStoreRelocationOffset<int32_t>(MachineType::Int32());
143 RunLoadStoreRelocationOffset<uint32_t>(MachineType::Uint32());
144 RunLoadStoreRelocationOffset<void*>(MachineType::AnyTagged());
145 RunLoadStoreRelocationOffset<float>(MachineType::Float32());
146 RunLoadStoreRelocationOffset<double>(MachineType::Float64());
147}
148
149TEST(Uint32LessThanRelocation) {
150 RawMachineAssemblerTester<uint32_t> m;
151 RawMachineLabel within_bounds, out_of_bounds;
152 Node* index = m.Int32Constant(0x200);
153 Node* limit =
154 m.RelocatableInt32Constant(0x200, RelocInfo::WASM_MEMORY_SIZE_REFERENCE);
155 Node* cond = m.AddNode(m.machine()->Uint32LessThan(), index, limit);
156 m.Branch(cond, &within_bounds, &out_of_bounds);
157 m.Bind(&within_bounds);
158 m.Return(m.Int32Constant(0xaced));
159 m.Bind(&out_of_bounds);
160 m.Return(m.Int32Constant(0xdeadbeef));
161 // Check that index is out of bounds with current size
162 CHECK_EQ(0xdeadbeef, m.Call());
163 m.GenerateCode();
164
165 Handle<Code> code = m.GetCode();
166 UpdateMemoryReferences(code, reinterpret_cast<Address>(1234),
167 reinterpret_cast<Address>(1234), 0x200, 0x400);
168 // Check that after limit is increased, index is within bounds.
169 CHECK_EQ(0xaced, m.Call());
170}