Line data Source code
1 : // Copyright 2015 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 <stdlib.h>
6 : #include <string.h>
7 :
8 : #include "src/api-inl.h"
9 : #include "src/objects-inl.h"
10 : #include "src/snapshot/code-serializer.h"
11 : #include "src/version.h"
12 : #include "src/wasm/module-decoder.h"
13 : #include "src/wasm/wasm-engine.h"
14 : #include "src/wasm/wasm-memory.h"
15 : #include "src/wasm/wasm-module-builder.h"
16 : #include "src/wasm/wasm-module.h"
17 : #include "src/wasm/wasm-objects-inl.h"
18 : #include "src/wasm/wasm-opcodes.h"
19 :
20 : #include "test/cctest/cctest.h"
21 : #include "test/common/wasm/flag-utils.h"
22 : #include "test/common/wasm/test-signatures.h"
23 : #include "test/common/wasm/wasm-macro-gen.h"
24 : #include "test/common/wasm/wasm-module-runner.h"
25 :
26 : namespace v8 {
27 : namespace internal {
28 : namespace wasm {
29 : namespace test_run_wasm_module {
30 :
31 : using testing::CompileAndInstantiateForTesting;
32 :
33 : namespace {
34 : void Cleanup(Isolate* isolate = CcTest::InitIsolateOnce()) {
35 : // By sending a low memory notifications, we will try hard to collect all
36 : // garbage and will therefore also invoke all weak callbacks of actually
37 : // unreachable persistent handles.
38 125 : reinterpret_cast<v8::Isolate*>(isolate)->LowMemoryNotification();
39 : }
40 :
41 164 : void TestModule(Zone* zone, WasmModuleBuilder* builder,
42 : int32_t expected_result) {
43 : ZoneBuffer buffer(zone);
44 164 : builder->WriteTo(buffer);
45 :
46 : Isolate* isolate = CcTest::InitIsolateOnce();
47 : HandleScope scope(isolate);
48 164 : testing::SetupIsolateForWasmModule(isolate);
49 : int32_t result =
50 164 : testing::CompileAndRunWasmModule(isolate, buffer.begin(), buffer.end());
51 164 : CHECK_EQ(expected_result, result);
52 164 : }
53 :
54 4 : void TestModuleException(Zone* zone, WasmModuleBuilder* builder) {
55 : ZoneBuffer buffer(zone);
56 4 : builder->WriteTo(buffer);
57 :
58 : Isolate* isolate = CcTest::InitIsolateOnce();
59 : HandleScope scope(isolate);
60 4 : testing::SetupIsolateForWasmModule(isolate);
61 8 : v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
62 4 : testing::CompileAndRunWasmModule(isolate, buffer.begin(), buffer.end());
63 4 : CHECK(try_catch.HasCaught());
64 : isolate->clear_pending_exception();
65 4 : }
66 :
67 : void ExportAsMain(WasmFunctionBuilder* f) {
68 197 : f->builder()->AddExport(CStrVector("main"), f);
69 : }
70 :
71 : #define EMIT_CODE_WITH_END(f, code) \
72 : do { \
73 : f->EmitCode(code, sizeof(code)); \
74 : f->Emit(kExprEnd); \
75 : } while (false)
76 :
77 : } // namespace
78 :
79 26660 : TEST(Run_WasmModule_Return114) {
80 : {
81 : static const int32_t kReturnValue = 114;
82 4 : TestSignatures sigs;
83 8 : v8::internal::AccountingAllocator allocator;
84 8 : Zone zone(&allocator, ZONE_NAME);
85 :
86 4 : WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
87 4 : WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
88 : ExportAsMain(f);
89 4 : byte code[] = {WASM_I32V_2(kReturnValue)};
90 4 : EMIT_CODE_WITH_END(f, code);
91 4 : TestModule(&zone, builder, kReturnValue);
92 : }
93 : Cleanup();
94 4 : }
95 :
96 26660 : TEST(Run_WasmModule_CompilationHintsLazy) {
97 4 : if (!FLAG_wasm_tier_up || !FLAG_liftoff) return;
98 : {
99 : EXPERIMENTAL_FLAG_SCOPE(compilation_hints);
100 :
101 : static const int32_t kReturnValue = 114;
102 3 : TestSignatures sigs;
103 6 : v8::internal::AccountingAllocator allocator;
104 6 : Zone zone(&allocator, ZONE_NAME);
105 :
106 : // Build module with one lazy function.
107 3 : WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
108 3 : WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
109 : ExportAsMain(f);
110 3 : byte code[] = {WASM_I32V_2(kReturnValue)};
111 3 : EMIT_CODE_WITH_END(f, code);
112 : f->SetCompilationHint(WasmCompilationHintStrategy::kLazy,
113 : WasmCompilationHintTier::kBaseline,
114 3 : WasmCompilationHintTier::kOptimized);
115 :
116 : // Compile module. No function is actually compiled as the function is lazy.
117 : ZoneBuffer buffer(&zone);
118 3 : builder->WriteTo(buffer);
119 : Isolate* isolate = CcTest::InitIsolateOnce();
120 : HandleScope scope(isolate);
121 3 : testing::SetupIsolateForWasmModule(isolate);
122 3 : ErrorThrower thrower(isolate, "CompileAndRunWasmModule");
123 : MaybeHandle<WasmModuleObject> module = testing::CompileForTesting(
124 3 : isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()));
125 3 : CHECK(!module.is_null());
126 :
127 : // Lazy function was not invoked and therefore not compiled yet.
128 : int func_index = 0;
129 3 : NativeModule* native_module = module.ToHandleChecked()->native_module();
130 3 : CHECK(!native_module->HasCode(func_index));
131 :
132 : // Instantiate and invoke function.
133 : MaybeHandle<WasmInstanceObject> instance =
134 : isolate->wasm_engine()->SyncInstantiate(
135 6 : isolate, &thrower, module.ToHandleChecked(), {}, {});
136 3 : CHECK(!instance.is_null());
137 : int32_t result = testing::RunWasmModuleForTesting(
138 3 : isolate, instance.ToHandleChecked(), 0, nullptr);
139 3 : CHECK_EQ(kReturnValue, result);
140 :
141 : // Lazy function was invoked and therefore compiled.
142 3 : CHECK(native_module->HasCode(func_index));
143 6 : WasmCodeRefScope code_ref_scope;
144 3 : ExecutionTier actual_tier = native_module->GetCode(func_index)->tier();
145 : static_assert(ExecutionTier::kInterpreter < ExecutionTier::kLiftoff &&
146 : ExecutionTier::kLiftoff < ExecutionTier::kTurbofan,
147 : "Assume an order on execution tiers");
148 : ExecutionTier baseline_tier = ExecutionTier::kLiftoff;
149 3 : CHECK_LE(baseline_tier, actual_tier);
150 : }
151 : Cleanup();
152 : }
153 :
154 26660 : TEST(Run_WasmModule_CompilationHintsNoTiering) {
155 4 : if (!FLAG_wasm_tier_up || !FLAG_liftoff) return;
156 : {
157 : EXPERIMENTAL_FLAG_SCOPE(compilation_hints);
158 :
159 : static const int32_t kReturnValue = 114;
160 3 : TestSignatures sigs;
161 6 : v8::internal::AccountingAllocator allocator;
162 6 : Zone zone(&allocator, ZONE_NAME);
163 :
164 : // Build module with regularly compiled function (no tiering).
165 3 : WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
166 3 : WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
167 : ExportAsMain(f);
168 3 : byte code[] = {WASM_I32V_2(kReturnValue)};
169 3 : EMIT_CODE_WITH_END(f, code);
170 : f->SetCompilationHint(WasmCompilationHintStrategy::kEager,
171 : WasmCompilationHintTier::kBaseline,
172 3 : WasmCompilationHintTier::kBaseline);
173 :
174 : // Compile module.
175 : ZoneBuffer buffer(&zone);
176 3 : builder->WriteTo(buffer);
177 : Isolate* isolate = CcTest::InitIsolateOnce();
178 : HandleScope scope(isolate);
179 3 : testing::SetupIsolateForWasmModule(isolate);
180 3 : ErrorThrower thrower(isolate, "CompileAndRunWasmModule");
181 : MaybeHandle<WasmModuleObject> module = testing::CompileForTesting(
182 3 : isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()));
183 3 : CHECK(!module.is_null());
184 :
185 : // Synchronous compilation finished and no tiering units were initialized.
186 : int func_index = 0;
187 3 : NativeModule* native_module = module.ToHandleChecked()->native_module();
188 3 : CHECK(native_module->HasCode(func_index));
189 6 : WasmCodeRefScope code_ref_scope;
190 : ExecutionTier expected_tier = ExecutionTier::kLiftoff;
191 3 : ExecutionTier actual_tier = native_module->GetCode(func_index)->tier();
192 3 : CHECK_EQ(expected_tier, actual_tier);
193 : }
194 : Cleanup();
195 : }
196 :
197 26660 : TEST(Run_WasmModule_CompilationHintsTierUp) {
198 4 : if (!FLAG_wasm_tier_up || !FLAG_liftoff) return;
199 : {
200 : EXPERIMENTAL_FLAG_SCOPE(compilation_hints);
201 :
202 : static const int32_t kReturnValue = 114;
203 3 : TestSignatures sigs;
204 6 : v8::internal::AccountingAllocator allocator;
205 6 : Zone zone(&allocator, ZONE_NAME);
206 :
207 : // Build module with tiering compilation hint.
208 3 : WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
209 3 : WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
210 : ExportAsMain(f);
211 3 : byte code[] = {WASM_I32V_2(kReturnValue)};
212 3 : EMIT_CODE_WITH_END(f, code);
213 : f->SetCompilationHint(WasmCompilationHintStrategy::kEager,
214 : WasmCompilationHintTier::kBaseline,
215 3 : WasmCompilationHintTier::kOptimized);
216 :
217 : // Compile module.
218 : ZoneBuffer buffer(&zone);
219 3 : builder->WriteTo(buffer);
220 : Isolate* isolate = CcTest::InitIsolateOnce();
221 : HandleScope scope(isolate);
222 3 : testing::SetupIsolateForWasmModule(isolate);
223 3 : ErrorThrower thrower(isolate, "CompileAndRunWasmModule");
224 : MaybeHandle<WasmModuleObject> module = testing::CompileForTesting(
225 3 : isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()));
226 3 : CHECK(!module.is_null());
227 :
228 : // Expect code baseline code or top tier code.
229 : int func_index = 0;
230 3 : NativeModule* native_module = module.ToHandleChecked()->native_module();
231 3 : CHECK(native_module->HasCode(func_index));
232 6 : WasmCodeRefScope code_ref_scope;
233 3 : ExecutionTier actual_tier = native_module->GetCode(func_index)->tier();
234 : static_assert(ExecutionTier::kInterpreter < ExecutionTier::kLiftoff &&
235 : ExecutionTier::kLiftoff < ExecutionTier::kTurbofan,
236 : "Assume an order on execution tiers");
237 : ExecutionTier baseline_tier = ExecutionTier::kLiftoff;
238 3 : CHECK_LE(baseline_tier, actual_tier);
239 : ExecutionTier top_tier = ExecutionTier::kTurbofan;
240 3 : CHECK_LE(actual_tier, top_tier);
241 : }
242 : Cleanup();
243 : }
244 :
245 26660 : TEST(Run_WasmModule_CallAdd) {
246 : {
247 8 : v8::internal::AccountingAllocator allocator;
248 8 : Zone zone(&allocator, ZONE_NAME);
249 4 : TestSignatures sigs;
250 :
251 4 : WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
252 :
253 4 : WasmFunctionBuilder* f1 = builder->AddFunction(sigs.i_ii());
254 : uint16_t param1 = 0;
255 : uint16_t param2 = 1;
256 : byte code1[] = {
257 4 : WASM_I32_ADD(WASM_GET_LOCAL(param1), WASM_GET_LOCAL(param2))};
258 4 : EMIT_CODE_WITH_END(f1, code1);
259 :
260 4 : WasmFunctionBuilder* f2 = builder->AddFunction(sigs.i_v());
261 :
262 : ExportAsMain(f2);
263 : byte code2[] = {
264 4 : WASM_CALL_FUNCTION(f1->func_index(), WASM_I32V_2(77), WASM_I32V_1(22))};
265 4 : EMIT_CODE_WITH_END(f2, code2);
266 4 : TestModule(&zone, builder, 99);
267 : }
268 : Cleanup();
269 4 : }
270 :
271 26660 : TEST(Run_WasmModule_ReadLoadedDataSegment) {
272 : {
273 : static const byte kDataSegmentDest0 = 12;
274 8 : v8::internal::AccountingAllocator allocator;
275 8 : Zone zone(&allocator, ZONE_NAME);
276 4 : TestSignatures sigs;
277 :
278 4 : WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
279 4 : WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
280 :
281 : ExportAsMain(f);
282 : byte code[] = {
283 4 : WASM_LOAD_MEM(MachineType::Int32(), WASM_I32V_1(kDataSegmentDest0))};
284 4 : EMIT_CODE_WITH_END(f, code);
285 4 : byte data[] = {0xAA, 0xBB, 0xCC, 0xDD};
286 4 : builder->AddDataSegment(data, sizeof(data), kDataSegmentDest0);
287 4 : TestModule(&zone, builder, 0xDDCCBBAA);
288 : }
289 : Cleanup();
290 4 : }
291 :
292 26660 : TEST(Run_WasmModule_CheckMemoryIsZero) {
293 : {
294 : static const int kCheckSize = 16 * 1024;
295 8 : v8::internal::AccountingAllocator allocator;
296 8 : Zone zone(&allocator, ZONE_NAME);
297 4 : TestSignatures sigs;
298 :
299 4 : WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
300 4 : WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
301 :
302 4 : uint16_t localIndex = f->AddLocal(kWasmI32);
303 : ExportAsMain(f);
304 4 : byte code[] = {WASM_BLOCK_I(
305 : WASM_WHILE(
306 : WASM_I32_LTS(WASM_GET_LOCAL(localIndex), WASM_I32V_3(kCheckSize)),
307 : WASM_IF_ELSE(
308 : WASM_LOAD_MEM(MachineType::Int32(), WASM_GET_LOCAL(localIndex)),
309 : WASM_BRV(3, WASM_I32V_1(-1)),
310 : WASM_INC_LOCAL_BY(localIndex, 4))),
311 8 : WASM_I32V_1(11))};
312 4 : EMIT_CODE_WITH_END(f, code);
313 4 : TestModule(&zone, builder, 11);
314 : }
315 : Cleanup();
316 4 : }
317 :
318 26660 : TEST(Run_WasmModule_CallMain_recursive) {
319 : {
320 8 : v8::internal::AccountingAllocator allocator;
321 8 : Zone zone(&allocator, ZONE_NAME);
322 4 : TestSignatures sigs;
323 :
324 4 : WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
325 4 : WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
326 :
327 4 : uint16_t localIndex = f->AddLocal(kWasmI32);
328 : ExportAsMain(f);
329 : byte code[] = {
330 4 : WASM_SET_LOCAL(localIndex,
331 : WASM_LOAD_MEM(MachineType::Int32(), WASM_ZERO)),
332 4 : WASM_IF_ELSE_I(WASM_I32_LTS(WASM_GET_LOCAL(localIndex), WASM_I32V_1(5)),
333 : WASM_SEQ(WASM_STORE_MEM(MachineType::Int32(), WASM_ZERO,
334 : WASM_INC_LOCAL(localIndex)),
335 : WASM_CALL_FUNCTION0(0)),
336 12 : WASM_I32V_1(55))};
337 4 : EMIT_CODE_WITH_END(f, code);
338 4 : TestModule(&zone, builder, 55);
339 : }
340 : Cleanup();
341 4 : }
342 :
343 26660 : TEST(Run_WasmModule_Global) {
344 : {
345 8 : v8::internal::AccountingAllocator allocator;
346 8 : Zone zone(&allocator, ZONE_NAME);
347 4 : TestSignatures sigs;
348 :
349 4 : WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
350 4 : uint32_t global1 = builder->AddGlobal(kWasmI32, false);
351 4 : uint32_t global2 = builder->AddGlobal(kWasmI32, false);
352 4 : WasmFunctionBuilder* f1 = builder->AddFunction(sigs.i_v());
353 : byte code1[] = {
354 4 : WASM_I32_ADD(WASM_GET_GLOBAL(global1), WASM_GET_GLOBAL(global2))};
355 4 : EMIT_CODE_WITH_END(f1, code1);
356 4 : WasmFunctionBuilder* f2 = builder->AddFunction(sigs.i_v());
357 : ExportAsMain(f2);
358 : byte code2[] = {WASM_SET_GLOBAL(global1, WASM_I32V_1(56)),
359 : WASM_SET_GLOBAL(global2, WASM_I32V_1(41)),
360 4 : WASM_RETURN1(WASM_CALL_FUNCTION0(f1->func_index()))};
361 4 : EMIT_CODE_WITH_END(f2, code2);
362 4 : TestModule(&zone, builder, 97);
363 : }
364 : Cleanup();
365 4 : }
366 :
367 26660 : TEST(MemorySize) {
368 : {
369 : // Initial memory size is 16, see wasm-module-builder.cc
370 : static const int kExpectedValue = 16;
371 4 : TestSignatures sigs;
372 8 : v8::internal::AccountingAllocator allocator;
373 8 : Zone zone(&allocator, ZONE_NAME);
374 :
375 4 : WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
376 4 : WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
377 : ExportAsMain(f);
378 4 : byte code[] = {WASM_MEMORY_SIZE};
379 4 : EMIT_CODE_WITH_END(f, code);
380 4 : TestModule(&zone, builder, kExpectedValue);
381 : }
382 : Cleanup();
383 4 : }
384 :
385 26660 : TEST(Run_WasmModule_MemSize_GrowMem) {
386 : {
387 : // Initial memory size = 16 + MemoryGrow(10)
388 : static const int kExpectedValue = 26;
389 4 : TestSignatures sigs;
390 8 : v8::internal::AccountingAllocator allocator;
391 8 : Zone zone(&allocator, ZONE_NAME);
392 :
393 4 : WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
394 4 : WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
395 : ExportAsMain(f);
396 : byte code[] = {WASM_GROW_MEMORY(WASM_I32V_1(10)), WASM_DROP,
397 4 : WASM_MEMORY_SIZE};
398 4 : EMIT_CODE_WITH_END(f, code);
399 4 : TestModule(&zone, builder, kExpectedValue);
400 : }
401 : Cleanup();
402 4 : }
403 :
404 26660 : TEST(MemoryGrowZero) {
405 : {
406 : // Initial memory size is 16, see wasm-module-builder.cc
407 : static const int kExpectedValue = 16;
408 4 : TestSignatures sigs;
409 8 : v8::internal::AccountingAllocator allocator;
410 8 : Zone zone(&allocator, ZONE_NAME);
411 :
412 4 : WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
413 4 : WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
414 : ExportAsMain(f);
415 4 : byte code[] = {WASM_GROW_MEMORY(WASM_I32V(0))};
416 4 : EMIT_CODE_WITH_END(f, code);
417 4 : TestModule(&zone, builder, kExpectedValue);
418 : }
419 : Cleanup();
420 4 : }
421 :
422 4 : class InterruptThread : public v8::base::Thread {
423 : public:
424 : explicit InterruptThread(Isolate* isolate, int32_t* memory)
425 : : Thread(Options("TestInterruptLoop")),
426 : isolate_(isolate),
427 4 : memory_(memory) {}
428 :
429 4 : static void OnInterrupt(v8::Isolate* isolate, void* data) {
430 : int32_t* m = reinterpret_cast<int32_t*>(data);
431 : // Set the interrupt location to 0 to break the loop in {TestInterruptLoop}.
432 : Address ptr = reinterpret_cast<Address>(&m[interrupt_location_]);
433 : WriteLittleEndianValue<int32_t>(ptr, interrupt_value_);
434 4 : }
435 :
436 4 : void Run() override {
437 : // Wait for the main thread to write the signal value.
438 4 : int32_t val = 0;
439 : do {
440 4 : val = memory_[0];
441 : val = ReadLittleEndianValue<int32_t>(reinterpret_cast<Address>(&val));
442 4 : } while (val != signal_value_);
443 4 : isolate_->RequestInterrupt(&OnInterrupt, const_cast<int32_t*>(memory_));
444 4 : }
445 :
446 : Isolate* isolate_;
447 : volatile int32_t* memory_;
448 : static const int32_t interrupt_location_ = 10;
449 : static const int32_t interrupt_value_ = 154;
450 : static const int32_t signal_value_ = 1221;
451 : };
452 :
453 26660 : TEST(TestInterruptLoop) {
454 : {
455 : // Do not dump the module of this test because it contains an infinite loop.
456 : if (FLAG_dump_wasm_module) return;
457 :
458 : // This test tests that WebAssembly loops can be interrupted, i.e. that if
459 : // an
460 : // InterruptCallback is registered by {Isolate::RequestInterrupt}, then the
461 : // InterruptCallback is eventually called even if a loop in WebAssembly code
462 : // is executed.
463 : // Test setup:
464 : // The main thread executes a WebAssembly function with a loop. In the loop
465 : // {signal_value_} is written to memory to signal a helper thread that the
466 : // main thread reached the loop in the WebAssembly program. When the helper
467 : // thread reads {signal_value_} from memory, it registers the
468 : // InterruptCallback. Upon exeution, the InterruptCallback write into the
469 : // WebAssemblyMemory to end the loop in the WebAssembly program.
470 4 : TestSignatures sigs;
471 : Isolate* isolate = CcTest::InitIsolateOnce();
472 8 : v8::internal::AccountingAllocator allocator;
473 8 : Zone zone(&allocator, ZONE_NAME);
474 :
475 4 : WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
476 4 : WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
477 : ExportAsMain(f);
478 : byte code[] = {
479 8 : WASM_LOOP(
480 : WASM_IFB(WASM_NOT(WASM_LOAD_MEM(
481 : MachineType::Int32(),
482 : WASM_I32V(InterruptThread::interrupt_location_ * 4))),
483 : WASM_STORE_MEM(MachineType::Int32(), WASM_ZERO,
484 : WASM_I32V(InterruptThread::signal_value_)),
485 : WASM_BR(1))),
486 12 : WASM_I32V(121)};
487 4 : EMIT_CODE_WITH_END(f, code);
488 : ZoneBuffer buffer(&zone);
489 4 : builder->WriteTo(buffer);
490 :
491 : HandleScope scope(isolate);
492 4 : testing::SetupIsolateForWasmModule(isolate);
493 4 : ErrorThrower thrower(isolate, "Test");
494 : const Handle<WasmInstanceObject> instance =
495 8 : CompileAndInstantiateForTesting(
496 4 : isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()))
497 : .ToHandleChecked();
498 :
499 : Handle<JSArrayBuffer> memory(instance->memory_object()->array_buffer(),
500 : isolate);
501 : int32_t* memory_array = reinterpret_cast<int32_t*>(memory->backing_store());
502 :
503 : InterruptThread thread(isolate, memory_array);
504 4 : thread.Start();
505 4 : testing::RunWasmModuleForTesting(isolate, instance, 0, nullptr);
506 : Address address = reinterpret_cast<Address>(
507 : &memory_array[InterruptThread::interrupt_location_]);
508 4 : CHECK_EQ(InterruptThread::interrupt_value_,
509 : ReadLittleEndianValue<int32_t>(address));
510 : }
511 : Cleanup();
512 : }
513 :
514 26660 : TEST(Run_WasmModule_MemoryGrowInIf) {
515 : {
516 4 : TestSignatures sigs;
517 8 : v8::internal::AccountingAllocator allocator;
518 8 : Zone zone(&allocator, ZONE_NAME);
519 4 : WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
520 4 : WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
521 : ExportAsMain(f);
522 : byte code[] = {WASM_IF_ELSE_I(WASM_I32V(0), WASM_GROW_MEMORY(WASM_I32V(1)),
523 4 : WASM_I32V(12))};
524 4 : EMIT_CODE_WITH_END(f, code);
525 4 : TestModule(&zone, builder, 12);
526 : }
527 : Cleanup();
528 4 : }
529 :
530 26660 : TEST(Run_WasmModule_GrowMemOobOffset) {
531 : {
532 : static const int kPageSize = 0x10000;
533 : // Initial memory size = 16 + MemoryGrow(10)
534 : static const int index = kPageSize * 17 + 4;
535 : int value = 0xACED;
536 4 : TestSignatures sigs;
537 8 : v8::internal::AccountingAllocator allocator;
538 8 : Zone zone(&allocator, ZONE_NAME);
539 :
540 4 : WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
541 4 : WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
542 : ExportAsMain(f);
543 : byte code[] = {WASM_GROW_MEMORY(WASM_I32V_1(1)),
544 4 : WASM_STORE_MEM(MachineType::Int32(), WASM_I32V(index),
545 8 : WASM_I32V(value))};
546 4 : EMIT_CODE_WITH_END(f, code);
547 4 : TestModuleException(&zone, builder);
548 : }
549 : Cleanup();
550 4 : }
551 :
552 26660 : TEST(Run_WasmModule_GrowMemOobFixedIndex) {
553 : {
554 : static const int kPageSize = 0x10000;
555 : // Initial memory size = 16 + MemoryGrow(10)
556 : static const int index = kPageSize * 26 + 4;
557 : int value = 0xACED;
558 4 : TestSignatures sigs;
559 : Isolate* isolate = CcTest::InitIsolateOnce();
560 8 : Zone zone(isolate->allocator(), ZONE_NAME);
561 :
562 4 : WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
563 4 : WasmFunctionBuilder* f = builder->AddFunction(sigs.i_i());
564 : ExportAsMain(f);
565 : byte code[] = {WASM_GROW_MEMORY(WASM_GET_LOCAL(0)), WASM_DROP,
566 4 : WASM_STORE_MEM(MachineType::Int32(), WASM_I32V(index),
567 : WASM_I32V(value)),
568 8 : WASM_LOAD_MEM(MachineType::Int32(), WASM_I32V(index))};
569 4 : EMIT_CODE_WITH_END(f, code);
570 :
571 : HandleScope scope(isolate);
572 : ZoneBuffer buffer(&zone);
573 4 : builder->WriteTo(buffer);
574 4 : testing::SetupIsolateForWasmModule(isolate);
575 :
576 4 : ErrorThrower thrower(isolate, "Test");
577 : Handle<WasmInstanceObject> instance =
578 8 : CompileAndInstantiateForTesting(
579 4 : isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()))
580 4 : .ToHandleChecked();
581 :
582 : // Initial memory size is 16 pages, should trap till index > MemSize on
583 : // consecutive GrowMem calls
584 36 : for (uint32_t i = 1; i < 5; i++) {
585 16 : Handle<Object> params[1] = {Handle<Object>(Smi::FromInt(i), isolate)};
586 32 : v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
587 16 : testing::RunWasmModuleForTesting(isolate, instance, 1, params);
588 16 : CHECK(try_catch.HasCaught());
589 : isolate->clear_pending_exception();
590 : }
591 :
592 : Handle<Object> params[1] = {Handle<Object>(Smi::FromInt(1), isolate)};
593 : int32_t result =
594 4 : testing::RunWasmModuleForTesting(isolate, instance, 1, params);
595 4 : CHECK_EQ(0xACED, result);
596 : }
597 : Cleanup();
598 4 : }
599 :
600 26660 : TEST(Run_WasmModule_GrowMemOobVariableIndex) {
601 : {
602 : static const int kPageSize = 0x10000;
603 : int value = 0xACED;
604 4 : TestSignatures sigs;
605 : Isolate* isolate = CcTest::InitIsolateOnce();
606 8 : v8::internal::AccountingAllocator allocator;
607 8 : Zone zone(&allocator, ZONE_NAME);
608 :
609 4 : WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
610 4 : WasmFunctionBuilder* f = builder->AddFunction(sigs.i_i());
611 : ExportAsMain(f);
612 : byte code[] = {WASM_GROW_MEMORY(WASM_I32V_1(1)), WASM_DROP,
613 4 : WASM_STORE_MEM(MachineType::Int32(), WASM_GET_LOCAL(0),
614 : WASM_I32V(value)),
615 8 : WASM_LOAD_MEM(MachineType::Int32(), WASM_GET_LOCAL(0))};
616 4 : EMIT_CODE_WITH_END(f, code);
617 :
618 : HandleScope scope(isolate);
619 : ZoneBuffer buffer(&zone);
620 4 : builder->WriteTo(buffer);
621 4 : testing::SetupIsolateForWasmModule(isolate);
622 :
623 4 : ErrorThrower thrower(isolate, "Test");
624 : Handle<WasmInstanceObject> instance =
625 8 : CompileAndInstantiateForTesting(
626 4 : isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()))
627 4 : .ToHandleChecked();
628 :
629 : // Initial memory size is 16 pages, should trap till index > MemSize on
630 : // consecutive GrowMem calls
631 36 : for (int i = 1; i < 5; i++) {
632 : Handle<Object> params[1] = {
633 16 : Handle<Object>(Smi::FromInt((16 + i) * kPageSize - 3), isolate)};
634 32 : v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
635 16 : testing::RunWasmModuleForTesting(isolate, instance, 1, params);
636 16 : CHECK(try_catch.HasCaught());
637 : isolate->clear_pending_exception();
638 : }
639 :
640 36 : for (int i = 1; i < 5; i++) {
641 : Handle<Object> params[1] = {
642 16 : Handle<Object>(Smi::FromInt((20 + i) * kPageSize - 4), isolate)};
643 : int32_t result =
644 16 : testing::RunWasmModuleForTesting(isolate, instance, 1, params);
645 16 : CHECK_EQ(0xACED, result);
646 : }
647 :
648 8 : v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
649 : Handle<Object> params[1] = {
650 : Handle<Object>(Smi::FromInt(25 * kPageSize), isolate)};
651 4 : testing::RunWasmModuleForTesting(isolate, instance, 1, params);
652 4 : CHECK(try_catch.HasCaught());
653 : isolate->clear_pending_exception();
654 : }
655 : Cleanup();
656 4 : }
657 :
658 26660 : TEST(Run_WasmModule_Global_init) {
659 : {
660 8 : v8::internal::AccountingAllocator allocator;
661 8 : Zone zone(&allocator, ZONE_NAME);
662 4 : TestSignatures sigs;
663 :
664 4 : WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
665 : uint32_t global1 =
666 4 : builder->AddGlobal(kWasmI32, false, false, WasmInitExpr(777777));
667 : uint32_t global2 =
668 4 : builder->AddGlobal(kWasmI32, false, false, WasmInitExpr(222222));
669 4 : WasmFunctionBuilder* f1 = builder->AddFunction(sigs.i_v());
670 : byte code[] = {
671 4 : WASM_I32_ADD(WASM_GET_GLOBAL(global1), WASM_GET_GLOBAL(global2))};
672 4 : EMIT_CODE_WITH_END(f1, code);
673 : ExportAsMain(f1);
674 4 : TestModule(&zone, builder, 999999);
675 : }
676 : Cleanup();
677 4 : }
678 :
679 : template <typename CType>
680 24 : static void RunWasmModuleGlobalInitTest(ValueType type, CType expected) {
681 : {
682 48 : v8::internal::AccountingAllocator allocator;
683 48 : Zone zone(&allocator, ZONE_NAME);
684 24 : TestSignatures sigs;
685 :
686 24 : ValueType types[] = {type};
687 : FunctionSig sig(1, 0, types);
688 :
689 264 : for (int padding = 0; padding < 5; padding++) {
690 : // Test with a simple initializer
691 120 : WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
692 :
693 600 : for (int i = 0; i < padding; i++) { // pad global before
694 480 : builder->AddGlobal(kWasmI32, false, false, WasmInitExpr(i + 20000));
695 : }
696 : uint32_t global =
697 120 : builder->AddGlobal(type, false, false, WasmInitExpr(expected));
698 600 : for (int i = 0; i < padding; i++) { // pad global after
699 480 : builder->AddGlobal(kWasmI32, false, false, WasmInitExpr(i + 30000));
700 : }
701 :
702 120 : WasmFunctionBuilder* f1 = builder->AddFunction(&sig);
703 120 : byte code[] = {WASM_GET_GLOBAL(global)};
704 120 : EMIT_CODE_WITH_END(f1, code);
705 : ExportAsMain(f1);
706 120 : TestModule(&zone, builder, expected);
707 : }
708 : }
709 : Cleanup();
710 24 : }
711 :
712 26660 : TEST(Run_WasmModule_Global_i32) {
713 4 : RunWasmModuleGlobalInitTest<int32_t>(kWasmI32, -983489);
714 4 : RunWasmModuleGlobalInitTest<int32_t>(kWasmI32, 11223344);
715 4 : }
716 :
717 26660 : TEST(Run_WasmModule_Global_f32) {
718 4 : RunWasmModuleGlobalInitTest<float>(kWasmF32, -983.9f);
719 4 : RunWasmModuleGlobalInitTest<float>(kWasmF32, 1122.99f);
720 4 : }
721 :
722 26660 : TEST(Run_WasmModule_Global_f64) {
723 4 : RunWasmModuleGlobalInitTest<double>(kWasmF64, -833.9);
724 4 : RunWasmModuleGlobalInitTest<double>(kWasmF64, 86374.25);
725 4 : }
726 :
727 26660 : TEST(InitDataAtTheUpperLimit) {
728 : {
729 : Isolate* isolate = CcTest::InitIsolateOnce();
730 : HandleScope scope(isolate);
731 4 : testing::SetupIsolateForWasmModule(isolate);
732 :
733 4 : ErrorThrower thrower(isolate, "Run_WasmModule_InitDataAtTheUpperLimit");
734 :
735 : const byte data[] = {
736 : WASM_MODULE_HEADER, // --
737 : kMemorySectionCode, // --
738 : U32V_1(4), // section size
739 : ENTRY_COUNT(1), // --
740 : kHasMaximumFlag, // --
741 : 1, // initial size
742 : 2, // maximum size
743 : kDataSectionCode, // --
744 : U32V_1(9), // section size
745 : ENTRY_COUNT(1), // --
746 : 0, // linear memory index
747 : WASM_I32V_3(0xFFFF), // destination offset
748 : kExprEnd,
749 : U32V_1(1), // source size
750 : 'c' // data bytes
751 4 : };
752 :
753 : CompileAndInstantiateForTesting(
754 4 : isolate, &thrower, ModuleWireBytes(data, data + arraysize(data)));
755 4 : if (thrower.error()) {
756 0 : thrower.Reify()->Print();
757 0 : FATAL("compile or instantiate error");
758 : }
759 : }
760 : Cleanup();
761 4 : }
762 :
763 26660 : TEST(EmptyMemoryNonEmptyDataSegment) {
764 : {
765 : Isolate* isolate = CcTest::InitIsolateOnce();
766 : HandleScope scope(isolate);
767 4 : testing::SetupIsolateForWasmModule(isolate);
768 :
769 4 : ErrorThrower thrower(isolate, "Run_WasmModule_InitDataAtTheUpperLimit");
770 :
771 : const byte data[] = {
772 : WASM_MODULE_HEADER, // --
773 : kMemorySectionCode, // --
774 : U32V_1(4), // section size
775 : ENTRY_COUNT(1), // --
776 : kHasMaximumFlag, // --
777 : 0, // initial size
778 : 0, // maximum size
779 : kDataSectionCode, // --
780 : U32V_1(7), // section size
781 : ENTRY_COUNT(1), // --
782 : 0, // linear memory index
783 : WASM_I32V_1(8), // destination offset
784 : kExprEnd,
785 : U32V_1(1), // source size
786 : 'c' // data bytes
787 4 : };
788 :
789 : CompileAndInstantiateForTesting(
790 4 : isolate, &thrower, ModuleWireBytes(data, data + arraysize(data)));
791 : // It should not be possible to instantiate this module.
792 4 : CHECK(thrower.error());
793 : }
794 : Cleanup();
795 4 : }
796 :
797 26660 : TEST(EmptyMemoryEmptyDataSegment) {
798 : {
799 : Isolate* isolate = CcTest::InitIsolateOnce();
800 : HandleScope scope(isolate);
801 4 : testing::SetupIsolateForWasmModule(isolate);
802 :
803 4 : ErrorThrower thrower(isolate, "Run_WasmModule_InitDataAtTheUpperLimit");
804 :
805 : const byte data[] = {
806 : WASM_MODULE_HEADER, // --
807 : kMemorySectionCode, // --
808 : U32V_1(4), // section size
809 : ENTRY_COUNT(1), // --
810 : kHasMaximumFlag, // --
811 : 0, // initial size
812 : 0, // maximum size
813 : kDataSectionCode, // --
814 : U32V_1(6), // section size
815 : ENTRY_COUNT(1), // --
816 : 0, // linear memory index
817 : WASM_I32V_1(0), // destination offset
818 : kExprEnd,
819 : U32V_1(0), // source size
820 4 : };
821 :
822 : CompileAndInstantiateForTesting(
823 4 : isolate, &thrower, ModuleWireBytes(data, data + arraysize(data)));
824 : // It should be possible to instantiate this module.
825 4 : CHECK(!thrower.error());
826 : }
827 : Cleanup();
828 4 : }
829 :
830 26660 : TEST(MemoryWithOOBEmptyDataSegment) {
831 : {
832 : Isolate* isolate = CcTest::InitIsolateOnce();
833 : HandleScope scope(isolate);
834 4 : testing::SetupIsolateForWasmModule(isolate);
835 :
836 4 : ErrorThrower thrower(isolate, "Run_WasmModule_InitDataAtTheUpperLimit");
837 :
838 : const byte data[] = {
839 : WASM_MODULE_HEADER, // --
840 : kMemorySectionCode, // --
841 : U32V_1(4), // section size
842 : ENTRY_COUNT(1), // --
843 : kHasMaximumFlag, // --
844 : 1, // initial size
845 : 1, // maximum size
846 : kDataSectionCode, // --
847 : U32V_1(9), // section size
848 : ENTRY_COUNT(1), // --
849 : 0, // linear memory index
850 : WASM_I32V_4(0x2468ACE), // destination offset
851 : kExprEnd,
852 : U32V_1(0), // source size
853 4 : };
854 :
855 : CompileAndInstantiateForTesting(
856 4 : isolate, &thrower, ModuleWireBytes(data, data + arraysize(data)));
857 : // It should not be possible to instantiate this module.
858 4 : CHECK(thrower.error());
859 : }
860 : Cleanup();
861 4 : }
862 :
863 : // Utility to free the allocated memory for a buffer that is manually
864 : // externalized in a test.
865 : struct ManuallyExternalizedBuffer {
866 : Isolate* isolate_;
867 : Handle<JSArrayBuffer> buffer_;
868 : void* allocation_base_;
869 : size_t allocation_length_;
870 : bool const should_free_;
871 :
872 8 : ManuallyExternalizedBuffer(JSArrayBuffer buffer, Isolate* isolate)
873 : : isolate_(isolate),
874 : buffer_(buffer, isolate),
875 8 : allocation_base_(buffer->allocation_base()),
876 8 : allocation_length_(buffer->allocation_length()),
877 16 : should_free_(!isolate_->wasm_engine()->memory_tracker()->IsWasmMemory(
878 32 : buffer->backing_store())) {
879 16 : if (!isolate_->wasm_engine()->memory_tracker()->IsWasmMemory(
880 : buffer->backing_store())) {
881 0 : v8::Utils::ToLocal(buffer_)->Externalize();
882 : }
883 8 : }
884 8 : ~ManuallyExternalizedBuffer() {
885 8 : if (should_free_) {
886 0 : buffer_->FreeBackingStoreFromMainThread();
887 : }
888 : }
889 : };
890 :
891 26660 : TEST(Run_WasmModule_Buffer_Externalized_GrowMem) {
892 : {
893 : Isolate* isolate = CcTest::InitIsolateOnce();
894 : HandleScope scope(isolate);
895 4 : TestSignatures sigs;
896 8 : v8::internal::AccountingAllocator allocator;
897 8 : Zone zone(&allocator, ZONE_NAME);
898 :
899 4 : WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
900 4 : WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
901 : ExportAsMain(f);
902 : byte code[] = {WASM_GROW_MEMORY(WASM_I32V_1(6)), WASM_DROP,
903 4 : WASM_MEMORY_SIZE};
904 4 : EMIT_CODE_WITH_END(f, code);
905 :
906 : ZoneBuffer buffer(&zone);
907 4 : builder->WriteTo(buffer);
908 4 : testing::SetupIsolateForWasmModule(isolate);
909 4 : ErrorThrower thrower(isolate, "Test");
910 : const Handle<WasmInstanceObject> instance =
911 8 : CompileAndInstantiateForTesting(
912 4 : isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()))
913 : .ToHandleChecked();
914 : Handle<WasmMemoryObject> memory_object(instance->memory_object(), isolate);
915 :
916 : // Fake the Embedder flow by externalizing the array buffer.
917 4 : ManuallyExternalizedBuffer buffer1(memory_object->array_buffer(), isolate);
918 :
919 : // Grow using the API.
920 4 : uint32_t result = WasmMemoryObject::Grow(isolate, memory_object, 4);
921 4 : CHECK_EQ(16, result);
922 4 : CHECK(buffer1.buffer_->was_detached()); // growing always detaches
923 4 : CHECK_EQ(0, buffer1.buffer_->byte_length());
924 :
925 4 : CHECK_NE(*buffer1.buffer_, memory_object->array_buffer());
926 :
927 : // Fake the Embedder flow by externalizing the array buffer.
928 4 : ManuallyExternalizedBuffer buffer2(memory_object->array_buffer(), isolate);
929 :
930 : // Grow using an internal WASM bytecode.
931 4 : result = testing::RunWasmModuleForTesting(isolate, instance, 0, nullptr);
932 4 : CHECK_EQ(26, result);
933 4 : CHECK(buffer2.buffer_->was_detached()); // growing always detaches
934 4 : CHECK_EQ(0, buffer2.buffer_->byte_length());
935 4 : CHECK_NE(*buffer2.buffer_, memory_object->array_buffer());
936 : }
937 : Cleanup();
938 4 : }
939 :
940 26660 : TEST(Run_WasmModule_Buffer_Externalized_GrowMemMemSize) {
941 : {
942 : Isolate* isolate = CcTest::InitIsolateOnce();
943 : HandleScope scope(isolate);
944 : Handle<JSArrayBuffer> buffer;
945 8 : CHECK(wasm::NewArrayBuffer(isolate, 16 * kWasmPageSize).ToHandle(&buffer));
946 : Handle<WasmMemoryObject> mem_obj =
947 4 : WasmMemoryObject::New(isolate, buffer, 100);
948 4 : auto const contents = v8::Utils::ToLocal(buffer)->Externalize();
949 4 : int32_t result = WasmMemoryObject::Grow(isolate, mem_obj, 0);
950 4 : CHECK_EQ(16, result);
951 : constexpr bool is_wasm_memory = true;
952 : const JSArrayBuffer::Allocation allocation{contents.AllocationBase(),
953 : contents.AllocationLength(),
954 : contents.Data(), is_wasm_memory};
955 4 : JSArrayBuffer::FreeBackingStore(isolate, allocation);
956 : }
957 : Cleanup();
958 4 : }
959 :
960 26660 : TEST(Run_WasmModule_Buffer_Externalized_Detach) {
961 : {
962 : // Regression test for
963 : // https://bugs.chromium.org/p/chromium/issues/detail?id=731046
964 : Isolate* isolate = CcTest::InitIsolateOnce();
965 : HandleScope scope(isolate);
966 : Handle<JSArrayBuffer> buffer;
967 8 : CHECK(wasm::NewArrayBuffer(isolate, 16 * kWasmPageSize).ToHandle(&buffer));
968 4 : auto const contents = v8::Utils::ToLocal(buffer)->Externalize();
969 4 : wasm::DetachMemoryBuffer(isolate, buffer, true);
970 : constexpr bool is_wasm_memory = true;
971 : const JSArrayBuffer::Allocation allocation{contents.AllocationBase(),
972 : contents.AllocationLength(),
973 : contents.Data(), is_wasm_memory};
974 4 : JSArrayBuffer::FreeBackingStore(isolate, allocation);
975 : }
976 : Cleanup();
977 4 : }
978 :
979 26660 : TEST(Run_WasmModule_Buffer_Externalized_Regression_UseAfterFree) {
980 : // Regresion test for https://crbug.com/813876
981 : Isolate* isolate = CcTest::InitIsolateOnce();
982 : HandleScope scope(isolate);
983 : Handle<JSArrayBuffer> buffer;
984 8 : CHECK(wasm::NewArrayBuffer(isolate, 16 * kWasmPageSize).ToHandle(&buffer));
985 4 : Handle<WasmMemoryObject> mem = WasmMemoryObject::New(isolate, buffer, 128);
986 4 : auto contents = v8::Utils::ToLocal(buffer)->Externalize();
987 4 : WasmMemoryObject::Grow(isolate, mem, 0);
988 : constexpr bool is_wasm_memory = true;
989 4 : JSArrayBuffer::FreeBackingStore(
990 : isolate, JSArrayBuffer::Allocation(contents.AllocationBase(),
991 : contents.AllocationLength(),
992 4 : contents.Data(), is_wasm_memory));
993 : // Make sure we can write to the buffer without crashing
994 : uint32_t* int_buffer =
995 : reinterpret_cast<uint32_t*>(mem->array_buffer()->backing_store());
996 4 : int_buffer[0] = 0;
997 4 : }
998 :
999 : #if V8_TARGET_ARCH_64_BIT
1000 26660 : TEST(Run_WasmModule_Reclaim_Memory) {
1001 : // Make sure we can allocate memories without running out of address space.
1002 : Isolate* isolate = CcTest::InitIsolateOnce();
1003 : Handle<JSArrayBuffer> buffer;
1004 2052 : for (int i = 0; i < 256; ++i) {
1005 : HandleScope scope(isolate);
1006 2048 : CHECK(NewArrayBuffer(isolate, kWasmPageSize).ToHandle(&buffer));
1007 : }
1008 4 : }
1009 : #endif
1010 :
1011 26660 : TEST(AtomicOpDisassembly) {
1012 : {
1013 : EXPERIMENTAL_FLAG_SCOPE(threads);
1014 4 : TestSignatures sigs;
1015 : Isolate* isolate = CcTest::InitIsolateOnce();
1016 8 : v8::internal::AccountingAllocator allocator;
1017 8 : Zone zone(&allocator, ZONE_NAME);
1018 :
1019 4 : WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
1020 4 : builder->SetHasSharedMemory();
1021 4 : builder->SetMaxMemorySize(16);
1022 4 : WasmFunctionBuilder* f = builder->AddFunction(sigs.i_i());
1023 : ExportAsMain(f);
1024 : byte code[] = {
1025 : WASM_ATOMICS_STORE_OP(kExprI32AtomicStore, WASM_ZERO, WASM_GET_LOCAL(0),
1026 : MachineRepresentation::kWord32),
1027 : WASM_ATOMICS_LOAD_OP(kExprI32AtomicLoad, WASM_ZERO,
1028 4 : MachineRepresentation::kWord32)};
1029 4 : EMIT_CODE_WITH_END(f, code);
1030 :
1031 : HandleScope scope(isolate);
1032 : ZoneBuffer buffer(&zone);
1033 4 : builder->WriteTo(buffer);
1034 4 : testing::SetupIsolateForWasmModule(isolate);
1035 :
1036 4 : ErrorThrower thrower(isolate, "Test");
1037 4 : auto enabled_features = WasmFeaturesFromIsolate(isolate);
1038 : MaybeHandle<WasmModuleObject> module_object =
1039 : isolate->wasm_engine()->SyncCompile(
1040 : isolate, enabled_features, &thrower,
1041 4 : ModuleWireBytes(buffer.begin(), buffer.end()));
1042 :
1043 4 : module_object.ToHandleChecked()->DisassembleFunction(0);
1044 : }
1045 : Cleanup();
1046 4 : }
1047 :
1048 : #undef EMIT_CODE_WITH_END
1049 :
1050 : } // namespace test_run_wasm_module
1051 : } // namespace wasm
1052 : } // namespace internal
1053 79968 : } // namespace v8
|