Line data Source code
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 : #ifndef WASM_RUN_UTILS_H
6 : #define WASM_RUN_UTILS_H
7 :
8 : #include <setjmp.h>
9 : #include <stdint.h>
10 : #include <stdlib.h>
11 : #include <string.h>
12 : #include <array>
13 : #include <memory>
14 :
15 : #include "src/base/utils/random-number-generator.h"
16 : #include "src/compiler/compiler-source-position-table.h"
17 : #include "src/compiler/graph-visualizer.h"
18 : #include "src/compiler/int64-lowering.h"
19 : #include "src/compiler/js-graph.h"
20 : #include "src/compiler/node.h"
21 : #include "src/compiler/pipeline.h"
22 : #include "src/compiler/wasm-compiler.h"
23 : #include "src/compiler/zone-stats.h"
24 : #include "src/trap-handler/trap-handler.h"
25 : #include "src/wasm/function-body-decoder.h"
26 : #include "src/wasm/local-decl-encoder.h"
27 : #include "src/wasm/wasm-code-manager.h"
28 : #include "src/wasm/wasm-external-refs.h"
29 : #include "src/wasm/wasm-interpreter.h"
30 : #include "src/wasm/wasm-js.h"
31 : #include "src/wasm/wasm-module.h"
32 : #include "src/wasm/wasm-objects-inl.h"
33 : #include "src/wasm/wasm-objects.h"
34 : #include "src/wasm/wasm-opcodes.h"
35 : #include "src/wasm/wasm-tier.h"
36 : #include "src/zone/accounting-allocator.h"
37 : #include "src/zone/zone.h"
38 :
39 : #include "test/cctest/cctest.h"
40 : #include "test/cctest/compiler/call-tester.h"
41 : #include "test/cctest/compiler/graph-builder-tester.h"
42 : #include "test/cctest/compiler/value-helper.h"
43 : #include "test/common/wasm/flag-utils.h"
44 :
45 : namespace v8 {
46 : namespace internal {
47 : namespace wasm {
48 :
49 : constexpr uint32_t kMaxFunctions = 10;
50 : constexpr uint32_t kMaxGlobalsSize = 128;
51 :
52 : using compiler::CallDescriptor;
53 : using compiler::MachineTypeForC;
54 : using compiler::Node;
55 :
56 : // TODO(titzer): check traps more robustly in tests.
57 : // Currently, in tests, we just return 0xDEADBEEF from the function in which
58 : // the trap occurs if the runtime context is not available to throw a JavaScript
59 : // exception.
60 : #define CHECK_TRAP32(x) \
61 : CHECK_EQ(0xDEADBEEF, (bit_cast<uint32_t>(x)) & 0xFFFFFFFF)
62 : #define CHECK_TRAP64(x) \
63 : CHECK_EQ(0xDEADBEEFDEADBEEF, (bit_cast<uint64_t>(x)) & 0xFFFFFFFFFFFFFFFF)
64 : #define CHECK_TRAP(x) CHECK_TRAP32(x)
65 :
66 : #define WASM_WRAPPER_RETURN_VALUE 8754
67 :
68 : #define BUILD(r, ...) \
69 : do { \
70 : byte code[] = {__VA_ARGS__}; \
71 : r.Build(code, code + arraysize(code)); \
72 : } while (false)
73 :
74 : // For tests that must manually import a JSFunction with source code.
75 : struct ManuallyImportedJSFunction {
76 : FunctionSig* sig;
77 : Handle<JSFunction> js_function;
78 : };
79 :
80 : // A Wasm module builder. Globals are pre-set, however, memory and code may be
81 : // progressively added by a test. In turn, we piecemeal update the runtime
82 : // objects, i.e. {WasmInstanceObject}, {WasmModuleObject} and, if necessary,
83 : // the interpreter.
84 2187896 : class TestingModuleBuilder {
85 : public:
86 : TestingModuleBuilder(Zone*, ManuallyImportedJSFunction*, ExecutionTier,
87 : RuntimeExceptionSupport, LowerSimd);
88 :
89 384 : void ChangeOriginToAsmjs() { test_module_->origin = kAsmJsOrigin; }
90 :
91 : byte* AddMemory(uint32_t size, SharedFlag shared = SharedFlag::kNotShared);
92 :
93 : size_t CodeTableLength() const { return native_module_->num_functions(); }
94 :
95 : template <typename T>
96 : T* AddMemoryElems(uint32_t count) {
97 39908 : AddMemory(count * sizeof(T));
98 : return raw_mem_start<T>();
99 : }
100 :
101 : template <typename T>
102 : T* AddGlobal(
103 216 : ValueType type = ValueTypes::ValueTypeFor(MachineTypeForC<T>())) {
104 22144 : const WasmGlobal* global = AddGlobal(type);
105 22132 : return reinterpret_cast<T*>(globals_data_ + global->offset);
106 : }
107 :
108 3196 : byte AddSignature(FunctionSig* sig) {
109 : DCHECK_EQ(test_module_->signatures.size(),
110 : test_module_->signature_ids.size());
111 3196 : test_module_->signatures.push_back(sig);
112 3196 : auto canonical_sig_num = test_module_->signature_map.FindOrInsert(*sig);
113 3196 : test_module_->signature_ids.push_back(canonical_sig_num);
114 : size_t size = test_module_->signatures.size();
115 3196 : CHECK_GT(127, size);
116 3196 : return static_cast<byte>(size - 1);
117 : }
118 :
119 : uint32_t mem_size() { return mem_size_; }
120 :
121 : template <typename T>
122 : T* raw_mem_start() {
123 : DCHECK(mem_start_);
124 : return reinterpret_cast<T*>(mem_start_);
125 : }
126 :
127 : template <typename T>
128 : T* raw_mem_end() {
129 : DCHECK(mem_start_);
130 15924 : return reinterpret_cast<T*>(mem_start_ + mem_size_);
131 : }
132 :
133 : template <typename T>
134 : T raw_mem_at(int i) {
135 : DCHECK(mem_start_);
136 58560 : return ReadMemory(&(reinterpret_cast<T*>(mem_start_)[i]));
137 : }
138 :
139 : template <typename T>
140 : T raw_val_at(int i) {
141 792 : return ReadMemory(reinterpret_cast<T*>(mem_start_ + i));
142 : }
143 :
144 : template <typename T>
145 : void WriteMemory(T* p, T val) {
146 : WriteLittleEndianValue<T>(reinterpret_cast<Address>(p), val);
147 : }
148 :
149 : template <typename T>
150 : T ReadMemory(T* p) {
151 : return ReadLittleEndianValue<T>(reinterpret_cast<Address>(p));
152 : }
153 :
154 : // Zero-initialize the memory.
155 : void BlankMemory() {
156 : byte* raw = raw_mem_start<byte>();
157 624 : memset(raw, 0, mem_size_);
158 : }
159 :
160 : // Pseudo-randomly intialize the memory.
161 15564 : void RandomizeMemory(unsigned int seed = 88) {
162 : byte* raw = raw_mem_start<byte>();
163 : byte* end = raw_mem_end<byte>();
164 15564 : v8::base::RandomNumberGenerator rng;
165 15564 : rng.SetSeed(seed);
166 15564 : rng.NextBytes(raw, end - raw);
167 15564 : }
168 :
169 8 : void SetMaxMemPages(uint32_t maximum_pages) {
170 8 : test_module_->maximum_pages = maximum_pages;
171 8 : if (instance_object()->has_memory_object()) {
172 8 : instance_object()->memory_object()->set_maximum_pages(maximum_pages);
173 : }
174 8 : }
175 :
176 1124 : void SetHasSharedMemory() { test_module_->has_shared_memory = true; }
177 :
178 : enum FunctionType { kImport, kWasm };
179 : uint32_t AddFunction(FunctionSig* sig, const char* name, FunctionType type);
180 :
181 : // Wrap the code so it can be called as a JS function.
182 : Handle<JSFunction> WrapCode(uint32_t index);
183 :
184 : // If function_indexes is {nullptr}, the contents of the table will be
185 : // initialized with null functions.
186 : void AddIndirectFunctionTable(const uint16_t* function_indexes,
187 : uint32_t table_size);
188 :
189 : uint32_t AddBytes(Vector<const byte> bytes);
190 :
191 : uint32_t AddException(FunctionSig* sig);
192 :
193 : uint32_t AddPassiveDataSegment(Vector<const byte> bytes);
194 :
195 : WasmFunction* GetFunctionAt(int index) {
196 1102888 : return &test_module_->functions[index];
197 : }
198 :
199 : WasmInterpreter* interpreter() const { return interpreter_; }
200 : bool interpret() const { return interpreter_ != nullptr; }
201 : LowerSimd lower_simd() const { return lower_simd_; }
202 : Isolate* isolate() const { return isolate_; }
203 : Handle<WasmInstanceObject> instance_object() const {
204 : return instance_object_;
205 : }
206 : WasmCode* GetFunctionCode(uint32_t index) const {
207 : return native_module_->code(index);
208 : }
209 : Address globals_start() const {
210 : return reinterpret_cast<Address>(globals_data_);
211 : }
212 :
213 9611764 : void SetExecutable() { native_module_->SetExecutable(true); }
214 :
215 : CompilationEnv CreateCompilationEnv();
216 :
217 : ExecutionTier execution_tier() const { return execution_tier_; }
218 :
219 : RuntimeExceptionSupport runtime_exception_support() const {
220 : return runtime_exception_support_;
221 : }
222 :
223 : private:
224 : std::shared_ptr<WasmModule> test_module_;
225 : WasmModule* test_module_ptr_;
226 : Isolate* isolate_;
227 : WasmFeatures enabled_features_;
228 : uint32_t global_offset = 0;
229 : byte* mem_start_ = nullptr;
230 : uint32_t mem_size_ = 0;
231 : alignas(16) byte globals_data_[kMaxGlobalsSize];
232 : WasmInterpreter* interpreter_ = nullptr;
233 : ExecutionTier execution_tier_;
234 : Handle<WasmInstanceObject> instance_object_;
235 : NativeModule* native_module_ = nullptr;
236 : RuntimeExceptionSupport runtime_exception_support_;
237 : LowerSimd lower_simd_;
238 :
239 : // Data segment arrays that are normally allocated on the instance.
240 : std::vector<byte> data_segment_data_;
241 : std::vector<Address> data_segment_starts_;
242 : std::vector<uint32_t> data_segment_sizes_;
243 : std::vector<byte> dropped_data_segments_;
244 :
245 : const WasmGlobal* AddGlobal(ValueType type);
246 :
247 : Handle<WasmInstanceObject> InitInstanceObject();
248 : };
249 :
250 : void TestBuildingGraph(Zone* zone, compiler::JSGraph* jsgraph,
251 : CompilationEnv* module, FunctionSig* sig,
252 : compiler::SourcePositionTable* source_position_table,
253 : const byte* start, const byte* end);
254 :
255 : class WasmFunctionWrapper : private compiler::GraphAndBuilders {
256 : public:
257 : WasmFunctionWrapper(Zone* zone, int num_params);
258 :
259 : void Init(CallDescriptor* call_descriptor, MachineType return_type,
260 : Vector<MachineType> param_types);
261 :
262 : template <typename ReturnType, typename... ParamTypes>
263 16432 : void Init(CallDescriptor* call_descriptor) {
264 : std::array<MachineType, sizeof...(ParamTypes)> param_machine_types{
265 16432 : {MachineTypeForC<ParamTypes>()...}};
266 : Vector<MachineType> param_vec(param_machine_types.data(),
267 : param_machine_types.size());
268 729176 : Init(call_descriptor, MachineTypeForC<ReturnType>(), param_vec);
269 16432 : }
270 :
271 9607416 : void SetInnerCode(WasmCode* code) {
272 : intptr_t address = static_cast<intptr_t>(code->instruction_start());
273 9607416 : compiler::NodeProperties::ChangeOp(
274 : inner_code_node_,
275 19214832 : common()->ExternalConstant(ExternalReference::FromRawAddress(address)));
276 9607416 : }
277 :
278 729176 : const compiler::Operator* IntPtrConstant(intptr_t value) {
279 : return machine()->Is32()
280 0 : ? common()->Int32Constant(static_cast<int32_t>(value))
281 1458352 : : common()->Int64Constant(static_cast<int64_t>(value));
282 : }
283 :
284 9607416 : void SetInstance(Handle<WasmInstanceObject> instance) {
285 19214832 : compiler::NodeProperties::ChangeOp(context_address_,
286 9607416 : common()->HeapConstant(instance));
287 9607416 : }
288 :
289 : Handle<Code> GetWrapperCode();
290 :
291 : Signature<MachineType>* signature() const { return signature_; }
292 :
293 : private:
294 : Node* inner_code_node_;
295 : Node* context_address_;
296 : MaybeHandle<Code> code_;
297 : Signature<MachineType>* signature_;
298 : };
299 :
300 : // A helper for compiling wasm functions for testing.
301 : // It contains the internal state for compilation (i.e. TurboFan graph) and
302 : // interpretation (by adding to the interpreter manually).
303 2205712 : class WasmFunctionCompiler : public compiler::GraphAndBuilders {
304 : public:
305 : ~WasmFunctionCompiler();
306 :
307 : Isolate* isolate() { return builder_->isolate(); }
308 729176 : CallDescriptor* descriptor() {
309 729176 : if (descriptor_ == nullptr) {
310 729176 : descriptor_ = compiler::GetWasmCallDescriptor(zone(), sig);
311 : }
312 729176 : return descriptor_;
313 : }
314 1101652 : uint32_t function_index() { return function_->func_index; }
315 :
316 : void Build(const byte* start, const byte* end);
317 :
318 : byte AllocateLocal(ValueType type) {
319 193552 : uint32_t index = local_decls.AddLocals(1, type);
320 5204 : byte result = static_cast<byte>(index);
321 : DCHECK_EQ(index, result);
322 : return result;
323 : }
324 :
325 304 : void SetSigIndex(int sig_index) { function_->sig_index = sig_index; }
326 :
327 : private:
328 : friend class WasmRunnerBase;
329 :
330 : WasmFunctionCompiler(Zone* zone, FunctionSig* sig,
331 : TestingModuleBuilder* builder, const char* name);
332 :
333 : compiler::JSGraph jsgraph;
334 : FunctionSig* sig;
335 : // The call descriptor is initialized when the function is compiled.
336 : CallDescriptor* descriptor_;
337 : TestingModuleBuilder* builder_;
338 : WasmFunction* function_;
339 : LocalDeclEncoder local_decls;
340 : compiler::SourcePositionTable source_position_table_;
341 : WasmInterpreter* interpreter_;
342 : };
343 :
344 : // A helper class to build a module around Wasm bytecode, generate machine
345 : // code, and run that code.
346 1093948 : class WasmRunnerBase : public HandleAndZoneScope {
347 : public:
348 1093948 : WasmRunnerBase(ManuallyImportedJSFunction* maybe_import,
349 : ExecutionTier execution_tier, int num_params,
350 : RuntimeExceptionSupport runtime_exception_support,
351 : LowerSimd lower_simd)
352 : : zone_(&allocator_, ZONE_NAME),
353 : builder_(&zone_, maybe_import, execution_tier,
354 : runtime_exception_support, lower_simd),
355 3281844 : wrapper_(&zone_, num_params) {}
356 :
357 : // Builds a graph from the given Wasm code and generates the machine
358 : // code and call wrapper for that graph. This method must not be called
359 : // more than once.
360 1088548 : void Build(const byte* start, const byte* end) {
361 1088548 : CHECK(!compiled_);
362 1088548 : compiled_ = true;
363 1088548 : functions_[0]->Build(start, end);
364 1088548 : }
365 :
366 : // Resets the state for building the next function.
367 : // The main function called will always be the first function.
368 : template <typename ReturnType, typename... ParamTypes>
369 1069384 : WasmFunctionCompiler& NewFunction(const char* name = nullptr) {
370 1094164 : return NewFunction(CreateSig<ReturnType, ParamTypes...>(), name);
371 : }
372 :
373 : // Resets the state for building the next function.
374 : // The main function called will be the last generated function.
375 : // Returns the index of the previously built function.
376 1102856 : WasmFunctionCompiler& NewFunction(FunctionSig* sig,
377 : const char* name = nullptr) {
378 3308568 : functions_.emplace_back(
379 2205712 : new WasmFunctionCompiler(&zone_, sig, &builder_, name));
380 1102856 : return *functions_.back();
381 : }
382 :
383 : byte AllocateLocal(ValueType type) {
384 : return functions_[0]->AllocateLocal(type);
385 : }
386 :
387 : uint32_t function_index() { return functions_[0]->function_index(); }
388 4705240 : WasmFunction* function() { return functions_[0]->function_; }
389 : WasmInterpreter* interpreter() {
390 : DCHECK(interpret());
391 4698336 : return functions_[0]->interpreter_;
392 : }
393 : bool possible_nondeterminism() { return possible_nondeterminism_; }
394 24 : TestingModuleBuilder& builder() { return builder_; }
395 : Zone* zone() { return &zone_; }
396 :
397 : bool interpret() { return builder_.interpret(); }
398 :
399 : template <typename ReturnType, typename... ParamTypes>
400 24816 : FunctionSig* CreateSig() {
401 : std::array<MachineType, sizeof...(ParamTypes)> param_machine_types{
402 24816 : {MachineTypeForC<ParamTypes>()...}};
403 : Vector<MachineType> param_vec(param_machine_types.data(),
404 : param_machine_types.size());
405 1094200 : return CreateSig(MachineTypeForC<ReturnType>(), param_vec);
406 : }
407 :
408 : private:
409 : FunctionSig* CreateSig(MachineType return_type,
410 : Vector<MachineType> param_types);
411 :
412 : protected:
413 : v8::internal::AccountingAllocator allocator_;
414 : Zone zone_;
415 : TestingModuleBuilder builder_;
416 : std::vector<std::unique_ptr<WasmFunctionCompiler>> functions_;
417 : WasmFunctionWrapper wrapper_;
418 : bool compiled_ = false;
419 : bool possible_nondeterminism_ = false;
420 : int32_t main_fn_index_ = 0;
421 :
422 : public:
423 : // This field has to be static. Otherwise, gcc complains about the use in
424 : // the lambda context below.
425 : static bool trap_happened;
426 : };
427 :
428 : template <typename ReturnType, typename... ParamTypes>
429 2187896 : class WasmRunner : public WasmRunnerBase {
430 : public:
431 1093948 : WasmRunner(ExecutionTier execution_tier,
432 : ManuallyImportedJSFunction* maybe_import = nullptr,
433 : const char* main_fn_name = "main",
434 : RuntimeExceptionSupport runtime_exception_support =
435 : kNoRuntimeExceptionSupport,
436 : LowerSimd lower_simd = kNoLowerSimd)
437 : : WasmRunnerBase(maybe_import, execution_tier, sizeof...(ParamTypes),
438 1093948 : runtime_exception_support, lower_simd) {
439 : WasmFunctionCompiler& main_fn =
440 1069292 : NewFunction<ReturnType, ParamTypes...>(main_fn_name);
441 : // Non-zero if there is an import.
442 1093948 : main_fn_index_ = main_fn.function_index();
443 :
444 1093948 : if (!interpret()) {
445 729176 : wrapper_.Init<ReturnType, ParamTypes...>(main_fn.descriptor());
446 : }
447 1093948 : }
448 :
449 : WasmRunner(ExecutionTier execution_tier, LowerSimd lower_simd)
450 : : WasmRunner(execution_tier, nullptr, "main", kNoRuntimeExceptionSupport,
451 12640 : lower_simd) {}
452 :
453 14305736 : ReturnType Call(ParamTypes... p) {
454 : DCHECK(compiled_);
455 14305736 : if (interpret()) return CallInterpreter(p...);
456 :
457 9607416 : ReturnType return_value = static_cast<ReturnType>(0xDEADBEEFDEADBEEF);
458 9607416 : WasmRunnerBase::trap_happened = false;
459 :
460 145120 : auto trap_callback = []() -> void {
461 72560 : WasmRunnerBase::trap_happened = true;
462 72560 : set_trap_callback_for_testing(nullptr);
463 0 : };
464 9607416 : set_trap_callback_for_testing(trap_callback);
465 :
466 19214832 : wrapper_.SetInnerCode(builder_.GetFunctionCode(main_fn_index_));
467 9607416 : wrapper_.SetInstance(builder_.instance_object());
468 : builder_.SetExecutable();
469 9607416 : Handle<Code> wrapper_code = wrapper_.GetWrapperCode();
470 : compiler::CodeRunner<int32_t> runner(CcTest::InitIsolateOnce(),
471 : wrapper_code, wrapper_.signature());
472 : int32_t result;
473 : {
474 : trap_handler::SetThreadInWasm();
475 :
476 9607416 : result = runner.Call(static_cast<void*>(&p)...,
477 : static_cast<void*>(&return_value));
478 :
479 : trap_handler::ClearThreadInWasm();
480 : }
481 9607416 : CHECK_EQ(WASM_WRAPPER_RETURN_VALUE, result);
482 : return WasmRunnerBase::trap_happened
483 : ? static_cast<ReturnType>(0xDEADBEEFDEADBEEF)
484 9607416 : : return_value;
485 : }
486 :
487 4698320 : ReturnType CallInterpreter(ParamTypes... p) {
488 4698320 : WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
489 4698320 : thread->Reset();
490 : std::array<WasmValue, sizeof...(p)> args{{WasmValue(p)...}};
491 4698320 : thread->InitFrame(function(), args.data());
492 4698320 : thread->Run();
493 9396640 : CHECK_GT(thread->NumInterpretedCalls(), 0);
494 4698320 : if (thread->state() == WasmInterpreter::FINISHED) {
495 4662036 : WasmValue val = thread->GetReturnValue();
496 4662036 : possible_nondeterminism_ |= thread->PossibleNondeterminism();
497 : return val.to<ReturnType>();
498 36284 : } else if (thread->state() == WasmInterpreter::TRAPPED) {
499 : // TODO(titzer): return the correct trap code
500 : int64_t result = 0xDEADBEEFDEADBEEF;
501 0 : return static_cast<ReturnType>(result);
502 : } else {
503 : // TODO(titzer): falling off end
504 0 : return ReturnType{0};
505 : }
506 : }
507 :
508 6900 : void CheckCallApplyViaJS(double expected, uint32_t function_index,
509 : Handle<Object>* buffer, int count) {
510 : Isolate* isolate = builder_.isolate();
511 6900 : if (jsfuncs_.size() <= function_index) {
512 4188 : jsfuncs_.resize(function_index + 1);
513 : }
514 6900 : if (jsfuncs_[function_index].is_null()) {
515 4200 : jsfuncs_[function_index] = builder_.WrapCode(function_index);
516 : }
517 6900 : Handle<JSFunction> jsfunc = jsfuncs_[function_index];
518 13800 : Handle<Object> global(isolate->context()->global_object(), isolate);
519 : MaybeHandle<Object> retval =
520 6900 : Execution::TryCall(isolate, jsfunc, global, count, buffer,
521 6900 : Execution::MessageHandling::kReport, nullptr);
522 :
523 6900 : if (retval.is_null()) {
524 1980 : CHECK_EQ(expected, static_cast<double>(0xDEADBEEF));
525 : } else {
526 : Handle<Object> result = retval.ToHandleChecked();
527 4920 : if (result->IsSmi()) {
528 3024 : CHECK_EQ(expected, Smi::ToInt(*result));
529 : } else {
530 1896 : CHECK(result->IsHeapNumber());
531 1896 : CHECK_DOUBLE_EQ(expected, HeapNumber::cast(*result)->value());
532 : }
533 : }
534 :
535 6900 : if (builder_.interpret()) {
536 4600 : CHECK_GT(builder_.interpreter()->GetThread(0)->NumInterpretedCalls(), 0);
537 : }
538 6900 : }
539 :
540 2664 : void CheckCallViaJS(double expected, ParamTypes... p) {
541 : Isolate* isolate = builder_.isolate();
542 2664 : Handle<Object> buffer[] = {isolate->factory()->NewNumber(p)...};
543 2664 : CheckCallApplyViaJS(expected, function()->func_index, buffer, sizeof...(p));
544 2664 : }
545 :
546 : Handle<Code> GetWrapperCode() { return wrapper_.GetWrapperCode(); }
547 :
548 : private:
549 : std::vector<Handle<JSFunction>> jsfuncs_;
550 : };
551 :
552 : // A macro to define tests that run in different engine configurations.
553 : #define WASM_EXEC_TEST(name) \
554 : void RunWasm_##name(ExecutionTier execution_tier); \
555 : TEST(RunWasmTurbofan_##name) { RunWasm_##name(ExecutionTier::kOptimized); } \
556 : TEST(RunWasmLiftoff_##name) { RunWasm_##name(ExecutionTier::kBaseline); } \
557 : TEST(RunWasmInterpreter_##name) { \
558 : RunWasm_##name(ExecutionTier::kInterpreter); \
559 : } \
560 : void RunWasm_##name(ExecutionTier execution_tier)
561 :
562 : #define WASM_COMPILED_EXEC_TEST(name) \
563 : void RunWasm_##name(ExecutionTier execution_tier); \
564 : TEST(RunWasmTurbofan_##name) { RunWasm_##name(ExecutionTier::kOptimized); } \
565 : TEST(RunWasmLiftoff_##name) { RunWasm_##name(ExecutionTier::kBaseline); } \
566 : void RunWasm_##name(ExecutionTier execution_tier)
567 :
568 : } // namespace wasm
569 : } // namespace internal
570 : } // namespace v8
571 :
572 : #endif
|