• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <stdint.h>
6 #include <stdlib.h>
7 #include <string.h>
8 
9 #include "src/wasm/wasm-macro-gen.h"
10 
11 #include "src/wasm/wasm-interpreter.h"
12 
13 #include "test/cctest/cctest.h"
14 #include "test/cctest/compiler/value-helper.h"
15 #include "test/cctest/wasm/test-signatures.h"
16 #include "test/cctest/wasm/wasm-run-utils.h"
17 
18 using namespace v8::base;
19 using namespace v8::internal;
20 using namespace v8::internal::compiler;
21 using namespace v8::internal::wasm;
22 
23 namespace v8 {
24 namespace internal {
25 namespace wasm {
26 
TEST(Run_WasmInt8Const_i)27 TEST(Run_WasmInt8Const_i) {
28   WasmRunner<int32_t> r(kExecuteInterpreted);
29   const byte kExpectedValue = 109;
30   // return(kExpectedValue)
31   BUILD(r, WASM_I8(kExpectedValue));
32   CHECK_EQ(kExpectedValue, r.Call());
33 }
34 
TEST(Run_WasmIfElse)35 TEST(Run_WasmIfElse) {
36   WasmRunner<int32_t> r(kExecuteInterpreted, MachineType::Int32());
37   BUILD(r, WASM_IF_ELSE(WASM_GET_LOCAL(0), WASM_I8(9), WASM_I8(10)));
38   CHECK_EQ(10, r.Call(0));
39   CHECK_EQ(9, r.Call(1));
40 }
41 
TEST(Run_WasmIfReturn)42 TEST(Run_WasmIfReturn) {
43   WasmRunner<int32_t> r(kExecuteInterpreted, MachineType::Int32());
44   BUILD(r, WASM_IF(WASM_GET_LOCAL(0), WASM_RETURN1(WASM_I8(77))), WASM_I8(65));
45   CHECK_EQ(65, r.Call(0));
46   CHECK_EQ(77, r.Call(1));
47 }
48 
TEST(Run_WasmNopsN)49 TEST(Run_WasmNopsN) {
50   const int kMaxNops = 10;
51   byte code[kMaxNops + 2];
52   for (int nops = 0; nops < kMaxNops; nops++) {
53     byte expected = static_cast<byte>(20 + nops);
54     memset(code, kExprNop, sizeof(code));
55     code[nops] = kExprI8Const;
56     code[nops + 1] = expected;
57 
58     WasmRunner<int32_t> r(kExecuteInterpreted);
59     r.Build(code, code + nops + 2);
60     CHECK_EQ(expected, r.Call());
61   }
62 }
63 
TEST(Run_WasmConstsN)64 TEST(Run_WasmConstsN) {
65   const int kMaxConsts = 10;
66   byte code[kMaxConsts * 2];
67   for (int count = 1; count < kMaxConsts; count++) {
68     for (int i = 0; i < count; i++) {
69       code[i * 2] = kExprI8Const;
70       code[i * 2 + 1] = static_cast<byte>(count * 10 + i);
71     }
72     byte expected = static_cast<byte>(count * 11 - 1);
73 
74     WasmRunner<int32_t> r(kExecuteInterpreted);
75     r.Build(code, code + (count * 2));
76     CHECK_EQ(expected, r.Call());
77   }
78 }
79 
TEST(Run_WasmBlocksN)80 TEST(Run_WasmBlocksN) {
81   const int kMaxNops = 10;
82   const int kExtra = 4;
83   byte code[kMaxNops + kExtra];
84   for (int nops = 0; nops < kMaxNops; nops++) {
85     byte expected = static_cast<byte>(30 + nops);
86     memset(code, kExprNop, sizeof(code));
87     code[0] = kExprBlock;
88     code[1 + nops] = kExprI8Const;
89     code[1 + nops + 1] = expected;
90     code[1 + nops + 2] = kExprEnd;
91 
92     WasmRunner<int32_t> r(kExecuteInterpreted);
93     r.Build(code, code + nops + kExtra);
94     CHECK_EQ(expected, r.Call());
95   }
96 }
97 
TEST(Run_WasmBlockBreakN)98 TEST(Run_WasmBlockBreakN) {
99   const int kMaxNops = 10;
100   const int kExtra = 6;
101   byte code[kMaxNops + kExtra];
102   for (int nops = 0; nops < kMaxNops; nops++) {
103     // Place the break anywhere within the block.
104     for (int index = 0; index < nops; index++) {
105       memset(code, kExprNop, sizeof(code));
106       code[0] = kExprBlock;
107       code[sizeof(code) - 1] = kExprEnd;
108 
109       int expected = nops * 11 + index;
110       code[1 + index + 0] = kExprI8Const;
111       code[1 + index + 1] = static_cast<byte>(expected);
112       code[1 + index + 2] = kExprBr;
113       code[1 + index + 3] = ARITY_1;
114       code[1 + index + 4] = 0;
115 
116       WasmRunner<int32_t> r(kExecuteInterpreted);
117       r.Build(code, code + kMaxNops + kExtra);
118       CHECK_EQ(expected, r.Call());
119     }
120   }
121 }
122 
TEST(Run_Wasm_nested_ifs_i)123 TEST(Run_Wasm_nested_ifs_i) {
124   WasmRunner<int32_t> r(kExecuteInterpreted, MachineType::Int32(),
125                         MachineType::Int32());
126 
127   BUILD(r, WASM_IF_ELSE(
128                WASM_GET_LOCAL(0),
129                WASM_IF_ELSE(WASM_GET_LOCAL(1), WASM_I8(11), WASM_I8(12)),
130                WASM_IF_ELSE(WASM_GET_LOCAL(1), WASM_I8(13), WASM_I8(14))));
131 
132   CHECK_EQ(11, r.Call(1, 1));
133   CHECK_EQ(12, r.Call(1, 0));
134   CHECK_EQ(13, r.Call(0, 1));
135   CHECK_EQ(14, r.Call(0, 0));
136 }
137 
138 // Make tests more robust by not hard-coding offsets of various operations.
139 // The {Find} method finds the offsets for the given bytecodes, returning
140 // the offsets in an array.
Find(byte * code,size_t code_size,int n,...)141 SmartArrayPointer<int> Find(byte* code, size_t code_size, int n, ...) {
142   va_list vl;
143   va_start(vl, n);
144 
145   SmartArrayPointer<int> offsets(new int[n]);
146 
147   for (int i = 0; i < n; i++) {
148     offsets[i] = -1;
149   }
150 
151   int pos = 0;
152   WasmOpcode current = static_cast<WasmOpcode>(va_arg(vl, int));
153   for (size_t i = 0; i < code_size; i++) {
154     if (code[i] == current) {
155       offsets[pos++] = static_cast<int>(i);
156       if (pos == n) break;
157       current = static_cast<WasmOpcode>(va_arg(vl, int));
158     }
159   }
160   va_end(vl);
161 
162   return offsets;
163 }
164 
TEST(Breakpoint_I32Add)165 TEST(Breakpoint_I32Add) {
166   static const int kLocalsDeclSize = 1;
167   static const int kNumBreakpoints = 3;
168   byte code[] = {WASM_I32_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))};
169   SmartArrayPointer<int> offsets =
170       Find(code, sizeof(code), kNumBreakpoints, kExprGetLocal, kExprGetLocal,
171            kExprI32Add);
172 
173   WasmRunner<int32_t> r(kExecuteInterpreted, MachineType::Uint32(),
174                         MachineType::Uint32());
175 
176   r.Build(code, code + arraysize(code));
177 
178   WasmInterpreter* interpreter = r.interpreter();
179   WasmInterpreter::Thread* thread = interpreter->GetThread(0);
180   for (int i = 0; i < kNumBreakpoints; i++) {
181     interpreter->SetBreakpoint(r.function(), kLocalsDeclSize + offsets[i],
182                                true);
183   }
184 
185   FOR_UINT32_INPUTS(a) {
186     for (uint32_t b = 11; b < 3000000000u; b += 1000000000u) {
187       thread->Reset();
188       WasmVal args[] = {WasmVal(*a), WasmVal(b)};
189       thread->PushFrame(r.function(), args);
190 
191       for (int i = 0; i < kNumBreakpoints; i++) {
192         thread->Run();  // run to next breakpoint
193         // Check the thread stopped at the right pc.
194         CHECK_EQ(WasmInterpreter::PAUSED, thread->state());
195         CHECK_EQ(kLocalsDeclSize + offsets[i], thread->GetBreakpointPc());
196       }
197 
198       thread->Run();  // run to completion
199 
200       // Check the thread finished with the right value.
201       CHECK_EQ(WasmInterpreter::FINISHED, thread->state());
202       uint32_t expected = (*a) + (b);
203       CHECK_EQ(expected, thread->GetReturnValue().to<uint32_t>());
204     }
205   }
206 }
207 
TEST(Step_I32Mul)208 TEST(Step_I32Mul) {
209   static const int kTraceLength = 4;
210   byte code[] = {WASM_I32_MUL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))};
211 
212   WasmRunner<int32_t> r(kExecuteInterpreted, MachineType::Uint32(),
213                         MachineType::Uint32());
214 
215   r.Build(code, code + arraysize(code));
216 
217   WasmInterpreter* interpreter = r.interpreter();
218   WasmInterpreter::Thread* thread = interpreter->GetThread(0);
219 
220   FOR_UINT32_INPUTS(a) {
221     for (uint32_t b = 33; b < 3000000000u; b += 1000000000u) {
222       thread->Reset();
223       WasmVal args[] = {WasmVal(*a), WasmVal(b)};
224       thread->PushFrame(r.function(), args);
225 
226       // Run instructions one by one.
227       for (int i = 0; i < kTraceLength - 1; i++) {
228         thread->Step();
229         // Check the thread stopped.
230         CHECK_EQ(WasmInterpreter::PAUSED, thread->state());
231       }
232 
233       // Run last instruction.
234       thread->Step();
235 
236       // Check the thread finished with the right value.
237       CHECK_EQ(WasmInterpreter::FINISHED, thread->state());
238       uint32_t expected = (*a) * (b);
239       CHECK_EQ(expected, thread->GetReturnValue().to<uint32_t>());
240     }
241   }
242 }
243 
TEST(Breakpoint_I32And_disable)244 TEST(Breakpoint_I32And_disable) {
245   static const int kLocalsDeclSize = 1;
246   static const int kNumBreakpoints = 1;
247   byte code[] = {WASM_I32_AND(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))};
248   SmartArrayPointer<int> offsets =
249       Find(code, sizeof(code), kNumBreakpoints, kExprI32And);
250 
251   WasmRunner<int32_t> r(kExecuteInterpreted, MachineType::Uint32(),
252                         MachineType::Uint32());
253 
254   r.Build(code, code + arraysize(code));
255 
256   WasmInterpreter* interpreter = r.interpreter();
257   WasmInterpreter::Thread* thread = interpreter->GetThread(0);
258 
259   FOR_UINT32_INPUTS(a) {
260     for (uint32_t b = 11; b < 3000000000u; b += 1000000000u) {
261       // Run with and without breakpoints.
262       for (int do_break = 0; do_break < 2; do_break++) {
263         interpreter->SetBreakpoint(r.function(), kLocalsDeclSize + offsets[0],
264                                    do_break);
265         thread->Reset();
266         WasmVal args[] = {WasmVal(*a), WasmVal(b)};
267         thread->PushFrame(r.function(), args);
268 
269         if (do_break) {
270           thread->Run();  // run to next breakpoint
271           // Check the thread stopped at the right pc.
272           CHECK_EQ(WasmInterpreter::PAUSED, thread->state());
273           CHECK_EQ(kLocalsDeclSize + offsets[0], thread->GetBreakpointPc());
274         }
275 
276         thread->Run();  // run to completion
277 
278         // Check the thread finished with the right value.
279         CHECK_EQ(WasmInterpreter::FINISHED, thread->state());
280         uint32_t expected = (*a) & (b);
281         CHECK_EQ(expected, thread->GetReturnValue().to<uint32_t>());
282       }
283     }
284   }
285 }
286 
287 }  // namespace wasm
288 }  // namespace internal
289 }  // namespace v8
290