// Copyright 2015 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/wasm/wasm-objects.h" #include "src/utils.h" #include "src/assembler-inl.h" #include "src/base/iterator.h" #include "src/compiler/wasm-compiler.h" #include "src/debug/debug-interface.h" #include "src/objects-inl.h" #include "src/wasm/module-decoder.h" #include "src/wasm/wasm-code-specialization.h" #include "src/wasm/wasm-module.h" #include "src/wasm/wasm-text.h" #define TRACE(...) \ do { \ if (FLAG_trace_wasm_instances) PrintF(__VA_ARGS__); \ } while (false) #define TRACE_CHAIN(instance) \ do { \ instance->PrintInstancesChain(); \ } while (false) using namespace v8::internal; using namespace v8::internal::wasm; #define DEFINE_GETTER0(getter, Container, name, field, type) \ type* Container::name() { return type::cast(getter(field)); } #define DEFINE_ACCESSORS0(getter, setter, Container, name, field, type) \ DEFINE_GETTER0(getter, Container, name, field, type) \ void Container::set_##name(type* value) { return setter(field, value); } #define DEFINE_OPTIONAL_ACCESSORS0(getter, setter, Container, name, field, \ type) \ DEFINE_ACCESSORS0(getter, setter, Container, name, field, type) \ bool Container::has_##name() { \ return !getter(field)->IsUndefined(GetIsolate()); \ } #define DEFINE_OPTIONAL_GETTER0(getter, Container, name, field, type) \ DEFINE_GETTER0(getter, Container, name, field, type) \ bool Container::has_##name() { \ return !getter(field)->IsUndefined(GetIsolate()); \ } #define DEFINE_GETTER0(getter, Container, name, field, type) \ type* Container::name() { return type::cast(getter(field)); } #define DEFINE_OBJ_GETTER(Container, name, field, type) \ DEFINE_GETTER0(GetEmbedderField, Container, name, field, type) #define DEFINE_OBJ_ACCESSORS(Container, name, field, type) \ DEFINE_ACCESSORS0(GetEmbedderField, SetEmbedderField, Container, name, \ field, type) #define DEFINE_OPTIONAL_OBJ_ACCESSORS(Container, name, field, type) \ DEFINE_OPTIONAL_ACCESSORS0(GetEmbedderField, SetEmbedderField, Container, \ name, field, type) #define DEFINE_ARR_GETTER(Container, name, field, type) \ DEFINE_GETTER0(get, Container, name, field, type) #define DEFINE_ARR_ACCESSORS(Container, name, field, type) \ DEFINE_ACCESSORS0(get, set, Container, name, field, type) #define DEFINE_OPTIONAL_ARR_ACCESSORS(Container, name, field, type) \ DEFINE_OPTIONAL_ACCESSORS0(get, set, Container, name, field, type) #define DEFINE_OPTIONAL_ARR_GETTER(Container, name, field, type) \ DEFINE_OPTIONAL_GETTER0(get, Container, name, field, type) namespace { // An iterator that returns first the module itself, then all modules linked via // next, then all linked via prev. class CompiledModulesIterator : public std::iterator> { public: CompiledModulesIterator(Isolate* isolate, Handle start_module, bool at_end) : isolate_(isolate), start_module_(start_module), current_(at_end ? Handle::null() : start_module) {} Handle operator*() const { DCHECK(!current_.is_null()); return current_; } void operator++() { Advance(); } bool operator!=(const CompiledModulesIterator& other) { DCHECK(start_module_.is_identical_to(other.start_module_)); return !current_.is_identical_to(other.current_); } private: void Advance() { DCHECK(!current_.is_null()); if (!is_backwards_) { if (current_->has_weak_next_instance()) { WeakCell* weak_next = current_->ptr_to_weak_next_instance(); if (!weak_next->cleared()) { current_ = handle(WasmCompiledModule::cast(weak_next->value()), isolate_); return; } } // No more modules in next-links, now try the previous-links. is_backwards_ = true; current_ = start_module_; } if (current_->has_weak_prev_instance()) { WeakCell* weak_prev = current_->ptr_to_weak_prev_instance(); if (!weak_prev->cleared()) { current_ = handle(WasmCompiledModule::cast(weak_prev->value()), isolate_); return; } } current_ = Handle::null(); } friend class CompiledModuleInstancesIterator; Isolate* isolate_; Handle start_module_; Handle current_; bool is_backwards_ = false; }; // An iterator based on the CompiledModulesIterator, but it returns all live // instances, not the WasmCompiledModules itself. class CompiledModuleInstancesIterator : public std::iterator> { public: CompiledModuleInstancesIterator(Isolate* isolate, Handle start_module, bool at_end) : it(isolate, start_module, at_end) { while (NeedToAdvance()) ++it; } Handle operator*() { return handle( WasmInstanceObject::cast((*it)->weak_owning_instance()->value()), it.isolate_); } void operator++() { do { ++it; } while (NeedToAdvance()); } bool operator!=(const CompiledModuleInstancesIterator& other) { return it != other.it; } private: bool NeedToAdvance() { return !it.current_.is_null() && (!it.current_->has_weak_owning_instance() || it.current_->ptr_to_weak_owning_instance()->cleared()); } CompiledModulesIterator it; }; v8::base::iterator_range iterate_compiled_module_instance_chain( Isolate* isolate, Handle compiled_module) { return {CompiledModuleInstancesIterator(isolate, compiled_module, false), CompiledModuleInstancesIterator(isolate, compiled_module, true)}; } #ifdef DEBUG bool IsBreakablePosition(Handle compiled_module, int func_index, int offset_in_func) { DisallowHeapAllocation no_gc; AccountingAllocator alloc; Zone tmp(&alloc, ZONE_NAME); BodyLocalDecls locals(&tmp); const byte* module_start = compiled_module->module_bytes()->GetChars(); WasmFunction& func = compiled_module->module()->functions[func_index]; BytecodeIterator iterator(module_start + func.code_start_offset, module_start + func.code_end_offset, &locals); DCHECK_LT(0, locals.encoded_size); for (uint32_t offset : iterator.offsets()) { if (offset > static_cast(offset_in_func)) break; if (offset == static_cast(offset_in_func)) return true; } return false; } #endif // DEBUG } // namespace Handle WasmModuleObject::New( Isolate* isolate, Handle compiled_module) { WasmModule* module = compiled_module->module(); Handle module_object; if (module->is_wasm()) { Handle module_cons( isolate->native_context()->wasm_module_constructor()); module_object = isolate->factory()->NewJSObject(module_cons); Handle module_sym(isolate->native_context()->wasm_module_sym()); Object::SetProperty(module_object, module_sym, module_object, STRICT) .Check(); } else { DCHECK(module->is_asm_js()); Handle map = isolate->factory()->NewMap( JS_OBJECT_TYPE, JSObject::kHeaderSize + WasmModuleObject::kFieldCount * kPointerSize); module_object = isolate->factory()->NewJSObjectFromMap(map, TENURED); } module_object->SetEmbedderField(WasmModuleObject::kCompiledModule, *compiled_module); Handle link_to_module = isolate->factory()->NewWeakCell(module_object); compiled_module->set_weak_wasm_module(link_to_module); return Handle::cast(module_object); } WasmModuleObject* WasmModuleObject::cast(Object* object) { DCHECK(object->IsJSObject()); // TODO(titzer): brand check for WasmModuleObject. return reinterpret_cast(object); } bool WasmModuleObject::IsWasmModuleObject(Object* object) { return object->IsJSObject() && JSObject::cast(object)->GetEmbedderFieldCount() == kFieldCount; } DEFINE_OBJ_GETTER(WasmModuleObject, compiled_module, kCompiledModule, WasmCompiledModule) Handle WasmTableObject::New(Isolate* isolate, uint32_t initial, int64_t maximum, Handle* js_functions) { Handle table_ctor( isolate->native_context()->wasm_table_constructor()); Handle table_obj = isolate->factory()->NewJSObject(table_ctor); table_obj->SetEmbedderField(kWrapperTracerHeader, Smi::kZero); *js_functions = isolate->factory()->NewFixedArray(initial); Object* null = isolate->heap()->null_value(); for (int i = 0; i < static_cast(initial); ++i) { (*js_functions)->set(i, null); } table_obj->SetEmbedderField(kFunctions, *(*js_functions)); Handle max = isolate->factory()->NewNumber(maximum); table_obj->SetEmbedderField(kMaximum, *max); Handle dispatch_tables = isolate->factory()->NewFixedArray(0); table_obj->SetEmbedderField(kDispatchTables, *dispatch_tables); Handle table_sym(isolate->native_context()->wasm_table_sym()); Object::SetProperty(table_obj, table_sym, table_obj, STRICT).Check(); return Handle::cast(table_obj); } Handle WasmTableObject::AddDispatchTable( Isolate* isolate, Handle table_obj, Handle instance, int table_index, Handle function_table, Handle signature_table) { Handle dispatch_tables( FixedArray::cast(table_obj->GetEmbedderField(kDispatchTables)), isolate); DCHECK_EQ(0, dispatch_tables->length() % 4); if (instance.is_null()) return dispatch_tables; // TODO(titzer): use weak cells here to avoid leaking instances. // Grow the dispatch table and add a new triple at the end. Handle new_dispatch_tables = isolate->factory()->CopyFixedArrayAndGrow(dispatch_tables, 4); new_dispatch_tables->set(dispatch_tables->length() + 0, *instance); new_dispatch_tables->set(dispatch_tables->length() + 1, Smi::FromInt(table_index)); new_dispatch_tables->set(dispatch_tables->length() + 2, *function_table); new_dispatch_tables->set(dispatch_tables->length() + 3, *signature_table); table_obj->SetEmbedderField(WasmTableObject::kDispatchTables, *new_dispatch_tables); return new_dispatch_tables; } DEFINE_OBJ_ACCESSORS(WasmTableObject, functions, kFunctions, FixedArray) DEFINE_OBJ_GETTER(WasmTableObject, dispatch_tables, kDispatchTables, FixedArray) uint32_t WasmTableObject::current_length() { return functions()->length(); } bool WasmTableObject::has_maximum_length() { return GetEmbedderField(kMaximum)->Number() >= 0; } int64_t WasmTableObject::maximum_length() { return static_cast(GetEmbedderField(kMaximum)->Number()); } WasmTableObject* WasmTableObject::cast(Object* object) { DCHECK(object && object->IsJSObject()); // TODO(titzer): brand check for WasmTableObject. return reinterpret_cast(object); } void WasmTableObject::grow(Isolate* isolate, uint32_t count) { Handle dispatch_tables( FixedArray::cast(GetEmbedderField(kDispatchTables))); DCHECK_EQ(0, dispatch_tables->length() % 4); uint32_t old_size = functions()->length(); Zone specialization_zone(isolate->allocator(), ZONE_NAME); for (int i = 0; i < dispatch_tables->length(); i += 4) { Handle old_function_table( FixedArray::cast(dispatch_tables->get(i + 2))); Handle old_signature_table( FixedArray::cast(dispatch_tables->get(i + 3))); Handle new_function_table = isolate->factory()->CopyFixedArrayAndGrow(old_function_table, count); Handle new_signature_table = isolate->factory()->CopyFixedArrayAndGrow(old_signature_table, count); // Update dispatch tables with new function/signature tables dispatch_tables->set(i + 2, *new_function_table); dispatch_tables->set(i + 3, *new_signature_table); // Patch the code of the respective instance. CodeSpecialization code_specialization(isolate, &specialization_zone); code_specialization.PatchTableSize(old_size, old_size + count); code_specialization.RelocateObject(old_function_table, new_function_table); code_specialization.RelocateObject(old_signature_table, new_signature_table); code_specialization.ApplyToWholeInstance( WasmInstanceObject::cast(dispatch_tables->get(i))); } } namespace { Handle GrowMemoryBuffer(Isolate* isolate, Handle old_buffer, uint32_t pages, uint32_t max_pages) { Address old_mem_start = nullptr; uint32_t old_size = 0; if (!old_buffer.is_null()) { DCHECK(old_buffer->byte_length()->IsNumber()); old_mem_start = static_cast
(old_buffer->backing_store()); old_size = old_buffer->byte_length()->Number(); } DCHECK_GE(std::numeric_limits::max(), old_size + pages * WasmModule::kPageSize); uint32_t new_size = old_size + pages * WasmModule::kPageSize; if (new_size <= old_size || max_pages * WasmModule::kPageSize < new_size || FLAG_wasm_max_mem_pages * WasmModule::kPageSize < new_size) { return Handle::null(); } // TODO(gdeepti): Change the protection here instead of allocating a new // buffer before guard regions are turned on, see issue #5886. const bool enable_guard_regions = (old_buffer.is_null() && EnableGuardRegions()) || (!old_buffer.is_null() && old_buffer->has_guard_region()); Handle new_buffer = NewArrayBuffer(isolate, new_size, enable_guard_regions); if (new_buffer.is_null()) return new_buffer; Address new_mem_start = static_cast
(new_buffer->backing_store()); memcpy(new_mem_start, old_mem_start, old_size); return new_buffer; } // May GC, because SetSpecializationMemInfoFrom may GC void SetInstanceMemory(Isolate* isolate, Handle instance, Handle buffer) { instance->set_memory_buffer(*buffer); WasmCompiledModule::SetSpecializationMemInfoFrom( isolate->factory(), handle(instance->compiled_module()), buffer); if (instance->has_debug_info()) { instance->debug_info()->UpdateMemory(*buffer); } } void UncheckedUpdateInstanceMemory(Isolate* isolate, Handle instance, Address old_mem_start, uint32_t old_size) { DCHECK(instance->has_memory_buffer()); Handle mem_buffer(instance->memory_buffer()); uint32_t new_size = mem_buffer->byte_length()->Number(); Address new_mem_start = static_cast
(mem_buffer->backing_store()); DCHECK_NOT_NULL(new_mem_start); Zone specialization_zone(isolate->allocator(), ZONE_NAME); CodeSpecialization code_specialization(isolate, &specialization_zone); code_specialization.RelocateMemoryReferences(old_mem_start, old_size, new_mem_start, new_size); code_specialization.ApplyToWholeInstance(*instance); } } // namespace Handle WasmMemoryObject::New(Isolate* isolate, Handle buffer, int32_t maximum) { Handle memory_ctor( isolate->native_context()->wasm_memory_constructor()); Handle memory_obj = isolate->factory()->NewJSObject(memory_ctor, TENURED); memory_obj->SetEmbedderField(kWrapperTracerHeader, Smi::kZero); buffer.is_null() ? memory_obj->SetEmbedderField( kArrayBuffer, isolate->heap()->undefined_value()) : memory_obj->SetEmbedderField(kArrayBuffer, *buffer); Handle max = isolate->factory()->NewNumber(maximum); memory_obj->SetEmbedderField(kMaximum, *max); Handle memory_sym(isolate->native_context()->wasm_memory_sym()); Object::SetProperty(memory_obj, memory_sym, memory_obj, STRICT).Check(); return Handle::cast(memory_obj); } DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmMemoryObject, buffer, kArrayBuffer, JSArrayBuffer) DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmMemoryObject, instances_link, kInstancesLink, WasmInstanceWrapper) uint32_t WasmMemoryObject::current_pages() { uint32_t byte_length; CHECK(buffer()->byte_length()->ToUint32(&byte_length)); return byte_length / wasm::WasmModule::kPageSize; } bool WasmMemoryObject::has_maximum_pages() { return GetEmbedderField(kMaximum)->Number() >= 0; } int32_t WasmMemoryObject::maximum_pages() { return static_cast(GetEmbedderField(kMaximum)->Number()); } WasmMemoryObject* WasmMemoryObject::cast(Object* object) { DCHECK(object && object->IsJSObject()); // TODO(titzer): brand check for WasmMemoryObject. return reinterpret_cast(object); } void WasmMemoryObject::AddInstance(Isolate* isolate, Handle instance) { Handle instance_wrapper = handle(instance->instance_wrapper()); if (has_instances_link()) { Handle current_wrapper(instances_link()); DCHECK(WasmInstanceWrapper::IsWasmInstanceWrapper(*current_wrapper)); DCHECK(!current_wrapper->has_previous()); instance_wrapper->set_next_wrapper(*current_wrapper); current_wrapper->set_previous_wrapper(*instance_wrapper); } set_instances_link(*instance_wrapper); } void WasmMemoryObject::ResetInstancesLink(Isolate* isolate) { Handle undefined = isolate->factory()->undefined_value(); SetEmbedderField(kInstancesLink, *undefined); } // static int32_t WasmMemoryObject::Grow(Isolate* isolate, Handle memory_object, uint32_t pages) { Handle old_buffer; uint32_t old_size = 0; Address old_mem_start = nullptr; if (memory_object->has_buffer()) { old_buffer = handle(memory_object->buffer()); old_size = old_buffer->byte_length()->Number(); old_mem_start = static_cast
(old_buffer->backing_store()); } Handle new_buffer; // Return current size if grow by 0. if (pages == 0) { // Even for pages == 0, we need to attach a new JSArrayBuffer with the same // backing store and neuter the old one to be spec compliant. if (!old_buffer.is_null() && old_size != 0) { new_buffer = SetupArrayBuffer( isolate, old_buffer->allocation_base(), old_buffer->allocation_length(), old_buffer->backing_store(), old_size, old_buffer->is_external(), old_buffer->has_guard_region()); memory_object->set_buffer(*new_buffer); } DCHECK_EQ(0, old_size % WasmModule::kPageSize); return old_size / WasmModule::kPageSize; } if (!memory_object->has_instances_link()) { // Memory object does not have an instance associated with it, just grow uint32_t max_pages; if (memory_object->has_maximum_pages()) { max_pages = static_cast(memory_object->maximum_pages()); if (FLAG_wasm_max_mem_pages < max_pages) return -1; } else { max_pages = FLAG_wasm_max_mem_pages; } new_buffer = GrowMemoryBuffer(isolate, old_buffer, pages, max_pages); if (new_buffer.is_null()) return -1; } else { Handle instance_wrapper( memory_object->instances_link()); DCHECK(WasmInstanceWrapper::IsWasmInstanceWrapper(*instance_wrapper)); DCHECK(instance_wrapper->has_instance()); Handle instance = instance_wrapper->instance_object(); DCHECK(IsWasmInstance(*instance)); uint32_t max_pages = instance->GetMaxMemoryPages(); // Grow memory object buffer and update instances associated with it. new_buffer = GrowMemoryBuffer(isolate, old_buffer, pages, max_pages); if (new_buffer.is_null()) return -1; DCHECK(!instance_wrapper->has_previous()); SetInstanceMemory(isolate, instance, new_buffer); UncheckedUpdateInstanceMemory(isolate, instance, old_mem_start, old_size); while (instance_wrapper->has_next()) { instance_wrapper = instance_wrapper->next_wrapper(); DCHECK(WasmInstanceWrapper::IsWasmInstanceWrapper(*instance_wrapper)); Handle instance = instance_wrapper->instance_object(); DCHECK(IsWasmInstance(*instance)); SetInstanceMemory(isolate, instance, new_buffer); UncheckedUpdateInstanceMemory(isolate, instance, old_mem_start, old_size); } } memory_object->set_buffer(*new_buffer); DCHECK_EQ(0, old_size % WasmModule::kPageSize); return old_size / WasmModule::kPageSize; } DEFINE_OBJ_ACCESSORS(WasmInstanceObject, compiled_module, kCompiledModule, WasmCompiledModule) DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, globals_buffer, kGlobalsArrayBuffer, JSArrayBuffer) DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, memory_buffer, kMemoryArrayBuffer, JSArrayBuffer) DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, memory_object, kMemoryObject, WasmMemoryObject) DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, debug_info, kDebugInfo, WasmDebugInfo) DEFINE_OPTIONAL_OBJ_ACCESSORS(WasmInstanceObject, instance_wrapper, kWasmMemInstanceWrapper, WasmInstanceWrapper) WasmModuleObject* WasmInstanceObject::module_object() { return *compiled_module()->wasm_module(); } WasmModule* WasmInstanceObject::module() { return compiled_module()->module(); } Handle WasmInstanceObject::GetOrCreateDebugInfo( Handle instance) { if (instance->has_debug_info()) return handle(instance->debug_info()); Handle new_info = WasmDebugInfo::New(instance); DCHECK(instance->has_debug_info()); return new_info; } WasmInstanceObject* WasmInstanceObject::cast(Object* object) { DCHECK(IsWasmInstanceObject(object)); return reinterpret_cast(object); } bool WasmInstanceObject::IsWasmInstanceObject(Object* object) { if (!object->IsJSObject()) return false; JSObject* obj = JSObject::cast(object); Isolate* isolate = obj->GetIsolate(); if (obj->GetEmbedderFieldCount() != kFieldCount) { return false; } Object* mem = obj->GetEmbedderField(kMemoryArrayBuffer); if (!(mem->IsUndefined(isolate) || mem->IsJSArrayBuffer()) || !WasmCompiledModule::IsWasmCompiledModule( obj->GetEmbedderField(kCompiledModule))) { return false; } // All checks passed. return true; } Handle WasmInstanceObject::New( Isolate* isolate, Handle compiled_module) { Handle instance_cons( isolate->native_context()->wasm_instance_constructor()); Handle instance_object = isolate->factory()->NewJSObject(instance_cons, TENURED); instance_object->SetEmbedderField(kWrapperTracerHeader, Smi::kZero); Handle instance_sym(isolate->native_context()->wasm_instance_sym()); Object::SetProperty(instance_object, instance_sym, instance_object, STRICT) .Check(); Handle instance( reinterpret_cast(*instance_object), isolate); instance->SetEmbedderField(kCompiledModule, *compiled_module); instance->SetEmbedderField(kMemoryObject, isolate->heap()->undefined_value()); Handle instance_wrapper = WasmInstanceWrapper::New(isolate, instance); instance->SetEmbedderField(kWasmMemInstanceWrapper, *instance_wrapper); return instance; } int32_t WasmInstanceObject::GetMemorySize() { if (!has_memory_buffer()) return 0; uint32_t bytes = memory_buffer()->byte_length()->Number(); DCHECK_EQ(0, bytes % WasmModule::kPageSize); return bytes / WasmModule::kPageSize; } int32_t WasmInstanceObject::GrowMemory(Isolate* isolate, Handle instance, uint32_t pages) { if (pages == 0) return instance->GetMemorySize(); if (instance->has_memory_object()) { return WasmMemoryObject::Grow( isolate, handle(instance->memory_object(), isolate), pages); } // No other instances to grow, grow just the one. uint32_t old_size = 0; Address old_mem_start = nullptr; Handle old_buffer; if (instance->has_memory_buffer()) { old_buffer = handle(instance->memory_buffer(), isolate); old_size = old_buffer->byte_length()->Number(); old_mem_start = static_cast
(old_buffer->backing_store()); } uint32_t max_pages = instance->GetMaxMemoryPages(); Handle buffer = GrowMemoryBuffer(isolate, old_buffer, pages, max_pages); if (buffer.is_null()) return -1; SetInstanceMemory(isolate, instance, buffer); UncheckedUpdateInstanceMemory(isolate, instance, old_mem_start, old_size); DCHECK_EQ(0, old_size % WasmModule::kPageSize); return old_size / WasmModule::kPageSize; } uint32_t WasmInstanceObject::GetMaxMemoryPages() { if (has_memory_object()) { if (memory_object()->has_maximum_pages()) { uint32_t maximum = static_cast(memory_object()->maximum_pages()); if (maximum < FLAG_wasm_max_mem_pages) return maximum; } } uint32_t compiled_max_pages = compiled_module()->module()->max_mem_pages; Isolate* isolate = GetIsolate(); assert(compiled_module()->module()->is_wasm()); isolate->counters()->wasm_wasm_max_mem_pages_count()->AddSample( compiled_max_pages); if (compiled_max_pages != 0) return compiled_max_pages; return FLAG_wasm_max_mem_pages; } WasmInstanceObject* WasmExportedFunction::instance() { return WasmInstanceObject::cast(GetEmbedderField(kInstance)); } int WasmExportedFunction::function_index() { int32_t func_index; CHECK(GetEmbedderField(kIndex)->ToInt32(&func_index)); return func_index; } WasmExportedFunction* WasmExportedFunction::cast(Object* object) { DCHECK(object && object->IsJSFunction()); DCHECK_EQ(Code::JS_TO_WASM_FUNCTION, JSFunction::cast(object)->code()->kind()); // TODO(titzer): brand check for WasmExportedFunction. return reinterpret_cast(object); } Handle WasmExportedFunction::New( Isolate* isolate, Handle instance, MaybeHandle maybe_name, int func_index, int arity, Handle export_wrapper) { Handle name; if (maybe_name.is_null()) { EmbeddedVector buffer; int length = SNPrintF(buffer, "%d", func_index); name = isolate->factory() ->NewStringFromOneByte( Vector::cast(buffer.SubVector(0, length))) .ToHandleChecked(); } else { name = maybe_name.ToHandleChecked(); } DCHECK_EQ(Code::JS_TO_WASM_FUNCTION, export_wrapper->kind()); Handle shared = isolate->factory()->NewSharedFunctionInfo(name, export_wrapper, false); shared->set_length(arity); shared->set_internal_formal_parameter_count(arity); Handle function = isolate->factory()->NewFunction( isolate->wasm_function_map(), name, export_wrapper); function->SetEmbedderField(kWrapperTracerHeader, Smi::kZero); function->set_shared(*shared); function->SetEmbedderField(kInstance, *instance); function->SetEmbedderField(kIndex, Smi::FromInt(func_index)); return Handle::cast(function); } bool WasmSharedModuleData::IsWasmSharedModuleData(Object* object) { if (!object->IsFixedArray()) return false; FixedArray* arr = FixedArray::cast(object); if (arr->length() != kFieldCount) return false; Isolate* isolate = arr->GetIsolate(); if (!arr->get(kModuleWrapper)->IsForeign()) return false; if (!arr->get(kModuleBytes)->IsUndefined(isolate) && !arr->get(kModuleBytes)->IsSeqOneByteString()) return false; if (!arr->get(kScript)->IsScript()) return false; if (!arr->get(kAsmJsOffsetTable)->IsUndefined(isolate) && !arr->get(kAsmJsOffsetTable)->IsByteArray()) return false; if (!arr->get(kBreakPointInfos)->IsUndefined(isolate) && !arr->get(kBreakPointInfos)->IsFixedArray()) return false; return true; } WasmSharedModuleData* WasmSharedModuleData::cast(Object* object) { DCHECK(IsWasmSharedModuleData(object)); return reinterpret_cast(object); } wasm::WasmModule* WasmSharedModuleData::module() { // We populate the kModuleWrapper field with a Foreign holding the // address to the address of a WasmModule. This is because we can // handle both cases when the WasmModule's lifetime is managed through // a Managed object, as well as cases when it's managed // by the embedder. CcTests fall into the latter case. return *(reinterpret_cast( Foreign::cast(get(kModuleWrapper))->foreign_address())); } DEFINE_OPTIONAL_ARR_ACCESSORS(WasmSharedModuleData, module_bytes, kModuleBytes, SeqOneByteString); DEFINE_ARR_GETTER(WasmSharedModuleData, script, kScript, Script); DEFINE_OPTIONAL_ARR_ACCESSORS(WasmSharedModuleData, asm_js_offset_table, kAsmJsOffsetTable, ByteArray); DEFINE_OPTIONAL_ARR_GETTER(WasmSharedModuleData, breakpoint_infos, kBreakPointInfos, FixedArray); DEFINE_OPTIONAL_ARR_GETTER(WasmSharedModuleData, lazy_compilation_orchestrator, kLazyCompilationOrchestrator, Foreign); Handle WasmSharedModuleData::New( Isolate* isolate, Handle module_wrapper, Handle module_bytes, Handle