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