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