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 "src/wasm/wasm-objects.h"
6 : #include "src/utils.h"
7 :
8 : #include "src/assembler-inl.h"
9 : #include "src/base/iterator.h"
10 : #include "src/code-factory.h"
11 : #include "src/compiler/wasm-compiler.h"
12 : #include "src/counters.h"
13 : #include "src/debug/debug-interface.h"
14 : #include "src/objects-inl.h"
15 : #include "src/objects/debug-objects-inl.h"
16 : #include "src/objects/shared-function-info.h"
17 : #include "src/objects/struct-inl.h"
18 : #include "src/trap-handler/trap-handler.h"
19 : #include "src/vector.h"
20 : #include "src/wasm/jump-table-assembler.h"
21 : #include "src/wasm/module-compiler.h"
22 : #include "src/wasm/module-decoder.h"
23 : #include "src/wasm/module-instantiate.h"
24 : #include "src/wasm/value-type.h"
25 : #include "src/wasm/wasm-code-manager.h"
26 : #include "src/wasm/wasm-engine.h"
27 : #include "src/wasm/wasm-limits.h"
28 : #include "src/wasm/wasm-memory.h"
29 : #include "src/wasm/wasm-module.h"
30 : #include "src/wasm/wasm-objects-inl.h"
31 : #include "src/wasm/wasm-text.h"
32 :
33 : #define TRACE(...) \
34 : do { \
35 : if (FLAG_trace_wasm_instances) PrintF(__VA_ARGS__); \
36 : } while (false)
37 :
38 : #define TRACE_IFT(...) \
39 : do { \
40 : if (false) PrintF(__VA_ARGS__); \
41 : } while (false)
42 :
43 : namespace v8 {
44 : namespace internal {
45 :
46 : // Import a few often used types from the wasm namespace.
47 : using WasmFunction = wasm::WasmFunction;
48 : using WasmModule = wasm::WasmModule;
49 :
50 : namespace {
51 :
52 : // Manages the natively-allocated memory for a WasmInstanceObject. Since
53 : // an instance finalizer is not guaranteed to run upon isolate shutdown,
54 : // we must use a Managed<WasmInstanceNativeAllocations> to guarantee
55 : // it is freed.
56 : // Native allocations are the signature ids and targets for indirect call
57 : // targets, as well as the call targets for imported functions.
58 : class WasmInstanceNativeAllocations {
59 : public:
60 : // Helper macro to set an internal field and the corresponding field
61 : // on an instance.
62 : #define SET(instance, field, value) \
63 : { \
64 : auto v = value; \
65 : this->field##_ = v; \
66 : instance->set_##field(v); \
67 : }
68 :
69 : // Allocates initial native storage for a given instance.
70 1231090 : WasmInstanceNativeAllocations(Handle<WasmInstanceObject> instance,
71 : size_t num_imported_functions,
72 : size_t num_imported_mutable_globals,
73 : size_t num_data_segments,
74 1231090 : size_t num_elem_segments) {
75 1231090 : SET(instance, imported_function_targets,
76 : reinterpret_cast<Address*>(
77 : calloc(num_imported_functions, sizeof(Address))));
78 1231090 : SET(instance, imported_mutable_globals,
79 : reinterpret_cast<Address*>(
80 : calloc(num_imported_mutable_globals, sizeof(Address))));
81 1231090 : SET(instance, data_segment_starts,
82 : reinterpret_cast<Address*>(calloc(num_data_segments, sizeof(Address))));
83 1231090 : SET(instance, data_segment_sizes,
84 : reinterpret_cast<uint32_t*>(
85 : calloc(num_data_segments, sizeof(uint32_t))));
86 1231090 : SET(instance, dropped_data_segments,
87 : reinterpret_cast<uint8_t*>(calloc(num_data_segments, sizeof(uint8_t))));
88 1231090 : SET(instance, dropped_elem_segments,
89 : reinterpret_cast<uint8_t*>(calloc(num_elem_segments, sizeof(uint8_t))));
90 1231090 : }
91 2462180 : ~WasmInstanceNativeAllocations() {
92 1231090 : ::free(indirect_function_table_sig_ids_);
93 1231090 : indirect_function_table_sig_ids_ = nullptr;
94 1231090 : ::free(indirect_function_table_targets_);
95 1231090 : indirect_function_table_targets_ = nullptr;
96 1231090 : ::free(imported_function_targets_);
97 1231090 : imported_function_targets_ = nullptr;
98 1231090 : ::free(imported_mutable_globals_);
99 1231090 : imported_mutable_globals_ = nullptr;
100 1231090 : ::free(data_segment_starts_);
101 1231090 : data_segment_starts_ = nullptr;
102 1231090 : ::free(data_segment_sizes_);
103 1231090 : data_segment_sizes_ = nullptr;
104 1231090 : ::free(dropped_data_segments_);
105 1231090 : dropped_data_segments_ = nullptr;
106 1231090 : ::free(dropped_elem_segments_);
107 1231090 : dropped_elem_segments_ = nullptr;
108 1231090 : }
109 : // Resizes the indirect function table.
110 3273 : void resize_indirect_function_table(Isolate* isolate,
111 : Handle<WasmInstanceObject> instance,
112 : uint32_t new_size) {
113 : uint32_t old_size = instance->indirect_function_table_size();
114 : void* new_sig_ids = nullptr;
115 : void* new_targets = nullptr;
116 : Handle<FixedArray> new_refs;
117 3273 : if (indirect_function_table_sig_ids_) {
118 : // Reallocate the old storage.
119 888 : new_sig_ids = realloc(indirect_function_table_sig_ids_,
120 888 : new_size * sizeof(uint32_t));
121 : new_targets =
122 888 : realloc(indirect_function_table_targets_, new_size * sizeof(Address));
123 :
124 : Handle<FixedArray> old(instance->indirect_function_table_refs(), isolate);
125 : new_refs = isolate->factory()->CopyFixedArrayAndGrow(
126 888 : old, static_cast<int>(new_size - old_size));
127 : } else {
128 : // Allocate new storage.
129 2385 : new_sig_ids = malloc(new_size * sizeof(uint32_t));
130 2385 : new_targets = malloc(new_size * sizeof(Address));
131 2385 : new_refs = isolate->factory()->NewFixedArray(static_cast<int>(new_size));
132 : }
133 : // Initialize new entries.
134 : instance->set_indirect_function_table_size(new_size);
135 3273 : SET(instance, indirect_function_table_sig_ids,
136 : reinterpret_cast<uint32_t*>(new_sig_ids));
137 3273 : SET(instance, indirect_function_table_targets,
138 : reinterpret_cast<Address*>(new_targets));
139 :
140 3273 : instance->set_indirect_function_table_refs(*new_refs);
141 40447627 : for (uint32_t j = old_size; j < new_size; j++) {
142 40444354 : IndirectFunctionTableEntry(instance, static_cast<int>(j)).clear();
143 : }
144 3273 : }
145 : uint32_t* indirect_function_table_sig_ids_ = nullptr;
146 : Address* indirect_function_table_targets_ = nullptr;
147 : Address* imported_function_targets_ = nullptr;
148 : Address* imported_mutable_globals_ = nullptr;
149 : Address* data_segment_starts_ = nullptr;
150 : uint32_t* data_segment_sizes_ = nullptr;
151 : uint8_t* dropped_data_segments_ = nullptr;
152 : uint8_t* dropped_elem_segments_ = nullptr;
153 : #undef SET
154 : };
155 :
156 : size_t EstimateNativeAllocationsSize(const WasmModule* module) {
157 : size_t estimate =
158 1231090 : sizeof(WasmInstanceNativeAllocations) +
159 2462180 : (1 * kSystemPointerSize * module->num_imported_mutable_globals) +
160 1231090 : (2 * kSystemPointerSize * module->num_imported_functions) +
161 1231090 : ((kSystemPointerSize + sizeof(uint32_t) + sizeof(uint8_t)) *
162 1231090 : module->num_declared_data_segments);
163 1233983 : for (auto& table : module->tables) {
164 2893 : estimate += 3 * kSystemPointerSize * table.initial_size;
165 : }
166 : return estimate;
167 : }
168 :
169 : WasmInstanceNativeAllocations* GetNativeAllocations(
170 : WasmInstanceObject instance) {
171 : return Managed<WasmInstanceNativeAllocations>::cast(
172 : instance->managed_native_allocations())
173 : ->raw();
174 : }
175 :
176 : #ifdef DEBUG
177 : bool IsBreakablePosition(wasm::NativeModule* native_module, int func_index,
178 : int offset_in_func) {
179 : AccountingAllocator alloc;
180 : Zone tmp(&alloc, ZONE_NAME);
181 : wasm::BodyLocalDecls locals(&tmp);
182 : const byte* module_start = native_module->wire_bytes().start();
183 : const WasmFunction& func = native_module->module()->functions[func_index];
184 : wasm::BytecodeIterator iterator(module_start + func.code.offset(),
185 : module_start + func.code.end_offset(),
186 : &locals);
187 : DCHECK_LT(0, locals.encoded_size);
188 : for (uint32_t offset : iterator.offsets()) {
189 : if (offset > static_cast<uint32_t>(offset_in_func)) break;
190 : if (offset == static_cast<uint32_t>(offset_in_func)) return true;
191 : }
192 : return false;
193 : }
194 : #endif // DEBUG
195 :
196 : enum DispatchTableElements : int {
197 : kDispatchTableInstanceOffset,
198 : kDispatchTableIndexOffset,
199 : kDispatchTableFunctionTableOffset,
200 : // Marker:
201 : kDispatchTableNumElements
202 : };
203 :
204 : } // namespace
205 :
206 : // static
207 1094412 : Handle<WasmModuleObject> WasmModuleObject::New(
208 : Isolate* isolate, const wasm::WasmFeatures& enabled,
209 : std::shared_ptr<const wasm::WasmModule> shared_module,
210 : OwnedVector<const uint8_t> wire_bytes, Handle<Script> script,
211 : Handle<ByteArray> asm_js_offset_table) {
212 : // Create a new {NativeModule} first.
213 : size_t code_size_estimate =
214 1094412 : wasm::WasmCodeManager::EstimateNativeModuleCodeSize(shared_module.get());
215 : auto native_module = isolate->wasm_engine()->NewNativeModule(
216 : isolate, enabled, code_size_estimate,
217 2188824 : wasm::NativeModule::kCanAllocateMoreMemory, std::move(shared_module));
218 2188824 : native_module->SetWireBytes(std::move(wire_bytes));
219 1094412 : native_module->SetRuntimeStubs(isolate);
220 :
221 : // Delegate to the shared {WasmModuleObject::New} allocator.
222 : Handle<WasmModuleObject> module_object =
223 2188824 : New(isolate, std::move(native_module), script, code_size_estimate);
224 1094412 : if (!asm_js_offset_table.is_null()) {
225 0 : module_object->set_asm_js_offset_table(*asm_js_offset_table);
226 : }
227 2188824 : return module_object;
228 : }
229 :
230 : // static
231 1096831 : Handle<WasmModuleObject> WasmModuleObject::New(
232 : Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module,
233 : Handle<Script> script, size_t code_size_estimate) {
234 : const WasmModule* module = native_module->module();
235 1096831 : int export_wrapper_size = static_cast<int>(module->num_exported_functions);
236 : Handle<FixedArray> export_wrappers = isolate->factory()->NewFixedArray(
237 1096831 : export_wrapper_size, AllocationType::kOld);
238 : return New(isolate, std::move(native_module), script, export_wrappers,
239 2193662 : code_size_estimate);
240 : }
241 :
242 : // static
243 1237207 : Handle<WasmModuleObject> WasmModuleObject::New(
244 : Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module,
245 : Handle<Script> script, Handle<FixedArray> export_wrappers,
246 : size_t code_size_estimate) {
247 : const WasmModule* module = native_module->module();
248 :
249 : // Use the given shared {NativeModule}, but increase its reference count by
250 : // allocating a new {Managed<T>} that the {WasmModuleObject} references.
251 : size_t memory_estimate =
252 : code_size_estimate +
253 1237207 : wasm::WasmCodeManager::EstimateNativeModuleNonCodeSize(module);
254 : Handle<Managed<wasm::NativeModule>> managed_native_module =
255 : Managed<wasm::NativeModule>::FromSharedPtr(isolate, memory_estimate,
256 1237207 : std::move(native_module));
257 :
258 : Handle<WasmModuleObject> module_object = Handle<WasmModuleObject>::cast(
259 1237207 : isolate->factory()->NewJSObject(isolate->wasm_module_constructor()));
260 1237207 : module_object->set_export_wrappers(*export_wrappers);
261 1237207 : if (script->type() == Script::TYPE_WASM) {
262 1232189 : script->set_wasm_module_object(*module_object);
263 : }
264 1237207 : module_object->set_script(*script);
265 2474414 : module_object->set_weak_instance_list(
266 1237207 : ReadOnlyRoots(isolate).empty_weak_array_list());
267 1237207 : module_object->set_managed_native_module(*managed_native_module);
268 1237207 : return module_object;
269 : }
270 :
271 116 : bool WasmModuleObject::SetBreakPoint(Handle<WasmModuleObject> module_object,
272 : int* position,
273 : Handle<BreakPoint> break_point) {
274 : Isolate* isolate = module_object->GetIsolate();
275 :
276 : // Find the function for this breakpoint.
277 116 : int func_index = module_object->GetContainingFunction(*position);
278 116 : if (func_index < 0) return false;
279 348 : const WasmFunction& func = module_object->module()->functions[func_index];
280 116 : int offset_in_func = *position - func.code.offset();
281 :
282 : // According to the current design, we should only be called with valid
283 : // breakable positions.
284 : DCHECK(IsBreakablePosition(module_object->native_module(), func_index,
285 : offset_in_func));
286 :
287 : // Insert new break point into break_positions of module object.
288 116 : WasmModuleObject::AddBreakpoint(module_object, *position, break_point);
289 :
290 : // Iterate over all instances of this module and tell them to set this new
291 : // breakpoint. We do this using the weak list of all instances.
292 : Handle<WeakArrayList> weak_instance_list(module_object->weak_instance_list(),
293 : isolate);
294 348 : for (int i = 0; i < weak_instance_list->length(); ++i) {
295 : MaybeObject maybe_instance = weak_instance_list->Get(i);
296 116 : if (maybe_instance->IsWeak()) {
297 : Handle<WasmInstanceObject> instance(
298 : WasmInstanceObject::cast(maybe_instance->GetHeapObjectAssumeWeak()),
299 : isolate);
300 : Handle<WasmDebugInfo> debug_info =
301 116 : WasmInstanceObject::GetOrCreateDebugInfo(instance);
302 116 : WasmDebugInfo::SetBreakpoint(debug_info, func_index, offset_in_func);
303 : }
304 : }
305 :
306 : return true;
307 : }
308 :
309 : namespace {
310 :
311 : int GetBreakpointPos(Isolate* isolate, Object break_point_info_or_undef) {
312 2360 : if (break_point_info_or_undef->IsUndefined(isolate)) return kMaxInt;
313 : return BreakPointInfo::cast(break_point_info_or_undef)->source_position();
314 : }
315 :
316 676 : int FindBreakpointInfoInsertPos(Isolate* isolate,
317 : Handle<FixedArray> breakpoint_infos,
318 : int position) {
319 : // Find insert location via binary search, taking care of undefined values on
320 : // the right. Position is always greater than zero.
321 : DCHECK_LT(0, position);
322 :
323 : int left = 0; // inclusive
324 : int right = breakpoint_infos->length(); // exclusive
325 2252 : while (right - left > 1) {
326 1576 : int mid = left + (right - left) / 2;
327 : Object mid_obj = breakpoint_infos->get(mid);
328 1576 : if (GetBreakpointPos(isolate, mid_obj) <= position) {
329 : left = mid;
330 : } else {
331 : right = mid;
332 : }
333 : }
334 :
335 : int left_pos = GetBreakpointPos(isolate, breakpoint_infos->get(left));
336 676 : return left_pos < position ? left + 1 : left;
337 : }
338 :
339 : } // namespace
340 :
341 116 : void WasmModuleObject::AddBreakpoint(Handle<WasmModuleObject> module_object,
342 : int position,
343 : Handle<BreakPoint> break_point) {
344 : Isolate* isolate = module_object->GetIsolate();
345 : Handle<FixedArray> breakpoint_infos;
346 116 : if (module_object->has_breakpoint_infos()) {
347 : breakpoint_infos = handle(module_object->breakpoint_infos(), isolate);
348 : } else {
349 : breakpoint_infos =
350 56 : isolate->factory()->NewFixedArray(4, AllocationType::kOld);
351 56 : module_object->set_breakpoint_infos(*breakpoint_infos);
352 : }
353 :
354 : int insert_pos =
355 116 : FindBreakpointInfoInsertPos(isolate, breakpoint_infos, position);
356 :
357 : // If a BreakPointInfo object already exists for this position, add the new
358 : // breakpoint object and return.
359 224 : if (insert_pos < breakpoint_infos->length() &&
360 : GetBreakpointPos(isolate, breakpoint_infos->get(insert_pos)) ==
361 : position) {
362 : Handle<BreakPointInfo> old_info(
363 : BreakPointInfo::cast(breakpoint_infos->get(insert_pos)), isolate);
364 0 : BreakPointInfo::SetBreakPoint(isolate, old_info, break_point);
365 : return;
366 : }
367 :
368 : // Enlarge break positions array if necessary.
369 116 : bool need_realloc = !breakpoint_infos->get(breakpoint_infos->length() - 1)
370 : ->IsUndefined(isolate);
371 : Handle<FixedArray> new_breakpoint_infos = breakpoint_infos;
372 116 : if (need_realloc) {
373 : new_breakpoint_infos = isolate->factory()->NewFixedArray(
374 12 : 2 * breakpoint_infos->length(), AllocationType::kOld);
375 12 : module_object->set_breakpoint_infos(*new_breakpoint_infos);
376 : // Copy over the entries [0, insert_pos).
377 108 : for (int i = 0; i < insert_pos; ++i)
378 48 : new_breakpoint_infos->set(i, breakpoint_infos->get(i));
379 : }
380 :
381 : // Move elements [insert_pos, ...] up by one.
382 532 : for (int i = breakpoint_infos->length() - 1; i >= insert_pos; --i) {
383 : Object entry = breakpoint_infos->get(i);
384 416 : if (entry->IsUndefined(isolate)) continue;
385 112 : new_breakpoint_infos->set(i + 1, entry);
386 : }
387 :
388 : // Generate new BreakpointInfo.
389 : Handle<BreakPointInfo> breakpoint_info =
390 116 : isolate->factory()->NewBreakPointInfo(position);
391 116 : BreakPointInfo::SetBreakPoint(isolate, breakpoint_info, break_point);
392 :
393 : // Now insert new position at insert_pos.
394 232 : new_breakpoint_infos->set(insert_pos, *breakpoint_info);
395 : }
396 :
397 134655 : void WasmModuleObject::SetBreakpointsOnNewInstance(
398 : Handle<WasmModuleObject> module_object,
399 : Handle<WasmInstanceObject> instance) {
400 269310 : if (!module_object->has_breakpoint_infos()) return;
401 : Isolate* isolate = module_object->GetIsolate();
402 : Handle<WasmDebugInfo> debug_info =
403 0 : WasmInstanceObject::GetOrCreateDebugInfo(instance);
404 :
405 : Handle<FixedArray> breakpoint_infos(module_object->breakpoint_infos(),
406 : isolate);
407 : // If the array exists, it should not be empty.
408 : DCHECK_LT(0, breakpoint_infos->length());
409 :
410 0 : for (int i = 0, e = breakpoint_infos->length(); i < e; ++i) {
411 : Handle<Object> obj(breakpoint_infos->get(i), isolate);
412 0 : if (obj->IsUndefined(isolate)) {
413 : for (; i < e; ++i) {
414 : DCHECK(breakpoint_infos->get(i)->IsUndefined(isolate));
415 : }
416 : break;
417 : }
418 : Handle<BreakPointInfo> breakpoint_info = Handle<BreakPointInfo>::cast(obj);
419 : int position = breakpoint_info->source_position();
420 :
421 : // Find the function for this breakpoint, and set the breakpoint.
422 0 : int func_index = module_object->GetContainingFunction(position);
423 : DCHECK_LE(0, func_index);
424 0 : const WasmFunction& func = module_object->module()->functions[func_index];
425 0 : int offset_in_func = position - func.code.offset();
426 0 : WasmDebugInfo::SetBreakpoint(debug_info, func_index, offset_in_func);
427 : }
428 : }
429 :
430 : namespace {
431 :
432 : enum AsmJsOffsetTableEntryLayout {
433 : kOTEByteOffset,
434 : kOTECallPosition,
435 : kOTENumberConvPosition,
436 : kOTESize
437 : };
438 :
439 784 : Handle<ByteArray> GetDecodedAsmJsOffsetTable(
440 : Handle<WasmModuleObject> module_object, Isolate* isolate) {
441 : DCHECK(module_object->is_asm_js());
442 : Handle<ByteArray> offset_table(module_object->asm_js_offset_table(), isolate);
443 :
444 : // The last byte in the asm_js_offset_tables ByteArray tells whether it is
445 : // still encoded (0) or decoded (1).
446 : enum AsmJsTableType : int { Encoded = 0, Decoded = 1 };
447 784 : int table_type = offset_table->get(offset_table->length() - 1);
448 : DCHECK(table_type == Encoded || table_type == Decoded);
449 784 : if (table_type == Decoded) return offset_table;
450 :
451 140 : wasm::AsmJsOffsets asm_offsets;
452 : {
453 : DisallowHeapAllocation no_gc;
454 : byte* bytes_start = offset_table->GetDataStartAddress();
455 : byte* bytes_end = reinterpret_cast<byte*>(
456 140 : reinterpret_cast<Address>(bytes_start) + offset_table->length() - 1);
457 280 : asm_offsets = wasm::DecodeAsmJsOffsets(bytes_start, bytes_end).value();
458 : }
459 : // Wasm bytes must be valid and must contain asm.js offset table.
460 : DCHECK_GE(kMaxInt, asm_offsets.size());
461 140 : int num_functions = static_cast<int>(asm_offsets.size());
462 : int num_imported_functions =
463 280 : static_cast<int>(module_object->module()->num_imported_functions);
464 : DCHECK_EQ(module_object->module()->functions.size(),
465 : static_cast<size_t>(num_functions) + num_imported_functions);
466 : int num_entries = 0;
467 804 : for (int func = 0; func < num_functions; ++func) {
468 332 : size_t new_size = asm_offsets[func].size();
469 : DCHECK_LE(new_size, static_cast<size_t>(kMaxInt) - num_entries);
470 332 : num_entries += static_cast<int>(new_size);
471 : }
472 : // One byte to encode that this is a decoded table.
473 : DCHECK_GE(kMaxInt,
474 : 1 + static_cast<uint64_t>(num_entries) * kOTESize * kIntSize);
475 140 : int total_size = 1 + num_entries * kOTESize * kIntSize;
476 : Handle<ByteArray> decoded_table =
477 140 : isolate->factory()->NewByteArray(total_size, AllocationType::kOld);
478 : decoded_table->set(total_size - 1, AsmJsTableType::Decoded);
479 140 : module_object->set_asm_js_offset_table(*decoded_table);
480 :
481 : int idx = 0;
482 : const std::vector<WasmFunction>& wasm_funs =
483 280 : module_object->module()->functions;
484 804 : for (int func = 0; func < num_functions; ++func) {
485 332 : std::vector<wasm::AsmJsOffsetEntry>& func_asm_offsets = asm_offsets[func];
486 332 : if (func_asm_offsets.empty()) continue;
487 384 : int func_offset = wasm_funs[num_imported_functions + func].code.offset();
488 640 : for (wasm::AsmJsOffsetEntry& e : func_asm_offsets) {
489 : // Byte offsets must be strictly monotonously increasing:
490 : DCHECK_IMPLIES(idx > 0, func_offset + e.byte_offset >
491 : decoded_table->get_int(idx - kOTESize));
492 448 : decoded_table->set_int(idx + kOTEByteOffset, func_offset + e.byte_offset);
493 448 : decoded_table->set_int(idx + kOTECallPosition, e.source_position_call);
494 448 : decoded_table->set_int(idx + kOTENumberConvPosition,
495 : e.source_position_number_conversion);
496 448 : idx += kOTESize;
497 : }
498 : }
499 : DCHECK_EQ(total_size, idx * kIntSize + 1);
500 140 : return decoded_table;
501 : }
502 :
503 : } // namespace
504 :
505 152004 : int WasmModuleObject::GetSourcePosition(Handle<WasmModuleObject> module_object,
506 : uint32_t func_index,
507 : uint32_t byte_offset,
508 : bool is_at_number_conversion) {
509 : Isolate* isolate = module_object->GetIsolate();
510 304008 : const WasmModule* module = module_object->module();
511 :
512 152004 : if (module->origin != wasm::kAsmJsOrigin) {
513 : // for non-asm.js modules, we just add the function's start offset
514 : // to make a module-relative position.
515 151220 : return byte_offset + module_object->GetFunctionOffset(func_index);
516 : }
517 :
518 : // asm.js modules have an additional offset table that must be searched.
519 : Handle<ByteArray> offset_table =
520 784 : GetDecodedAsmJsOffsetTable(module_object, isolate);
521 :
522 : DCHECK_LT(func_index, module->functions.size());
523 784 : uint32_t func_code_offset = module->functions[func_index].code.offset();
524 784 : uint32_t total_offset = func_code_offset + byte_offset;
525 :
526 : // Binary search for the total byte offset.
527 : int left = 0; // inclusive
528 784 : int right = offset_table->length() / kIntSize / kOTESize; // exclusive
529 : DCHECK_LT(left, right);
530 2264 : while (right - left > 1) {
531 1480 : int mid = left + (right - left) / 2;
532 1480 : int mid_entry = offset_table->get_int(kOTESize * mid);
533 : DCHECK_GE(kMaxInt, mid_entry);
534 1480 : if (static_cast<uint32_t>(mid_entry) <= total_offset) {
535 : left = mid;
536 : } else {
537 : right = mid;
538 : }
539 : }
540 : // There should be an entry for each position that could show up on the stack
541 : // trace:
542 : DCHECK_EQ(total_offset, offset_table->get_int(kOTESize * left));
543 784 : int idx = is_at_number_conversion ? kOTENumberConvPosition : kOTECallPosition;
544 784 : return offset_table->get_int(kOTESize * left + idx);
545 : }
546 :
547 88 : v8::debug::WasmDisassembly WasmModuleObject::DisassembleFunction(
548 : int func_index) {
549 : DisallowHeapAllocation no_gc;
550 :
551 176 : if (func_index < 0 ||
552 88 : static_cast<uint32_t>(func_index) >= module()->functions.size())
553 0 : return {};
554 :
555 88 : wasm::ModuleWireBytes wire_bytes(native_module()->wire_bytes());
556 :
557 176 : std::ostringstream disassembly_os;
558 : v8::debug::WasmDisassembly::OffsetTable offset_table;
559 :
560 88 : PrintWasmText(module(), wire_bytes, static_cast<uint32_t>(func_index),
561 88 : disassembly_os, &offset_table);
562 :
563 88 : return {disassembly_os.str(), std::move(offset_table)};
564 : }
565 :
566 80 : bool WasmModuleObject::GetPossibleBreakpoints(
567 : const v8::debug::Location& start, const v8::debug::Location& end,
568 : std::vector<v8::debug::BreakLocation>* locations) {
569 : DisallowHeapAllocation no_gc;
570 :
571 : const std::vector<WasmFunction>& functions = module()->functions;
572 240 : if (start.GetLineNumber() < 0 || start.GetColumnNumber() < 0 ||
573 160 : (!end.IsEmpty() &&
574 160 : (end.GetLineNumber() < 0 || end.GetColumnNumber() < 0)))
575 : return false;
576 :
577 : // start_func_index, start_offset and end_func_index is inclusive.
578 : // end_offset is exclusive.
579 : // start_offset and end_offset are module-relative byte offsets.
580 80 : uint32_t start_func_index = start.GetLineNumber();
581 160 : if (start_func_index >= functions.size()) return false;
582 80 : int start_func_len = functions[start_func_index].code.length();
583 80 : if (start.GetColumnNumber() > start_func_len) return false;
584 : uint32_t start_offset =
585 72 : functions[start_func_index].code.offset() + start.GetColumnNumber();
586 : uint32_t end_func_index;
587 : uint32_t end_offset;
588 72 : if (end.IsEmpty()) {
589 : // Default: everything till the end of the Script.
590 0 : end_func_index = static_cast<uint32_t>(functions.size() - 1);
591 0 : end_offset = functions[end_func_index].code.end_offset();
592 : } else {
593 : // If end is specified: Use it and check for valid input.
594 72 : end_func_index = static_cast<uint32_t>(end.GetLineNumber());
595 :
596 : // Special case: Stop before the start of the next function. Change to: Stop
597 : // at the end of the function before, such that we don't disassemble the
598 : // next function also.
599 72 : if (end.GetColumnNumber() == 0 && end_func_index > 0) {
600 32 : --end_func_index;
601 32 : end_offset = functions[end_func_index].code.end_offset();
602 : } else {
603 80 : if (end_func_index >= functions.size()) return false;
604 : end_offset =
605 40 : functions[end_func_index].code.offset() + end.GetColumnNumber();
606 40 : if (end_offset > functions[end_func_index].code.end_offset())
607 : return false;
608 : }
609 : }
610 :
611 144 : AccountingAllocator alloc;
612 144 : Zone tmp(&alloc, ZONE_NAME);
613 72 : const byte* module_start = native_module()->wire_bytes().start();
614 :
615 144 : for (uint32_t func_idx = start_func_index; func_idx <= end_func_index;
616 : ++func_idx) {
617 72 : const WasmFunction& func = functions[func_idx];
618 72 : if (func.code.length() == 0) continue;
619 :
620 : wasm::BodyLocalDecls locals(&tmp);
621 : wasm::BytecodeIterator iterator(module_start + func.code.offset(),
622 : module_start + func.code.end_offset(),
623 72 : &locals);
624 : DCHECK_LT(0u, locals.encoded_size);
625 684 : for (uint32_t offset : iterator.offsets()) {
626 320 : uint32_t total_offset = func.code.offset() + offset;
627 320 : if (total_offset >= end_offset) {
628 : DCHECK_EQ(end_func_index, func_idx);
629 : break;
630 : }
631 292 : if (total_offset < start_offset) continue;
632 152 : locations->emplace_back(func_idx, offset, debug::kCommonBreakLocation);
633 : }
634 : }
635 : return true;
636 : }
637 :
638 560 : MaybeHandle<FixedArray> WasmModuleObject::CheckBreakPoints(
639 : Isolate* isolate, Handle<WasmModuleObject> module_object, int position) {
640 560 : if (!module_object->has_breakpoint_infos()) return {};
641 :
642 : Handle<FixedArray> breakpoint_infos(module_object->breakpoint_infos(),
643 : isolate);
644 : int insert_pos =
645 560 : FindBreakpointInfoInsertPos(isolate, breakpoint_infos, position);
646 560 : if (insert_pos >= breakpoint_infos->length()) return {};
647 :
648 : Handle<Object> maybe_breakpoint_info(breakpoint_infos->get(insert_pos),
649 : isolate);
650 560 : if (maybe_breakpoint_info->IsUndefined(isolate)) return {};
651 : Handle<BreakPointInfo> breakpoint_info =
652 : Handle<BreakPointInfo>::cast(maybe_breakpoint_info);
653 328 : if (breakpoint_info->source_position() != position) return {};
654 :
655 : // There is no support for conditional break points. Just assume that every
656 : // break point always hits.
657 : Handle<Object> break_points(breakpoint_info->break_points(), isolate);
658 216 : if (break_points->IsFixedArray()) {
659 0 : return Handle<FixedArray>::cast(break_points);
660 : }
661 216 : Handle<FixedArray> break_points_hit = isolate->factory()->NewFixedArray(1);
662 216 : break_points_hit->set(0, *break_points);
663 216 : return break_points_hit;
664 : }
665 :
666 242038 : MaybeHandle<String> WasmModuleObject::ExtractUtf8StringFromModuleBytes(
667 : Isolate* isolate, Handle<WasmModuleObject> module_object,
668 : wasm::WireBytesRef ref) {
669 : // TODO(wasm): cache strings from modules if it's a performance win.
670 : Vector<const uint8_t> wire_bytes =
671 484077 : module_object->native_module()->wire_bytes();
672 242039 : return ExtractUtf8StringFromModuleBytes(isolate, wire_bytes, ref);
673 : }
674 :
675 257132 : MaybeHandle<String> WasmModuleObject::ExtractUtf8StringFromModuleBytes(
676 : Isolate* isolate, Vector<const uint8_t> wire_bytes,
677 : wasm::WireBytesRef ref) {
678 499171 : Vector<const uint8_t> name_vec = wire_bytes + ref.offset();
679 257132 : name_vec.Truncate(ref.length());
680 : // UTF8 validation happens at decode time.
681 : DCHECK(unibrow::Utf8::ValidateEncoding(name_vec.start(), name_vec.length()));
682 : return isolate->factory()->NewStringFromUtf8(
683 499171 : Vector<const char>::cast(name_vec));
684 : }
685 :
686 604 : MaybeHandle<String> WasmModuleObject::GetModuleNameOrNull(
687 : Isolate* isolate, Handle<WasmModuleObject> module_object) {
688 1208 : const WasmModule* module = module_object->module();
689 604 : if (!module->name.is_set()) return {};
690 24 : return ExtractUtf8StringFromModuleBytes(isolate, module_object, module->name);
691 : }
692 :
693 3404 : MaybeHandle<String> WasmModuleObject::GetFunctionNameOrNull(
694 : Isolate* isolate, Handle<WasmModuleObject> module_object,
695 : uint32_t func_index) {
696 : DCHECK_LT(func_index, module_object->module()->functions.size());
697 : wasm::WireBytesRef name = module_object->module()->LookupFunctionName(
698 : wasm::ModuleWireBytes(module_object->native_module()->wire_bytes()),
699 10212 : func_index);
700 3404 : if (!name.is_set()) return {};
701 3196 : return ExtractUtf8StringFromModuleBytes(isolate, module_object, name);
702 : }
703 :
704 840 : Handle<String> WasmModuleObject::GetFunctionName(
705 : Isolate* isolate, Handle<WasmModuleObject> module_object,
706 : uint32_t func_index) {
707 : MaybeHandle<String> name =
708 840 : GetFunctionNameOrNull(isolate, module_object, func_index);
709 840 : if (!name.is_null()) return name.ToHandleChecked();
710 : EmbeddedVector<char, 32> buffer;
711 0 : int length = SNPrintF(buffer, "wasm-function[%u]", func_index);
712 : return isolate->factory()
713 0 : ->NewStringFromOneByte(Vector<uint8_t>::cast(buffer.SubVector(0, length)))
714 : .ToHandleChecked();
715 : }
716 :
717 16 : Vector<const uint8_t> WasmModuleObject::GetRawFunctionName(
718 : uint32_t func_index) {
719 : DCHECK_GT(module()->functions.size(), func_index);
720 16 : wasm::ModuleWireBytes wire_bytes(native_module()->wire_bytes());
721 : wasm::WireBytesRef name_ref =
722 16 : module()->LookupFunctionName(wire_bytes, func_index);
723 16 : wasm::WasmName name = wire_bytes.GetNameOrNull(name_ref);
724 16 : return Vector<const uint8_t>::cast(name);
725 : }
726 :
727 151876 : int WasmModuleObject::GetFunctionOffset(uint32_t func_index) {
728 : const std::vector<WasmFunction>& functions = module()->functions;
729 303752 : if (static_cast<uint32_t>(func_index) >= functions.size()) return -1;
730 : DCHECK_GE(kMaxInt, functions[func_index].code.offset());
731 151876 : return static_cast<int>(functions[func_index].code.offset());
732 : }
733 :
734 744 : int WasmModuleObject::GetContainingFunction(uint32_t byte_offset) {
735 : const std::vector<WasmFunction>& functions = module()->functions;
736 :
737 : // Binary search for a function containing the given position.
738 : int left = 0; // inclusive
739 744 : int right = static_cast<int>(functions.size()); // exclusive
740 744 : if (right == 0) return false;
741 1376 : while (right - left > 1) {
742 632 : int mid = left + (right - left) / 2;
743 1264 : if (functions[mid].code.offset() <= byte_offset) {
744 : left = mid;
745 : } else {
746 : right = mid;
747 : }
748 : }
749 : // If the found function does not contains the given position, return -1.
750 744 : const WasmFunction& func = functions[left];
751 1488 : if (byte_offset < func.code.offset() ||
752 : byte_offset >= func.code.end_offset()) {
753 : return -1;
754 : }
755 :
756 744 : return left;
757 : }
758 :
759 752 : bool WasmModuleObject::GetPositionInfo(uint32_t position,
760 : Script::PositionInfo* info) {
761 752 : if (script()->source_mapping_url()->IsString()) {
762 124 : if (module()->functions.size() == 0) return false;
763 124 : info->line = 0;
764 124 : info->column = position;
765 124 : info->line_start = module()->functions[0].code.offset();
766 124 : info->line_end = module()->functions.back().code.end_offset();
767 124 : return true;
768 : }
769 628 : int func_index = GetContainingFunction(position);
770 628 : if (func_index < 0) return false;
771 :
772 628 : const WasmFunction& function = module()->functions[func_index];
773 :
774 628 : info->line = func_index;
775 628 : info->column = position - function.code.offset();
776 628 : info->line_start = function.code.offset();
777 628 : info->line_end = function.code.end_offset();
778 628 : return true;
779 : }
780 :
781 4725 : Handle<WasmTableObject> WasmTableObject::New(Isolate* isolate,
782 : wasm::ValueType type,
783 : uint32_t initial, bool has_maximum,
784 : uint32_t maximum,
785 : Handle<FixedArray>* elements) {
786 : Handle<JSFunction> table_ctor(
787 14175 : isolate->native_context()->wasm_table_constructor(), isolate);
788 : auto table_obj = Handle<WasmTableObject>::cast(
789 4725 : isolate->factory()->NewJSObject(table_ctor));
790 :
791 4725 : Handle<FixedArray> backing_store = isolate->factory()->NewFixedArray(initial);
792 4725 : Object null = ReadOnlyRoots(isolate).null_value();
793 88215 : for (int i = 0; i < static_cast<int>(initial); ++i) {
794 41745 : backing_store->set(i, null);
795 : }
796 :
797 : table_obj->set_raw_type(static_cast<int>(type));
798 4725 : table_obj->set_elements(*backing_store);
799 : Handle<Object> max;
800 4725 : if (has_maximum) {
801 3373 : max = isolate->factory()->NewNumberFromUint(maximum);
802 : } else {
803 : max = isolate->factory()->undefined_value();
804 : }
805 4725 : table_obj->set_maximum_length(*max);
806 :
807 4725 : table_obj->set_dispatch_tables(ReadOnlyRoots(isolate).empty_fixed_array());
808 4725 : if (elements != nullptr) {
809 1708 : *elements = backing_store;
810 : }
811 4725 : return Handle<WasmTableObject>::cast(table_obj);
812 : }
813 :
814 4073 : void WasmTableObject::AddDispatchTable(Isolate* isolate,
815 : Handle<WasmTableObject> table_obj,
816 : Handle<WasmInstanceObject> instance,
817 : int table_index) {
818 : Handle<FixedArray> dispatch_tables(table_obj->dispatch_tables(), isolate);
819 : int old_length = dispatch_tables->length();
820 : DCHECK_EQ(0, old_length % kDispatchTableNumElements);
821 :
822 4073 : if (instance.is_null()) return;
823 : // TODO(titzer): use weak cells here to avoid leaking instances.
824 :
825 : // Grow the dispatch table and add a new entry at the end.
826 : Handle<FixedArray> new_dispatch_tables =
827 : isolate->factory()->CopyFixedArrayAndGrow(dispatch_tables,
828 4073 : kDispatchTableNumElements);
829 :
830 12219 : new_dispatch_tables->set(old_length + kDispatchTableInstanceOffset,
831 4073 : *instance);
832 : new_dispatch_tables->set(old_length + kDispatchTableIndexOffset,
833 : Smi::FromInt(table_index));
834 :
835 4073 : table_obj->set_dispatch_tables(*new_dispatch_tables);
836 : }
837 :
838 400 : void WasmTableObject::Grow(Isolate* isolate, uint32_t count) {
839 400 : if (count == 0) return; // Degenerate case: nothing to do.
840 :
841 : Handle<FixedArray> dispatch_tables(this->dispatch_tables(), isolate);
842 : DCHECK_EQ(0, dispatch_tables->length() % kDispatchTableNumElements);
843 400 : uint32_t old_size = elements()->length();
844 :
845 : // Tables are stored in the instance object, no code patching is
846 : // necessary. We simply have to grow the raw tables in each instance
847 : // that has imported this table.
848 :
849 : // TODO(titzer): replace the dispatch table with a weak list of all
850 : // the instances that import a given table.
851 2192 : for (int i = 0; i < dispatch_tables->length();
852 : i += kDispatchTableNumElements) {
853 : Handle<WasmInstanceObject> instance(
854 : WasmInstanceObject::cast(dispatch_tables->get(i)), isolate);
855 : DCHECK_EQ(old_size, instance->indirect_function_table_size());
856 896 : uint32_t new_size = old_size + count;
857 : WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(instance,
858 896 : new_size);
859 : }
860 : }
861 :
862 13912 : bool WasmTableObject::IsInBounds(Isolate* isolate,
863 : Handle<WasmTableObject> table,
864 : uint32_t entry_index) {
865 : return (entry_index <
866 27816 : static_cast<uint32_t>(std::numeric_limits<int>::max()) &&
867 27816 : static_cast<int>(entry_index) < table->elements()->length());
868 : }
869 :
870 3336 : bool WasmTableObject::IsValidElement(Isolate* isolate,
871 : Handle<WasmTableObject> table,
872 : Handle<Object> element) {
873 : // Anyref tables take everything.
874 3336 : if (table->type() == wasm::kWasmAnyRef) return true;
875 : // Anyfunc tables can store {null} or {WasmExportedFunction} objects.
876 3288 : if (element->IsNull(isolate)) return true;
877 2136 : return WasmExportedFunction::IsWasmExportedFunction(*element);
878 : }
879 :
880 3112 : void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table,
881 : uint32_t index, Handle<Object> element) {
882 : // Callers need to perform bounds checks, type check, and error handling.
883 : DCHECK(IsInBounds(isolate, table, index));
884 : DCHECK(IsValidElement(isolate, table, element));
885 :
886 : Handle<FixedArray> elements(table->elements(), isolate);
887 : // The FixedArray is addressed with int's.
888 3112 : int entry_index = static_cast<int>(index);
889 3112 : if (table->type() == wasm::kWasmAnyRef) {
890 48 : elements->set(entry_index, *element);
891 48 : return;
892 : }
893 :
894 3064 : if (element->IsNull(isolate)) {
895 1152 : ClearDispatchTables(isolate, table, entry_index); // Degenerate case.
896 2304 : elements->set(entry_index, ReadOnlyRoots(isolate).null_value());
897 1152 : return;
898 : }
899 :
900 : DCHECK(WasmExportedFunction::IsWasmExportedFunction(*element));
901 : auto exported_function = Handle<WasmExportedFunction>::cast(element);
902 : Handle<WasmInstanceObject> target_instance(exported_function->instance(),
903 3824 : isolate);
904 1912 : int func_index = exported_function->function_index();
905 1912 : auto* wasm_function = &target_instance->module()->functions[func_index];
906 : DCHECK_NOT_NULL(wasm_function);
907 : DCHECK_NOT_NULL(wasm_function->sig);
908 5736 : UpdateDispatchTables(isolate, table, entry_index, wasm_function->sig,
909 : handle(exported_function->instance(), isolate),
910 1912 : func_index);
911 1912 : elements->set(entry_index, *element);
912 : }
913 :
914 10464 : Handle<Object> WasmTableObject::Get(Isolate* isolate,
915 : Handle<WasmTableObject> table,
916 : uint32_t index) {
917 : Handle<FixedArray> elements(table->elements(), isolate);
918 : // Callers need to perform bounds checks and error handling.
919 : DCHECK(IsInBounds(isolate, table, index));
920 :
921 : // The FixedArray is addressed with int's.
922 10464 : int entry_index = static_cast<int>(index);
923 :
924 : Handle<Object> element(elements->get(entry_index), isolate);
925 :
926 : // First we handle the easy anyref table case.
927 10464 : if (table->type() == wasm::kWasmAnyRef) return element;
928 :
929 : // Now we handle the anyfunc case.
930 10408 : if (WasmExportedFunction::IsWasmExportedFunction(*element)) {
931 4832 : return element;
932 : }
933 :
934 5576 : if (element->IsNull(isolate)) {
935 4472 : return element;
936 : }
937 :
938 : // {element} is not a valid entry in the table. It has to be a placeholder
939 : // for lazy initialization.
940 : Handle<Tuple2> tuple = Handle<Tuple2>::cast(element);
941 : auto instance = handle(WasmInstanceObject::cast(tuple->value1()), isolate);
942 : int function_index = Smi::cast(tuple->value2()).value();
943 :
944 : // Check if we already compiled a wrapper for the function but did not store
945 : // it in the table slot yet.
946 : MaybeHandle<Object> maybe_element =
947 : WasmInstanceObject::GetWasmExportedFunction(isolate, instance,
948 1104 : function_index);
949 1104 : if (maybe_element.ToHandle(&element)) {
950 56 : elements->set(entry_index, *element);
951 56 : return element;
952 : }
953 :
954 2096 : const WasmModule* module = instance->module_object()->module();
955 1048 : const WasmFunction& function = module->functions[function_index];
956 : // Exported functions got their wrapper compiled during instantiation.
957 1048 : CHECK(!function.exported);
958 : Handle<Code> wrapper_code =
959 2096 : compiler::CompileJSToWasmWrapper(isolate, function.sig, function.imported)
960 1048 : .ToHandleChecked();
961 :
962 : MaybeHandle<String> function_name = WasmModuleObject::GetFunctionNameOrNull(
963 2096 : isolate, handle(instance->module_object(), isolate), function_index);
964 :
965 : Handle<WasmExportedFunction> result = WasmExportedFunction::New(
966 : isolate, instance, function_name, function_index,
967 1048 : static_cast<int>(function.sig->parameter_count()), wrapper_code);
968 :
969 2096 : elements->set(entry_index, *result);
970 : WasmInstanceObject::SetWasmExportedFunction(isolate, instance, function_index,
971 1048 : result);
972 1048 : return result;
973 : }
974 :
975 12053 : void WasmTableObject::UpdateDispatchTables(
976 : Isolate* isolate, Handle<WasmTableObject> table, int entry_index,
977 : wasm::FunctionSig* sig, Handle<WasmInstanceObject> target_instance,
978 : int target_func_index) {
979 : // We simply need to update the IFTs for each instance that imports
980 : // this table.
981 : Handle<FixedArray> dispatch_tables(table->dispatch_tables(), isolate);
982 : DCHECK_EQ(0, dispatch_tables->length() % kDispatchTableNumElements);
983 :
984 23189 : for (int i = 0; i < dispatch_tables->length();
985 : i += kDispatchTableNumElements) {
986 : int table_index =
987 5568 : Smi::cast(dispatch_tables->get(i + kDispatchTableIndexOffset))->value();
988 5568 : if (table_index > 0) {
989 : // Only table 0 has a dispatch table in the instance at the moment.
990 : // TODO(ahaas): Introduce dispatch tables for the other tables as well.
991 : continue;
992 : }
993 : Handle<WasmInstanceObject> instance(
994 : WasmInstanceObject::cast(
995 : dispatch_tables->get(i + kDispatchTableInstanceOffset)),
996 : isolate);
997 : // Note that {SignatureMap::Find} may return {-1} if the signature is
998 : // not found; it will simply never match any check.
999 5544 : auto sig_id = instance->module()->signature_map.Find(*sig);
1000 : IndirectFunctionTableEntry(instance, entry_index)
1001 5544 : .Set(sig_id, target_instance, target_func_index);
1002 : }
1003 12053 : }
1004 :
1005 1152 : void WasmTableObject::ClearDispatchTables(Isolate* isolate,
1006 : Handle<WasmTableObject> table,
1007 : int index) {
1008 : Handle<FixedArray> dispatch_tables(table->dispatch_tables(), isolate);
1009 : DCHECK_EQ(0, dispatch_tables->length() % kDispatchTableNumElements);
1010 2912 : for (int i = 0; i < dispatch_tables->length();
1011 : i += kDispatchTableNumElements) {
1012 : Handle<WasmInstanceObject> target_instance(
1013 : WasmInstanceObject::cast(
1014 : dispatch_tables->get(i + kDispatchTableInstanceOffset)),
1015 : isolate);
1016 : DCHECK_LT(index, target_instance->indirect_function_table_size());
1017 880 : IndirectFunctionTableEntry(target_instance, index).clear();
1018 : }
1019 1152 : }
1020 :
1021 9829 : void WasmTableObject::SetFunctionTablePlaceholder(
1022 : Isolate* isolate, Handle<WasmTableObject> table, int entry_index,
1023 : Handle<WasmInstanceObject> instance, int func_index) {
1024 : // Put (instance, func_index) as a Tuple2 into the table_index.
1025 : // The {WasmExportedFunction} will be created lazily.
1026 : Handle<Tuple2> tuple = isolate->factory()->NewTuple2(
1027 : instance, Handle<Smi>(Smi::FromInt(func_index), isolate),
1028 9829 : AllocationType::kYoung);
1029 19658 : table->elements()->set(entry_index, *tuple);
1030 9829 : }
1031 :
1032 2109768 : void WasmTableObject::GetFunctionTableEntry(
1033 : Isolate* isolate, Handle<WasmTableObject> table, int entry_index,
1034 : bool* is_valid, bool* is_null, MaybeHandle<WasmInstanceObject>* instance,
1035 : int* function_index) {
1036 : DCHECK_EQ(table->type(), wasm::kWasmAnyFunc);
1037 : DCHECK_LT(entry_index, table->elements()->length());
1038 : // We initialize {is_valid} with {true}. We may change it later.
1039 2109768 : *is_valid = true;
1040 : Handle<Object> element(table->elements()->get(entry_index), isolate);
1041 :
1042 2109768 : *is_null = element->IsNull(isolate);
1043 2109768 : if (*is_null) return;
1044 :
1045 2924 : if (WasmExportedFunction::IsWasmExportedFunction(*element)) {
1046 : auto target_func = Handle<WasmExportedFunction>::cast(element);
1047 2176 : *instance = handle(target_func->instance(), isolate);
1048 1088 : *function_index = target_func->function_index();
1049 : return;
1050 1836 : } else if (element->IsTuple2()) {
1051 : auto tuple = Handle<Tuple2>::cast(element);
1052 1836 : *instance = handle(WasmInstanceObject::cast(tuple->value1()), isolate);
1053 1836 : *function_index = Smi::cast(tuple->value2()).value();
1054 : return;
1055 : }
1056 0 : *is_valid = false;
1057 : }
1058 :
1059 : namespace {
1060 2200 : bool AdjustBufferPermissions(Isolate* isolate, Handle<JSArrayBuffer> old_buffer,
1061 : size_t new_size) {
1062 2200 : if (new_size > old_buffer->allocation_length()) return false;
1063 : void* old_mem_start = old_buffer->backing_store();
1064 : size_t old_size = old_buffer->byte_length();
1065 2200 : if (old_size != new_size) {
1066 : DCHECK_NOT_NULL(old_mem_start);
1067 : DCHECK_GE(new_size, old_size);
1068 : // If adjusting permissions fails, propagate error back to return
1069 : // failure to grow.
1070 1724 : if (!i::SetPermissions(GetPlatformPageAllocator(), old_mem_start, new_size,
1071 : PageAllocator::kReadWrite)) {
1072 : return false;
1073 : }
1074 : reinterpret_cast<v8::Isolate*>(isolate)
1075 1724 : ->AdjustAmountOfExternalAllocatedMemory(new_size - old_size);
1076 : }
1077 : return true;
1078 : }
1079 :
1080 2100 : MaybeHandle<JSArrayBuffer> MemoryGrowBuffer(Isolate* isolate,
1081 : Handle<JSArrayBuffer> old_buffer,
1082 : size_t new_size) {
1083 4200 : CHECK_EQ(0, new_size % wasm::kWasmPageSize);
1084 : // Reusing the backing store from externalized buffers causes problems with
1085 : // Blink's array buffers. The connection between the two is lost, which can
1086 : // lead to Blink not knowing about the other reference to the buffer and
1087 : // freeing it too early.
1088 2100 : if (old_buffer->is_external() || new_size > old_buffer->allocation_length()) {
1089 : // We couldn't reuse the old backing store, so create a new one and copy the
1090 : // old contents in.
1091 : Handle<JSArrayBuffer> new_buffer;
1092 16 : if (!wasm::NewArrayBuffer(isolate, new_size).ToHandle(&new_buffer)) {
1093 0 : return {};
1094 : }
1095 : wasm::WasmMemoryTracker* const memory_tracker =
1096 : isolate->wasm_engine()->memory_tracker();
1097 : // If the old buffer had full guard regions, we can only safely use the new
1098 : // buffer if it also has full guard regions. Otherwise, we'd have to
1099 : // recompile all the instances using this memory to insert bounds checks.
1100 : void* old_mem_start = old_buffer->backing_store();
1101 16 : if (memory_tracker->HasFullGuardRegions(old_mem_start) &&
1102 8 : !memory_tracker->HasFullGuardRegions(new_buffer->backing_store())) {
1103 0 : return {};
1104 : }
1105 : size_t old_size = old_buffer->byte_length();
1106 8 : if (old_size == 0) return new_buffer;
1107 : memcpy(new_buffer->backing_store(), old_mem_start, old_size);
1108 : DCHECK(old_buffer.is_null() || !old_buffer->is_shared());
1109 : constexpr bool free_memory = true;
1110 8 : i::wasm::DetachMemoryBuffer(isolate, old_buffer, free_memory);
1111 8 : return new_buffer;
1112 : } else {
1113 2092 : if (!AdjustBufferPermissions(isolate, old_buffer, new_size)) return {};
1114 : // NOTE: We must allocate a new array buffer here because the spec
1115 : // assumes that ArrayBuffers do not change size.
1116 : void* backing_store = old_buffer->backing_store();
1117 : bool is_external = old_buffer->is_external();
1118 : // Disconnect buffer early so GC won't free it.
1119 2092 : i::wasm::DetachMemoryBuffer(isolate, old_buffer, false);
1120 : Handle<JSArrayBuffer> new_buffer =
1121 2092 : wasm::SetupArrayBuffer(isolate, backing_store, new_size, is_external);
1122 2092 : return new_buffer;
1123 : }
1124 : }
1125 :
1126 : // May GC, because SetSpecializationMemInfoFrom may GC
1127 59055 : void SetInstanceMemory(Handle<WasmInstanceObject> instance,
1128 : Handle<JSArrayBuffer> buffer) {
1129 118110 : instance->SetRawMemory(reinterpret_cast<byte*>(buffer->backing_store()),
1130 59055 : buffer->byte_length());
1131 : #if DEBUG
1132 : if (!FLAG_mock_arraybuffer_allocator) {
1133 : // To flush out bugs earlier, in DEBUG mode, check that all pages of the
1134 : // memory are accessible by reading and writing one byte on each page.
1135 : // Don't do this if the mock ArrayBuffer allocator is enabled.
1136 : byte* mem_start = instance->memory_start();
1137 : size_t mem_size = instance->memory_size();
1138 : for (size_t offset = 0; offset < mem_size; offset += wasm::kWasmPageSize) {
1139 : byte val = mem_start[offset];
1140 : USE(val);
1141 : mem_start[offset] = val;
1142 : }
1143 : }
1144 : #endif
1145 59055 : }
1146 :
1147 : } // namespace
1148 :
1149 55243 : Handle<WasmMemoryObject> WasmMemoryObject::New(
1150 : Isolate* isolate, MaybeHandle<JSArrayBuffer> maybe_buffer,
1151 : uint32_t maximum) {
1152 : // TODO(kschimpf): Do we need to add an argument that defines the
1153 : // style of memory the user prefers (with/without trap handling), so
1154 : // that the memory will match the style of the compiled wasm module.
1155 : // See issue v8:7143
1156 : Handle<JSFunction> memory_ctor(
1157 165728 : isolate->native_context()->wasm_memory_constructor(), isolate);
1158 : auto memory_obj = Handle<WasmMemoryObject>::cast(
1159 55242 : isolate->factory()->NewJSObject(memory_ctor, AllocationType::kOld));
1160 :
1161 : Handle<JSArrayBuffer> buffer;
1162 55243 : if (!maybe_buffer.ToHandle(&buffer)) {
1163 : // If no buffer was provided, create a 0-length one.
1164 12 : buffer = wasm::SetupArrayBuffer(isolate, nullptr, 0, false);
1165 : }
1166 55243 : memory_obj->set_array_buffer(*buffer);
1167 55243 : memory_obj->set_maximum_pages(maximum);
1168 :
1169 55243 : return memory_obj;
1170 : }
1171 :
1172 4371 : MaybeHandle<WasmMemoryObject> WasmMemoryObject::New(Isolate* isolate,
1173 : uint32_t initial,
1174 : uint32_t maximum,
1175 : bool is_shared_memory) {
1176 : Handle<JSArrayBuffer> buffer;
1177 4371 : size_t size = static_cast<size_t>(i::wasm::kWasmPageSize) *
1178 4371 : static_cast<size_t>(initial);
1179 4371 : if (is_shared_memory) {
1180 249 : size_t max_size = static_cast<size_t>(i::wasm::kWasmPageSize) *
1181 249 : static_cast<size_t>(maximum);
1182 498 : if (!i::wasm::NewSharedArrayBuffer(isolate, size, max_size)
1183 : .ToHandle(&buffer)) {
1184 0 : return {};
1185 : }
1186 : } else {
1187 8244 : if (!i::wasm::NewArrayBuffer(isolate, size).ToHandle(&buffer)) {
1188 8 : return {};
1189 : }
1190 : }
1191 4363 : return New(isolate, buffer, maximum);
1192 : }
1193 :
1194 1206 : bool WasmMemoryObject::has_full_guard_region(Isolate* isolate) {
1195 : const wasm::WasmMemoryTracker::AllocationData* allocation =
1196 : isolate->wasm_engine()->memory_tracker()->FindAllocationData(
1197 1206 : array_buffer()->backing_store());
1198 1206 : CHECK_NOT_NULL(allocation);
1199 :
1200 : Address allocation_base =
1201 1206 : reinterpret_cast<Address>(allocation->allocation_base);
1202 1206 : Address buffer_start = reinterpret_cast<Address>(allocation->buffer_start);
1203 :
1204 : // Return whether the allocation covers every possible Wasm heap index.
1205 : //
1206 : // We always have the following relationship:
1207 : // allocation_base <= buffer_start <= buffer_start + memory_size <=
1208 : // allocation_base + allocation_length
1209 : // (in other words, the buffer fits within the allocation)
1210 : //
1211 : // The space between buffer_start + memory_size and allocation_base +
1212 : // allocation_length is the guard region. Here we make sure the guard region
1213 : // is large enough for any Wasm heap offset.
1214 1206 : return buffer_start + wasm::kWasmMaxHeapOffset <=
1215 1206 : allocation_base + allocation->allocation_length;
1216 : }
1217 :
1218 54984 : void WasmMemoryObject::AddInstance(Isolate* isolate,
1219 : Handle<WasmMemoryObject> memory,
1220 : Handle<WasmInstanceObject> instance) {
1221 : Handle<WeakArrayList> old_instances =
1222 : memory->has_instances()
1223 : ? Handle<WeakArrayList>(memory->instances(), isolate)
1224 : : handle(ReadOnlyRoots(isolate->heap()).empty_weak_array_list(),
1225 107243 : isolate);
1226 : Handle<WeakArrayList> new_instances = WeakArrayList::AddToEnd(
1227 54984 : isolate, old_instances, MaybeObjectHandle::Weak(instance));
1228 54985 : memory->set_instances(*new_instances);
1229 : Handle<JSArrayBuffer> buffer(memory->array_buffer(), isolate);
1230 54986 : SetInstanceMemory(instance, buffer);
1231 54987 : }
1232 :
1233 2316 : void WasmMemoryObject::update_instances(Isolate* isolate,
1234 : Handle<JSArrayBuffer> buffer) {
1235 2316 : if (has_instances()) {
1236 : Handle<WeakArrayList> instances(this->instances(), isolate);
1237 10532 : for (int i = 0; i < instances->length(); i++) {
1238 : MaybeObject elem = instances->Get(i);
1239 : HeapObject heap_object;
1240 4244 : if (elem->GetHeapObjectIfWeak(&heap_object)) {
1241 : Handle<WasmInstanceObject> instance(
1242 : WasmInstanceObject::cast(heap_object), isolate);
1243 4068 : SetInstanceMemory(instance, buffer);
1244 : } else {
1245 : DCHECK(elem->IsCleared());
1246 : }
1247 : }
1248 : }
1249 2316 : set_array_buffer(*buffer);
1250 2316 : }
1251 :
1252 : // static
1253 2432 : int32_t WasmMemoryObject::Grow(Isolate* isolate,
1254 : Handle<WasmMemoryObject> memory_object,
1255 : uint32_t pages) {
1256 7296 : TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "GrowMemory");
1257 : Handle<JSArrayBuffer> old_buffer(memory_object->array_buffer(), isolate);
1258 2432 : if (old_buffer->is_shared() && !FLAG_wasm_grow_shared_memory) return -1;
1259 : auto* memory_tracker = isolate->wasm_engine()->memory_tracker();
1260 2432 : if (!memory_tracker->IsWasmMemoryGrowable(old_buffer)) return -1;
1261 :
1262 : // Checks for maximum memory size, compute new size.
1263 2424 : uint32_t maximum_pages = wasm::max_mem_pages();
1264 2424 : if (memory_object->has_maximum_pages()) {
1265 : maximum_pages = std::min(
1266 4560 : maximum_pages, static_cast<uint32_t>(memory_object->maximum_pages()));
1267 : }
1268 2424 : CHECK_GE(wasm::max_mem_pages(), maximum_pages);
1269 : size_t old_size = old_buffer->byte_length();
1270 4848 : CHECK_EQ(0, old_size % wasm::kWasmPageSize);
1271 2424 : size_t old_pages = old_size / wasm::kWasmPageSize;
1272 4848 : CHECK_GE(wasm::max_mem_pages(), old_pages);
1273 4632 : if ((pages > maximum_pages - old_pages) || // exceeds remaining
1274 2208 : (pages > wasm::max_mem_pages() - old_pages)) { // exceeds limit
1275 : return -1;
1276 : }
1277 : size_t new_size =
1278 2208 : static_cast<size_t>(old_pages + pages) * wasm::kWasmPageSize;
1279 :
1280 : // Memory is grown, but the memory objects and instances are not yet updated.
1281 : // Handle this in the interrupt handler so that it's safe for all the isolates
1282 : // that share this buffer to be updated safely.
1283 : Handle<JSArrayBuffer> new_buffer;
1284 2208 : if (old_buffer->is_shared()) {
1285 : // Adjust protections for the buffer.
1286 108 : if (!AdjustBufferPermissions(isolate, old_buffer, new_size)) {
1287 : return -1;
1288 : }
1289 : void* backing_store = old_buffer->backing_store();
1290 108 : if (memory_tracker->IsWasmSharedMemory(backing_store)) {
1291 : // This memory is shared between different isolates.
1292 : DCHECK(old_buffer->is_shared());
1293 : // Update pending grow state, and trigger a grow interrupt on all the
1294 : // isolates that share this buffer.
1295 100 : memory_tracker->SetPendingUpdateOnGrow(old_buffer, new_size);
1296 : // Handle interrupts for this isolate so that the instances with this
1297 : // isolate are updated.
1298 100 : isolate->stack_guard()->HandleInterrupts();
1299 : // Failure to allocate, or adjust pemissions already handled here, and
1300 : // updates to instances handled in the interrupt handler safe to return.
1301 100 : return static_cast<uint32_t>(old_size / wasm::kWasmPageSize);
1302 : }
1303 : // SharedArrayBuffer, but not shared across isolates. Setup a new buffer
1304 : // with updated permissions and update the instances.
1305 : new_buffer =
1306 : wasm::SetupArrayBuffer(isolate, backing_store, new_size,
1307 8 : old_buffer->is_external(), SharedFlag::kShared);
1308 8 : memory_object->update_instances(isolate, new_buffer);
1309 : } else {
1310 4200 : if (!MemoryGrowBuffer(isolate, old_buffer, new_size)
1311 : .ToHandle(&new_buffer)) {
1312 : return -1;
1313 : }
1314 : }
1315 : // Update instances if any.
1316 2108 : memory_object->update_instances(isolate, new_buffer);
1317 2108 : return static_cast<uint32_t>(old_size / wasm::kWasmPageSize);
1318 : }
1319 :
1320 : // static
1321 8164 : MaybeHandle<WasmGlobalObject> WasmGlobalObject::New(
1322 : Isolate* isolate, MaybeHandle<JSArrayBuffer> maybe_untagged_buffer,
1323 : MaybeHandle<FixedArray> maybe_tagged_buffer, wasm::ValueType type,
1324 : int32_t offset, bool is_mutable) {
1325 : Handle<JSFunction> global_ctor(
1326 24492 : isolate->native_context()->wasm_global_constructor(), isolate);
1327 : auto global_obj = Handle<WasmGlobalObject>::cast(
1328 8164 : isolate->factory()->NewJSObject(global_ctor));
1329 :
1330 8164 : if (wasm::ValueTypes::IsReferenceType(type)) {
1331 : DCHECK(maybe_untagged_buffer.is_null());
1332 : Handle<FixedArray> tagged_buffer;
1333 656 : if (!maybe_tagged_buffer.ToHandle(&tagged_buffer)) {
1334 : // If no buffer was provided, create one.
1335 : tagged_buffer =
1336 352 : isolate->factory()->NewFixedArray(1, AllocationType::kOld);
1337 352 : CHECK_EQ(offset, 0);
1338 : }
1339 656 : global_obj->set_tagged_buffer(*tagged_buffer);
1340 : } else {
1341 : DCHECK(maybe_tagged_buffer.is_null());
1342 : Handle<JSArrayBuffer> untagged_buffer;
1343 7508 : uint32_t type_size = wasm::ValueTypes::ElementSizeInBytes(type);
1344 7508 : if (!maybe_untagged_buffer.ToHandle(&untagged_buffer)) {
1345 : // If no buffer was provided, create one long enough for the given type.
1346 : untagged_buffer = isolate->factory()->NewJSArrayBuffer(
1347 6976 : SharedFlag::kNotShared, AllocationType::kOld);
1348 :
1349 : const bool initialize = true;
1350 6976 : if (!JSArrayBuffer::SetupAllocatingData(untagged_buffer, isolate,
1351 : type_size, initialize)) {
1352 0 : return {};
1353 : }
1354 : }
1355 :
1356 : // Check that the offset is in bounds.
1357 15016 : CHECK_LE(offset + type_size, untagged_buffer->byte_length());
1358 :
1359 7508 : global_obj->set_untagged_buffer(*untagged_buffer);
1360 : }
1361 : global_obj->set_flags(0);
1362 16328 : global_obj->set_type(type);
1363 : global_obj->set_offset(offset);
1364 16328 : global_obj->set_is_mutable(is_mutable);
1365 :
1366 8164 : return global_obj;
1367 : }
1368 :
1369 20223057 : void IndirectFunctionTableEntry::clear() {
1370 20223057 : instance_->indirect_function_table_sig_ids()[index_] = -1;
1371 20223057 : instance_->indirect_function_table_targets()[index_] = 0;
1372 40446114 : instance_->indirect_function_table_refs()->set(
1373 60669171 : index_, ReadOnlyRoots(instance_->GetIsolate()).undefined_value());
1374 20223057 : }
1375 :
1376 18693 : void IndirectFunctionTableEntry::Set(int sig_id,
1377 : Handle<WasmInstanceObject> target_instance,
1378 : int target_func_index) {
1379 : TRACE_IFT(
1380 : "IFT entry %p[%d] = {sig_id=%d, target_instance=%p, "
1381 : "target_func_index=%d}\n",
1382 : reinterpret_cast<void*>(instance_->ptr()), index_, sig_id,
1383 : reinterpret_cast<void*>(target_instance->ptr()), target_func_index);
1384 :
1385 : Object ref;
1386 : Address call_target = 0;
1387 18693 : if (target_func_index <
1388 18693 : static_cast<int>(target_instance->module()->num_imported_functions)) {
1389 : // The function in the target instance was imported. Use its imports table,
1390 : // which contains a tuple needed by the import wrapper.
1391 : ImportedFunctionEntry entry(target_instance, target_func_index);
1392 1032 : ref = entry.object_ref();
1393 : call_target = entry.target();
1394 : } else {
1395 : // The function in the target instance was not imported.
1396 17661 : ref = *target_instance;
1397 17661 : call_target = target_instance->GetCallTarget(target_func_index);
1398 : }
1399 :
1400 : // Set the signature id, the target, and the receiver ref.
1401 18693 : instance_->indirect_function_table_sig_ids()[index_] = sig_id;
1402 18693 : instance_->indirect_function_table_targets()[index_] = call_target;
1403 37386 : instance_->indirect_function_table_refs()->set(index_, ref);
1404 18693 : }
1405 :
1406 40576 : Object IndirectFunctionTableEntry::object_ref() {
1407 81152 : return instance_->indirect_function_table_refs()->get(index_);
1408 : }
1409 :
1410 40696 : int IndirectFunctionTableEntry::sig_id() {
1411 40696 : return instance_->indirect_function_table_sig_ids()[index_];
1412 : }
1413 :
1414 40576 : Address IndirectFunctionTableEntry::target() {
1415 40576 : return instance_->indirect_function_table_targets()[index_];
1416 : }
1417 :
1418 596 : void IndirectFunctionTableEntry::CopyFrom(
1419 : const IndirectFunctionTableEntry& that) {
1420 596 : instance_->indirect_function_table_sig_ids()[index_] =
1421 596 : that.instance_->indirect_function_table_sig_ids()[that.index_];
1422 596 : instance_->indirect_function_table_targets()[index_] =
1423 596 : that.instance_->indirect_function_table_targets()[that.index_];
1424 1192 : instance_->indirect_function_table_refs()->set(
1425 1788 : index_, that.instance_->indirect_function_table_refs()->get(that.index_));
1426 596 : }
1427 :
1428 12625 : void ImportedFunctionEntry::SetWasmToJs(
1429 : Isolate* isolate, Handle<JSReceiver> callable,
1430 : const wasm::WasmCode* wasm_to_js_wrapper) {
1431 : TRACE_IFT("Import callable %p[%d] = {callable=%p, target=%p}\n",
1432 : reinterpret_cast<void*>(instance_->ptr()), index_,
1433 : reinterpret_cast<void*>(callable->ptr()),
1434 : wasm_to_js_wrapper->instructions().start());
1435 : DCHECK_EQ(wasm::WasmCode::kWasmToJsWrapper, wasm_to_js_wrapper->kind());
1436 : Handle<Tuple2> tuple =
1437 12625 : isolate->factory()->NewTuple2(instance_, callable, AllocationType::kOld);
1438 25250 : instance_->imported_function_refs()->set(index_, *tuple);
1439 12625 : instance_->imported_function_targets()[index_] =
1440 12625 : wasm_to_js_wrapper->instruction_start();
1441 12625 : }
1442 :
1443 107288 : void ImportedFunctionEntry::SetWasmToWasm(WasmInstanceObject instance,
1444 : Address call_target) {
1445 : TRACE_IFT("Import WASM %p[%d] = {instance=%p, target=%" PRIuPTR "}\n",
1446 : reinterpret_cast<void*>(instance_->ptr()), index_,
1447 : reinterpret_cast<void*>(instance->ptr()), call_target);
1448 214576 : instance_->imported_function_refs()->set(index_, instance);
1449 107288 : instance_->imported_function_targets()[index_] = call_target;
1450 107288 : }
1451 :
1452 0 : WasmInstanceObject ImportedFunctionEntry::instance() {
1453 : // The imported reference entry is either a target instance or a tuple
1454 : // of this instance and the target callable.
1455 0 : Object value = instance_->imported_function_refs()->get(index_);
1456 0 : if (value->IsWasmInstanceObject()) {
1457 : return WasmInstanceObject::cast(value);
1458 : }
1459 : Tuple2 tuple = Tuple2::cast(value);
1460 : return WasmInstanceObject::cast(tuple->value1());
1461 : }
1462 :
1463 0 : JSReceiver ImportedFunctionEntry::callable() {
1464 0 : return JSReceiver::cast(Tuple2::cast(object_ref())->value2());
1465 : }
1466 :
1467 9221 : Object ImportedFunctionEntry::object_ref() {
1468 18442 : return instance_->imported_function_refs()->get(index_);
1469 : }
1470 :
1471 8189 : Address ImportedFunctionEntry::target() {
1472 9221 : return instance_->imported_function_targets()[index_];
1473 : }
1474 :
1475 : // static
1476 : constexpr uint16_t WasmInstanceObject::kTaggedFieldOffsets[];
1477 :
1478 : // static
1479 4909 : bool WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
1480 : Handle<WasmInstanceObject> instance, uint32_t minimum_size) {
1481 : uint32_t old_size = instance->indirect_function_table_size();
1482 4909 : if (old_size >= minimum_size) return false; // Nothing to do.
1483 :
1484 : Isolate* isolate = instance->GetIsolate();
1485 : HandleScope scope(isolate);
1486 : auto native_allocations = GetNativeAllocations(*instance);
1487 : native_allocations->resize_indirect_function_table(isolate, instance,
1488 3273 : minimum_size);
1489 : return true;
1490 : }
1491 :
1492 1331625 : void WasmInstanceObject::SetRawMemory(byte* mem_start, size_t mem_size) {
1493 1331625 : CHECK_LE(mem_size, wasm::max_mem_bytes());
1494 : #if V8_HOST_ARCH_64_BIT
1495 1331625 : uint64_t mem_mask64 = base::bits::RoundUpToPowerOfTwo64(mem_size) - 1;
1496 : set_memory_start(mem_start);
1497 : set_memory_size(mem_size);
1498 : set_memory_mask(mem_mask64);
1499 : #else
1500 : // Must handle memory > 2GiB specially.
1501 : CHECK_LE(mem_size, size_t{kMaxUInt32});
1502 : uint32_t mem_mask32 =
1503 : (mem_size > 2 * size_t{GB})
1504 : ? 0xFFFFFFFFu
1505 : : base::bits::RoundUpToPowerOfTwo32(static_cast<uint32_t>(mem_size)) -
1506 : 1;
1507 : set_memory_start(mem_start);
1508 : set_memory_size(mem_size);
1509 : set_memory_mask(mem_mask32);
1510 : #endif
1511 1331625 : }
1512 :
1513 149017 : const WasmModule* WasmInstanceObject::module() {
1514 1085692 : return module_object()->module();
1515 : }
1516 :
1517 37681 : Handle<WasmDebugInfo> WasmInstanceObject::GetOrCreateDebugInfo(
1518 : Handle<WasmInstanceObject> instance) {
1519 37681 : if (instance->has_debug_info()) {
1520 : return handle(instance->debug_info(), instance->GetIsolate());
1521 : }
1522 1719 : Handle<WasmDebugInfo> new_info = WasmDebugInfo::New(instance);
1523 : DCHECK(instance->has_debug_info());
1524 1719 : return new_info;
1525 : }
1526 :
1527 1231090 : Handle<WasmInstanceObject> WasmInstanceObject::New(
1528 : Isolate* isolate, Handle<WasmModuleObject> module_object) {
1529 : Handle<JSFunction> instance_cons(
1530 3693270 : isolate->native_context()->wasm_instance_constructor(), isolate);
1531 : Handle<JSObject> instance_object =
1532 1231090 : isolate->factory()->NewJSObject(instance_cons, AllocationType::kOld);
1533 :
1534 : Handle<WasmInstanceObject> instance(
1535 : WasmInstanceObject::cast(*instance_object), isolate);
1536 : instance->clear_padding();
1537 :
1538 : // Initialize the imported function arrays.
1539 2462180 : auto module = module_object->module();
1540 1231090 : auto num_imported_functions = module->num_imported_functions;
1541 1231090 : auto num_imported_mutable_globals = module->num_imported_mutable_globals;
1542 1231090 : auto num_data_segments = module->num_declared_data_segments;
1543 : size_t native_allocations_size = EstimateNativeAllocationsSize(module);
1544 : auto native_allocations = Managed<WasmInstanceNativeAllocations>::Allocate(
1545 : isolate, native_allocations_size, instance, num_imported_functions,
1546 : num_imported_mutable_globals, num_data_segments,
1547 1231090 : module->elem_segments.size());
1548 2462178 : instance->set_managed_native_allocations(*native_allocations);
1549 :
1550 : Handle<FixedArray> imported_function_refs =
1551 1231090 : isolate->factory()->NewFixedArray(num_imported_functions);
1552 1231090 : instance->set_imported_function_refs(*imported_function_refs);
1553 :
1554 1231088 : Handle<Code> centry_stub = CodeFactory::CEntry(isolate);
1555 1231090 : instance->set_centry_stub(*centry_stub);
1556 :
1557 1231090 : instance->SetRawMemory(nullptr, 0);
1558 : instance->set_isolate_root(isolate->isolate_root());
1559 : instance->set_stack_limit_address(
1560 : isolate->stack_guard()->address_of_jslimit());
1561 : instance->set_real_stack_limit_address(
1562 : isolate->stack_guard()->address_of_real_jslimit());
1563 : instance->set_globals_start(nullptr);
1564 : instance->set_indirect_function_table_size(0);
1565 : instance->set_indirect_function_table_sig_ids(nullptr);
1566 : instance->set_indirect_function_table_targets(nullptr);
1567 3693270 : instance->set_native_context(*isolate->native_context());
1568 1231090 : instance->set_module_object(*module_object);
1569 1231088 : instance->set_undefined_value(ReadOnlyRoots(isolate).undefined_value());
1570 1231088 : instance->set_null_value(ReadOnlyRoots(isolate).null_value());
1571 2462180 : instance->set_jump_table_start(
1572 : module_object->native_module()->jump_table_start());
1573 :
1574 : // Insert the new instance into the modules weak list of instances.
1575 : // TODO(mstarzinger): Allow to reuse holes in the {WeakArrayList} below.
1576 : Handle<WeakArrayList> weak_instance_list(module_object->weak_instance_list(),
1577 : isolate);
1578 : weak_instance_list = WeakArrayList::AddToEnd(
1579 1231090 : isolate, weak_instance_list, MaybeObjectHandle::Weak(instance));
1580 1231090 : module_object->set_weak_instance_list(*weak_instance_list);
1581 :
1582 1231090 : InitDataSegmentArrays(instance, module_object);
1583 1231090 : InitElemSegmentArrays(instance, module_object);
1584 :
1585 1231089 : return instance;
1586 : }
1587 :
1588 : // static
1589 1231088 : void WasmInstanceObject::InitDataSegmentArrays(
1590 : Handle<WasmInstanceObject> instance,
1591 : Handle<WasmModuleObject> module_object) {
1592 2462177 : auto module = module_object->module();
1593 2462179 : auto wire_bytes = module_object->native_module()->wire_bytes();
1594 1231090 : auto num_data_segments = module->num_declared_data_segments;
1595 : // The number of declared data segments will be zero if there is no DataCount
1596 : // section. These arrays will not be allocated nor initialized in that case,
1597 : // since they cannot be used (since the validator checks that number of
1598 : // declared data segments when validating the memory.init and memory.drop
1599 : // instructions).
1600 : DCHECK(num_data_segments == 0 ||
1601 : num_data_segments == module->data_segments.size());
1602 1231234 : for (size_t i = 0; i < num_data_segments; ++i) {
1603 : const wasm::WasmDataSegment& segment = module->data_segments[i];
1604 : // Set the active segments to being already dropped, since memory.init on
1605 : // a dropped passive segment and an active segment have the same
1606 : // behavior.
1607 72 : instance->dropped_data_segments()[i] = segment.active ? 1 : 0;
1608 :
1609 : // Initialize the pointer and size of passive segments.
1610 : auto source_bytes = wire_bytes.SubVector(segment.source.offset(),
1611 72 : segment.source.end_offset());
1612 72 : instance->data_segment_starts()[i] =
1613 72 : reinterpret_cast<Address>(source_bytes.start());
1614 72 : instance->data_segment_sizes()[i] = source_bytes.length();
1615 : }
1616 1231090 : }
1617 :
1618 1231090 : void WasmInstanceObject::InitElemSegmentArrays(
1619 : Handle<WasmInstanceObject> instance,
1620 : Handle<WasmModuleObject> module_object) {
1621 2462180 : auto module = module_object->module();
1622 : auto num_elem_segments = module->elem_segments.size();
1623 1235372 : for (size_t i = 0; i < num_elem_segments; ++i) {
1624 : const wasm::WasmElemSegment& segment = module->elem_segments[i];
1625 : // Set the active segments to being already dropped, since table.init on
1626 : // a dropped passive segment and an active segment have the same
1627 : // behavior.
1628 2141 : instance->dropped_elem_segments()[i] = segment.active ? 1 : 0;
1629 : }
1630 1231090 : }
1631 :
1632 124837 : Address WasmInstanceObject::GetCallTarget(uint32_t func_index) {
1633 124837 : wasm::NativeModule* native_module = module_object()->native_module();
1634 124837 : if (func_index < native_module->num_imported_functions()) {
1635 0 : return imported_function_targets()[func_index];
1636 : }
1637 124837 : return native_module->GetCallTargetForFunction(func_index);
1638 : }
1639 :
1640 : namespace {
1641 276 : void CopyTableEntriesImpl(Handle<WasmInstanceObject> instance, uint32_t dst,
1642 : uint32_t src, uint32_t count, bool copy_backward) {
1643 : DCHECK(IsInBounds(dst, count, instance->indirect_function_table_size()));
1644 276 : if (copy_backward) {
1645 252 : for (uint32_t i = count; i > 0; i--) {
1646 108 : auto to_entry = IndirectFunctionTableEntry(instance, dst + i - 1);
1647 108 : auto from_entry = IndirectFunctionTableEntry(instance, src + i - 1);
1648 108 : to_entry.CopyFrom(from_entry);
1649 : }
1650 : } else {
1651 1216 : for (uint32_t i = 0; i < count; i++) {
1652 488 : auto to_entry = IndirectFunctionTableEntry(instance, dst + i);
1653 488 : auto from_entry = IndirectFunctionTableEntry(instance, src + i);
1654 488 : to_entry.CopyFrom(from_entry);
1655 : }
1656 : }
1657 276 : }
1658 : } // namespace
1659 :
1660 : // static
1661 2328 : bool WasmInstanceObject::CopyTableEntries(Isolate* isolate,
1662 : Handle<WasmInstanceObject> instance,
1663 : uint32_t table_src_index,
1664 : uint32_t table_dst_index,
1665 : uint32_t dst, uint32_t src,
1666 : uint32_t count) {
1667 2328 : if (static_cast<int>(table_dst_index) >= instance->tables()->length()) {
1668 : return false;
1669 : }
1670 2328 : if (static_cast<int>(table_src_index) >= instance->tables()->length()) {
1671 : return false;
1672 : }
1673 :
1674 : // TODO(titzer): multiple tables in TableCopy
1675 2328 : CHECK_EQ(0, table_src_index);
1676 2328 : CHECK_EQ(0, table_dst_index);
1677 : auto max = instance->indirect_function_table_size();
1678 2328 : bool copy_backward = src < dst && dst - src < count;
1679 : bool ok = ClampToBounds(dst, &count, max);
1680 : // Use & instead of && so the clamp is not short-circuited.
1681 : ok &= ClampToBounds(src, &count, max);
1682 :
1683 : // If performing a partial copy when copying backward, then the first access
1684 : // will be out-of-bounds, so no entries should be copied.
1685 2328 : if (copy_backward && !ok) return ok;
1686 :
1687 2304 : if (dst == src || count == 0) return ok; // no-op
1688 :
1689 : // TODO(titzer): multiple tables in TableCopy
1690 : auto table = handle(
1691 : WasmTableObject::cast(instance->tables()->get(table_src_index)), isolate);
1692 : // Broadcast table copy operation to all instances that import this table.
1693 : Handle<FixedArray> dispatch_tables(table->dispatch_tables(), isolate);
1694 804 : for (int i = 0; i < dispatch_tables->length();
1695 : i += kDispatchTableNumElements) {
1696 : Handle<WasmInstanceObject> target_instance(
1697 : WasmInstanceObject::cast(
1698 : dispatch_tables->get(i + kDispatchTableInstanceOffset)),
1699 : isolate);
1700 276 : CopyTableEntriesImpl(target_instance, dst, src, count, copy_backward);
1701 : }
1702 :
1703 : // Copy the function entries.
1704 : auto dst_table = handle(
1705 : WasmTableObject::cast(instance->tables()->get(table_dst_index)), isolate);
1706 : auto src_table = handle(
1707 : WasmTableObject::cast(instance->tables()->get(table_src_index)), isolate);
1708 252 : if (copy_backward) {
1709 252 : for (uint32_t i = count; i > 0; i--) {
1710 432 : dst_table->elements()->set(dst + i - 1,
1711 216 : src_table->elements()->get(src + i - 1));
1712 : }
1713 : } else {
1714 1112 : for (uint32_t i = 0; i < count; i++) {
1715 1344 : dst_table->elements()->set(dst + i, src_table->elements()->get(src + i));
1716 : }
1717 : }
1718 : return ok;
1719 : }
1720 :
1721 : // static
1722 336 : bool WasmInstanceObject::InitTableEntries(Isolate* isolate,
1723 : Handle<WasmInstanceObject> instance,
1724 : uint32_t table_index,
1725 : uint32_t segment_index, uint32_t dst,
1726 : uint32_t src, uint32_t count) {
1727 : // Note that this implementation just calls through to module instantiation.
1728 : // This is intentional, so that the runtime only depends on the object
1729 : // methods, and not the module instantiation logic.
1730 : return wasm::LoadElemSegment(isolate, instance, table_index, segment_index,
1731 336 : dst, src, count);
1732 : }
1733 :
1734 238153 : MaybeHandle<WasmExportedFunction> WasmInstanceObject::GetWasmExportedFunction(
1735 : Isolate* isolate, Handle<WasmInstanceObject> instance, int index) {
1736 : MaybeHandle<WasmExportedFunction> result;
1737 238153 : if (instance->has_wasm_exported_functions()) {
1738 : Object val = instance->wasm_exported_functions()->get(index);
1739 212897 : if (!val->IsUndefined(isolate)) {
1740 : result = Handle<WasmExportedFunction>(WasmExportedFunction::cast(val),
1741 : isolate);
1742 : }
1743 : }
1744 238153 : return result;
1745 : }
1746 :
1747 334717 : void WasmInstanceObject::SetWasmExportedFunction(
1748 : Isolate* isolate, Handle<WasmInstanceObject> instance, int index,
1749 : Handle<WasmExportedFunction> val) {
1750 : Handle<FixedArray> functions;
1751 334717 : if (!instance->has_wasm_exported_functions()) {
1752 : // lazily-allocate the wasm exported functions.
1753 : functions = isolate->factory()->NewFixedArray(
1754 130564 : static_cast<int>(instance->module()->functions.size()));
1755 130564 : instance->set_wasm_exported_functions(*functions);
1756 : } else {
1757 : functions =
1758 : Handle<FixedArray>(instance->wasm_exported_functions(), isolate);
1759 : }
1760 669432 : functions->set(index, *val);
1761 334716 : }
1762 :
1763 : // static
1764 96 : Handle<WasmExceptionObject> WasmExceptionObject::New(
1765 : Isolate* isolate, const wasm::FunctionSig* sig,
1766 : Handle<HeapObject> exception_tag) {
1767 : Handle<JSFunction> exception_cons(
1768 288 : isolate->native_context()->wasm_exception_constructor(), isolate);
1769 : Handle<JSObject> exception_object =
1770 96 : isolate->factory()->NewJSObject(exception_cons, AllocationType::kOld);
1771 : Handle<WasmExceptionObject> exception =
1772 : Handle<WasmExceptionObject>::cast(exception_object);
1773 :
1774 : // Serialize the signature.
1775 : DCHECK_EQ(0, sig->return_count());
1776 : DCHECK_LE(sig->parameter_count(), std::numeric_limits<int>::max());
1777 96 : int sig_size = static_cast<int>(sig->parameter_count());
1778 : Handle<PodArray<wasm::ValueType>> serialized_sig =
1779 : PodArray<wasm::ValueType>::New(isolate, sig_size, AllocationType::kOld);
1780 : int index = 0; // Index into the {PodArray} above.
1781 112 : for (wasm::ValueType param : sig->parameters()) {
1782 8 : serialized_sig->set(index++, param);
1783 : }
1784 96 : exception->set_serialized_signature(*serialized_sig);
1785 96 : exception->set_exception_tag(*exception_tag);
1786 :
1787 96 : return exception;
1788 : }
1789 :
1790 56 : bool WasmExceptionObject::IsSignatureEqual(const wasm::FunctionSig* sig) {
1791 : DCHECK_EQ(0, sig->return_count());
1792 : DCHECK_LE(sig->parameter_count(), std::numeric_limits<int>::max());
1793 56 : int sig_size = static_cast<int>(sig->parameter_count());
1794 56 : if (sig_size != serialized_signature()->length()) return false;
1795 48 : for (int index = 0; index < sig_size; ++index) {
1796 0 : if (sig->GetParam(index) != serialized_signature()->get(index)) {
1797 : return false;
1798 : }
1799 : }
1800 : return true;
1801 : }
1802 :
1803 : // static
1804 604 : Handle<JSReceiver> WasmExceptionPackage::New(
1805 : Isolate* isolate, Handle<WasmExceptionTag> exception_tag, int size) {
1806 : Handle<Object> exception = isolate->factory()->NewWasmRuntimeError(
1807 604 : MessageTemplate::kWasmExceptionError);
1808 1208 : CHECK(!Object::SetProperty(isolate, exception,
1809 : isolate->factory()->wasm_exception_tag_symbol(),
1810 : exception_tag, StoreOrigin::kMaybeKeyed,
1811 : Just(ShouldThrow::kThrowOnError))
1812 : .is_null());
1813 604 : Handle<FixedArray> values = isolate->factory()->NewFixedArray(size);
1814 1208 : CHECK(!Object::SetProperty(isolate, exception,
1815 : isolate->factory()->wasm_exception_values_symbol(),
1816 : values, StoreOrigin::kMaybeKeyed,
1817 : Just(ShouldThrow::kThrowOnError))
1818 : .is_null());
1819 604 : return Handle<JSReceiver>::cast(exception);
1820 : }
1821 :
1822 : // static
1823 1312 : Handle<Object> WasmExceptionPackage::GetExceptionTag(
1824 : Isolate* isolate, Handle<Object> exception_object) {
1825 1312 : if (exception_object->IsJSReceiver()) {
1826 1216 : Handle<JSReceiver> exception = Handle<JSReceiver>::cast(exception_object);
1827 : Handle<Object> tag;
1828 3648 : if (JSReceiver::GetProperty(isolate, exception,
1829 1216 : isolate->factory()->wasm_exception_tag_symbol())
1830 : .ToHandle(&tag)) {
1831 1216 : return tag;
1832 : }
1833 : }
1834 96 : return ReadOnlyRoots(isolate).undefined_value_handle();
1835 : }
1836 :
1837 : // static
1838 2372 : Handle<Object> WasmExceptionPackage::GetExceptionValues(
1839 : Isolate* isolate, Handle<Object> exception_object) {
1840 2372 : if (exception_object->IsJSReceiver()) {
1841 2372 : Handle<JSReceiver> exception = Handle<JSReceiver>::cast(exception_object);
1842 : Handle<Object> values;
1843 7116 : if (JSReceiver::GetProperty(
1844 : isolate, exception,
1845 2372 : isolate->factory()->wasm_exception_values_symbol())
1846 : .ToHandle(&values)) {
1847 : DCHECK(values->IsFixedArray());
1848 2372 : return values;
1849 : }
1850 : }
1851 0 : return ReadOnlyRoots(isolate).undefined_value_handle();
1852 : }
1853 :
1854 : #ifdef DEBUG
1855 :
1856 : namespace {
1857 :
1858 : constexpr uint32_t kBytesPerExceptionValuesArrayElement = 2;
1859 :
1860 : size_t ComputeEncodedElementSize(wasm::ValueType type) {
1861 : size_t byte_size =
1862 : static_cast<size_t>(wasm::ValueTypes::ElementSizeInBytes(type));
1863 : DCHECK_EQ(byte_size % kBytesPerExceptionValuesArrayElement, 0);
1864 : DCHECK_LE(1, byte_size / kBytesPerExceptionValuesArrayElement);
1865 : return byte_size / kBytesPerExceptionValuesArrayElement;
1866 : }
1867 :
1868 : } // namespace
1869 :
1870 : #endif // DEBUG
1871 :
1872 : // static
1873 1155 : uint32_t WasmExceptionPackage::GetEncodedSize(
1874 : const wasm::WasmException* exception) {
1875 1155 : const wasm::WasmExceptionSig* sig = exception->sig;
1876 : uint32_t encoded_size = 0;
1877 2583 : for (size_t i = 0; i < sig->parameter_count(); ++i) {
1878 714 : switch (sig->GetParam(i)) {
1879 : case wasm::kWasmI32:
1880 : case wasm::kWasmF32:
1881 : DCHECK_EQ(2, ComputeEncodedElementSize(sig->GetParam(i)));
1882 440 : encoded_size += 2;
1883 440 : break;
1884 : case wasm::kWasmI64:
1885 : case wasm::kWasmF64:
1886 : DCHECK_EQ(4, ComputeEncodedElementSize(sig->GetParam(i)));
1887 116 : encoded_size += 4;
1888 116 : break;
1889 : case wasm::kWasmS128:
1890 : DCHECK_EQ(8, ComputeEncodedElementSize(sig->GetParam(i)));
1891 36 : encoded_size += 8;
1892 36 : break;
1893 : case wasm::kWasmAnyRef:
1894 122 : encoded_size += 1;
1895 122 : break;
1896 : default:
1897 0 : UNREACHABLE();
1898 : }
1899 : }
1900 1155 : return encoded_size;
1901 : }
1902 :
1903 253682 : bool WasmExportedFunction::IsWasmExportedFunction(Object object) {
1904 253682 : if (!object->IsJSFunction()) return false;
1905 : JSFunction js_function = JSFunction::cast(object);
1906 242558 : if (Code::JS_TO_WASM_FUNCTION != js_function->code()->kind()) return false;
1907 : DCHECK(js_function->shared()->HasWasmExportedFunctionData());
1908 222568 : return true;
1909 : }
1910 :
1911 326432 : WasmInstanceObject WasmExportedFunction::instance() {
1912 652864 : return shared()->wasm_exported_function_data()->instance();
1913 : }
1914 :
1915 217457 : int WasmExportedFunction::function_index() {
1916 434914 : return shared()->wasm_exported_function_data()->function_index();
1917 : }
1918 :
1919 237115 : Handle<WasmExportedFunction> WasmExportedFunction::New(
1920 : Isolate* isolate, Handle<WasmInstanceObject> instance,
1921 : MaybeHandle<String> maybe_name, int func_index, int arity,
1922 : Handle<Code> export_wrapper) {
1923 : DCHECK_EQ(Code::JS_TO_WASM_FUNCTION, export_wrapper->kind());
1924 237116 : int num_imported_functions = instance->module()->num_imported_functions;
1925 : int jump_table_offset = -1;
1926 237116 : if (func_index >= num_imported_functions) {
1927 : ptrdiff_t jump_table_diff =
1928 710229 : instance->module_object()->native_module()->jump_table_offset(
1929 : func_index);
1930 : DCHECK(jump_table_diff >= 0 && jump_table_diff <= INT_MAX);
1931 236741 : jump_table_offset = static_cast<int>(jump_table_diff);
1932 : }
1933 : Handle<WasmExportedFunctionData> function_data =
1934 : Handle<WasmExportedFunctionData>::cast(isolate->factory()->NewStruct(
1935 237113 : WASM_EXPORTED_FUNCTION_DATA_TYPE, AllocationType::kOld));
1936 237116 : function_data->set_wrapper_code(*export_wrapper);
1937 237116 : function_data->set_instance(*instance);
1938 : function_data->set_jump_table_offset(jump_table_offset);
1939 : function_data->set_function_index(func_index);
1940 : Handle<String> name;
1941 237116 : if (!maybe_name.ToHandle(&name)) {
1942 : EmbeddedVector<char, 16> buffer;
1943 227994 : int length = SNPrintF(buffer, "%d", func_index);
1944 : name = isolate->factory()
1945 455988 : ->NewStringFromOneByte(
1946 227994 : Vector<uint8_t>::cast(buffer.SubVector(0, length)))
1947 227994 : .ToHandleChecked();
1948 : }
1949 : NewFunctionArgs args = NewFunctionArgs::ForWasm(
1950 237116 : name, function_data, isolate->sloppy_function_without_prototype_map());
1951 237115 : Handle<JSFunction> js_function = isolate->factory()->NewFunction(args);
1952 : // According to the spec, exported functions should not have a [[Construct]]
1953 : // method.
1954 : DCHECK(!js_function->IsConstructor());
1955 : js_function->shared()->set_length(arity);
1956 : js_function->shared()->set_internal_formal_parameter_count(arity);
1957 237114 : return Handle<WasmExportedFunction>::cast(js_function);
1958 : }
1959 :
1960 107064 : Address WasmExportedFunction::GetWasmCallTarget() {
1961 107064 : return instance()->GetCallTarget(function_index());
1962 : }
1963 :
1964 0 : wasm::FunctionSig* WasmExportedFunction::sig() {
1965 0 : return instance()->module()->functions[function_index()].sig;
1966 : }
1967 :
1968 692 : Handle<WasmExceptionTag> WasmExceptionTag::New(Isolate* isolate, int index) {
1969 : Handle<WasmExceptionTag> result =
1970 : Handle<WasmExceptionTag>::cast(isolate->factory()->NewStruct(
1971 692 : WASM_EXCEPTION_TAG_TYPE, AllocationType::kOld));
1972 : result->set_index(index);
1973 692 : return result;
1974 : }
1975 :
1976 2469 : Handle<AsmWasmData> AsmWasmData::New(
1977 : Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module,
1978 : Handle<FixedArray> export_wrappers, Handle<ByteArray> asm_js_offset_table,
1979 : Handle<HeapNumber> uses_bitset) {
1980 : const WasmModule* module = native_module->module();
1981 : size_t memory_estimate =
1982 2469 : wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module) +
1983 2469 : wasm::WasmCodeManager::EstimateNativeModuleNonCodeSize(module);
1984 : Handle<Managed<wasm::NativeModule>> managed_native_module =
1985 : Managed<wasm::NativeModule>::FromSharedPtr(isolate, memory_estimate,
1986 2469 : std::move(native_module));
1987 : Handle<AsmWasmData> result = Handle<AsmWasmData>::cast(
1988 2469 : isolate->factory()->NewStruct(ASM_WASM_DATA_TYPE, AllocationType::kOld));
1989 2469 : result->set_managed_native_module(*managed_native_module);
1990 2469 : result->set_export_wrappers(*export_wrappers);
1991 2469 : result->set_asm_js_offset_table(*asm_js_offset_table);
1992 2469 : result->set_uses_bitset(*uses_bitset);
1993 2469 : return result;
1994 : }
1995 :
1996 : #undef TRACE
1997 : #undef TRACE_IFT
1998 : } // namespace internal
1999 122004 : } // namespace v8
|