Line data Source code
1 : // Copyright 2017 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 "test/cctest/wasm/wasm-run-utils.h"
6 :
7 : #include "src/assembler-inl.h"
8 : #include "src/code-tracer.h"
9 : #include "src/heap/heap-inl.h"
10 : #include "src/wasm/graph-builder-interface.h"
11 : #include "src/wasm/wasm-import-wrapper-cache.h"
12 : #include "src/wasm/wasm-memory.h"
13 : #include "src/wasm/wasm-objects-inl.h"
14 :
15 : namespace v8 {
16 : namespace internal {
17 : namespace wasm {
18 :
19 1094224 : TestingModuleBuilder::TestingModuleBuilder(
20 : Zone* zone, ManuallyImportedJSFunction* maybe_import, ExecutionTier tier,
21 : RuntimeExceptionSupport exception_support, LowerSimd lower_simd)
22 : : test_module_(std::make_shared<WasmModule>()),
23 : test_module_ptr_(test_module_.get()),
24 : isolate_(CcTest::InitIsolateOnce()),
25 : enabled_features_(WasmFeaturesFromIsolate(isolate_)),
26 : execution_tier_(tier),
27 : runtime_exception_support_(exception_support),
28 3282672 : lower_simd_(lower_simd) {
29 1094224 : WasmJs::Install(isolate_, true);
30 1094224 : test_module_->untagged_globals_buffer_size = kMaxGlobalsSize;
31 1094224 : memset(globals_data_, 0, sizeof(globals_data_));
32 :
33 : uint32_t maybe_import_index = 0;
34 1094224 : if (maybe_import) {
35 : // Manually add an imported function before any other functions.
36 : // This must happen before the instance object is created, since the
37 : // instance object allocates import entries.
38 2028 : maybe_import_index = AddFunction(maybe_import->sig, nullptr, kImport);
39 : DCHECK_EQ(0, maybe_import_index);
40 : }
41 :
42 1094224 : instance_object_ = InitInstanceObject();
43 1094224 : Handle<FixedArray> tables(isolate_->factory()->NewFixedArray(0));
44 1094224 : instance_object_->set_tables(*tables);
45 :
46 1094224 : if (maybe_import) {
47 : // Manually compile an import wrapper and insert it into the instance.
48 6084 : CodeSpaceMemoryModificationScope modification_scope(isolate_->heap());
49 4056 : auto kind = compiler::GetWasmImportCallKind(maybe_import->js_function,
50 2028 : maybe_import->sig, false);
51 4056 : auto import_wrapper = native_module_->import_wrapper_cache()->GetOrCompile(
52 4056 : isolate_->wasm_engine(), isolate_->counters(), kind, maybe_import->sig);
53 :
54 : ImportedFunctionEntry(instance_object_, maybe_import_index)
55 4056 : .SetWasmToJs(isolate_, maybe_import->js_function, import_wrapper);
56 : }
57 :
58 1094224 : if (tier == ExecutionTier::kInterpreter) {
59 364912 : interpreter_ = WasmDebugInfo::SetupForTesting(instance_object_);
60 : }
61 1094224 : }
62 :
63 41480 : byte* TestingModuleBuilder::AddMemory(uint32_t size, SharedFlag shared) {
64 41480 : CHECK(!test_module_->has_memory);
65 41480 : CHECK_NULL(mem_start_);
66 41480 : CHECK_EQ(0, mem_size_);
67 : DCHECK(!instance_object_->has_memory_object());
68 : DCHECK_IMPLIES(test_module_->origin == kWasmOrigin,
69 : size % kWasmPageSize == 0);
70 41480 : test_module_->has_memory = true;
71 : uint32_t max_size =
72 41480 : (test_module_->maximum_pages != 0) ? test_module_->maximum_pages : size;
73 : uint32_t alloc_size = RoundUp(size, kWasmPageSize);
74 : Handle<JSArrayBuffer> new_buffer;
75 41480 : if (shared == SharedFlag::kShared) {
76 16 : CHECK(NewSharedArrayBuffer(isolate_, alloc_size, max_size)
77 : .ToHandle(&new_buffer));
78 : } else {
79 82944 : CHECK(NewArrayBuffer(isolate_, alloc_size).ToHandle(&new_buffer));
80 : }
81 41480 : CHECK(!new_buffer.is_null());
82 41480 : mem_start_ = reinterpret_cast<byte*>(new_buffer->backing_store());
83 41480 : mem_size_ = size;
84 41480 : CHECK(size == 0 || mem_start_);
85 41480 : memset(mem_start_, 0, size);
86 :
87 : // Create the WasmMemoryObject.
88 : Handle<WasmMemoryObject> memory_object =
89 41480 : WasmMemoryObject::New(isolate_, new_buffer, max_size);
90 41480 : instance_object_->set_memory_object(*memory_object);
91 41480 : WasmMemoryObject::AddInstance(isolate_, memory_object, instance_object_);
92 : // TODO(wasm): Delete the following two lines when test-run-wasm will use a
93 : // multiple of kPageSize as memory size. At the moment, the effect of these
94 : // two lines is used to shrink the memory for testing purposes.
95 82960 : instance_object_->SetRawMemory(mem_start_, mem_size_);
96 41480 : return mem_start_;
97 : }
98 :
99 1105304 : uint32_t TestingModuleBuilder::AddFunction(FunctionSig* sig, const char* name,
100 : FunctionType type) {
101 1105304 : if (test_module_->functions.size() == 0) {
102 : // TODO(titzer): Reserving space here to avoid the underlying WasmFunction
103 : // structs from moving.
104 1094224 : test_module_->functions.reserve(kMaxFunctions);
105 : }
106 1105304 : uint32_t index = static_cast<uint32_t>(test_module_->functions.size());
107 3315912 : test_module_->functions.push_back({sig, index, 0, {0, 0}, false, false});
108 1105304 : if (type == kImport) {
109 : DCHECK_EQ(0, test_module_->num_declared_functions);
110 2028 : ++test_module_->num_imported_functions;
111 2028 : test_module_->functions.back().imported = true;
112 : } else {
113 1103276 : ++test_module_->num_declared_functions;
114 : }
115 : DCHECK_EQ(test_module_->functions.size(),
116 : test_module_->num_imported_functions +
117 : test_module_->num_declared_functions);
118 1105304 : if (name) {
119 1094772 : Vector<const byte> name_vec = Vector<const byte>::cast(CStrVector(name));
120 3284316 : test_module_->AddFunctionNameForTesting(
121 1094772 : index, {AddBytes(name_vec), static_cast<uint32_t>(name_vec.length())});
122 : }
123 1105304 : if (interpreter_) {
124 367596 : interpreter_->AddFunctionForTesting(&test_module_->functions.back());
125 : // Patch the jump table to call the interpreter for this function.
126 : wasm::WasmCompilationResult result = compiler::CompileWasmInterpreterEntry(
127 735192 : isolate_->wasm_engine(), native_module_->enabled_features(), index,
128 735192 : sig);
129 367596 : std::unique_ptr<wasm::WasmCode> code = native_module_->AddCode(
130 : index, result.code_desc, result.frame_slot_count,
131 : result.tagged_parameter_slots, std::move(result.protected_instructions),
132 : std::move(result.source_positions), wasm::WasmCode::kInterpreterEntry,
133 1837980 : wasm::ExecutionTier::kInterpreter);
134 367596 : native_module_->PublishCode(std::move(code));
135 : }
136 : DCHECK_LT(index, kMaxFunctions); // limited for testing.
137 1105304 : return index;
138 : }
139 :
140 4396 : Handle<JSFunction> TestingModuleBuilder::WrapCode(uint32_t index) {
141 : SetExecutable();
142 8792 : FunctionSig* sig = test_module_->functions[index].sig;
143 : MaybeHandle<Code> maybe_ret_code =
144 4396 : compiler::CompileJSToWasmWrapper(isolate_, sig, false);
145 : Handle<Code> ret_code = maybe_ret_code.ToHandleChecked();
146 : Handle<JSFunction> ret = WasmExportedFunction::New(
147 : isolate_, instance_object(), MaybeHandle<String>(),
148 : static_cast<int>(index), static_cast<int>(sig->parameter_count()),
149 4396 : ret_code);
150 :
151 : // Add reference to the exported wrapper code.
152 : Handle<WasmModuleObject> module_object(instance_object()->module_object(),
153 4396 : isolate_);
154 4396 : Handle<FixedArray> old_arr(module_object->export_wrappers(), isolate_);
155 : Handle<FixedArray> new_arr =
156 4396 : isolate_->factory()->NewFixedArray(old_arr->length() + 1);
157 4396 : old_arr->CopyTo(0, *new_arr, 0, old_arr->length());
158 8792 : new_arr->set(old_arr->length(), *ret_code);
159 4396 : module_object->set_export_wrappers(*new_arr);
160 4396 : return ret;
161 : }
162 :
163 1648 : void TestingModuleBuilder::AddIndirectFunctionTable(
164 : const uint16_t* function_indexes, uint32_t table_size) {
165 : auto instance = instance_object();
166 : uint32_t table_index = static_cast<uint32_t>(test_module_->tables.size());
167 1648 : test_module_->tables.emplace_back();
168 : WasmTable& table = test_module_->tables.back();
169 1648 : table.initial_size = table_size;
170 1648 : table.maximum_size = table_size;
171 1648 : table.has_maximum_size = true;
172 1648 : table.type = kWasmAnyFunc;
173 : WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
174 1648 : instance_object(), table_size);
175 : Handle<WasmTableObject> table_obj =
176 1648 : WasmTableObject::New(isolate_, table.type, table.initial_size,
177 3296 : table.has_maximum_size, table.maximum_size, nullptr);
178 :
179 1648 : WasmTableObject::AddDispatchTable(isolate_, table_obj, instance_object_,
180 1648 : table_index);
181 :
182 1648 : if (function_indexes) {
183 804 : for (uint32_t i = 0; i < table_size; ++i) {
184 340 : WasmFunction& function = test_module_->functions[function_indexes[i]];
185 340 : int sig_id = test_module_->signature_map.Find(*function.sig);
186 : IndirectFunctionTableEntry(instance, i)
187 680 : .Set(sig_id, instance, function.func_index);
188 340 : WasmTableObject::SetFunctionTablePlaceholder(
189 680 : isolate_, table_obj, i, instance_object_, function_indexes[i]);
190 : }
191 : }
192 :
193 1648 : Handle<FixedArray> old_tables(instance_object_->tables(), isolate_);
194 1648 : Handle<FixedArray> new_tables = isolate_->factory()->CopyFixedArrayAndGrow(
195 3296 : old_tables, old_tables->length() + 1);
196 3296 : new_tables->set(old_tables->length(), *table_obj);
197 1648 : instance_object_->set_tables(*new_tables);
198 1648 : }
199 :
200 2192648 : uint32_t TestingModuleBuilder::AddBytes(Vector<const byte> bytes) {
201 2192648 : Vector<const uint8_t> old_bytes = native_module_->wire_bytes();
202 2192648 : uint32_t old_size = static_cast<uint32_t>(old_bytes.size());
203 : // Avoid placing strings at offset 0, this might be interpreted as "not
204 : // set", e.g. for function names.
205 2192648 : uint32_t bytes_offset = old_size ? old_size : 1;
206 2192648 : size_t new_size = bytes_offset + bytes.size();
207 : OwnedVector<uint8_t> new_bytes = OwnedVector<uint8_t>::New(new_size);
208 2192648 : if (old_size > 0) {
209 : memcpy(new_bytes.start(), old_bytes.start(), old_size);
210 : }
211 2192648 : memcpy(new_bytes.start() + bytes_offset, bytes.start(), bytes.length());
212 4385296 : native_module_->SetWireBytes(std::move(new_bytes));
213 2192648 : return bytes_offset;
214 : }
215 :
216 36 : uint32_t TestingModuleBuilder::AddException(FunctionSig* sig) {
217 : DCHECK_EQ(0, sig->return_count());
218 36 : uint32_t index = static_cast<uint32_t>(test_module_->exceptions.size());
219 72 : test_module_->exceptions.push_back(WasmException{sig});
220 36 : Handle<WasmExceptionTag> tag = WasmExceptionTag::New(isolate_, index);
221 36 : Handle<FixedArray> table(instance_object_->exceptions_table(), isolate_);
222 36 : table = isolate_->factory()->CopyFixedArrayAndGrow(table, 1);
223 36 : instance_object_->set_exceptions_table(*table);
224 72 : table->set(index, *tag);
225 36 : return index;
226 : }
227 :
228 60 : uint32_t TestingModuleBuilder::AddPassiveDataSegment(Vector<const byte> bytes) {
229 60 : uint32_t index = static_cast<uint32_t>(test_module_->data_segments.size());
230 : DCHECK_EQ(index, test_module_->data_segments.size());
231 : DCHECK_EQ(index, data_segment_starts_.size());
232 : DCHECK_EQ(index, data_segment_sizes_.size());
233 : DCHECK_EQ(index, dropped_data_segments_.size());
234 :
235 : // Add a passive data segment. This isn't used by function compilation, but
236 : // but it keeps the index in sync. The data segment's source will not be
237 : // correct, since we don't store data in the module wire bytes.
238 60 : test_module_->data_segments.emplace_back();
239 :
240 : // The num_declared_data_segments (from the DataCount section) is used
241 : // to validate the segment index, during function compilation.
242 60 : test_module_->num_declared_data_segments = index + 1;
243 :
244 : Address old_data_address =
245 60 : reinterpret_cast<Address>(data_segment_data_.data());
246 : size_t old_data_size = data_segment_data_.size();
247 60 : data_segment_data_.resize(old_data_size + bytes.length());
248 : Address new_data_address =
249 60 : reinterpret_cast<Address>(data_segment_data_.data());
250 :
251 60 : memcpy(data_segment_data_.data() + old_data_size, bytes.start(),
252 : bytes.length());
253 :
254 : // The data_segment_data_ offset may have moved, so update all the starts.
255 60 : for (Address& start : data_segment_starts_) {
256 0 : start += new_data_address - old_data_address;
257 : }
258 120 : data_segment_starts_.push_back(new_data_address + old_data_size);
259 120 : data_segment_sizes_.push_back(bytes.length());
260 120 : dropped_data_segments_.push_back(0);
261 :
262 : // The vector pointers may have moved, so update the instance object.
263 : instance_object_->set_data_segment_starts(data_segment_starts_.data());
264 : instance_object_->set_data_segment_sizes(data_segment_sizes_.data());
265 : instance_object_->set_dropped_data_segments(dropped_data_segments_.data());
266 60 : return index;
267 : }
268 :
269 48 : uint32_t TestingModuleBuilder::AddPassiveElementSegment(
270 : const std::vector<uint32_t>& entries) {
271 48 : uint32_t index = static_cast<uint32_t>(test_module_->elem_segments.size());
272 : DCHECK_EQ(index, dropped_elem_segments_.size());
273 :
274 48 : test_module_->elem_segments.emplace_back();
275 : auto& elem_segment = test_module_->elem_segments.back();
276 48 : elem_segment.entries = entries;
277 :
278 : // The vector pointers may have moved, so update the instance object.
279 96 : dropped_elem_segments_.push_back(0);
280 : instance_object_->set_dropped_elem_segments(dropped_elem_segments_.data());
281 48 : return index;
282 : }
283 :
284 731760 : CompilationEnv TestingModuleBuilder::CreateCompilationEnv() {
285 : // This is a hack so we don't need to call
286 : // trap_handler::IsTrapHandlerEnabled().
287 : const bool is_trap_handler_enabled =
288 731760 : V8_TRAP_HANDLER_SUPPORTED && i::FLAG_wasm_trap_handler;
289 731760 : return {test_module_ptr_,
290 : is_trap_handler_enabled ? kUseTrapHandler : kNoTrapHandler,
291 1463520 : runtime_exception_support_, enabled_features_, lower_simd()};
292 : }
293 :
294 22240 : const WasmGlobal* TestingModuleBuilder::AddGlobal(ValueType type) {
295 22240 : byte size = ValueTypes::MemSize(ValueTypes::MachineTypeFor(type));
296 22240 : global_offset = (global_offset + size - 1) & ~(size - 1); // align
297 66720 : test_module_->globals.push_back(
298 : {type, true, WasmInitExpr(), {global_offset}, false, false});
299 22240 : global_offset += size;
300 : // limit number of globals.
301 22240 : CHECK_LT(global_offset, kMaxGlobalsSize);
302 22240 : return &test_module_->globals.back();
303 : }
304 :
305 1094224 : Handle<WasmInstanceObject> TestingModuleBuilder::InitInstanceObject() {
306 : Handle<Script> script =
307 2188448 : isolate_->factory()->NewScript(isolate_->factory()->empty_string());
308 : script->set_type(Script::TYPE_WASM);
309 : Handle<WasmModuleObject> module_object =
310 : WasmModuleObject::New(isolate_, enabled_features_, test_module_, {},
311 4376896 : script, Handle<ByteArray>::null());
312 : // This method is called when we initialize TestEnvironment. We don't
313 : // have a memory yet, so we won't create it here. We'll update the
314 : // interpreter when we get a memory. We do have globals, though.
315 1094224 : native_module_ = module_object->native_module();
316 1094224 : native_module_->ReserveCodeTableForTesting(kMaxFunctions);
317 :
318 1094224 : auto instance = WasmInstanceObject::New(isolate_, module_object);
319 2188448 : instance->set_exceptions_table(*isolate_->factory()->empty_fixed_array());
320 1094224 : instance->set_globals_start(globals_data_);
321 1094224 : return instance;
322 : }
323 :
324 492 : void TestBuildingGraphWithBuilder(compiler::WasmGraphBuilder* builder,
325 : Zone* zone, FunctionSig* sig,
326 : const byte* start, const byte* end) {
327 492 : WasmFeatures unused_detected_features;
328 : FunctionBody body(sig, 0, start, end);
329 : DecodeResult result =
330 984 : BuildTFGraph(zone->allocator(), kAllWasmFeatures, nullptr, builder,
331 : &unused_detected_features, body, nullptr);
332 492 : if (result.failed()) {
333 : #ifdef DEBUG
334 : if (!FLAG_trace_wasm_decoder) {
335 : // Retry the compilation with the tracing flag on, to help in debugging.
336 : FLAG_trace_wasm_decoder = true;
337 : result = BuildTFGraph(zone->allocator(), kAllWasmFeatures, nullptr,
338 : builder, &unused_detected_features, body, nullptr);
339 : }
340 : #endif
341 :
342 : FATAL("Verification failed; pc = +%x, msg = %s", result.error().offset(),
343 0 : result.error().message().c_str());
344 : }
345 492 : builder->LowerInt64();
346 492 : if (!CpuFeatures::SupportsWasmSimd128()) {
347 0 : builder->SimdScalarLoweringForTesting();
348 : }
349 492 : }
350 :
351 492 : void TestBuildingGraph(Zone* zone, compiler::JSGraph* jsgraph,
352 : CompilationEnv* module, FunctionSig* sig,
353 : compiler::SourcePositionTable* source_position_table,
354 : const byte* start, const byte* end) {
355 : compiler::WasmGraphBuilder builder(module, zone, jsgraph, sig,
356 492 : source_position_table);
357 492 : TestBuildingGraphWithBuilder(&builder, zone, sig, start, end);
358 492 : }
359 :
360 1094224 : WasmFunctionWrapper::WasmFunctionWrapper(Zone* zone, int num_params)
361 : : GraphAndBuilders(zone),
362 : inner_code_node_(nullptr),
363 : context_address_(nullptr),
364 2188448 : signature_(nullptr) {
365 : // One additional parameter for the pointer to the return value memory.
366 1094224 : Signature<MachineType>::Builder sig_builder(zone, 1, num_params + 1);
367 :
368 : sig_builder.AddReturn(MachineType::Int32());
369 3349216 : for (int i = 0; i < num_params + 1; i++) {
370 : sig_builder.AddParam(MachineType::Pointer());
371 : }
372 1094224 : signature_ = sig_builder.Build();
373 1094224 : }
374 :
375 729312 : void WasmFunctionWrapper::Init(CallDescriptor* call_descriptor,
376 : MachineType return_type,
377 : Vector<MachineType> param_types) {
378 : DCHECK_NOT_NULL(call_descriptor);
379 : DCHECK_EQ(signature_->parameter_count(), param_types.length() + 1);
380 :
381 : // Create the TF graph for the wrapper.
382 :
383 : // Function, context_address, effect, and control.
384 729312 : Node** parameters = zone()->NewArray<Node*>(param_types.length() + 4);
385 : int start_value_output_count =
386 729312 : static_cast<int>(signature_->parameter_count()) + 1;
387 729312 : graph()->SetStart(
388 : graph()->NewNode(common()->Start(start_value_output_count)));
389 : Node* effect = graph()->start();
390 : int parameter_count = 0;
391 :
392 : // Dummy node which gets replaced in SetInnerCode.
393 1458624 : inner_code_node_ = graph()->NewNode(common()->Int32Constant(0));
394 729312 : parameters[parameter_count++] = inner_code_node_;
395 :
396 : // Dummy node that gets replaced in SetContextAddress.
397 1458624 : context_address_ = graph()->NewNode(IntPtrConstant(0));
398 729312 : parameters[parameter_count++] = context_address_;
399 :
400 : int param_idx = 0;
401 773576 : for (MachineType t : param_types) {
402 : DCHECK_NE(MachineType::None(), t);
403 66396 : parameters[parameter_count] = graph()->NewNode(
404 : machine()->Load(t),
405 : graph()->NewNode(common()->Parameter(param_idx++), graph()->start()),
406 22132 : graph()->NewNode(common()->Int32Constant(0)), effect, graph()->start());
407 22132 : effect = parameters[parameter_count++];
408 : }
409 :
410 729312 : parameters[parameter_count++] = effect;
411 729312 : parameters[parameter_count++] = graph()->start();
412 729312 : Node* call = graph()->NewNode(common()->Call(call_descriptor),
413 729312 : parameter_count, parameters);
414 :
415 729312 : if (!return_type.IsNone()) {
416 2901536 : effect = graph()->NewNode(
417 : machine()->Store(compiler::StoreRepresentation(
418 : return_type.representation(), WriteBarrierKind::kNoWriteBarrier)),
419 : graph()->NewNode(common()->Parameter(param_types.length()),
420 : graph()->start()),
421 : graph()->NewNode(common()->Int32Constant(0)), call, effect,
422 : graph()->start());
423 : }
424 729312 : Node* zero = graph()->NewNode(common()->Int32Constant(0));
425 1458624 : Node* r = graph()->NewNode(
426 : common()->Return(), zero,
427 : graph()->NewNode(common()->Int32Constant(WASM_WRAPPER_RETURN_VALUE)),
428 : effect, graph()->start());
429 729312 : graph()->SetEnd(graph()->NewNode(common()->End(1), r));
430 729312 : }
431 :
432 9612676 : Handle<Code> WasmFunctionWrapper::GetWrapperCode() {
433 : Handle<Code> code;
434 9612676 : if (!code_.ToHandle(&code)) {
435 : Isolate* isolate = CcTest::InitIsolateOnce();
436 :
437 : auto call_descriptor =
438 724944 : compiler::Linkage::GetSimplifiedCDescriptor(zone(), signature_, true);
439 :
440 : if (kSystemPointerSize == 4) {
441 : size_t num_params = signature_->parameter_count();
442 : // One additional parameter for the pointer of the return value.
443 : Signature<MachineRepresentation>::Builder rep_builder(zone(), 1,
444 : num_params + 1);
445 :
446 : rep_builder.AddReturn(MachineRepresentation::kWord32);
447 : for (size_t i = 0; i < num_params + 1; i++) {
448 : rep_builder.AddParam(MachineRepresentation::kWord32);
449 : }
450 : compiler::Int64Lowering r(graph(), machine(), common(), zone(),
451 : rep_builder.Build());
452 : r.LowerGraph();
453 : }
454 :
455 : OptimizedCompilationInfo info(ArrayVector("testing"), graph()->zone(),
456 1449888 : Code::C_WASM_ENTRY);
457 : code_ = compiler::Pipeline::GenerateCodeForTesting(
458 : &info, isolate, call_descriptor, graph(),
459 724944 : AssemblerOptions::Default(isolate));
460 : code = code_.ToHandleChecked();
461 : #ifdef ENABLE_DISASSEMBLER
462 : if (FLAG_print_opt_code) {
463 : CodeTracer::Scope tracing_scope(isolate->GetCodeTracer());
464 : OFStream os(tracing_scope.file());
465 :
466 : code->Disassemble("wasm wrapper", os);
467 : }
468 : #endif
469 : }
470 :
471 9612676 : return code;
472 : }
473 :
474 1097876 : void WasmFunctionCompiler::Build(const byte* start, const byte* end) {
475 1097876 : size_t locals_size = local_decls.Size();
476 1097876 : size_t total_size = end - start + locals_size + 1;
477 1097876 : byte* buffer = static_cast<byte*>(zone()->New(total_size));
478 : // Prepend the local decls to the code.
479 1097876 : local_decls.Emit(buffer);
480 : // Emit the code.
481 1097876 : memcpy(buffer + locals_size, start, end - start);
482 : // Append an extra end opcode.
483 1097876 : buffer[total_size - 1] = kExprEnd;
484 :
485 : start = buffer;
486 1097876 : end = buffer + total_size;
487 :
488 1097876 : CHECK_GE(kMaxInt, end - start);
489 1097876 : int len = static_cast<int>(end - start);
490 2195752 : function_->code = {builder_->AddBytes(Vector<const byte>(start, len)),
491 2195752 : static_cast<uint32_t>(len)};
492 :
493 1097876 : if (interpreter_) {
494 : // Add the code to the interpreter; do not generate compiled code.
495 366116 : interpreter_->SetFunctionCodeForTesting(function_, start, end);
496 366116 : return;
497 : }
498 :
499 731760 : Vector<const uint8_t> wire_bytes = builder_->instance_object()
500 1463520 : ->module_object()
501 : ->native_module()
502 731760 : ->wire_bytes();
503 :
504 731760 : CompilationEnv env = builder_->CreateCompilationEnv();
505 731760 : ScopedVector<uint8_t> func_wire_bytes(function_->code.length());
506 731760 : memcpy(func_wire_bytes.start(), wire_bytes.start() + function_->code.offset(),
507 : func_wire_bytes.length());
508 :
509 : FunctionBody func_body{function_->sig, function_->code.offset(),
510 : func_wire_bytes.start(), func_wire_bytes.end()};
511 : NativeModule* native_module =
512 1463520 : builder_->instance_object()->module_object()->native_module();
513 1463520 : WasmCompilationUnit unit(function_->func_index, builder_->execution_tier());
514 731760 : WasmFeatures unused_detected_features;
515 : WasmCompilationResult result = unit.ExecuteCompilation(
516 : isolate()->wasm_engine(), &env,
517 1463520 : native_module->compilation_state()->GetWireBytesStorage(),
518 1463520 : isolate()->counters(), &unused_detected_features);
519 731760 : WasmCode* code = native_module->AddCompiledCode(std::move(result));
520 : DCHECK_NOT_NULL(code);
521 731760 : if (WasmCode::ShouldBeLogged(isolate())) code->LogCode(isolate());
522 : }
523 :
524 1103276 : WasmFunctionCompiler::WasmFunctionCompiler(Zone* zone, FunctionSig* sig,
525 : TestingModuleBuilder* builder,
526 : const char* name)
527 : : GraphAndBuilders(zone),
528 : jsgraph(builder->isolate(), this->graph(), this->common(), nullptr,
529 : nullptr, this->machine()),
530 : sig(sig),
531 : descriptor_(nullptr),
532 : builder_(builder),
533 : local_decls(zone, sig),
534 : source_position_table_(this->graph()),
535 3309828 : interpreter_(builder->interpreter()) {
536 : // Get a new function from the testing module.
537 1103276 : int index = builder->AddFunction(sig, name, TestingModuleBuilder::kWasm);
538 2206552 : function_ = builder_->GetFunctionAt(index);
539 1103276 : }
540 :
541 : WasmFunctionCompiler::~WasmFunctionCompiler() = default;
542 :
543 1094476 : FunctionSig* WasmRunnerBase::CreateSig(MachineType return_type,
544 : Vector<MachineType> param_types) {
545 1094476 : int return_count = return_type.IsNone() ? 0 : 1;
546 : int param_count = param_types.length();
547 :
548 : // Allocate storage array in zone.
549 1094476 : ValueType* sig_types = zone_.NewArray<ValueType>(return_count + param_count);
550 :
551 : // Convert machine types to local types, and check that there are no
552 : // MachineType::None()'s in the parameters.
553 : int idx = 0;
554 1094476 : if (return_count) sig_types[idx++] = ValueTypes::ValueTypeFor(return_type);
555 1161676 : for (MachineType param : param_types) {
556 33600 : CHECK_NE(MachineType::None(), param);
557 33600 : sig_types[idx++] = ValueTypes::ValueTypeFor(param);
558 : }
559 2188952 : return new (&zone_) FunctionSig(return_count, param_count, sig_types);
560 : }
561 :
562 : // static
563 : bool WasmRunnerBase::trap_happened;
564 :
565 : } // namespace wasm
566 : } // namespace internal
567 79917 : } // namespace v8
|