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/compiler/wasm-compiler.h"
11 #include "src/debug/debug-interface.h"
12 #include "src/objects-inl.h"
13 #include "src/objects/debug-objects-inl.h"
14 #include "src/trap-handler/trap-handler.h"
15 #include "src/wasm/module-compiler.h"
16 #include "src/wasm/module-decoder.h"
17 #include "src/wasm/wasm-code-manager.h"
18 #include "src/wasm/wasm-engine.h"
19 #include "src/wasm/wasm-limits.h"
20 #include "src/wasm/wasm-memory.h"
21 #include "src/wasm/wasm-module.h"
22 #include "src/wasm/wasm-objects-inl.h"
23 #include "src/wasm/wasm-text.h"
24
25 #define TRACE(...) \
26 do { \
27 if (FLAG_trace_wasm_instances) PrintF(__VA_ARGS__); \
28 } while (false)
29
30 #define TRACE_IFT(...) \
31 do { \
32 if (false) PrintF(__VA_ARGS__); \
33 } while (false)
34
35 namespace v8 {
36 namespace internal {
37
38 // Import a few often used types from the wasm namespace.
39 using WasmFunction = wasm::WasmFunction;
40 using WasmModule = wasm::WasmModule;
41
42 namespace {
43
44 // Manages the natively-allocated memory for a WasmInstanceObject. Since
45 // an instance finalizer is not guaranteed to run upon isolate shutdown,
46 // we must use a Managed<WasmInstanceNativeAllocations> to guarantee
47 // it is freed.
48 // Native allocations are the signature ids and targets for indirect call
49 // targets, as well as the call targets for imported functions.
50 class WasmInstanceNativeAllocations {
51 public:
52 // Helper macro to set an internal field and the corresponding field
53 // on an instance.
54 #define SET(instance, field, value) \
55 { \
56 auto v = value; \
57 this->field##_ = v; \
58 instance->set_##field(v); \
59 }
60
61 // Allocates initial native storage for a given instance.
WasmInstanceNativeAllocations(Handle<WasmInstanceObject> instance,size_t num_imported_functions,size_t num_imported_mutable_globals)62 WasmInstanceNativeAllocations(Handle<WasmInstanceObject> instance,
63 size_t num_imported_functions,
64 size_t num_imported_mutable_globals) {
65 SET(instance, imported_function_targets,
66 reinterpret_cast<Address*>(
67 calloc(num_imported_functions, sizeof(Address))));
68 SET(instance, imported_mutable_globals,
69 reinterpret_cast<Address*>(
70 calloc(num_imported_mutable_globals, sizeof(Address))));
71 }
~WasmInstanceNativeAllocations()72 ~WasmInstanceNativeAllocations() { free(); }
73 // Frees natively-allocated storage.
free()74 void free() {
75 ::free(indirect_function_table_sig_ids_);
76 ::free(indirect_function_table_targets_);
77 ::free(imported_function_targets_);
78 ::free(imported_mutable_globals_);
79 indirect_function_table_sig_ids_ = nullptr;
80 indirect_function_table_targets_ = nullptr;
81 imported_function_targets_ = nullptr;
82 imported_mutable_globals_ = nullptr;
83 }
84 // Resizes the indirect function table.
resize_indirect_function_table(Isolate * isolate,Handle<WasmInstanceObject> instance,uint32_t new_size)85 void resize_indirect_function_table(Isolate* isolate,
86 Handle<WasmInstanceObject> instance,
87 uint32_t new_size) {
88 uint32_t old_size = instance->indirect_function_table_size();
89 void* new_sig_ids = nullptr;
90 void* new_targets = nullptr;
91 Handle<FixedArray> new_instances;
92 if (indirect_function_table_sig_ids_) {
93 // Reallocate the old storage.
94 new_sig_ids = realloc(indirect_function_table_sig_ids_,
95 new_size * sizeof(uint32_t));
96 new_targets =
97 realloc(indirect_function_table_targets_, new_size * sizeof(Address));
98
99 Handle<FixedArray> old(instance->indirect_function_table_instances(),
100 isolate);
101 new_instances = isolate->factory()->CopyFixedArrayAndGrow(
102 old, static_cast<int>(new_size - old_size));
103 } else {
104 // Allocate new storage.
105 new_sig_ids = malloc(new_size * sizeof(uint32_t));
106 new_targets = malloc(new_size * sizeof(Address));
107 new_instances =
108 isolate->factory()->NewFixedArray(static_cast<int>(new_size));
109 }
110 // Initialize new entries.
111 instance->set_indirect_function_table_size(new_size);
112 SET(instance, indirect_function_table_sig_ids,
113 reinterpret_cast<uint32_t*>(new_sig_ids));
114 SET(instance, indirect_function_table_targets,
115 reinterpret_cast<Address*>(new_targets));
116
117 instance->set_indirect_function_table_instances(*new_instances);
118 for (uint32_t j = old_size; j < new_size; j++) {
119 IndirectFunctionTableEntry(instance, static_cast<int>(j)).clear();
120 }
121 }
122 uint32_t* indirect_function_table_sig_ids_ = nullptr;
123 Address* indirect_function_table_targets_ = nullptr;
124 Address* imported_function_targets_ = nullptr;
125 Address* imported_mutable_globals_ = nullptr;
126 #undef SET
127 };
128
GetNativeAllocations(WasmInstanceObject * instance)129 WasmInstanceNativeAllocations* GetNativeAllocations(
130 WasmInstanceObject* instance) {
131 return reinterpret_cast<Managed<WasmInstanceNativeAllocations>*>(
132 instance->managed_native_allocations())
133 ->raw();
134 }
135
136 // An iterator that returns first the module itself, then all modules linked via
137 // next, then all linked via prev.
138 class CompiledModulesIterator
139 : public v8::base::iterator<std::input_iterator_tag,
140 Handle<WasmCompiledModule>> {
141 public:
CompiledModulesIterator(Isolate * isolate,Handle<WasmCompiledModule> start_module,bool at_end)142 CompiledModulesIterator(Isolate* isolate,
143 Handle<WasmCompiledModule> start_module, bool at_end)
144 : isolate_(isolate),
145 start_module_(start_module),
146 current_(
147 at_end ? Handle<WasmCompiledModule>::null()
148 : Handle<WasmCompiledModule>::New(*start_module, isolate)) {}
149
operator *() const150 Handle<WasmCompiledModule> operator*() const {
151 DCHECK(!current_.is_null());
152 return current_;
153 }
154
operator ++()155 void operator++() { Advance(); }
156
operator !=(const CompiledModulesIterator & other)157 bool operator!=(const CompiledModulesIterator& other) {
158 DCHECK(start_module_.is_identical_to(other.start_module_));
159 return !current_.is_identical_to(other.current_);
160 }
161
162 private:
Advance()163 void Advance() {
164 DCHECK(!current_.is_null());
165 if (!is_backwards_) {
166 if (current_->has_next_instance()) {
167 *current_.location() = current_->next_instance();
168 return;
169 }
170 // No more modules in next-links, now try the previous-links.
171 is_backwards_ = true;
172 current_ = start_module_;
173 }
174 if (current_->has_prev_instance()) {
175 *current_.location() = current_->prev_instance();
176 return;
177 }
178 current_ = Handle<WasmCompiledModule>::null();
179 }
180
181 friend class CompiledModuleInstancesIterator;
182 Isolate* isolate_;
183 Handle<WasmCompiledModule> start_module_;
184 Handle<WasmCompiledModule> current_;
185 bool is_backwards_ = false;
186 };
187
188 // An iterator based on the CompiledModulesIterator, but it returns all live
189 // instances, not the WasmCompiledModules itself.
190 class CompiledModuleInstancesIterator
191 : public v8::base::iterator<std::input_iterator_tag,
192 Handle<WasmInstanceObject>> {
193 public:
CompiledModuleInstancesIterator(Isolate * isolate,Handle<WasmCompiledModule> start_module,bool at_end)194 CompiledModuleInstancesIterator(Isolate* isolate,
195 Handle<WasmCompiledModule> start_module,
196 bool at_end)
197 : it(isolate, start_module, at_end) {
198 while (NeedToAdvance()) ++it;
199 }
200
operator *()201 Handle<WasmInstanceObject> operator*() {
202 return handle(
203 WasmInstanceObject::cast((*it)->weak_owning_instance()->value()),
204 it.isolate_);
205 }
206
operator ++()207 void operator++() {
208 do {
209 ++it;
210 } while (NeedToAdvance());
211 }
212
operator !=(const CompiledModuleInstancesIterator & other)213 bool operator!=(const CompiledModuleInstancesIterator& other) {
214 return it != other.it;
215 }
216
217 private:
NeedToAdvance()218 bool NeedToAdvance() {
219 return !it.current_.is_null() && !it.current_->has_instance();
220 }
221 CompiledModulesIterator it;
222 };
223
224 v8::base::iterator_range<CompiledModuleInstancesIterator>
iterate_compiled_module_instance_chain(Isolate * isolate,Handle<WasmModuleObject> module_object)225 iterate_compiled_module_instance_chain(Isolate* isolate,
226 Handle<WasmModuleObject> module_object) {
227 Handle<WasmCompiledModule> compiled_module(module_object->compiled_module());
228 return {CompiledModuleInstancesIterator(isolate, compiled_module, false),
229 CompiledModuleInstancesIterator(isolate, compiled_module, true)};
230 }
231
232 #ifdef DEBUG
IsBreakablePosition(WasmSharedModuleData * shared,int func_index,int offset_in_func)233 bool IsBreakablePosition(WasmSharedModuleData* shared, int func_index,
234 int offset_in_func) {
235 DisallowHeapAllocation no_gc;
236 AccountingAllocator alloc;
237 Zone tmp(&alloc, ZONE_NAME);
238 wasm::BodyLocalDecls locals(&tmp);
239 const byte* module_start = shared->module_bytes()->GetChars();
240 WasmFunction& func = shared->module()->functions[func_index];
241 wasm::BytecodeIterator iterator(module_start + func.code.offset(),
242 module_start + func.code.end_offset(),
243 &locals);
244 DCHECK_LT(0, locals.encoded_size);
245 for (uint32_t offset : iterator.offsets()) {
246 if (offset > static_cast<uint32_t>(offset_in_func)) break;
247 if (offset == static_cast<uint32_t>(offset_in_func)) return true;
248 }
249 return false;
250 }
251 #endif // DEBUG
252
253 enum DispatchTableElements : int {
254 kDispatchTableInstanceOffset,
255 kDispatchTableIndexOffset,
256 kDispatchTableFunctionTableOffset,
257 // Marker:
258 kDispatchTableNumElements
259 };
260
261 } // namespace
262
New(Isolate * isolate,Handle<WasmCompiledModule> compiled_module,Handle<FixedArray> export_wrappers,Handle<WasmSharedModuleData> shared)263 Handle<WasmModuleObject> WasmModuleObject::New(
264 Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
265 Handle<FixedArray> export_wrappers, Handle<WasmSharedModuleData> shared) {
266 Handle<JSFunction> module_cons(
267 isolate->native_context()->wasm_module_constructor());
268 auto module_object = Handle<WasmModuleObject>::cast(
269 isolate->factory()->NewJSObject(module_cons));
270 module_object->set_compiled_module(*compiled_module);
271 module_object->set_export_wrappers(*export_wrappers);
272 if (shared->script()->type() == Script::TYPE_WASM) {
273 shared->script()->set_wasm_module_object(*module_object);
274 }
275 module_object->set_shared(*shared);
276
277 compiled_module->LogWasmCodes(isolate);
278 return module_object;
279 }
280
SetBreakPoint(Handle<WasmModuleObject> module_object,int * position,Handle<BreakPoint> break_point)281 bool WasmModuleObject::SetBreakPoint(Handle<WasmModuleObject> module_object,
282 int* position,
283 Handle<BreakPoint> break_point) {
284 Isolate* isolate = module_object->GetIsolate();
285 Handle<WasmSharedModuleData> shared(module_object->shared(), isolate);
286
287 // Find the function for this breakpoint.
288 int func_index = shared->GetContainingFunction(*position);
289 if (func_index < 0) return false;
290 WasmFunction& func = shared->module()->functions[func_index];
291 int offset_in_func = *position - func.code.offset();
292
293 // According to the current design, we should only be called with valid
294 // breakable positions.
295 DCHECK(IsBreakablePosition(*shared, func_index, offset_in_func));
296
297 // Insert new break point into break_positions of shared module data.
298 WasmSharedModuleData::AddBreakpoint(shared, *position, break_point);
299
300 // Iterate over all instances of this module and tell them to set this new
301 // breakpoint.
302 for (Handle<WasmInstanceObject> instance :
303 iterate_compiled_module_instance_chain(isolate, module_object)) {
304 Handle<WasmDebugInfo> debug_info =
305 WasmInstanceObject::GetOrCreateDebugInfo(instance);
306 WasmDebugInfo::SetBreakpoint(debug_info, func_index, offset_in_func);
307 }
308
309 return true;
310 }
311
ValidateStateForTesting(Isolate * isolate,Handle<WasmModuleObject> module_obj)312 void WasmModuleObject::ValidateStateForTesting(
313 Isolate* isolate, Handle<WasmModuleObject> module_obj) {
314 DisallowHeapAllocation no_gc;
315 WasmCompiledModule* compiled_module = module_obj->compiled_module();
316 CHECK(!compiled_module->has_prev_instance());
317 CHECK(!compiled_module->has_next_instance());
318 CHECK(!compiled_module->has_instance());
319 }
320
New(Isolate * isolate,uint32_t initial,int64_t maximum,Handle<FixedArray> * js_functions)321 Handle<WasmTableObject> WasmTableObject::New(Isolate* isolate, uint32_t initial,
322 int64_t maximum,
323 Handle<FixedArray>* js_functions) {
324 Handle<JSFunction> table_ctor(
325 isolate->native_context()->wasm_table_constructor());
326 auto table_obj = Handle<WasmTableObject>::cast(
327 isolate->factory()->NewJSObject(table_ctor));
328
329 *js_functions = isolate->factory()->NewFixedArray(initial);
330 Object* null = isolate->heap()->null_value();
331 for (int i = 0; i < static_cast<int>(initial); ++i) {
332 (*js_functions)->set(i, null);
333 }
334 table_obj->set_functions(**js_functions);
335 DCHECK_EQ(maximum, static_cast<int>(maximum));
336 Handle<Object> max = isolate->factory()->NewNumber(maximum);
337 table_obj->set_maximum_length(*max);
338
339 table_obj->set_dispatch_tables(isolate->heap()->empty_fixed_array());
340 return Handle<WasmTableObject>::cast(table_obj);
341 }
342
AddDispatchTable(Isolate * isolate,Handle<WasmTableObject> table_obj,Handle<WasmInstanceObject> instance,int table_index)343 void WasmTableObject::AddDispatchTable(Isolate* isolate,
344 Handle<WasmTableObject> table_obj,
345 Handle<WasmInstanceObject> instance,
346 int table_index) {
347 Handle<FixedArray> dispatch_tables(table_obj->dispatch_tables());
348 int old_length = dispatch_tables->length();
349 DCHECK_EQ(0, old_length % kDispatchTableNumElements);
350
351 if (instance.is_null()) return;
352 // TODO(titzer): use weak cells here to avoid leaking instances.
353
354 // Grow the dispatch table and add a new entry at the end.
355 Handle<FixedArray> new_dispatch_tables =
356 isolate->factory()->CopyFixedArrayAndGrow(dispatch_tables,
357 kDispatchTableNumElements);
358
359 new_dispatch_tables->set(old_length + kDispatchTableInstanceOffset,
360 *instance);
361 new_dispatch_tables->set(old_length + kDispatchTableIndexOffset,
362 Smi::FromInt(table_index));
363
364 table_obj->set_dispatch_tables(*new_dispatch_tables);
365 }
366
Grow(Isolate * isolate,uint32_t count)367 void WasmTableObject::Grow(Isolate* isolate, uint32_t count) {
368 if (count == 0) return; // Degenerate case: nothing to do.
369
370 Handle<FixedArray> dispatch_tables(this->dispatch_tables());
371 DCHECK_EQ(0, dispatch_tables->length() % kDispatchTableNumElements);
372 uint32_t old_size = functions()->length();
373
374 // Tables are stored in the instance object, no code patching is
375 // necessary. We simply have to grow the raw tables in each instance
376 // that has imported this table.
377
378 // TODO(titzer): replace the dispatch table with a weak list of all
379 // the instances that import a given table.
380 for (int i = 0; i < dispatch_tables->length();
381 i += kDispatchTableNumElements) {
382 Handle<WasmInstanceObject> instance(
383 WasmInstanceObject::cast(dispatch_tables->get(i)), isolate);
384 DCHECK_EQ(old_size, instance->indirect_function_table_size());
385 uint32_t new_size = old_size + count;
386 WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(instance,
387 new_size);
388 }
389 }
390
Set(Isolate * isolate,Handle<WasmTableObject> table,int32_t table_index,Handle<JSFunction> function)391 void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table,
392 int32_t table_index, Handle<JSFunction> function) {
393 Handle<FixedArray> array(table->functions(), isolate);
394 if (function.is_null()) {
395 ClearDispatchTables(isolate, table, table_index); // Degenerate case.
396 array->set(table_index, isolate->heap()->null_value());
397 return;
398 }
399
400 // TODO(titzer): Change this to MaybeHandle<WasmExportedFunction>
401 DCHECK(WasmExportedFunction::IsWasmExportedFunction(*function));
402 auto exported_function = Handle<WasmExportedFunction>::cast(function);
403 Handle<WasmInstanceObject> other_instance(exported_function->instance());
404 int func_index = exported_function->function_index();
405 auto* wasm_function = &other_instance->module()->functions[func_index];
406 DCHECK_NOT_NULL(wasm_function);
407 DCHECK_NOT_NULL(wasm_function->sig);
408 Address call_target = exported_function->GetWasmCallTarget();
409 UpdateDispatchTables(isolate, table, table_index, wasm_function->sig,
410 handle(exported_function->instance()), call_target);
411 array->set(table_index, *function);
412 }
413
UpdateDispatchTables(Isolate * isolate,Handle<WasmTableObject> table,int table_index,wasm::FunctionSig * sig,Handle<WasmInstanceObject> from_instance,Address call_target)414 void WasmTableObject::UpdateDispatchTables(
415 Isolate* isolate, Handle<WasmTableObject> table, int table_index,
416 wasm::FunctionSig* sig, Handle<WasmInstanceObject> from_instance,
417 Address call_target) {
418 // We simply need to update the IFTs for each instance that imports
419 // this table.
420 Handle<FixedArray> dispatch_tables(table->dispatch_tables(), isolate);
421 DCHECK_EQ(0, dispatch_tables->length() % kDispatchTableNumElements);
422
423 for (int i = 0; i < dispatch_tables->length();
424 i += kDispatchTableNumElements) {
425 Handle<WasmInstanceObject> to_instance(
426 WasmInstanceObject::cast(
427 dispatch_tables->get(i + kDispatchTableInstanceOffset)),
428 isolate);
429 // Note that {SignatureMap::Find} may return {-1} if the signature is
430 // not found; it will simply never match any check.
431 auto sig_id = to_instance->module()->signature_map.Find(sig);
432 IndirectFunctionTableEntry(to_instance, table_index)
433 .set(sig_id, *from_instance, call_target);
434 }
435 }
436
ClearDispatchTables(Isolate * isolate,Handle<WasmTableObject> table,int index)437 void WasmTableObject::ClearDispatchTables(Isolate* isolate,
438 Handle<WasmTableObject> table,
439 int index) {
440 Handle<FixedArray> dispatch_tables(table->dispatch_tables(), isolate);
441 DCHECK_EQ(0, dispatch_tables->length() % kDispatchTableNumElements);
442 for (int i = 0; i < dispatch_tables->length();
443 i += kDispatchTableNumElements) {
444 Handle<WasmInstanceObject> target_instance(
445 WasmInstanceObject::cast(
446 dispatch_tables->get(i + kDispatchTableInstanceOffset)),
447 isolate);
448 DCHECK_LT(index, target_instance->indirect_function_table_size());
449 IndirectFunctionTableEntry(target_instance, index).clear();
450 }
451 }
452
453 namespace {
GrowMemoryBuffer(Isolate * isolate,Handle<JSArrayBuffer> old_buffer,uint32_t pages,uint32_t maximum_pages)454 MaybeHandle<JSArrayBuffer> GrowMemoryBuffer(Isolate* isolate,
455 Handle<JSArrayBuffer> old_buffer,
456 uint32_t pages,
457 uint32_t maximum_pages) {
458 if (!old_buffer->is_growable()) return {};
459 void* old_mem_start = old_buffer->backing_store();
460 uint32_t old_size = 0;
461 CHECK(old_buffer->byte_length()->ToUint32(&old_size));
462 DCHECK_EQ(0, old_size % wasm::kWasmPageSize);
463 uint32_t old_pages = old_size / wasm::kWasmPageSize;
464 DCHECK_GE(std::numeric_limits<uint32_t>::max(),
465 old_size + pages * wasm::kWasmPageSize);
466 if (old_pages > maximum_pages || pages > maximum_pages - old_pages) return {};
467 size_t new_size =
468 static_cast<size_t>(old_pages + pages) * wasm::kWasmPageSize;
469 if (new_size > FLAG_wasm_max_mem_pages * wasm::kWasmPageSize ||
470 new_size > kMaxInt) {
471 return {};
472 }
473 // Reusing the backing store from externalized buffers causes problems with
474 // Blink's array buffers. The connection between the two is lost, which can
475 // lead to Blink not knowing about the other reference to the buffer and
476 // freeing it too early.
477 if (!old_buffer->is_external() && old_size != 0 &&
478 ((new_size < old_buffer->allocation_length()) || old_size == new_size)) {
479 DCHECK_NOT_NULL(old_buffer->backing_store());
480 if (old_size != new_size) {
481 // If adjusting permissions fails, propagate error back to return
482 // failure to grow.
483 DCHECK(!isolate->wasm_engine()->memory_tracker()->IsEmptyBackingStore(
484 old_mem_start));
485 if (!i::SetPermissions(old_mem_start, new_size,
486 PageAllocator::kReadWrite)) {
487 return {};
488 }
489 reinterpret_cast<v8::Isolate*>(isolate)
490 ->AdjustAmountOfExternalAllocatedMemory(pages * wasm::kWasmPageSize);
491 }
492 // NOTE: We must allocate a new array buffer here because the spec
493 // assumes that ArrayBuffers do not change size.
494 void* backing_store = old_buffer->backing_store();
495 bool is_external = old_buffer->is_external();
496 // Disconnect buffer early so GC won't free it.
497 i::wasm::DetachMemoryBuffer(isolate, old_buffer, false);
498 Handle<JSArrayBuffer> new_buffer =
499 wasm::SetupArrayBuffer(isolate, backing_store, new_size, is_external);
500 return new_buffer;
501 } else {
502 // We couldn't reuse the old backing store, so create a new one and copy the
503 // old contents in.
504 Handle<JSArrayBuffer> new_buffer;
505 if (!wasm::NewArrayBuffer(isolate, new_size).ToHandle(&new_buffer)) {
506 return {};
507 }
508 if (old_size == 0) return new_buffer;
509 memcpy(new_buffer->backing_store(), old_mem_start, old_size);
510 DCHECK(old_buffer.is_null() || !old_buffer->is_shared());
511 constexpr bool free_memory = true;
512 i::wasm::DetachMemoryBuffer(isolate, old_buffer, free_memory);
513 return new_buffer;
514 }
515 }
516
517 // May GC, because SetSpecializationMemInfoFrom may GC
SetInstanceMemory(Isolate * isolate,Handle<WasmInstanceObject> instance,Handle<JSArrayBuffer> buffer)518 void SetInstanceMemory(Isolate* isolate, Handle<WasmInstanceObject> instance,
519 Handle<JSArrayBuffer> buffer) {
520 instance->SetRawMemory(reinterpret_cast<byte*>(buffer->backing_store()),
521 buffer->byte_length()->Number());
522 #if DEBUG
523 // To flush out bugs earlier, in DEBUG mode, check that all pages of the
524 // memory are accessible by reading and writing one byte on each page.
525 byte* mem_start = instance->memory_start();
526 uintptr_t mem_size = instance->memory_size();
527 for (uint32_t offset = 0; offset < mem_size; offset += wasm::kWasmPageSize) {
528 byte val = mem_start[offset];
529 USE(val);
530 mem_start[offset] = val;
531 }
532 #endif
533 }
534
535 } // namespace
536
New(Isolate * isolate,MaybeHandle<JSArrayBuffer> maybe_buffer,int32_t maximum)537 Handle<WasmMemoryObject> WasmMemoryObject::New(
538 Isolate* isolate, MaybeHandle<JSArrayBuffer> maybe_buffer,
539 int32_t maximum) {
540 // TODO(kschimpf): Do we need to add an argument that defines the
541 // style of memory the user prefers (with/without trap handling), so
542 // that the memory will match the style of the compiled wasm module.
543 // See issue v8:7143
544 Handle<JSFunction> memory_ctor(
545 isolate->native_context()->wasm_memory_constructor());
546 auto memory_obj = Handle<WasmMemoryObject>::cast(
547 isolate->factory()->NewJSObject(memory_ctor, TENURED));
548
549 Handle<JSArrayBuffer> buffer;
550 if (maybe_buffer.is_null()) {
551 // If no buffer was provided, create a 0-length one.
552 buffer = wasm::SetupArrayBuffer(isolate, nullptr, 0, false);
553 } else {
554 buffer = maybe_buffer.ToHandleChecked();
555 // Paranoid check that the buffer size makes sense.
556 uint32_t mem_size = 0;
557 CHECK(buffer->byte_length()->ToUint32(&mem_size));
558 }
559 memory_obj->set_array_buffer(*buffer);
560 memory_obj->set_maximum_pages(maximum);
561
562 return memory_obj;
563 }
564
current_pages()565 uint32_t WasmMemoryObject::current_pages() {
566 uint32_t byte_length;
567 CHECK(array_buffer()->byte_length()->ToUint32(&byte_length));
568 return byte_length / wasm::kWasmPageSize;
569 }
570
AddInstance(Isolate * isolate,Handle<WasmMemoryObject> memory,Handle<WasmInstanceObject> instance)571 void WasmMemoryObject::AddInstance(Isolate* isolate,
572 Handle<WasmMemoryObject> memory,
573 Handle<WasmInstanceObject> instance) {
574 Handle<FixedArrayOfWeakCells> old_instances =
575 memory->has_instances()
576 ? Handle<FixedArrayOfWeakCells>(memory->instances(), isolate)
577 : Handle<FixedArrayOfWeakCells>::null();
578 Handle<FixedArrayOfWeakCells> new_instances =
579 FixedArrayOfWeakCells::Add(old_instances, instance);
580 memory->set_instances(*new_instances);
581 Handle<JSArrayBuffer> buffer(memory->array_buffer(), isolate);
582 SetInstanceMemory(isolate, instance, buffer);
583 }
584
RemoveInstance(Isolate * isolate,Handle<WasmMemoryObject> memory,Handle<WasmInstanceObject> instance)585 void WasmMemoryObject::RemoveInstance(Isolate* isolate,
586 Handle<WasmMemoryObject> memory,
587 Handle<WasmInstanceObject> instance) {
588 if (memory->has_instances()) {
589 memory->instances()->Remove(instance);
590 }
591 }
592
593 // static
Grow(Isolate * isolate,Handle<WasmMemoryObject> memory_object,uint32_t pages)594 int32_t WasmMemoryObject::Grow(Isolate* isolate,
595 Handle<WasmMemoryObject> memory_object,
596 uint32_t pages) {
597 Handle<JSArrayBuffer> old_buffer(memory_object->array_buffer());
598 if (!old_buffer->is_growable()) return -1;
599 uint32_t old_size = 0;
600 CHECK(old_buffer->byte_length()->ToUint32(&old_size));
601 DCHECK_EQ(0, old_size % wasm::kWasmPageSize);
602 Handle<JSArrayBuffer> new_buffer;
603
604 uint32_t maximum_pages = FLAG_wasm_max_mem_pages;
605 if (memory_object->has_maximum_pages()) {
606 maximum_pages = Min(FLAG_wasm_max_mem_pages,
607 static_cast<uint32_t>(memory_object->maximum_pages()));
608 }
609 if (!GrowMemoryBuffer(isolate, old_buffer, pages, maximum_pages)
610 .ToHandle(&new_buffer)) {
611 return -1;
612 }
613
614 if (memory_object->has_instances()) {
615 Handle<FixedArrayOfWeakCells> instances(memory_object->instances(),
616 isolate);
617 for (int i = 0; i < instances->Length(); i++) {
618 Object* elem = instances->Get(i);
619 if (!elem->IsWasmInstanceObject()) continue;
620 Handle<WasmInstanceObject> instance(WasmInstanceObject::cast(elem),
621 isolate);
622 SetInstanceMemory(isolate, instance, new_buffer);
623 }
624 }
625 memory_object->set_array_buffer(*new_buffer);
626 return old_size / wasm::kWasmPageSize;
627 }
628
629 // static
New(Isolate * isolate,MaybeHandle<JSArrayBuffer> maybe_buffer,wasm::ValueType type,int32_t offset,bool is_mutable)630 MaybeHandle<WasmGlobalObject> WasmGlobalObject::New(
631 Isolate* isolate, MaybeHandle<JSArrayBuffer> maybe_buffer,
632 wasm::ValueType type, int32_t offset, bool is_mutable) {
633 Handle<JSFunction> global_ctor(
634 isolate->native_context()->wasm_global_constructor());
635 auto global_obj = Handle<WasmGlobalObject>::cast(
636 isolate->factory()->NewJSObject(global_ctor));
637
638 uint32_t type_size = wasm::ValueTypes::ElementSizeInBytes(type);
639
640 Handle<JSArrayBuffer> buffer;
641 if (!maybe_buffer.ToHandle(&buffer)) {
642 // If no buffer was provided, create one long enough for the given type.
643 buffer =
644 isolate->factory()->NewJSArrayBuffer(SharedFlag::kNotShared, TENURED);
645
646 const bool initialize = true;
647 if (!JSArrayBuffer::SetupAllocatingData(buffer, isolate, type_size,
648 initialize)) {
649 return {};
650 }
651 }
652
653 // Check that the offset is in bounds.
654 uint32_t buffer_size = 0;
655 CHECK(buffer->byte_length()->ToUint32(&buffer_size));
656 CHECK(offset + type_size <= buffer_size);
657
658 global_obj->set_array_buffer(*buffer);
659 global_obj->set_flags(0);
660 global_obj->set_type(type);
661 global_obj->set_offset(offset);
662 global_obj->set_is_mutable(is_mutable);
663
664 return global_obj;
665 }
666
clear()667 void IndirectFunctionTableEntry::clear() {
668 instance_->indirect_function_table_sig_ids()[index_] = -1;
669 instance_->indirect_function_table_targets()[index_] = 0;
670 instance_->indirect_function_table_instances()->set(
671 index_, instance_->GetIsolate()->heap()->undefined_value());
672 }
673
set(int sig_id,WasmInstanceObject * instance,Address call_target)674 void IndirectFunctionTableEntry::set(int sig_id, WasmInstanceObject* instance,
675 Address call_target) {
676 TRACE_IFT("IFT entry %p[%d] = {sig_id=%d, instance=%p, target=%" PRIuPTR
677 "}\n",
678 *instance_, index_, sig_id, instance, call_target);
679 instance_->indirect_function_table_sig_ids()[index_] = sig_id;
680 instance_->indirect_function_table_targets()[index_] = call_target;
681 instance_->indirect_function_table_instances()->set(index_, instance);
682 }
683
instance()684 WasmInstanceObject* IndirectFunctionTableEntry::instance() {
685 return WasmInstanceObject::cast(
686 instance_->indirect_function_table_instances()->get(index_));
687 }
688
sig_id()689 int IndirectFunctionTableEntry::sig_id() {
690 return instance_->indirect_function_table_sig_ids()[index_];
691 }
692
target()693 Address IndirectFunctionTableEntry::target() {
694 return instance_->indirect_function_table_targets()[index_];
695 }
696
set_wasm_to_js(JSReceiver * callable,const wasm::WasmCode * wasm_to_js_wrapper)697 void ImportedFunctionEntry::set_wasm_to_js(
698 JSReceiver* callable, const wasm::WasmCode* wasm_to_js_wrapper) {
699 TRACE_IFT("Import callable %p[%d] = {callable=%p, target=%p}\n", *instance_,
700 index_, callable, wasm_to_js_wrapper->instructions().start());
701 DCHECK_EQ(wasm::WasmCode::kWasmToJsWrapper, wasm_to_js_wrapper->kind());
702 instance_->imported_function_instances()->set(index_, *instance_);
703 instance_->imported_function_callables()->set(index_, callable);
704 instance_->imported_function_targets()[index_] =
705 wasm_to_js_wrapper->instruction_start();
706 }
707
set_wasm_to_wasm(WasmInstanceObject * instance,Address call_target)708 void ImportedFunctionEntry::set_wasm_to_wasm(WasmInstanceObject* instance,
709 Address call_target) {
710 TRACE_IFT("Import WASM %p[%d] = {instance=%p, target=%" PRIuPTR "}\n",
711 *instance_, index_, instance, call_target);
712 instance_->imported_function_instances()->set(index_, instance);
713 instance_->imported_function_callables()->set(
714 index_, instance_->GetHeap()->undefined_value());
715 instance_->imported_function_targets()[index_] = call_target;
716 }
717
instance()718 WasmInstanceObject* ImportedFunctionEntry::instance() {
719 return WasmInstanceObject::cast(
720 instance_->imported_function_instances()->get(index_));
721 }
722
callable()723 JSReceiver* ImportedFunctionEntry::callable() {
724 return JSReceiver::cast(
725 instance_->imported_function_callables()->get(index_));
726 }
727
target()728 Address ImportedFunctionEntry::target() {
729 return instance_->imported_function_targets()[index_];
730 }
731
is_js_receiver_entry()732 bool ImportedFunctionEntry::is_js_receiver_entry() {
733 return instance_->imported_function_callables()->get(index_)->IsJSReceiver();
734 }
735
EnsureIndirectFunctionTableWithMinimumSize(Handle<WasmInstanceObject> instance,uint32_t minimum_size)736 bool WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
737 Handle<WasmInstanceObject> instance, uint32_t minimum_size) {
738 uint32_t old_size = instance->indirect_function_table_size();
739 if (old_size >= minimum_size) return false; // Nothing to do.
740
741 Isolate* isolate = instance->GetIsolate();
742 HandleScope scope(isolate);
743 auto native_allocations = GetNativeAllocations(*instance);
744 native_allocations->resize_indirect_function_table(isolate, instance,
745 minimum_size);
746 return true;
747 }
748
SetRawMemory(byte * mem_start,uint32_t mem_size)749 void WasmInstanceObject::SetRawMemory(byte* mem_start, uint32_t mem_size) {
750 DCHECK_LE(mem_size, wasm::kV8MaxWasmMemoryPages * wasm::kWasmPageSize);
751 uint32_t mem_size64 = mem_size;
752 uint32_t mem_mask64 = base::bits::RoundUpToPowerOfTwo32(mem_size) - 1;
753 DCHECK_LE(mem_size, mem_mask64 + 1);
754 set_memory_start(mem_start);
755 set_memory_size(mem_size64);
756 set_memory_mask(mem_mask64);
757 }
758
module()759 WasmModule* WasmInstanceObject::module() {
760 return module_object()->shared()->module();
761 }
762
GetOrCreateDebugInfo(Handle<WasmInstanceObject> instance)763 Handle<WasmDebugInfo> WasmInstanceObject::GetOrCreateDebugInfo(
764 Handle<WasmInstanceObject> instance) {
765 if (instance->has_debug_info()) return handle(instance->debug_info());
766 Handle<WasmDebugInfo> new_info = WasmDebugInfo::New(instance);
767 DCHECK(instance->has_debug_info());
768 return new_info;
769 }
770
New(Isolate * isolate,Handle<WasmModuleObject> module_object,Handle<WasmCompiledModule> compiled_module)771 Handle<WasmInstanceObject> WasmInstanceObject::New(
772 Isolate* isolate, Handle<WasmModuleObject> module_object,
773 Handle<WasmCompiledModule> compiled_module) {
774 Handle<JSFunction> instance_cons(
775 isolate->native_context()->wasm_instance_constructor());
776 Handle<JSObject> instance_object =
777 isolate->factory()->NewJSObject(instance_cons, TENURED);
778
779 Handle<WasmInstanceObject> instance(
780 reinterpret_cast<WasmInstanceObject*>(*instance_object), isolate);
781
782 // Initialize the imported function arrays.
783 auto num_imported_functions =
784 module_object->shared()->module()->num_imported_functions;
785 auto num_imported_mutable_globals =
786 module_object->shared()->module()->num_imported_mutable_globals;
787 auto native_allocations = Managed<WasmInstanceNativeAllocations>::Allocate(
788 isolate, instance, num_imported_functions, num_imported_mutable_globals);
789 instance->set_managed_native_allocations(*native_allocations);
790
791 Handle<FixedArray> imported_function_instances =
792 isolate->factory()->NewFixedArray(num_imported_functions);
793
794 instance->set_imported_function_instances(*imported_function_instances);
795 Handle<FixedArray> imported_function_callables =
796 isolate->factory()->NewFixedArray(num_imported_functions);
797
798 instance->set_imported_function_callables(*imported_function_callables);
799
800 instance->SetRawMemory(nullptr, 0);
801 instance->set_globals_start(nullptr);
802 instance->set_indirect_function_table_size(0);
803 instance->set_indirect_function_table_sig_ids(nullptr);
804 instance->set_indirect_function_table_targets(nullptr);
805 instance->set_compiled_module(*compiled_module);
806 instance->set_native_context(*isolate->native_context());
807 instance->set_module_object(*module_object);
808
809 return instance;
810 }
811
ValidateInstancesChainForTesting(Isolate * isolate,Handle<WasmModuleObject> module_obj,int instance_count)812 void WasmInstanceObject::ValidateInstancesChainForTesting(
813 Isolate* isolate, Handle<WasmModuleObject> module_obj, int instance_count) {
814 CHECK_GE(instance_count, 0);
815 DisallowHeapAllocation no_gc;
816 WasmCompiledModule* compiled_module = module_obj->compiled_module();
817 Object* prev = nullptr;
818 int found_instances = compiled_module->has_instance() ? 1 : 0;
819 WasmCompiledModule* current_instance = compiled_module;
820 while (current_instance->has_next_instance()) {
821 CHECK((prev == nullptr && !current_instance->has_prev_instance()) ||
822 current_instance->prev_instance() == prev);
823 CHECK(current_instance->weak_owning_instance()
824 ->value()
825 ->IsWasmInstanceObject());
826 prev = current_instance;
827 current_instance =
828 WasmCompiledModule::cast(current_instance->next_instance());
829 ++found_instances;
830 CHECK_LE(found_instances, instance_count);
831 }
832 CHECK_EQ(found_instances, instance_count);
833 }
834
835 namespace {
InstanceFinalizer(const v8::WeakCallbackInfo<void> & data)836 void InstanceFinalizer(const v8::WeakCallbackInfo<void>& data) {
837 DisallowHeapAllocation no_gc;
838 JSObject** p = reinterpret_cast<JSObject**>(data.GetParameter());
839 WasmInstanceObject* instance = reinterpret_cast<WasmInstanceObject*>(*p);
840 Isolate* isolate = reinterpret_cast<Isolate*>(data.GetIsolate());
841 // If a link to shared memory instances exists, update the list of memory
842 // instances before the instance is destroyed.
843 WasmCompiledModule* compiled_module = instance->compiled_module();
844 wasm::NativeModule* native_module = compiled_module->GetNativeModule();
845 if (native_module) {
846 TRACE("Finalizing %zu {\n", native_module->instance_id);
847 } else {
848 TRACE("Finalized already cleaned up compiled module\n");
849 }
850
851 // Since the order of finalizers is not guaranteed, it can be the case
852 // that {instance->compiled_module()->module()}, which is a
853 // {Managed<WasmModule>} has been collected earlier in this GC cycle.
854 // Weak references to this instance won't be cleared until
855 // the next GC cycle, so we need to manually break some links (such as
856 // the weak references from {WasmMemoryObject::instances}.
857 if (instance->has_memory_object()) {
858 WasmMemoryObject::RemoveInstance(isolate, handle(instance->memory_object()),
859 handle(instance));
860 }
861
862 // We want to maintain a link from the {WasmModuleObject} to the first link
863 // within the linked {WasmInstanceObject} list, even if the last instance is
864 // finalized. This allows us to clone new {WasmCompiledModule} objects during
865 // instantiation without having to regenerate the compiled module.
866 WasmModuleObject* module_object = instance->module_object();
867 WasmCompiledModule* current_template = module_object->compiled_module();
868 DCHECK(!current_template->has_prev_instance());
869 if (current_template == compiled_module) {
870 if (!compiled_module->has_next_instance()) {
871 WasmCompiledModule::Reset(isolate, compiled_module);
872 } else {
873 module_object->set_compiled_module(compiled_module->next_instance());
874 }
875 }
876
877 // Free raw C++ memory associated with the instance.
878 GetNativeAllocations(instance)->free();
879
880 compiled_module->RemoveFromChain();
881
882 GlobalHandles::Destroy(reinterpret_cast<Object**>(p));
883 TRACE("}\n");
884 }
885
886 } // namespace
887
InstallFinalizer(Isolate * isolate,Handle<WasmInstanceObject> instance)888 void WasmInstanceObject::InstallFinalizer(Isolate* isolate,
889 Handle<WasmInstanceObject> instance) {
890 Handle<Object> global_handle = isolate->global_handles()->Create(*instance);
891 GlobalHandles::MakeWeak(global_handle.location(), global_handle.location(),
892 InstanceFinalizer, v8::WeakCallbackType::kFinalizer);
893 }
894
GetCallTarget(uint32_t func_index)895 Address WasmInstanceObject::GetCallTarget(uint32_t func_index) {
896 wasm::NativeModule* native_module = compiled_module()->GetNativeModule();
897 if (func_index < native_module->num_imported_functions()) {
898 return imported_function_targets()[func_index];
899 }
900 return native_module->GetCallTargetForFunction(func_index);
901 }
902
IsWasmExportedFunction(Object * object)903 bool WasmExportedFunction::IsWasmExportedFunction(Object* object) {
904 if (!object->IsJSFunction()) return false;
905 Handle<JSFunction> js_function(JSFunction::cast(object));
906 if (Code::JS_TO_WASM_FUNCTION != js_function->code()->kind()) return false;
907 DCHECK(js_function->shared()->HasWasmExportedFunctionData());
908 return true;
909 }
910
cast(Object * object)911 WasmExportedFunction* WasmExportedFunction::cast(Object* object) {
912 DCHECK(IsWasmExportedFunction(object));
913 return reinterpret_cast<WasmExportedFunction*>(object);
914 }
915
instance()916 WasmInstanceObject* WasmExportedFunction::instance() {
917 return shared()->wasm_exported_function_data()->instance();
918 }
919
function_index()920 int WasmExportedFunction::function_index() {
921 return shared()->wasm_exported_function_data()->function_index();
922 }
923
New(Isolate * isolate,Handle<WasmInstanceObject> instance,MaybeHandle<String> maybe_name,int func_index,int arity,Handle<Code> export_wrapper)924 Handle<WasmExportedFunction> WasmExportedFunction::New(
925 Isolate* isolate, Handle<WasmInstanceObject> instance,
926 MaybeHandle<String> maybe_name, int func_index, int arity,
927 Handle<Code> export_wrapper) {
928 DCHECK_EQ(Code::JS_TO_WASM_FUNCTION, export_wrapper->kind());
929 Handle<WasmExportedFunctionData> function_data =
930 Handle<WasmExportedFunctionData>::cast(isolate->factory()->NewStruct(
931 WASM_EXPORTED_FUNCTION_DATA_TYPE, TENURED));
932 function_data->set_wrapper_code(*export_wrapper);
933 function_data->set_instance(*instance);
934 function_data->set_function_index(func_index);
935 Handle<String> name;
936 if (!maybe_name.ToHandle(&name)) {
937 EmbeddedVector<char, 16> buffer;
938 int length = SNPrintF(buffer, "%d", func_index);
939 name = isolate->factory()
940 ->NewStringFromOneByte(
941 Vector<uint8_t>::cast(buffer.SubVector(0, length)))
942 .ToHandleChecked();
943 }
944 NewFunctionArgs args = NewFunctionArgs::ForWasm(
945 name, function_data, isolate->sloppy_function_without_prototype_map());
946 Handle<JSFunction> js_function = isolate->factory()->NewFunction(args);
947 // According to the spec, exported functions should not have a [[Construct]]
948 // method.
949 DCHECK(!js_function->IsConstructor());
950 js_function->shared()->set_length(arity);
951 js_function->shared()->set_internal_formal_parameter_count(arity);
952 return Handle<WasmExportedFunction>::cast(js_function);
953 }
954
GetWasmCode()955 wasm::WasmCode* WasmExportedFunction::GetWasmCode() {
956 Address target = GetWasmCallTarget();
957 wasm::WasmCode* wasm_code =
958 GetIsolate()->wasm_engine()->code_manager()->LookupCode(target);
959 return wasm_code;
960 }
961
GetWasmCallTarget()962 Address WasmExportedFunction::GetWasmCallTarget() {
963 return instance()->GetCallTarget(function_index());
964 }
965
module() const966 WasmModule* WasmSharedModuleData::module() const {
967 return Managed<WasmModule>::cast(managed_module())->raw();
968 }
969
New(Isolate * isolate,Handle<Foreign> managed_module,Handle<SeqOneByteString> module_bytes,Handle<Script> script,Handle<ByteArray> asm_js_offset_table)970 Handle<WasmSharedModuleData> WasmSharedModuleData::New(
971 Isolate* isolate, Handle<Foreign> managed_module,
972 Handle<SeqOneByteString> module_bytes, Handle<Script> script,
973 Handle<ByteArray> asm_js_offset_table) {
974 Handle<WasmSharedModuleData> data = Handle<WasmSharedModuleData>::cast(
975 isolate->factory()->NewStruct(WASM_SHARED_MODULE_DATA_TYPE, TENURED));
976 data->set_managed_module(*managed_module);
977 if (!module_bytes.is_null()) {
978 data->set_module_bytes(*module_bytes);
979 }
980 if (!script.is_null()) {
981 data->set_script(*script);
982 }
983 if (!asm_js_offset_table.is_null()) {
984 data->set_asm_js_offset_table(*asm_js_offset_table);
985 }
986 return data;
987 }
988
is_asm_js()989 bool WasmSharedModuleData::is_asm_js() {
990 bool asm_js = module()->is_asm_js();
991 DCHECK_EQ(asm_js, script()->IsUserJavaScript());
992 DCHECK_EQ(asm_js, has_asm_js_offset_table());
993 return asm_js;
994 }
995
996 namespace {
997
GetBreakpointPos(Isolate * isolate,Object * break_point_info_or_undef)998 int GetBreakpointPos(Isolate* isolate, Object* break_point_info_or_undef) {
999 if (break_point_info_or_undef->IsUndefined(isolate)) return kMaxInt;
1000 return BreakPointInfo::cast(break_point_info_or_undef)->source_position();
1001 }
1002
FindBreakpointInfoInsertPos(Isolate * isolate,Handle<FixedArray> breakpoint_infos,int position)1003 int FindBreakpointInfoInsertPos(Isolate* isolate,
1004 Handle<FixedArray> breakpoint_infos,
1005 int position) {
1006 // Find insert location via binary search, taking care of undefined values on
1007 // the right. Position is always greater than zero.
1008 DCHECK_LT(0, position);
1009
1010 int left = 0; // inclusive
1011 int right = breakpoint_infos->length(); // exclusive
1012 while (right - left > 1) {
1013 int mid = left + (right - left) / 2;
1014 Object* mid_obj = breakpoint_infos->get(mid);
1015 if (GetBreakpointPos(isolate, mid_obj) <= position) {
1016 left = mid;
1017 } else {
1018 right = mid;
1019 }
1020 }
1021
1022 int left_pos = GetBreakpointPos(isolate, breakpoint_infos->get(left));
1023 return left_pos < position ? left + 1 : left;
1024 }
1025
1026 } // namespace
1027
AddBreakpoint(Handle<WasmSharedModuleData> shared,int position,Handle<BreakPoint> break_point)1028 void WasmSharedModuleData::AddBreakpoint(Handle<WasmSharedModuleData> shared,
1029 int position,
1030 Handle<BreakPoint> break_point) {
1031 Isolate* isolate = shared->GetIsolate();
1032 Handle<FixedArray> breakpoint_infos;
1033 if (shared->has_breakpoint_infos()) {
1034 breakpoint_infos = handle(shared->breakpoint_infos(), isolate);
1035 } else {
1036 breakpoint_infos = isolate->factory()->NewFixedArray(4, TENURED);
1037 shared->set_breakpoint_infos(*breakpoint_infos);
1038 }
1039
1040 int insert_pos =
1041 FindBreakpointInfoInsertPos(isolate, breakpoint_infos, position);
1042
1043 // If a BreakPointInfo object already exists for this position, add the new
1044 // breakpoint object and return.
1045 if (insert_pos < breakpoint_infos->length() &&
1046 GetBreakpointPos(isolate, breakpoint_infos->get(insert_pos)) ==
1047 position) {
1048 Handle<BreakPointInfo> old_info(
1049 BreakPointInfo::cast(breakpoint_infos->get(insert_pos)), isolate);
1050 BreakPointInfo::SetBreakPoint(old_info, break_point);
1051 return;
1052 }
1053
1054 // Enlarge break positions array if necessary.
1055 bool need_realloc = !breakpoint_infos->get(breakpoint_infos->length() - 1)
1056 ->IsUndefined(isolate);
1057 Handle<FixedArray> new_breakpoint_infos = breakpoint_infos;
1058 if (need_realloc) {
1059 new_breakpoint_infos = isolate->factory()->NewFixedArray(
1060 2 * breakpoint_infos->length(), TENURED);
1061 shared->set_breakpoint_infos(*new_breakpoint_infos);
1062 // Copy over the entries [0, insert_pos).
1063 for (int i = 0; i < insert_pos; ++i)
1064 new_breakpoint_infos->set(i, breakpoint_infos->get(i));
1065 }
1066
1067 // Move elements [insert_pos, ...] up by one.
1068 for (int i = breakpoint_infos->length() - 1; i >= insert_pos; --i) {
1069 Object* entry = breakpoint_infos->get(i);
1070 if (entry->IsUndefined(isolate)) continue;
1071 new_breakpoint_infos->set(i + 1, entry);
1072 }
1073
1074 // Generate new BreakpointInfo.
1075 Handle<BreakPointInfo> breakpoint_info =
1076 isolate->factory()->NewBreakPointInfo(position);
1077 BreakPointInfo::SetBreakPoint(breakpoint_info, break_point);
1078
1079 // Now insert new position at insert_pos.
1080 new_breakpoint_infos->set(insert_pos, *breakpoint_info);
1081 }
1082
SetBreakpointsOnNewInstance(Handle<WasmSharedModuleData> shared,Handle<WasmInstanceObject> instance)1083 void WasmSharedModuleData::SetBreakpointsOnNewInstance(
1084 Handle<WasmSharedModuleData> shared, Handle<WasmInstanceObject> instance) {
1085 if (!shared->has_breakpoint_infos()) return;
1086 Isolate* isolate = shared->GetIsolate();
1087 Handle<WasmDebugInfo> debug_info =
1088 WasmInstanceObject::GetOrCreateDebugInfo(instance);
1089
1090 Handle<FixedArray> breakpoint_infos(shared->breakpoint_infos(), isolate);
1091 // If the array exists, it should not be empty.
1092 DCHECK_LT(0, breakpoint_infos->length());
1093
1094 for (int i = 0, e = breakpoint_infos->length(); i < e; ++i) {
1095 Handle<Object> obj(breakpoint_infos->get(i), isolate);
1096 if (obj->IsUndefined(isolate)) {
1097 for (; i < e; ++i) {
1098 DCHECK(breakpoint_infos->get(i)->IsUndefined(isolate));
1099 }
1100 break;
1101 }
1102 Handle<BreakPointInfo> breakpoint_info = Handle<BreakPointInfo>::cast(obj);
1103 int position = breakpoint_info->source_position();
1104
1105 // Find the function for this breakpoint, and set the breakpoint.
1106 int func_index = shared->GetContainingFunction(position);
1107 DCHECK_LE(0, func_index);
1108 WasmFunction& func = shared->module()->functions[func_index];
1109 int offset_in_func = position - func.code.offset();
1110 WasmDebugInfo::SetBreakpoint(debug_info, func_index, offset_in_func);
1111 }
1112 }
1113
1114 namespace {
1115
1116 enum AsmJsOffsetTableEntryLayout {
1117 kOTEByteOffset,
1118 kOTECallPosition,
1119 kOTENumberConvPosition,
1120 kOTESize
1121 };
1122
GetDecodedAsmJsOffsetTable(Handle<WasmSharedModuleData> shared,Isolate * isolate)1123 Handle<ByteArray> GetDecodedAsmJsOffsetTable(
1124 Handle<WasmSharedModuleData> shared, Isolate* isolate) {
1125 DCHECK(shared->is_asm_js());
1126 Handle<ByteArray> offset_table(shared->asm_js_offset_table(), isolate);
1127
1128 // The last byte in the asm_js_offset_tables ByteArray tells whether it is
1129 // still encoded (0) or decoded (1).
1130 enum AsmJsTableType : int { Encoded = 0, Decoded = 1 };
1131 int table_type = offset_table->get(offset_table->length() - 1);
1132 DCHECK(table_type == Encoded || table_type == Decoded);
1133 if (table_type == Decoded) return offset_table;
1134
1135 wasm::AsmJsOffsetsResult asm_offsets;
1136 {
1137 DisallowHeapAllocation no_gc;
1138 byte* bytes_start = offset_table->GetDataStartAddress();
1139 byte* bytes_end = reinterpret_cast<byte*>(
1140 reinterpret_cast<Address>(bytes_start) + offset_table->length() - 1);
1141 asm_offsets = wasm::DecodeAsmJsOffsets(bytes_start, bytes_end);
1142 }
1143 // Wasm bytes must be valid and must contain asm.js offset table.
1144 DCHECK(asm_offsets.ok());
1145 DCHECK_GE(kMaxInt, asm_offsets.val.size());
1146 int num_functions = static_cast<int>(asm_offsets.val.size());
1147 int num_imported_functions =
1148 static_cast<int>(shared->module()->num_imported_functions);
1149 DCHECK_EQ(shared->module()->functions.size(),
1150 static_cast<size_t>(num_functions) + num_imported_functions);
1151 int num_entries = 0;
1152 for (int func = 0; func < num_functions; ++func) {
1153 size_t new_size = asm_offsets.val[func].size();
1154 DCHECK_LE(new_size, static_cast<size_t>(kMaxInt) - num_entries);
1155 num_entries += static_cast<int>(new_size);
1156 }
1157 // One byte to encode that this is a decoded table.
1158 DCHECK_GE(kMaxInt,
1159 1 + static_cast<uint64_t>(num_entries) * kOTESize * kIntSize);
1160 int total_size = 1 + num_entries * kOTESize * kIntSize;
1161 Handle<ByteArray> decoded_table =
1162 isolate->factory()->NewByteArray(total_size, TENURED);
1163 decoded_table->set(total_size - 1, AsmJsTableType::Decoded);
1164 shared->set_asm_js_offset_table(*decoded_table);
1165
1166 int idx = 0;
1167 std::vector<WasmFunction>& wasm_funs = shared->module()->functions;
1168 for (int func = 0; func < num_functions; ++func) {
1169 std::vector<wasm::AsmJsOffsetEntry>& func_asm_offsets =
1170 asm_offsets.val[func];
1171 if (func_asm_offsets.empty()) continue;
1172 int func_offset = wasm_funs[num_imported_functions + func].code.offset();
1173 for (wasm::AsmJsOffsetEntry& e : func_asm_offsets) {
1174 // Byte offsets must be strictly monotonously increasing:
1175 DCHECK_IMPLIES(idx > 0, func_offset + e.byte_offset >
1176 decoded_table->get_int(idx - kOTESize));
1177 decoded_table->set_int(idx + kOTEByteOffset, func_offset + e.byte_offset);
1178 decoded_table->set_int(idx + kOTECallPosition, e.source_position_call);
1179 decoded_table->set_int(idx + kOTENumberConvPosition,
1180 e.source_position_number_conversion);
1181 idx += kOTESize;
1182 }
1183 }
1184 DCHECK_EQ(total_size, idx * kIntSize + 1);
1185 return decoded_table;
1186 }
1187
1188 } // namespace
1189
GetSourcePosition(Handle<WasmSharedModuleData> shared,uint32_t func_index,uint32_t byte_offset,bool is_at_number_conversion)1190 int WasmSharedModuleData::GetSourcePosition(Handle<WasmSharedModuleData> shared,
1191 uint32_t func_index,
1192 uint32_t byte_offset,
1193 bool is_at_number_conversion) {
1194 Isolate* isolate = shared->GetIsolate();
1195 const WasmModule* module = shared->module();
1196
1197 if (!module->is_asm_js()) {
1198 // for non-asm.js modules, we just add the function's start offset
1199 // to make a module-relative position.
1200 return byte_offset + shared->GetFunctionOffset(func_index);
1201 }
1202
1203 // asm.js modules have an additional offset table that must be searched.
1204 Handle<ByteArray> offset_table = GetDecodedAsmJsOffsetTable(shared, isolate);
1205
1206 DCHECK_LT(func_index, module->functions.size());
1207 uint32_t func_code_offset = module->functions[func_index].code.offset();
1208 uint32_t total_offset = func_code_offset + byte_offset;
1209
1210 // Binary search for the total byte offset.
1211 int left = 0; // inclusive
1212 int right = offset_table->length() / kIntSize / kOTESize; // exclusive
1213 DCHECK_LT(left, right);
1214 while (right - left > 1) {
1215 int mid = left + (right - left) / 2;
1216 int mid_entry = offset_table->get_int(kOTESize * mid);
1217 DCHECK_GE(kMaxInt, mid_entry);
1218 if (static_cast<uint32_t>(mid_entry) <= total_offset) {
1219 left = mid;
1220 } else {
1221 right = mid;
1222 }
1223 }
1224 // There should be an entry for each position that could show up on the stack
1225 // trace:
1226 DCHECK_EQ(total_offset, offset_table->get_int(kOTESize * left));
1227 int idx = is_at_number_conversion ? kOTENumberConvPosition : kOTECallPosition;
1228 return offset_table->get_int(kOTESize * left + idx);
1229 }
1230
DisassembleFunction(int func_index)1231 v8::debug::WasmDisassembly WasmSharedModuleData::DisassembleFunction(
1232 int func_index) {
1233 DisallowHeapAllocation no_gc;
1234
1235 if (func_index < 0 ||
1236 static_cast<uint32_t>(func_index) >= module()->functions.size())
1237 return {};
1238
1239 SeqOneByteString* module_bytes_str = module_bytes();
1240 Vector<const byte> module_bytes(module_bytes_str->GetChars(),
1241 module_bytes_str->length());
1242
1243 std::ostringstream disassembly_os;
1244 v8::debug::WasmDisassembly::OffsetTable offset_table;
1245
1246 PrintWasmText(module(), module_bytes, static_cast<uint32_t>(func_index),
1247 disassembly_os, &offset_table);
1248
1249 return {disassembly_os.str(), std::move(offset_table)};
1250 }
1251
GetPossibleBreakpoints(const v8::debug::Location & start,const v8::debug::Location & end,std::vector<v8::debug::BreakLocation> * locations)1252 bool WasmSharedModuleData::GetPossibleBreakpoints(
1253 const v8::debug::Location& start, const v8::debug::Location& end,
1254 std::vector<v8::debug::BreakLocation>* locations) {
1255 DisallowHeapAllocation no_gc;
1256
1257 std::vector<WasmFunction>& functions = module()->functions;
1258 if (start.GetLineNumber() < 0 || start.GetColumnNumber() < 0 ||
1259 (!end.IsEmpty() &&
1260 (end.GetLineNumber() < 0 || end.GetColumnNumber() < 0)))
1261 return false;
1262
1263 // start_func_index, start_offset and end_func_index is inclusive.
1264 // end_offset is exclusive.
1265 // start_offset and end_offset are module-relative byte offsets.
1266 uint32_t start_func_index = start.GetLineNumber();
1267 if (start_func_index >= functions.size()) return false;
1268 int start_func_len = functions[start_func_index].code.length();
1269 if (start.GetColumnNumber() > start_func_len) return false;
1270 uint32_t start_offset =
1271 functions[start_func_index].code.offset() + start.GetColumnNumber();
1272 uint32_t end_func_index;
1273 uint32_t end_offset;
1274 if (end.IsEmpty()) {
1275 // Default: everything till the end of the Script.
1276 end_func_index = static_cast<uint32_t>(functions.size() - 1);
1277 end_offset = functions[end_func_index].code.end_offset();
1278 } else {
1279 // If end is specified: Use it and check for valid input.
1280 end_func_index = static_cast<uint32_t>(end.GetLineNumber());
1281
1282 // Special case: Stop before the start of the next function. Change to: Stop
1283 // at the end of the function before, such that we don't disassemble the
1284 // next function also.
1285 if (end.GetColumnNumber() == 0 && end_func_index > 0) {
1286 --end_func_index;
1287 end_offset = functions[end_func_index].code.end_offset();
1288 } else {
1289 if (end_func_index >= functions.size()) return false;
1290 end_offset =
1291 functions[end_func_index].code.offset() + end.GetColumnNumber();
1292 if (end_offset > functions[end_func_index].code.end_offset())
1293 return false;
1294 }
1295 }
1296
1297 AccountingAllocator alloc;
1298 Zone tmp(&alloc, ZONE_NAME);
1299 const byte* module_start = module_bytes()->GetChars();
1300
1301 for (uint32_t func_idx = start_func_index; func_idx <= end_func_index;
1302 ++func_idx) {
1303 WasmFunction& func = functions[func_idx];
1304 if (func.code.length() == 0) continue;
1305
1306 wasm::BodyLocalDecls locals(&tmp);
1307 wasm::BytecodeIterator iterator(module_start + func.code.offset(),
1308 module_start + func.code.end_offset(),
1309 &locals);
1310 DCHECK_LT(0u, locals.encoded_size);
1311 for (uint32_t offset : iterator.offsets()) {
1312 uint32_t total_offset = func.code.offset() + offset;
1313 if (total_offset >= end_offset) {
1314 DCHECK_EQ(end_func_index, func_idx);
1315 break;
1316 }
1317 if (total_offset < start_offset) continue;
1318 locations->emplace_back(func_idx, offset, debug::kCommonBreakLocation);
1319 }
1320 }
1321 return true;
1322 }
1323
CheckBreakPoints(Isolate * isolate,Handle<WasmSharedModuleData> shared,int position)1324 MaybeHandle<FixedArray> WasmSharedModuleData::CheckBreakPoints(
1325 Isolate* isolate, Handle<WasmSharedModuleData> shared, int position) {
1326 if (!shared->has_breakpoint_infos()) return {};
1327
1328 Handle<FixedArray> breakpoint_infos(shared->breakpoint_infos(), isolate);
1329 int insert_pos =
1330 FindBreakpointInfoInsertPos(isolate, breakpoint_infos, position);
1331 if (insert_pos >= breakpoint_infos->length()) return {};
1332
1333 Handle<Object> maybe_breakpoint_info(breakpoint_infos->get(insert_pos),
1334 isolate);
1335 if (maybe_breakpoint_info->IsUndefined(isolate)) return {};
1336 Handle<BreakPointInfo> breakpoint_info =
1337 Handle<BreakPointInfo>::cast(maybe_breakpoint_info);
1338 if (breakpoint_info->source_position() != position) return {};
1339
1340 // There is no support for conditional break points. Just assume that every
1341 // break point always hits.
1342 Handle<Object> break_points(breakpoint_info->break_points(), isolate);
1343 if (break_points->IsFixedArray()) {
1344 return Handle<FixedArray>::cast(break_points);
1345 }
1346 Handle<FixedArray> break_points_hit = isolate->factory()->NewFixedArray(1);
1347 break_points_hit->set(0, *break_points);
1348 return break_points_hit;
1349 }
1350
New(Isolate * isolate,WasmModule * module,wasm::ModuleEnv & env)1351 Handle<WasmCompiledModule> WasmCompiledModule::New(Isolate* isolate,
1352 WasmModule* module,
1353 wasm::ModuleEnv& env) {
1354 Handle<WasmCompiledModule> compiled_module = Handle<WasmCompiledModule>::cast(
1355 isolate->factory()->NewStruct(WASM_COMPILED_MODULE_TYPE, TENURED));
1356 compiled_module->set_weak_owning_instance(isolate->heap()->empty_weak_cell());
1357 {
1358 auto native_module =
1359 isolate->wasm_engine()->code_manager()->NewNativeModule(*module, env);
1360 Handle<Foreign> native_module_wrapper =
1361 Managed<wasm::NativeModule>::FromUniquePtr(isolate,
1362 std::move(native_module));
1363 compiled_module->set_native_module(*native_module_wrapper);
1364 }
1365
1366 // TODO(mtrofin): copy the rest of the specialization parameters over.
1367 // We're currently OK because we're only using defaults.
1368 return compiled_module;
1369 }
1370
Clone(Isolate * isolate,Handle<WasmCompiledModule> module)1371 Handle<WasmCompiledModule> WasmCompiledModule::Clone(
1372 Isolate* isolate, Handle<WasmCompiledModule> module) {
1373 Handle<FixedArray> code_copy;
1374 Handle<WasmCompiledModule> ret = Handle<WasmCompiledModule>::cast(
1375 isolate->factory()->NewStruct(WASM_COMPILED_MODULE_TYPE, TENURED));
1376 ret->set_weak_owning_instance(isolate->heap()->empty_weak_cell());
1377 ret->set_native_module(module->native_module());
1378
1379 // construct the wrapper in 2 steps, because its construction may trigger GC,
1380 // which would shift the this pointer in set_native_module.
1381 Handle<Foreign> native_module_wrapper =
1382 Managed<wasm::NativeModule>::FromSharedPtr(
1383 isolate,
1384 Managed<wasm::NativeModule>::cast(module->native_module())->get());
1385 ret->set_native_module(*native_module_wrapper);
1386
1387 return ret;
1388 }
1389
GetNativeModule() const1390 wasm::NativeModule* WasmCompiledModule::GetNativeModule() const {
1391 if (!has_native_module()) return nullptr;
1392 return Managed<wasm::NativeModule>::cast(native_module())->raw();
1393 }
1394
Reset(Isolate * isolate,WasmCompiledModule * compiled_module)1395 void WasmCompiledModule::Reset(Isolate* isolate,
1396 WasmCompiledModule* compiled_module) {
1397 DisallowHeapAllocation no_gc;
1398 compiled_module->reset_prev_instance();
1399 compiled_module->reset_next_instance();
1400 wasm::NativeModule* native_module = compiled_module->GetNativeModule();
1401 if (native_module == nullptr) return;
1402 native_module->SetExecutable(false);
1403
1404 TRACE("Resetting %zu\n", native_module->instance_id);
1405 if (native_module->use_trap_handler()) {
1406 native_module->ReleaseProtectedInstructions();
1407 }
1408 }
1409
ExtractUtf8StringFromModuleBytes(Isolate * isolate,Handle<WasmSharedModuleData> shared,wasm::WireBytesRef ref)1410 MaybeHandle<String> WasmSharedModuleData::ExtractUtf8StringFromModuleBytes(
1411 Isolate* isolate, Handle<WasmSharedModuleData> shared,
1412 wasm::WireBytesRef ref) {
1413 // TODO(wasm): cache strings from modules if it's a performance win.
1414 Handle<SeqOneByteString> module_bytes(shared->module_bytes(), isolate);
1415 return ExtractUtf8StringFromModuleBytes(isolate, module_bytes, ref);
1416 }
1417
ExtractUtf8StringFromModuleBytes(Isolate * isolate,Handle<SeqOneByteString> module_bytes,wasm::WireBytesRef ref)1418 MaybeHandle<String> WasmSharedModuleData::ExtractUtf8StringFromModuleBytes(
1419 Isolate* isolate, Handle<SeqOneByteString> module_bytes,
1420 wasm::WireBytesRef ref) {
1421 DCHECK_GE(module_bytes->length(), ref.end_offset());
1422 // UTF8 validation happens at decode time.
1423 DCHECK(unibrow::Utf8::ValidateEncoding(
1424 reinterpret_cast<const byte*>(module_bytes->GetCharsAddress() +
1425 ref.offset()),
1426 ref.length()));
1427 DCHECK_GE(kMaxInt, ref.offset());
1428 DCHECK_GE(kMaxInt, ref.length());
1429 return isolate->factory()->NewStringFromUtf8SubString(
1430 module_bytes, static_cast<int>(ref.offset()),
1431 static_cast<int>(ref.length()));
1432 }
1433
PrintInstancesChain()1434 void WasmCompiledModule::PrintInstancesChain() {
1435 #if DEBUG
1436 if (!FLAG_trace_wasm_instances) return;
1437 for (WasmCompiledModule* current = this; current != nullptr;) {
1438 PrintF("->%zu", current->GetNativeModule()->instance_id);
1439 if (!current->has_next_instance()) break;
1440 current = current->next_instance();
1441 }
1442 PrintF("\n");
1443 #endif
1444 }
1445
InsertInChain(WasmModuleObject * module)1446 void WasmCompiledModule::InsertInChain(WasmModuleObject* module) {
1447 DisallowHeapAllocation no_gc;
1448 WasmCompiledModule* original = module->compiled_module();
1449 set_next_instance(original);
1450 original->set_prev_instance(this);
1451 }
1452
RemoveFromChain()1453 void WasmCompiledModule::RemoveFromChain() {
1454 DisallowHeapAllocation no_gc;
1455 Isolate* isolate = GetIsolate();
1456
1457 Object* next = raw_next_instance();
1458 Object* prev = raw_prev_instance();
1459
1460 if (!prev->IsUndefined(isolate)) {
1461 WasmCompiledModule::cast(prev)->set_raw_next_instance(next);
1462 }
1463 if (!next->IsUndefined(isolate)) {
1464 WasmCompiledModule::cast(next)->set_raw_prev_instance(prev);
1465 }
1466 }
1467
GetModuleNameOrNull(Isolate * isolate,Handle<WasmSharedModuleData> shared)1468 MaybeHandle<String> WasmSharedModuleData::GetModuleNameOrNull(
1469 Isolate* isolate, Handle<WasmSharedModuleData> shared) {
1470 WasmModule* module = shared->module();
1471 if (!module->name.is_set()) return {};
1472 return ExtractUtf8StringFromModuleBytes(isolate, shared, module->name);
1473 }
1474
GetFunctionNameOrNull(Isolate * isolate,Handle<WasmSharedModuleData> shared,uint32_t func_index)1475 MaybeHandle<String> WasmSharedModuleData::GetFunctionNameOrNull(
1476 Isolate* isolate, Handle<WasmSharedModuleData> shared,
1477 uint32_t func_index) {
1478 DCHECK_LT(func_index, shared->module()->functions.size());
1479 wasm::WireBytesRef name =
1480 shared->module()->LookupName(shared->module_bytes(), func_index);
1481 if (!name.is_set()) return {};
1482 return ExtractUtf8StringFromModuleBytes(isolate, shared, name);
1483 }
1484
GetFunctionName(Isolate * isolate,Handle<WasmSharedModuleData> shared,uint32_t func_index)1485 Handle<String> WasmSharedModuleData::GetFunctionName(
1486 Isolate* isolate, Handle<WasmSharedModuleData> shared,
1487 uint32_t func_index) {
1488 MaybeHandle<String> name = GetFunctionNameOrNull(isolate, shared, func_index);
1489 if (!name.is_null()) return name.ToHandleChecked();
1490 return isolate->factory()->NewStringFromStaticChars("<WASM UNNAMED>");
1491 }
1492
GetRawFunctionName(uint32_t func_index)1493 Vector<const uint8_t> WasmSharedModuleData::GetRawFunctionName(
1494 uint32_t func_index) {
1495 DCHECK_GT(module()->functions.size(), func_index);
1496 SeqOneByteString* bytes = module_bytes();
1497 wasm::WireBytesRef name = module()->LookupName(bytes, func_index);
1498 DCHECK_GE(bytes->length(), name.end_offset());
1499 return Vector<const uint8_t>(
1500 reinterpret_cast<uint8_t*>(bytes->GetCharsAddress() + name.offset()),
1501 name.length());
1502 }
1503
GetFunctionOffset(uint32_t func_index)1504 int WasmSharedModuleData::GetFunctionOffset(uint32_t func_index) {
1505 std::vector<WasmFunction>& functions = module()->functions;
1506 if (static_cast<uint32_t>(func_index) >= functions.size()) return -1;
1507 DCHECK_GE(kMaxInt, functions[func_index].code.offset());
1508 return static_cast<int>(functions[func_index].code.offset());
1509 }
1510
GetContainingFunction(uint32_t byte_offset)1511 int WasmSharedModuleData::GetContainingFunction(uint32_t byte_offset) {
1512 std::vector<WasmFunction>& functions = module()->functions;
1513
1514 // Binary search for a function containing the given position.
1515 int left = 0; // inclusive
1516 int right = static_cast<int>(functions.size()); // exclusive
1517 if (right == 0) return false;
1518 while (right - left > 1) {
1519 int mid = left + (right - left) / 2;
1520 if (functions[mid].code.offset() <= byte_offset) {
1521 left = mid;
1522 } else {
1523 right = mid;
1524 }
1525 }
1526 // If the found function does not contains the given position, return -1.
1527 WasmFunction& func = functions[left];
1528 if (byte_offset < func.code.offset() ||
1529 byte_offset >= func.code.end_offset()) {
1530 return -1;
1531 }
1532
1533 return left;
1534 }
1535
GetPositionInfo(uint32_t position,Script::PositionInfo * info)1536 bool WasmSharedModuleData::GetPositionInfo(uint32_t position,
1537 Script::PositionInfo* info) {
1538 int func_index = GetContainingFunction(position);
1539 if (func_index < 0) return false;
1540
1541 WasmFunction& function = module()->functions[func_index];
1542
1543 info->line = func_index;
1544 info->column = position - function.code.offset();
1545 info->line_start = function.code.offset();
1546 info->line_end = function.code.end_offset();
1547 return true;
1548 }
1549
LogWasmCodes(Isolate * isolate)1550 void WasmCompiledModule::LogWasmCodes(Isolate* isolate) {
1551 if (!wasm::WasmCode::ShouldBeLogged(isolate)) return;
1552
1553 wasm::NativeModule* native_module = GetNativeModule();
1554 if (native_module == nullptr) return;
1555 // TODO(titzer): we skip the logging of the import wrappers
1556 // here, but they should be included somehow.
1557 const uint32_t start =
1558 native_module->shared_module_data()->module()->num_imported_functions;
1559 const uint32_t number_of_codes = native_module->function_count();
1560 for (uint32_t i = start; i < number_of_codes; i++) {
1561 wasm::WasmCode* code = native_module->code(i);
1562 if (code == nullptr) continue;
1563 code->LogCode(isolate);
1564 }
1565 }
1566
1567 #undef TRACE
1568 #undef TRACE_IFT
1569 } // namespace internal
1570 } // namespace v8
1571