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/base/iterator.h"
9#include "src/debug/debug-interface.h"
10#include "src/objects-inl.h"
11#include "src/wasm/module-decoder.h"
12#include "src/wasm/wasm-module.h"
13#include "src/wasm/wasm-text.h"
14
15#define TRACE(...)                                      \
16  do {                                                  \
17    if (FLAG_trace_wasm_instances) PrintF(__VA_ARGS__); \
18  } while (false)
19
20#define TRACE_CHAIN(instance)        \
21  do {                               \
22    instance->PrintInstancesChain(); \
23  } while (false)
24
25using namespace v8::internal;
26using namespace v8::internal::wasm;
27
28#define DEFINE_GETTER0(getter, Container, name, field, type) \
29  type* Container::name() { return type::cast(getter(field)); }
30
31#define DEFINE_ACCESSORS0(getter, setter, Container, name, field, type) \
32  DEFINE_GETTER0(getter, Container, name, field, type)                  \
33  void Container::set_##name(type* value) { return setter(field, value); }
34
35#define DEFINE_OPTIONAL_ACCESSORS0(getter, setter, Container, name, field, \
36                                   type)                                   \
37  DEFINE_ACCESSORS0(getter, setter, Container, name, field, type)          \
38  bool Container::has_##name() {                                           \
39    return !getter(field)->IsUndefined(GetIsolate());                      \
40  }
41
42#define DEFINE_OPTIONAL_GETTER0(getter, Container, name, field, type) \
43  DEFINE_GETTER0(getter, Container, name, field, type)                \
44  bool Container::has_##name() {                                      \
45    return !getter(field)->IsUndefined(GetIsolate());                 \
46  }
47
48#define DEFINE_GETTER0(getter, Container, name, field, type) \
49  type* Container::name() { return type::cast(getter(field)); }
50
51#define DEFINE_OBJ_GETTER(Container, name, field, type) \
52  DEFINE_GETTER0(GetInternalField, Container, name, field, type)
53#define DEFINE_OBJ_ACCESSORS(Container, name, field, type)               \
54  DEFINE_ACCESSORS0(GetInternalField, SetInternalField, Container, name, \
55                    field, type)
56#define DEFINE_OPTIONAL_OBJ_ACCESSORS(Container, name, field, type)         \
57  DEFINE_OPTIONAL_ACCESSORS0(GetInternalField, SetInternalField, Container, \
58                             name, field, type)
59#define DEFINE_ARR_GETTER(Container, name, field, type) \
60  DEFINE_GETTER0(get, Container, name, field, type)
61#define DEFINE_ARR_ACCESSORS(Container, name, field, type) \
62  DEFINE_ACCESSORS0(get, set, Container, name, field, type)
63#define DEFINE_OPTIONAL_ARR_ACCESSORS(Container, name, field, type) \
64  DEFINE_OPTIONAL_ACCESSORS0(get, set, Container, name, field, type)
65#define DEFINE_OPTIONAL_ARR_GETTER(Container, name, field, type) \
66  DEFINE_OPTIONAL_GETTER0(get, Container, name, field, type)
67
68namespace {
69
70uint32_t SafeUint32(Object* value) {
71  if (value->IsSmi()) {
72    int32_t val = Smi::cast(value)->value();
73    CHECK_GE(val, 0);
74    return static_cast<uint32_t>(val);
75  }
76  DCHECK(value->IsHeapNumber());
77  HeapNumber* num = HeapNumber::cast(value);
78  CHECK_GE(num->value(), 0.0);
79  CHECK_LE(num->value(), kMaxUInt32);
80  return static_cast<uint32_t>(num->value());
81}
82
83int32_t SafeInt32(Object* value) {
84  if (value->IsSmi()) {
85    return Smi::cast(value)->value();
86  }
87  DCHECK(value->IsHeapNumber());
88  HeapNumber* num = HeapNumber::cast(value);
89  CHECK_GE(num->value(), Smi::kMinValue);
90  CHECK_LE(num->value(), Smi::kMaxValue);
91  return static_cast<int32_t>(num->value());
92}
93
94// An iterator that returns first the module itself, then all modules linked via
95// next, then all linked via prev.
96class CompiledModulesIterator
97    : public std::iterator<std::input_iterator_tag,
98                           Handle<WasmCompiledModule>> {
99 public:
100  CompiledModulesIterator(Isolate* isolate,
101                          Handle<WasmCompiledModule> start_module, bool at_end)
102      : isolate_(isolate),
103        start_module_(start_module),
104        current_(at_end ? Handle<WasmCompiledModule>::null() : start_module) {}
105
106  Handle<WasmCompiledModule> operator*() const {
107    DCHECK(!current_.is_null());
108    return current_;
109  }
110
111  void operator++() { Advance(); }
112
113  bool operator!=(const CompiledModulesIterator& other) {
114    DCHECK(start_module_.is_identical_to(other.start_module_));
115    return !current_.is_identical_to(other.current_);
116  }
117
118 private:
119  void Advance() {
120    DCHECK(!current_.is_null());
121    if (!is_backwards_) {
122      if (current_->has_weak_next_instance()) {
123        WeakCell* weak_next = current_->ptr_to_weak_next_instance();
124        if (!weak_next->cleared()) {
125          current_ =
126              handle(WasmCompiledModule::cast(weak_next->value()), isolate_);
127          return;
128        }
129      }
130      // No more modules in next-links, now try the previous-links.
131      is_backwards_ = true;
132      current_ = start_module_;
133    }
134    if (current_->has_weak_prev_instance()) {
135      WeakCell* weak_prev = current_->ptr_to_weak_prev_instance();
136      if (!weak_prev->cleared()) {
137        current_ =
138            handle(WasmCompiledModule::cast(weak_prev->value()), isolate_);
139        return;
140      }
141    }
142    current_ = Handle<WasmCompiledModule>::null();
143  }
144
145  friend class CompiledModuleInstancesIterator;
146  Isolate* isolate_;
147  Handle<WasmCompiledModule> start_module_;
148  Handle<WasmCompiledModule> current_;
149  bool is_backwards_ = false;
150};
151
152// An iterator based on the CompiledModulesIterator, but it returns all live
153// instances, not the WasmCompiledModules itself.
154class CompiledModuleInstancesIterator
155    : public std::iterator<std::input_iterator_tag,
156                           Handle<WasmInstanceObject>> {
157 public:
158  CompiledModuleInstancesIterator(Isolate* isolate,
159                                  Handle<WasmCompiledModule> start_module,
160                                  bool at_end)
161      : it(isolate, start_module, at_end) {
162    while (NeedToAdvance()) ++it;
163  }
164
165  Handle<WasmInstanceObject> operator*() {
166    return handle(
167        WasmInstanceObject::cast((*it)->weak_owning_instance()->value()),
168        it.isolate_);
169  }
170
171  void operator++() {
172    do {
173      ++it;
174    } while (NeedToAdvance());
175  }
176
177  bool operator!=(const CompiledModuleInstancesIterator& other) {
178    return it != other.it;
179  }
180
181 private:
182  bool NeedToAdvance() {
183    return !it.current_.is_null() &&
184           (!it.current_->has_weak_owning_instance() ||
185            it.current_->ptr_to_weak_owning_instance()->cleared());
186  }
187  CompiledModulesIterator it;
188};
189
190v8::base::iterator_range<CompiledModuleInstancesIterator>
191iterate_compiled_module_instance_chain(
192    Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
193  return {CompiledModuleInstancesIterator(isolate, compiled_module, false),
194          CompiledModuleInstancesIterator(isolate, compiled_module, true)};
195}
196
197#ifdef DEBUG
198bool IsBreakablePosition(Handle<WasmCompiledModule> compiled_module,
199                         int func_index, int offset_in_func) {
200  DisallowHeapAllocation no_gc;
201  AccountingAllocator alloc;
202  Zone tmp(&alloc, ZONE_NAME);
203  BodyLocalDecls locals(&tmp);
204  const byte* module_start = compiled_module->module_bytes()->GetChars();
205  WasmFunction& func = compiled_module->module()->functions[func_index];
206  BytecodeIterator iterator(module_start + func.code_start_offset,
207                            module_start + func.code_end_offset, &locals);
208  DCHECK_LT(0, locals.encoded_size);
209  for (uint32_t offset : iterator.offsets()) {
210    if (offset > static_cast<uint32_t>(offset_in_func)) break;
211    if (offset == static_cast<uint32_t>(offset_in_func)) return true;
212  }
213  return false;
214}
215#endif  // DEBUG
216
217}  // namespace
218
219Handle<WasmModuleObject> WasmModuleObject::New(
220    Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
221  ModuleOrigin origin = compiled_module->module()->origin;
222
223  Handle<JSObject> module_object;
224  if (origin == ModuleOrigin::kWasmOrigin) {
225    Handle<JSFunction> module_cons(
226        isolate->native_context()->wasm_module_constructor());
227    module_object = isolate->factory()->NewJSObject(module_cons);
228    Handle<Symbol> module_sym(isolate->native_context()->wasm_module_sym());
229    Object::SetProperty(module_object, module_sym, module_object, STRICT)
230        .Check();
231  } else {
232    DCHECK(origin == ModuleOrigin::kAsmJsOrigin);
233    Handle<Map> map = isolate->factory()->NewMap(
234        JS_OBJECT_TYPE,
235        JSObject::kHeaderSize + WasmModuleObject::kFieldCount * kPointerSize);
236    module_object = isolate->factory()->NewJSObjectFromMap(map, TENURED);
237  }
238  module_object->SetInternalField(WasmModuleObject::kCompiledModule,
239                                  *compiled_module);
240  Handle<WeakCell> link_to_module =
241      isolate->factory()->NewWeakCell(module_object);
242  compiled_module->set_weak_wasm_module(link_to_module);
243  return Handle<WasmModuleObject>::cast(module_object);
244}
245
246WasmModuleObject* WasmModuleObject::cast(Object* object) {
247  DCHECK(object->IsJSObject());
248  // TODO(titzer): brand check for WasmModuleObject.
249  return reinterpret_cast<WasmModuleObject*>(object);
250}
251
252bool WasmModuleObject::IsWasmModuleObject(Object* object) {
253  return object->IsJSObject() &&
254         JSObject::cast(object)->GetInternalFieldCount() == kFieldCount;
255}
256
257DEFINE_OBJ_GETTER(WasmModuleObject, compiled_module, kCompiledModule,
258                  WasmCompiledModule)
259
260Handle<WasmTableObject> WasmTableObject::New(Isolate* isolate, uint32_t initial,
261                                             int64_t maximum,
262                                             Handle<FixedArray>* js_functions) {
263  Handle<JSFunction> table_ctor(
264      isolate->native_context()->wasm_table_constructor());
265  Handle<JSObject> table_obj = isolate->factory()->NewJSObject(table_ctor);
266  *js_functions = isolate->factory()->NewFixedArray(initial);
267  Object* null = isolate->heap()->null_value();
268  for (int i = 0; i < static_cast<int>(initial); ++i) {
269    (*js_functions)->set(i, null);
270  }
271  table_obj->SetInternalField(kFunctions, *(*js_functions));
272  Handle<Object> max = isolate->factory()->NewNumber(maximum);
273  table_obj->SetInternalField(kMaximum, *max);
274
275  Handle<FixedArray> dispatch_tables = isolate->factory()->NewFixedArray(0);
276  table_obj->SetInternalField(kDispatchTables, *dispatch_tables);
277  Handle<Symbol> table_sym(isolate->native_context()->wasm_table_sym());
278  Object::SetProperty(table_obj, table_sym, table_obj, STRICT).Check();
279  return Handle<WasmTableObject>::cast(table_obj);
280}
281
282DEFINE_OBJ_GETTER(WasmTableObject, dispatch_tables, kDispatchTables, FixedArray)
283
284Handle<FixedArray> WasmTableObject::AddDispatchTable(
285    Isolate* isolate, Handle<WasmTableObject> table_obj,
286    Handle<WasmInstanceObject> instance, int table_index,
287    Handle<FixedArray> function_table, Handle<FixedArray> signature_table) {
288  Handle<FixedArray> dispatch_tables(
289      FixedArray::cast(table_obj->GetInternalField(kDispatchTables)), isolate);
290  DCHECK_EQ(0, dispatch_tables->length() % 4);
291
292  if (instance.is_null()) return dispatch_tables;
293  // TODO(titzer): use weak cells here to avoid leaking instances.
294
295  // Grow the dispatch table and add a new triple at the end.
296  Handle<FixedArray> new_dispatch_tables =
297      isolate->factory()->CopyFixedArrayAndGrow(dispatch_tables, 4);
298
299  new_dispatch_tables->set(dispatch_tables->length() + 0, *instance);
300  new_dispatch_tables->set(dispatch_tables->length() + 1,
301                           Smi::FromInt(table_index));
302  new_dispatch_tables->set(dispatch_tables->length() + 2, *function_table);
303  new_dispatch_tables->set(dispatch_tables->length() + 3, *signature_table);
304
305  table_obj->SetInternalField(WasmTableObject::kDispatchTables,
306                              *new_dispatch_tables);
307
308  return new_dispatch_tables;
309}
310
311DEFINE_OBJ_ACCESSORS(WasmTableObject, functions, kFunctions, FixedArray)
312
313uint32_t WasmTableObject::current_length() { return functions()->length(); }
314
315bool WasmTableObject::has_maximum_length() {
316  return GetInternalField(kMaximum)->Number() >= 0;
317}
318
319int64_t WasmTableObject::maximum_length() {
320  return static_cast<int64_t>(GetInternalField(kMaximum)->Number());
321}
322
323WasmTableObject* WasmTableObject::cast(Object* object) {
324  DCHECK(object && object->IsJSObject());
325  // TODO(titzer): brand check for WasmTableObject.
326  return reinterpret_cast<WasmTableObject*>(object);
327}
328
329void WasmTableObject::Grow(Isolate* isolate, Handle<WasmTableObject> table,
330                           uint32_t count) {
331  Handle<FixedArray> dispatch_tables(table->dispatch_tables());
332  wasm::GrowDispatchTables(isolate, dispatch_tables,
333                           table->functions()->length(), count);
334}
335
336Handle<WasmMemoryObject> WasmMemoryObject::New(Isolate* isolate,
337                                               Handle<JSArrayBuffer> buffer,
338                                               int32_t maximum) {
339  Handle<JSFunction> memory_ctor(
340      isolate->native_context()->wasm_memory_constructor());
341  Handle<JSObject> memory_obj =
342      isolate->factory()->NewJSObject(memory_ctor, TENURED);
343  memory_obj->SetInternalField(kArrayBuffer, *buffer);
344  Handle<Object> max = isolate->factory()->NewNumber(maximum);
345  memory_obj->SetInternalField(kMaximum, *max);
346  Handle<Symbol> memory_sym(isolate->native_context()->wasm_memory_sym());
347  Object::SetProperty(memory_obj, memory_sym, memory_obj, STRICT).Check();
348  return Handle<WasmMemoryObject>::cast(memory_obj);
349}
350
351DEFINE_OBJ_ACCESSORS(WasmMemoryObject, buffer, kArrayBuffer, JSArrayBuffer)
352DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmMemoryObject, instances_link, kInstancesLink,
353                              WasmInstanceWrapper)
354
355uint32_t WasmMemoryObject::current_pages() {
356  return SafeUint32(buffer()->byte_length()) / wasm::WasmModule::kPageSize;
357}
358
359bool WasmMemoryObject::has_maximum_pages() {
360  return GetInternalField(kMaximum)->Number() >= 0;
361}
362
363int32_t WasmMemoryObject::maximum_pages() {
364  return static_cast<int32_t>(GetInternalField(kMaximum)->Number());
365}
366
367WasmMemoryObject* WasmMemoryObject::cast(Object* object) {
368  DCHECK(object && object->IsJSObject());
369  // TODO(titzer): brand check for WasmMemoryObject.
370  return reinterpret_cast<WasmMemoryObject*>(object);
371}
372
373void WasmMemoryObject::AddInstance(Isolate* isolate,
374                                   Handle<WasmInstanceObject> instance) {
375  Handle<WasmInstanceWrapper> instance_wrapper =
376      handle(instance->instance_wrapper());
377  if (has_instances_link()) {
378    Handle<WasmInstanceWrapper> current_wrapper(instances_link());
379    DCHECK(WasmInstanceWrapper::IsWasmInstanceWrapper(*current_wrapper));
380    DCHECK(!current_wrapper->has_previous());
381    instance_wrapper->set_next_wrapper(*current_wrapper);
382    current_wrapper->set_previous_wrapper(*instance_wrapper);
383  }
384  set_instances_link(*instance_wrapper);
385}
386
387void WasmMemoryObject::ResetInstancesLink(Isolate* isolate) {
388  Handle<Object> undefined = isolate->factory()->undefined_value();
389  SetInternalField(kInstancesLink, *undefined);
390}
391
392DEFINE_OBJ_ACCESSORS(WasmInstanceObject, compiled_module, kCompiledModule,
393                     WasmCompiledModule)
394DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, globals_buffer,
395                              kGlobalsArrayBuffer, JSArrayBuffer)
396DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, memory_buffer,
397                              kMemoryArrayBuffer, JSArrayBuffer)
398DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, memory_object, kMemoryObject,
399                              WasmMemoryObject)
400DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, debug_info, kDebugInfo,
401                              WasmDebugInfo)
402DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, instance_wrapper,
403                              kWasmMemInstanceWrapper, WasmInstanceWrapper)
404
405WasmModuleObject* WasmInstanceObject::module_object() {
406  return *compiled_module()->wasm_module();
407}
408
409WasmModule* WasmInstanceObject::module() { return compiled_module()->module(); }
410
411Handle<WasmDebugInfo> WasmInstanceObject::GetOrCreateDebugInfo(
412    Handle<WasmInstanceObject> instance) {
413  if (instance->has_debug_info()) return handle(instance->debug_info());
414  Handle<WasmDebugInfo> new_info = WasmDebugInfo::New(instance);
415  instance->set_debug_info(*new_info);
416  return new_info;
417}
418
419WasmInstanceObject* WasmInstanceObject::cast(Object* object) {
420  DCHECK(IsWasmInstanceObject(object));
421  return reinterpret_cast<WasmInstanceObject*>(object);
422}
423
424bool WasmInstanceObject::IsWasmInstanceObject(Object* object) {
425  if (!object->IsJSObject()) return false;
426
427  JSObject* obj = JSObject::cast(object);
428  Isolate* isolate = obj->GetIsolate();
429  if (obj->GetInternalFieldCount() != kFieldCount) {
430    return false;
431  }
432
433  Object* mem = obj->GetInternalField(kMemoryArrayBuffer);
434  if (!(mem->IsUndefined(isolate) || mem->IsJSArrayBuffer()) ||
435      !WasmCompiledModule::IsWasmCompiledModule(
436          obj->GetInternalField(kCompiledModule))) {
437    return false;
438  }
439
440  // All checks passed.
441  return true;
442}
443
444Handle<WasmInstanceObject> WasmInstanceObject::New(
445    Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
446  Handle<JSFunction> instance_cons(
447      isolate->native_context()->wasm_instance_constructor());
448  Handle<JSObject> instance_object =
449      isolate->factory()->NewJSObject(instance_cons, TENURED);
450  Handle<Symbol> instance_sym(isolate->native_context()->wasm_instance_sym());
451  Object::SetProperty(instance_object, instance_sym, instance_object, STRICT)
452      .Check();
453  Handle<WasmInstanceObject> instance(
454      reinterpret_cast<WasmInstanceObject*>(*instance_object), isolate);
455
456  instance->SetInternalField(kCompiledModule, *compiled_module);
457  instance->SetInternalField(kMemoryObject, isolate->heap()->undefined_value());
458  Handle<WasmInstanceWrapper> instance_wrapper =
459      WasmInstanceWrapper::New(isolate, instance);
460  instance->SetInternalField(kWasmMemInstanceWrapper, *instance_wrapper);
461  return instance;
462}
463
464WasmInstanceObject* WasmExportedFunction::instance() {
465  return WasmInstanceObject::cast(GetInternalField(kInstance));
466}
467
468int WasmExportedFunction::function_index() {
469  return SafeInt32(GetInternalField(kIndex));
470}
471
472WasmExportedFunction* WasmExportedFunction::cast(Object* object) {
473  DCHECK(object && object->IsJSFunction());
474  DCHECK_EQ(Code::JS_TO_WASM_FUNCTION,
475            JSFunction::cast(object)->code()->kind());
476  // TODO(titzer): brand check for WasmExportedFunction.
477  return reinterpret_cast<WasmExportedFunction*>(object);
478}
479
480Handle<WasmExportedFunction> WasmExportedFunction::New(
481    Isolate* isolate, Handle<WasmInstanceObject> instance,
482    MaybeHandle<String> maybe_name, int func_index, int arity,
483    Handle<Code> export_wrapper) {
484  Handle<String> name;
485  if (maybe_name.is_null()) {
486    EmbeddedVector<char, 16> buffer;
487    int length = SNPrintF(buffer, "%d", func_index);
488    name = isolate->factory()
489               ->NewStringFromAscii(
490                   Vector<const char>::cast(buffer.SubVector(0, length)))
491               .ToHandleChecked();
492  } else {
493    name = maybe_name.ToHandleChecked();
494  }
495  DCHECK_EQ(Code::JS_TO_WASM_FUNCTION, export_wrapper->kind());
496  Handle<SharedFunctionInfo> shared =
497      isolate->factory()->NewSharedFunctionInfo(name, export_wrapper, false);
498  shared->set_length(arity);
499  shared->set_internal_formal_parameter_count(arity);
500  Handle<JSFunction> function = isolate->factory()->NewFunction(
501      isolate->wasm_function_map(), name, export_wrapper);
502  function->set_shared(*shared);
503
504  function->SetInternalField(kInstance, *instance);
505  function->SetInternalField(kIndex, Smi::FromInt(func_index));
506  return Handle<WasmExportedFunction>::cast(function);
507}
508
509bool WasmSharedModuleData::IsWasmSharedModuleData(Object* object) {
510  if (!object->IsFixedArray()) return false;
511  FixedArray* arr = FixedArray::cast(object);
512  if (arr->length() != kFieldCount) return false;
513  Isolate* isolate = arr->GetIsolate();
514  if (!arr->get(kModuleWrapper)->IsForeign()) return false;
515  if (!arr->get(kModuleBytes)->IsUndefined(isolate) &&
516      !arr->get(kModuleBytes)->IsSeqOneByteString())
517    return false;
518  if (!arr->get(kScript)->IsScript()) return false;
519  if (!arr->get(kAsmJsOffsetTable)->IsUndefined(isolate) &&
520      !arr->get(kAsmJsOffsetTable)->IsByteArray())
521    return false;
522  if (!arr->get(kBreakPointInfos)->IsUndefined(isolate) &&
523      !arr->get(kBreakPointInfos)->IsFixedArray())
524    return false;
525  return true;
526}
527
528WasmSharedModuleData* WasmSharedModuleData::cast(Object* object) {
529  DCHECK(IsWasmSharedModuleData(object));
530  return reinterpret_cast<WasmSharedModuleData*>(object);
531}
532
533wasm::WasmModule* WasmSharedModuleData::module() {
534  // We populate the kModuleWrapper field with a Foreign holding the
535  // address to the address of a WasmModule. This is because we can
536  // handle both cases when the WasmModule's lifetime is managed through
537  // a Managed<WasmModule> object, as well as cases when it's managed
538  // by the embedder. CcTests fall into the latter case.
539  return *(reinterpret_cast<wasm::WasmModule**>(
540      Foreign::cast(get(kModuleWrapper))->foreign_address()));
541}
542
543DEFINE_OPTIONAL_ARR_ACCESSORS(WasmSharedModuleData, module_bytes, kModuleBytes,
544                              SeqOneByteString);
545DEFINE_ARR_GETTER(WasmSharedModuleData, script, kScript, Script);
546DEFINE_OPTIONAL_ARR_ACCESSORS(WasmSharedModuleData, asm_js_offset_table,
547                              kAsmJsOffsetTable, ByteArray);
548DEFINE_OPTIONAL_ARR_GETTER(WasmSharedModuleData, breakpoint_infos,
549                           kBreakPointInfos, FixedArray);
550
551Handle<WasmSharedModuleData> WasmSharedModuleData::New(
552    Isolate* isolate, Handle<Foreign> module_wrapper,
553    Handle<SeqOneByteString> module_bytes, Handle<Script> script,
554    Handle<ByteArray> asm_js_offset_table) {
555  Handle<FixedArray> arr =
556      isolate->factory()->NewFixedArray(kFieldCount, TENURED);
557
558  arr->set(kModuleWrapper, *module_wrapper);
559  if (!module_bytes.is_null()) {
560    arr->set(kModuleBytes, *module_bytes);
561  }
562  if (!script.is_null()) {
563    arr->set(kScript, *script);
564  }
565  if (!asm_js_offset_table.is_null()) {
566    arr->set(kAsmJsOffsetTable, *asm_js_offset_table);
567  }
568
569  DCHECK(WasmSharedModuleData::IsWasmSharedModuleData(*arr));
570  return Handle<WasmSharedModuleData>::cast(arr);
571}
572
573bool WasmSharedModuleData::is_asm_js() {
574  bool asm_js = module()->origin == wasm::ModuleOrigin::kAsmJsOrigin;
575  DCHECK_EQ(asm_js, script()->type() == Script::TYPE_NORMAL);
576  DCHECK_EQ(asm_js, has_asm_js_offset_table());
577  return asm_js;
578}
579
580void WasmSharedModuleData::ReinitializeAfterDeserialization(
581    Isolate* isolate, Handle<WasmSharedModuleData> shared) {
582  DCHECK(shared->get(kModuleWrapper)->IsUndefined(isolate));
583#ifdef DEBUG
584  // No BreakpointInfo objects should survive deserialization.
585  if (shared->has_breakpoint_infos()) {
586    for (int i = 0, e = shared->breakpoint_infos()->length(); i < e; ++i) {
587      DCHECK(shared->breakpoint_infos()->get(i)->IsUndefined(isolate));
588    }
589  }
590#endif
591
592  shared->set(kBreakPointInfos, isolate->heap()->undefined_value());
593
594  WasmModule* module = nullptr;
595  {
596    // We parse the module again directly from the module bytes, so
597    // the underlying storage must not be moved meanwhile.
598    DisallowHeapAllocation no_allocation;
599    SeqOneByteString* module_bytes = shared->module_bytes();
600    const byte* start =
601        reinterpret_cast<const byte*>(module_bytes->GetCharsAddress());
602    const byte* end = start + module_bytes->length();
603    // TODO(titzer): remember the module origin in the compiled_module
604    // For now, we assume serialized modules did not originate from asm.js.
605    ModuleResult result =
606        DecodeWasmModule(isolate, start, end, false, kWasmOrigin);
607    CHECK(result.ok());
608    CHECK_NOT_NULL(result.val);
609    module = const_cast<WasmModule*>(result.val);
610  }
611
612  Handle<WasmModuleWrapper> module_wrapper =
613      WasmModuleWrapper::New(isolate, module);
614
615  shared->set(kModuleWrapper, *module_wrapper);
616  DCHECK(WasmSharedModuleData::IsWasmSharedModuleData(*shared));
617}
618
619namespace {
620
621int GetBreakpointPos(Isolate* isolate, Object* break_point_info_or_undef) {
622  if (break_point_info_or_undef->IsUndefined(isolate)) return kMaxInt;
623  return BreakPointInfo::cast(break_point_info_or_undef)->source_position();
624}
625
626int FindBreakpointInfoInsertPos(Isolate* isolate,
627                                Handle<FixedArray> breakpoint_infos,
628                                int position) {
629  // Find insert location via binary search, taking care of undefined values on
630  // the right. Position is always greater than zero.
631  DCHECK_LT(0, position);
632
633  int left = 0;                            // inclusive
634  int right = breakpoint_infos->length();  // exclusive
635  while (right - left > 1) {
636    int mid = left + (right - left) / 2;
637    Object* mid_obj = breakpoint_infos->get(mid);
638    if (GetBreakpointPos(isolate, mid_obj) <= position) {
639      left = mid;
640    } else {
641      right = mid;
642    }
643  }
644
645  int left_pos = GetBreakpointPos(isolate, breakpoint_infos->get(left));
646  return left_pos < position ? left + 1 : left;
647}
648
649}  // namespace
650
651void WasmSharedModuleData::AddBreakpoint(Handle<WasmSharedModuleData> shared,
652                                         int position,
653                                         Handle<Object> break_point_object) {
654  Isolate* isolate = shared->GetIsolate();
655  Handle<FixedArray> breakpoint_infos;
656  if (shared->has_breakpoint_infos()) {
657    breakpoint_infos = handle(shared->breakpoint_infos(), isolate);
658  } else {
659    breakpoint_infos = isolate->factory()->NewFixedArray(4, TENURED);
660    shared->set(kBreakPointInfos, *breakpoint_infos);
661  }
662
663  int insert_pos =
664      FindBreakpointInfoInsertPos(isolate, breakpoint_infos, position);
665
666  // If a BreakPointInfo object already exists for this position, add the new
667  // breakpoint object and return.
668  if (insert_pos < breakpoint_infos->length() &&
669      GetBreakpointPos(isolate, breakpoint_infos->get(insert_pos)) ==
670          position) {
671    Handle<BreakPointInfo> old_info(
672        BreakPointInfo::cast(breakpoint_infos->get(insert_pos)), isolate);
673    BreakPointInfo::SetBreakPoint(old_info, break_point_object);
674    return;
675  }
676
677  // Enlarge break positions array if necessary.
678  bool need_realloc = !breakpoint_infos->get(breakpoint_infos->length() - 1)
679                           ->IsUndefined(isolate);
680  Handle<FixedArray> new_breakpoint_infos = breakpoint_infos;
681  if (need_realloc) {
682    new_breakpoint_infos = isolate->factory()->NewFixedArray(
683        2 * breakpoint_infos->length(), TENURED);
684    shared->set(kBreakPointInfos, *new_breakpoint_infos);
685    // Copy over the entries [0, insert_pos).
686    for (int i = 0; i < insert_pos; ++i)
687      new_breakpoint_infos->set(i, breakpoint_infos->get(i));
688  }
689
690  // Move elements [insert_pos+1, ...] up by one.
691  for (int i = insert_pos + 1; i < breakpoint_infos->length(); ++i) {
692    Object* entry = breakpoint_infos->get(i);
693    if (entry->IsUndefined(isolate)) break;
694    new_breakpoint_infos->set(i + 1, entry);
695  }
696
697  // Generate new BreakpointInfo.
698  Handle<BreakPointInfo> breakpoint_info =
699      isolate->factory()->NewBreakPointInfo(position);
700  BreakPointInfo::SetBreakPoint(breakpoint_info, break_point_object);
701
702  // Now insert new position at insert_pos.
703  new_breakpoint_infos->set(insert_pos, *breakpoint_info);
704}
705
706void WasmSharedModuleData::SetBreakpointsOnNewInstance(
707    Handle<WasmSharedModuleData> shared, Handle<WasmInstanceObject> instance) {
708  if (!shared->has_breakpoint_infos()) return;
709  Isolate* isolate = shared->GetIsolate();
710  Handle<WasmCompiledModule> compiled_module(instance->compiled_module(),
711                                             isolate);
712  Handle<WasmDebugInfo> debug_info =
713      WasmInstanceObject::GetOrCreateDebugInfo(instance);
714
715  Handle<FixedArray> breakpoint_infos(shared->breakpoint_infos(), isolate);
716  // If the array exists, it should not be empty.
717  DCHECK_LT(0, breakpoint_infos->length());
718
719  for (int i = 0, e = breakpoint_infos->length(); i < e; ++i) {
720    Handle<Object> obj(breakpoint_infos->get(i), isolate);
721    if (obj->IsUndefined(isolate)) {
722      for (; i < e; ++i) {
723        DCHECK(breakpoint_infos->get(i)->IsUndefined(isolate));
724      }
725      break;
726    }
727    Handle<BreakPointInfo> breakpoint_info = Handle<BreakPointInfo>::cast(obj);
728    int position = breakpoint_info->source_position();
729
730    // Find the function for this breakpoint, and set the breakpoint.
731    int func_index = compiled_module->GetContainingFunction(position);
732    DCHECK_LE(0, func_index);
733    WasmFunction& func = compiled_module->module()->functions[func_index];
734    int offset_in_func = position - func.code_start_offset;
735    WasmDebugInfo::SetBreakpoint(debug_info, func_index, offset_in_func);
736  }
737}
738
739Handle<WasmCompiledModule> WasmCompiledModule::New(
740    Isolate* isolate, Handle<WasmSharedModuleData> shared) {
741  Handle<FixedArray> ret =
742      isolate->factory()->NewFixedArray(PropertyIndices::Count, TENURED);
743  // WasmCompiledModule::cast would fail since fields are not set yet.
744  Handle<WasmCompiledModule> compiled_module(
745      reinterpret_cast<WasmCompiledModule*>(*ret), isolate);
746  compiled_module->InitId();
747  compiled_module->set_num_imported_functions(0);
748  compiled_module->set_shared(shared);
749  compiled_module->set_native_context(isolate->native_context());
750  return compiled_module;
751}
752
753void WasmCompiledModule::InitId() {
754#if DEBUG
755  static uint32_t instance_id_counter = 0;
756  set(kID_instance_id, Smi::FromInt(instance_id_counter++));
757  TRACE("New compiled module id: %d\n", instance_id());
758#endif
759}
760
761MaybeHandle<String> WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
762    Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
763    uint32_t offset, uint32_t size) {
764  // TODO(wasm): cache strings from modules if it's a performance win.
765  Handle<SeqOneByteString> module_bytes(compiled_module->module_bytes(),
766                                        isolate);
767  DCHECK_GE(module_bytes->length(), offset);
768  DCHECK_GE(module_bytes->length() - offset, size);
769  Address raw = module_bytes->GetCharsAddress() + offset;
770  if (!unibrow::Utf8::Validate(reinterpret_cast<const byte*>(raw), size))
771    return {};  // UTF8 decoding error for name.
772  DCHECK_GE(kMaxInt, offset);
773  DCHECK_GE(kMaxInt, size);
774  return isolate->factory()->NewStringFromUtf8SubString(
775      module_bytes, static_cast<int>(offset), static_cast<int>(size));
776}
777
778bool WasmCompiledModule::IsWasmCompiledModule(Object* obj) {
779  if (!obj->IsFixedArray()) return false;
780  FixedArray* arr = FixedArray::cast(obj);
781  if (arr->length() != PropertyIndices::Count) return false;
782  Isolate* isolate = arr->GetIsolate();
783#define WCM_CHECK_TYPE(NAME, TYPE_CHECK) \
784  do {                                   \
785    Object* obj = arr->get(kID_##NAME);  \
786    if (!(TYPE_CHECK)) return false;     \
787  } while (false);
788#define WCM_CHECK_OBJECT(TYPE, NAME) \
789  WCM_CHECK_TYPE(NAME, obj->IsUndefined(isolate) || obj->Is##TYPE())
790#define WCM_CHECK_WASM_OBJECT(TYPE, NAME) \
791  WCM_CHECK_TYPE(NAME, TYPE::Is##TYPE(obj))
792#define WCM_CHECK_WEAK_LINK(TYPE, NAME) WCM_CHECK_OBJECT(WeakCell, NAME)
793#define WCM_CHECK_SMALL_NUMBER(TYPE, NAME) WCM_CHECK_TYPE(NAME, obj->IsSmi())
794#define WCM_CHECK(KIND, TYPE, NAME) WCM_CHECK_##KIND(TYPE, NAME)
795  WCM_PROPERTY_TABLE(WCM_CHECK)
796#undef WCM_CHECK
797
798  // All checks passed.
799  return true;
800}
801
802void WasmCompiledModule::PrintInstancesChain() {
803#if DEBUG
804  if (!FLAG_trace_wasm_instances) return;
805  for (WasmCompiledModule* current = this; current != nullptr;) {
806    PrintF("->%d", current->instance_id());
807    if (!current->has_weak_next_instance()) break;
808    CHECK(!current->ptr_to_weak_next_instance()->cleared());
809    current =
810        WasmCompiledModule::cast(current->ptr_to_weak_next_instance()->value());
811  }
812  PrintF("\n");
813#endif
814}
815
816void WasmCompiledModule::ReinitializeAfterDeserialization(
817    Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
818  // This method must only be called immediately after deserialization.
819  // At this point, no module wrapper exists, so the shared module data is
820  // incomplete.
821  Handle<WasmSharedModuleData> shared(
822      static_cast<WasmSharedModuleData*>(compiled_module->get(kID_shared)),
823      isolate);
824  DCHECK(!WasmSharedModuleData::IsWasmSharedModuleData(*shared));
825  WasmSharedModuleData::ReinitializeAfterDeserialization(isolate, shared);
826  DCHECK(WasmSharedModuleData::IsWasmSharedModuleData(*shared));
827}
828
829uint32_t WasmCompiledModule::mem_size() const {
830  return has_memory() ? memory()->byte_length()->Number() : default_mem_size();
831}
832
833uint32_t WasmCompiledModule::default_mem_size() const {
834  return min_mem_pages() * WasmModule::kPageSize;
835}
836
837MaybeHandle<String> WasmCompiledModule::GetFunctionNameOrNull(
838    Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
839    uint32_t func_index) {
840  DCHECK_LT(func_index, compiled_module->module()->functions.size());
841  WasmFunction& function = compiled_module->module()->functions[func_index];
842  return WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
843      isolate, compiled_module, function.name_offset, function.name_length);
844}
845
846Handle<String> WasmCompiledModule::GetFunctionName(
847    Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
848    uint32_t func_index) {
849  MaybeHandle<String> name =
850      GetFunctionNameOrNull(isolate, compiled_module, func_index);
851  if (!name.is_null()) return name.ToHandleChecked();
852  return isolate->factory()->NewStringFromStaticChars("<WASM UNNAMED>");
853}
854
855Vector<const uint8_t> WasmCompiledModule::GetRawFunctionName(
856    uint32_t func_index) {
857  DCHECK_GT(module()->functions.size(), func_index);
858  WasmFunction& function = module()->functions[func_index];
859  SeqOneByteString* bytes = module_bytes();
860  DCHECK_GE(bytes->length(), function.name_offset);
861  DCHECK_GE(bytes->length() - function.name_offset, function.name_length);
862  return Vector<const uint8_t>(bytes->GetCharsAddress() + function.name_offset,
863                               function.name_length);
864}
865
866int WasmCompiledModule::GetFunctionOffset(uint32_t func_index) {
867  std::vector<WasmFunction>& functions = module()->functions;
868  if (static_cast<uint32_t>(func_index) >= functions.size()) return -1;
869  DCHECK_GE(kMaxInt, functions[func_index].code_start_offset);
870  return static_cast<int>(functions[func_index].code_start_offset);
871}
872
873int WasmCompiledModule::GetContainingFunction(uint32_t byte_offset) {
874  std::vector<WasmFunction>& functions = module()->functions;
875
876  // Binary search for a function containing the given position.
877  int left = 0;                                    // inclusive
878  int right = static_cast<int>(functions.size());  // exclusive
879  if (right == 0) return false;
880  while (right - left > 1) {
881    int mid = left + (right - left) / 2;
882    if (functions[mid].code_start_offset <= byte_offset) {
883      left = mid;
884    } else {
885      right = mid;
886    }
887  }
888  // If the found function does not contains the given position, return -1.
889  WasmFunction& func = functions[left];
890  if (byte_offset < func.code_start_offset ||
891      byte_offset >= func.code_end_offset) {
892    return -1;
893  }
894
895  return left;
896}
897
898bool WasmCompiledModule::GetPositionInfo(uint32_t position,
899                                         Script::PositionInfo* info) {
900  int func_index = GetContainingFunction(position);
901  if (func_index < 0) return false;
902
903  WasmFunction& function = module()->functions[func_index];
904
905  info->line = func_index;
906  info->column = position - function.code_start_offset;
907  info->line_start = function.code_start_offset;
908  info->line_end = function.code_end_offset;
909  return true;
910}
911
912namespace {
913
914enum AsmJsOffsetTableEntryLayout {
915  kOTEByteOffset,
916  kOTECallPosition,
917  kOTENumberConvPosition,
918  kOTESize
919};
920
921Handle<ByteArray> GetDecodedAsmJsOffsetTable(
922    Handle<WasmCompiledModule> compiled_module, Isolate* isolate) {
923  DCHECK(compiled_module->is_asm_js());
924  Handle<ByteArray> offset_table(
925      compiled_module->shared()->asm_js_offset_table(), isolate);
926
927  // The last byte in the asm_js_offset_tables ByteArray tells whether it is
928  // still encoded (0) or decoded (1).
929  enum AsmJsTableType : int { Encoded = 0, Decoded = 1 };
930  int table_type = offset_table->get(offset_table->length() - 1);
931  DCHECK(table_type == Encoded || table_type == Decoded);
932  if (table_type == Decoded) return offset_table;
933
934  AsmJsOffsetsResult asm_offsets;
935  {
936    DisallowHeapAllocation no_gc;
937    const byte* bytes_start = offset_table->GetDataStartAddress();
938    const byte* bytes_end = bytes_start + offset_table->length() - 1;
939    asm_offsets = wasm::DecodeAsmJsOffsets(bytes_start, bytes_end);
940  }
941  // Wasm bytes must be valid and must contain asm.js offset table.
942  DCHECK(asm_offsets.ok());
943  DCHECK_GE(kMaxInt, asm_offsets.val.size());
944  int num_functions = static_cast<int>(asm_offsets.val.size());
945  int num_imported_functions =
946      static_cast<int>(compiled_module->module()->num_imported_functions);
947  DCHECK_EQ(compiled_module->module()->functions.size(),
948            static_cast<size_t>(num_functions) + num_imported_functions);
949  int num_entries = 0;
950  for (int func = 0; func < num_functions; ++func) {
951    size_t new_size = asm_offsets.val[func].size();
952    DCHECK_LE(new_size, static_cast<size_t>(kMaxInt) - num_entries);
953    num_entries += static_cast<int>(new_size);
954  }
955  // One byte to encode that this is a decoded table.
956  DCHECK_GE(kMaxInt,
957            1 + static_cast<uint64_t>(num_entries) * kOTESize * kIntSize);
958  int total_size = 1 + num_entries * kOTESize * kIntSize;
959  Handle<ByteArray> decoded_table =
960      isolate->factory()->NewByteArray(total_size, TENURED);
961  decoded_table->set(total_size - 1, AsmJsTableType::Decoded);
962  compiled_module->shared()->set_asm_js_offset_table(*decoded_table);
963
964  int idx = 0;
965  std::vector<WasmFunction>& wasm_funs = compiled_module->module()->functions;
966  for (int func = 0; func < num_functions; ++func) {
967    std::vector<AsmJsOffsetEntry>& func_asm_offsets = asm_offsets.val[func];
968    if (func_asm_offsets.empty()) continue;
969    int func_offset =
970        wasm_funs[num_imported_functions + func].code_start_offset;
971    for (AsmJsOffsetEntry& e : func_asm_offsets) {
972      // Byte offsets must be strictly monotonously increasing:
973      DCHECK_IMPLIES(idx > 0, func_offset + e.byte_offset >
974                                  decoded_table->get_int(idx - kOTESize));
975      decoded_table->set_int(idx + kOTEByteOffset, func_offset + e.byte_offset);
976      decoded_table->set_int(idx + kOTECallPosition, e.source_position_call);
977      decoded_table->set_int(idx + kOTENumberConvPosition,
978                             e.source_position_number_conversion);
979      idx += kOTESize;
980    }
981  }
982  DCHECK_EQ(total_size, idx * kIntSize + 1);
983  return decoded_table;
984}
985
986}  // namespace
987
988int WasmCompiledModule::GetAsmJsSourcePosition(
989    Handle<WasmCompiledModule> compiled_module, uint32_t func_index,
990    uint32_t byte_offset, bool is_at_number_conversion) {
991  Isolate* isolate = compiled_module->GetIsolate();
992  Handle<ByteArray> offset_table =
993      GetDecodedAsmJsOffsetTable(compiled_module, isolate);
994
995  DCHECK_LT(func_index, compiled_module->module()->functions.size());
996  uint32_t func_code_offset =
997      compiled_module->module()->functions[func_index].code_start_offset;
998  uint32_t total_offset = func_code_offset + byte_offset;
999
1000  // Binary search for the total byte offset.
1001  int left = 0;                                              // inclusive
1002  int right = offset_table->length() / kIntSize / kOTESize;  // exclusive
1003  DCHECK_LT(left, right);
1004  while (right - left > 1) {
1005    int mid = left + (right - left) / 2;
1006    int mid_entry = offset_table->get_int(kOTESize * mid);
1007    DCHECK_GE(kMaxInt, mid_entry);
1008    if (static_cast<uint32_t>(mid_entry) <= total_offset) {
1009      left = mid;
1010    } else {
1011      right = mid;
1012    }
1013  }
1014  // There should be an entry for each position that could show up on the stack
1015  // trace:
1016  DCHECK_EQ(total_offset, offset_table->get_int(kOTESize * left));
1017  int idx = is_at_number_conversion ? kOTENumberConvPosition : kOTECallPosition;
1018  return offset_table->get_int(kOTESize * left + idx);
1019}
1020
1021v8::debug::WasmDisassembly WasmCompiledModule::DisassembleFunction(
1022    int func_index) {
1023  DisallowHeapAllocation no_gc;
1024
1025  if (func_index < 0 ||
1026      static_cast<uint32_t>(func_index) >= module()->functions.size())
1027    return {};
1028
1029  SeqOneByteString* module_bytes_str = module_bytes();
1030  Vector<const byte> module_bytes(module_bytes_str->GetChars(),
1031                                  module_bytes_str->length());
1032
1033  std::ostringstream disassembly_os;
1034  v8::debug::WasmDisassembly::OffsetTable offset_table;
1035
1036  PrintWasmText(module(), module_bytes, static_cast<uint32_t>(func_index),
1037                disassembly_os, &offset_table);
1038
1039  return {disassembly_os.str(), std::move(offset_table)};
1040}
1041
1042bool WasmCompiledModule::GetPossibleBreakpoints(
1043    const v8::debug::Location& start, const v8::debug::Location& end,
1044    std::vector<v8::debug::Location>* locations) {
1045  DisallowHeapAllocation no_gc;
1046
1047  std::vector<WasmFunction>& functions = module()->functions;
1048  if (start.GetLineNumber() < 0 || start.GetColumnNumber() < 0 ||
1049      (!end.IsEmpty() &&
1050       (end.GetLineNumber() < 0 || end.GetColumnNumber() < 0)))
1051    return false;
1052
1053  // start_func_index, start_offset and end_func_index is inclusive.
1054  // end_offset is exclusive.
1055  // start_offset and end_offset are module-relative byte offsets.
1056  uint32_t start_func_index = start.GetLineNumber();
1057  if (start_func_index >= functions.size()) return false;
1058  int start_func_len = functions[start_func_index].code_end_offset -
1059                       functions[start_func_index].code_start_offset;
1060  if (start.GetColumnNumber() > start_func_len) return false;
1061  uint32_t start_offset =
1062      functions[start_func_index].code_start_offset + start.GetColumnNumber();
1063  uint32_t end_func_index;
1064  uint32_t end_offset;
1065  if (end.IsEmpty()) {
1066    // Default: everything till the end of the Script.
1067    end_func_index = static_cast<uint32_t>(functions.size() - 1);
1068    end_offset = functions[end_func_index].code_end_offset;
1069  } else {
1070    // If end is specified: Use it and check for valid input.
1071    end_func_index = static_cast<uint32_t>(end.GetLineNumber());
1072
1073    // Special case: Stop before the start of the next function. Change to: Stop
1074    // at the end of the function before, such that we don't disassemble the
1075    // next function also.
1076    if (end.GetColumnNumber() == 0 && end_func_index > 0) {
1077      --end_func_index;
1078      end_offset = functions[end_func_index].code_end_offset;
1079    } else {
1080      if (end_func_index >= functions.size()) return false;
1081      end_offset =
1082          functions[end_func_index].code_start_offset + end.GetColumnNumber();
1083      if (end_offset > functions[end_func_index].code_end_offset) return false;
1084    }
1085  }
1086
1087  AccountingAllocator alloc;
1088  Zone tmp(&alloc, ZONE_NAME);
1089  const byte* module_start = module_bytes()->GetChars();
1090
1091  for (uint32_t func_idx = start_func_index; func_idx <= end_func_index;
1092       ++func_idx) {
1093    WasmFunction& func = functions[func_idx];
1094    if (func.code_start_offset == func.code_end_offset) continue;
1095
1096    BodyLocalDecls locals(&tmp);
1097    BytecodeIterator iterator(module_start + func.code_start_offset,
1098                              module_start + func.code_end_offset, &locals);
1099    DCHECK_LT(0u, locals.encoded_size);
1100    for (uint32_t offset : iterator.offsets()) {
1101      uint32_t total_offset = func.code_start_offset + offset;
1102      if (total_offset >= end_offset) {
1103        DCHECK_EQ(end_func_index, func_idx);
1104        break;
1105      }
1106      if (total_offset < start_offset) continue;
1107      locations->push_back(v8::debug::Location(func_idx, offset));
1108    }
1109  }
1110  return true;
1111}
1112
1113bool WasmCompiledModule::SetBreakPoint(
1114    Handle<WasmCompiledModule> compiled_module, int* position,
1115    Handle<Object> break_point_object) {
1116  Isolate* isolate = compiled_module->GetIsolate();
1117
1118  // Find the function for this breakpoint.
1119  int func_index = compiled_module->GetContainingFunction(*position);
1120  if (func_index < 0) return false;
1121  WasmFunction& func = compiled_module->module()->functions[func_index];
1122  int offset_in_func = *position - func.code_start_offset;
1123
1124  // According to the current design, we should only be called with valid
1125  // breakable positions.
1126  DCHECK(IsBreakablePosition(compiled_module, func_index, offset_in_func));
1127
1128  // Insert new break point into break_positions of shared module data.
1129  WasmSharedModuleData::AddBreakpoint(compiled_module->shared(), *position,
1130                                      break_point_object);
1131
1132  // Iterate over all instances of this module and tell them to set this new
1133  // breakpoint.
1134  for (Handle<WasmInstanceObject> instance :
1135       iterate_compiled_module_instance_chain(isolate, compiled_module)) {
1136    Handle<WasmDebugInfo> debug_info =
1137        WasmInstanceObject::GetOrCreateDebugInfo(instance);
1138    WasmDebugInfo::SetBreakpoint(debug_info, func_index, offset_in_func);
1139  }
1140
1141  return true;
1142}
1143
1144MaybeHandle<FixedArray> WasmCompiledModule::CheckBreakPoints(int position) {
1145  Isolate* isolate = GetIsolate();
1146  if (!shared()->has_breakpoint_infos()) return {};
1147
1148  Handle<FixedArray> breakpoint_infos(shared()->breakpoint_infos(), isolate);
1149  int insert_pos =
1150      FindBreakpointInfoInsertPos(isolate, breakpoint_infos, position);
1151  if (insert_pos >= breakpoint_infos->length()) return {};
1152
1153  Handle<Object> maybe_breakpoint_info(breakpoint_infos->get(insert_pos),
1154                                       isolate);
1155  if (maybe_breakpoint_info->IsUndefined(isolate)) return {};
1156  Handle<BreakPointInfo> breakpoint_info =
1157      Handle<BreakPointInfo>::cast(maybe_breakpoint_info);
1158  if (breakpoint_info->source_position() != position) return {};
1159
1160  Handle<Object> breakpoint_objects(breakpoint_info->break_point_objects(),
1161                                    isolate);
1162  return isolate->debug()->GetHitBreakPointObjects(breakpoint_objects);
1163}
1164
1165Handle<WasmInstanceWrapper> WasmInstanceWrapper::New(
1166    Isolate* isolate, Handle<WasmInstanceObject> instance) {
1167  Handle<FixedArray> array =
1168      isolate->factory()->NewFixedArray(kWrapperPropertyCount, TENURED);
1169  Handle<WasmInstanceWrapper> instance_wrapper(
1170      reinterpret_cast<WasmInstanceWrapper*>(*array), isolate);
1171  Handle<WeakCell> cell = isolate->factory()->NewWeakCell(instance);
1172  instance_wrapper->set(kWrapperInstanceObject, *cell);
1173  return instance_wrapper;
1174}
1175
1176bool WasmInstanceWrapper::IsWasmInstanceWrapper(Object* obj) {
1177  if (!obj->IsFixedArray()) return false;
1178  Handle<FixedArray> array = handle(FixedArray::cast(obj));
1179  if (array->length() != kWrapperPropertyCount) return false;
1180  if (!array->get(kWrapperInstanceObject)->IsWeakCell()) return false;
1181  Isolate* isolate = array->GetIsolate();
1182  if (!array->get(kNextInstanceWrapper)->IsUndefined(isolate) &&
1183      !array->get(kNextInstanceWrapper)->IsFixedArray())
1184    return false;
1185  if (!array->get(kPreviousInstanceWrapper)->IsUndefined(isolate) &&
1186      !array->get(kPreviousInstanceWrapper)->IsFixedArray())
1187    return false;
1188  return true;
1189}
1190