Home | History | Annotate | Download | only in wasm
      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 
     25 using namespace v8::internal;
     26 using 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 
     68 namespace {
     69 
     70 uint32_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 
     83 int32_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.
     96 class 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.
    154 class 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 
    190 v8::base::iterator_range<CompiledModuleInstancesIterator>
    191 iterate_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
    198 bool 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 
    219 Handle<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 
    246 WasmModuleObject* WasmModuleObject::cast(Object* object) {
    247   DCHECK(object->IsJSObject());
    248   // TODO(titzer): brand check for WasmModuleObject.
    249   return reinterpret_cast<WasmModuleObject*>(object);
    250 }
    251 
    252 bool WasmModuleObject::IsWasmModuleObject(Object* object) {
    253   return object->IsJSObject() &&
    254          JSObject::cast(object)->GetInternalFieldCount() == kFieldCount;
    255 }
    256 
    257 DEFINE_OBJ_GETTER(WasmModuleObject, compiled_module, kCompiledModule,
    258                   WasmCompiledModule)
    259 
    260 Handle<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 
    282 DEFINE_OBJ_GETTER(WasmTableObject, dispatch_tables, kDispatchTables, FixedArray)
    283 
    284 Handle<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 
    311 DEFINE_OBJ_ACCESSORS(WasmTableObject, functions, kFunctions, FixedArray)
    312 
    313 uint32_t WasmTableObject::current_length() { return functions()->length(); }
    314 
    315 bool WasmTableObject::has_maximum_length() {
    316   return GetInternalField(kMaximum)->Number() >= 0;
    317 }
    318 
    319 int64_t WasmTableObject::maximum_length() {
    320   return static_cast<int64_t>(GetInternalField(kMaximum)->Number());
    321 }
    322 
    323 WasmTableObject* WasmTableObject::cast(Object* object) {
    324   DCHECK(object && object->IsJSObject());
    325   // TODO(titzer): brand check for WasmTableObject.
    326   return reinterpret_cast<WasmTableObject*>(object);
    327 }
    328 
    329 void 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 
    336 Handle<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 
    351 DEFINE_OBJ_ACCESSORS(WasmMemoryObject, buffer, kArrayBuffer, JSArrayBuffer)
    352 DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmMemoryObject, instances_link, kInstancesLink,
    353                               WasmInstanceWrapper)
    354 
    355 uint32_t WasmMemoryObject::current_pages() {
    356   return SafeUint32(buffer()->byte_length()) / wasm::WasmModule::kPageSize;
    357 }
    358 
    359 bool WasmMemoryObject::has_maximum_pages() {
    360   return GetInternalField(kMaximum)->Number() >= 0;
    361 }
    362 
    363 int32_t WasmMemoryObject::maximum_pages() {
    364   return static_cast<int32_t>(GetInternalField(kMaximum)->Number());
    365 }
    366 
    367 WasmMemoryObject* WasmMemoryObject::cast(Object* object) {
    368   DCHECK(object && object->IsJSObject());
    369   // TODO(titzer): brand check for WasmMemoryObject.
    370   return reinterpret_cast<WasmMemoryObject*>(object);
    371 }
    372 
    373 void 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 
    387 void WasmMemoryObject::ResetInstancesLink(Isolate* isolate) {
    388   Handle<Object> undefined = isolate->factory()->undefined_value();
    389   SetInternalField(kInstancesLink, *undefined);
    390 }
    391 
    392 DEFINE_OBJ_ACCESSORS(WasmInstanceObject, compiled_module, kCompiledModule,
    393                      WasmCompiledModule)
    394 DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, globals_buffer,
    395                               kGlobalsArrayBuffer, JSArrayBuffer)
    396 DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, memory_buffer,
    397                               kMemoryArrayBuffer, JSArrayBuffer)
    398 DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, memory_object, kMemoryObject,
    399                               WasmMemoryObject)
    400 DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, debug_info, kDebugInfo,
    401                               WasmDebugInfo)
    402 DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, instance_wrapper,
    403                               kWasmMemInstanceWrapper, WasmInstanceWrapper)
    404 
    405 WasmModuleObject* WasmInstanceObject::module_object() {
    406   return *compiled_module()->wasm_module();
    407 }
    408 
    409 WasmModule* WasmInstanceObject::module() { return compiled_module()->module(); }
    410 
    411 Handle<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 
    419 WasmInstanceObject* WasmInstanceObject::cast(Object* object) {
    420   DCHECK(IsWasmInstanceObject(object));
    421   return reinterpret_cast<WasmInstanceObject*>(object);
    422 }
    423 
    424 bool 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 
    444 Handle<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 
    464 WasmInstanceObject* WasmExportedFunction::instance() {
    465   return WasmInstanceObject::cast(GetInternalField(kInstance));
    466 }
    467 
    468 int WasmExportedFunction::function_index() {
    469   return SafeInt32(GetInternalField(kIndex));
    470 }
    471 
    472 WasmExportedFunction* 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 
    480 Handle<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 
    509 bool 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 
    528 WasmSharedModuleData* WasmSharedModuleData::cast(Object* object) {
    529   DCHECK(IsWasmSharedModuleData(object));
    530   return reinterpret_cast<WasmSharedModuleData*>(object);
    531 }
    532 
    533 wasm::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 
    543 DEFINE_OPTIONAL_ARR_ACCESSORS(WasmSharedModuleData, module_bytes, kModuleBytes,
    544                               SeqOneByteString);
    545 DEFINE_ARR_GETTER(WasmSharedModuleData, script, kScript, Script);
    546 DEFINE_OPTIONAL_ARR_ACCESSORS(WasmSharedModuleData, asm_js_offset_table,
    547                               kAsmJsOffsetTable, ByteArray);
    548 DEFINE_OPTIONAL_ARR_GETTER(WasmSharedModuleData, breakpoint_infos,
    549                            kBreakPointInfos, FixedArray);
    550 
    551 Handle<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 
    573 bool 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 
    580 void 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 
    619 namespace {
    620 
    621 int 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 
    626 int 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 
    651 void 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 
    706 void 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 
    739 Handle<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 
    753 void 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 
    761 MaybeHandle<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 
    778 bool 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 
    802 void 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 
    816 void 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 
    829 uint32_t WasmCompiledModule::mem_size() const {
    830   return has_memory() ? memory()->byte_length()->Number() : default_mem_size();
    831 }
    832 
    833 uint32_t WasmCompiledModule::default_mem_size() const {
    834   return min_mem_pages() * WasmModule::kPageSize;
    835 }
    836 
    837 MaybeHandle<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 
    846 Handle<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 
    855 Vector<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 
    866 int 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 
    873 int 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 
    898 bool 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 
    912 namespace {
    913 
    914 enum AsmJsOffsetTableEntryLayout {
    915   kOTEByteOffset,
    916   kOTECallPosition,
    917   kOTENumberConvPosition,
    918   kOTESize
    919 };
    920 
    921 Handle<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 
    988 int 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 
   1021 v8::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 
   1042 bool 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 
   1113 bool 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 
   1144 MaybeHandle<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 
   1165 Handle<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 
   1176 bool 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