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