| Index: src/wasm/wasm-module.cc | 
| diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc | 
| index a25fd7b2fc0aebe1fc6b0c49b90f4e1f69bdb4fc..e48a841e45c8281733136585ff4b8bd0e6ae0d52 100644 | 
| --- a/src/wasm/wasm-module.cc | 
| +++ b/src/wasm/wasm-module.cc | 
| @@ -44,62 +44,17 @@ static const int kPlaceholderMarker = 1000000000; | 
|  | 
| enum JSFunctionExportInternalField { | 
| kInternalModuleInstance, | 
| -  kInternalArity, | 
| -  kInternalSignature | 
| +  kInternalFunctionIndex | 
| }; | 
|  | 
| // Internal constants for the layout of the module object. | 
| enum WasmInstanceObjectFields { | 
| kWasmCompiledModule = 0, | 
| -  kWasmModuleFunctionTable, | 
| -  kWasmModuleCodeTable, | 
| kWasmMemObject, | 
| kWasmMemArrayBuffer, | 
| kWasmGlobalsArrayBuffer, | 
| kWasmDebugInfo, | 
| -  kWasmModuleInternalFieldCount | 
| -}; | 
| - | 
| -enum WasmImportData { | 
| -  kImportKind,         // Smi. an ExternalKind | 
| -  kImportGlobalType,   // Smi. Type for globals. | 
| -  kImportIndex,        // Smi. index for the import. | 
| -  kModuleName,         // String | 
| -  kFunctionName,       // maybe String | 
| -  kOutputCount,        // Smi. an uint32_t | 
| -  kSignature,          // ByteArray. A copy of the data in FunctionSig | 
| -  kWasmImportDataSize  // Sentinel value. | 
| -}; | 
| - | 
| -enum WasmExportData { | 
| -  kExportKind,         // Smi. an ExternalKind | 
| -  kExportGlobalType,   // Smi. Type for globals. | 
| -  kExportName,         // String | 
| -  kExportArity,        // Smi, an int | 
| -  kExportIndex,        // Smi, an uint32_t | 
| -  kExportedSignature,  // ByteArray. A copy of the data in FunctionSig | 
| -  kWasmExportDataSize  // Sentinel value. | 
| -}; | 
| - | 
| -enum WasmGlobalInitData { | 
| -  kGlobalInitKind,   // 0 = constant, 1 = global index | 
| -  kGlobalInitType,   // Smi. Type for globals. | 
| -  kGlobalInitIndex,  // Smi, an uint32_t | 
| -  kGlobalInitValue,  // Number. | 
| -  kWasmGlobalInitDataSize | 
| -}; | 
| - | 
| -enum WasmSegmentInfo { | 
| -  kDestAddrKind,        // 0 = constant, 1 = global index | 
| -  kDestAddrValue,       // Smi. an uint32_t | 
| -  kSourceSize,          // Smi. an uint32_t | 
| -  kWasmSegmentInfoSize  // Sentinel value. | 
| -}; | 
| - | 
| -enum WasmIndirectFunctionTableData { | 
| -  kSize,                              // Smi. an uint32_t | 
| -  kTable,                             // FixedArray of indirect function table | 
| -  kWasmIndirectFunctionTableDataSize  // Sentinel value. | 
| +  kWasmInstanceInternalFieldCount | 
| }; | 
|  | 
| byte* raw_buffer_ptr(MaybeHandle<JSArrayBuffer> buffer, int offset) { | 
| @@ -110,53 +65,24 @@ uint32_t GetMinModuleMemSize(const WasmModule* module) { | 
| return WasmModule::kPageSize * module->min_mem_pages; | 
| } | 
|  | 
| -void SaveDataSegmentInfo(Factory* factory, const WasmModule* module, | 
| -                         Handle<WasmCompiledModule> compiled_module) { | 
| -  Handle<FixedArray> segments = factory->NewFixedArray( | 
| -      static_cast<int>(module->data_segments.size()), TENURED); | 
| -  uint32_t data_size = 0; | 
| -  for (const WasmDataSegment& segment : module->data_segments) { | 
| -    if (segment.source_size == 0) continue; | 
| -    data_size += segment.source_size; | 
| -  } | 
| -  Handle<ByteArray> data = factory->NewByteArray(data_size, TENURED); | 
| - | 
| -  uint32_t last_insertion_pos = 0; | 
| -  for (uint32_t i = 0; i < module->data_segments.size(); ++i) { | 
| -    const WasmDataSegment& segment = module->data_segments[i]; | 
| -    if (segment.source_size == 0) continue; | 
| -    Handle<ByteArray> js_segment = | 
| -        factory->NewByteArray(kWasmSegmentInfoSize * sizeof(uint32_t), TENURED); | 
| -    if (segment.dest_addr.kind == WasmInitExpr::kGlobalIndex) { | 
| -      // The destination address is the value of a global variable. | 
| -      js_segment->set_int(kDestAddrKind, 1); | 
| -      uint32_t offset = | 
| -          module->globals[segment.dest_addr.val.global_index].offset; | 
| -      js_segment->set_int(kDestAddrValue, static_cast<int>(offset)); | 
| -    } else { | 
| -      // The destination address is a constant. | 
| -      CHECK_EQ(WasmInitExpr::kI32Const, segment.dest_addr.kind); | 
| -      js_segment->set_int(kDestAddrKind, 0); | 
| -      js_segment->set_int(kDestAddrValue, segment.dest_addr.val.i32_const); | 
| -    } | 
| -    js_segment->set_int(kSourceSize, segment.source_size); | 
| -    segments->set(i, *js_segment); | 
| -    data->copy_in(last_insertion_pos, | 
| -                  module->module_start + segment.source_offset, | 
| -                  segment.source_size); | 
| -    last_insertion_pos += segment.source_size; | 
| -  } | 
| -  compiled_module->set_data_segments_info(segments); | 
| -  compiled_module->set_data_segments(data); | 
| +MaybeHandle<String> ExtractStringFromModuleBytes( | 
| +    Isolate* isolate, Handle<WasmCompiledModule> compiled_module, | 
| +    uint32_t offset, uint32_t size) { | 
| +  // TODO(wasm): cache strings from modules if it's a performance win. | 
| +  Handle<SeqOneByteString> module_bytes = compiled_module->module_bytes(); | 
| +  Address raw = module_bytes->GetCharsAddress() + offset; | 
| +  if (!unibrow::Utf8::Validate(reinterpret_cast<const byte*>(raw), size)) | 
| +    return {};  // UTF8 decoding error for name. | 
| +  return isolate->factory()->NewStringFromUtf8SubString( | 
| +      module_bytes, static_cast<int>(offset), static_cast<int>(size)); | 
| } | 
|  | 
| -void PatchFunctionTable(Handle<Code> code, | 
| -                        Handle<FixedArray> old_indirect_table, | 
| -                        Handle<FixedArray> new_indirect_table) { | 
| +void ReplaceReferenceInCode(Handle<Code> code, Handle<Object> old_ref, | 
| +                            Handle<Object> new_ref) { | 
| for (RelocIterator it(*code, 1 << RelocInfo::EMBEDDED_OBJECT); !it.done(); | 
| it.next()) { | 
| -    if (it.rinfo()->target_object() == *old_indirect_table) { | 
| -      it.rinfo()->set_target_object(*new_indirect_table); | 
| +    if (it.rinfo()->target_object() == *old_ref) { | 
| +      it.rinfo()->set_target_object(*new_ref); | 
| } | 
| } | 
| } | 
| @@ -185,33 +111,30 @@ Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, size_t size) { | 
| return buffer; | 
| } | 
|  | 
| -void RelocateInstanceCode(Handle<JSObject> instance, Address old_start, | 
| -                          Address start, uint32_t prev_size, | 
| -                          uint32_t new_size) { | 
| -  Handle<FixedArray> functions = Handle<FixedArray>( | 
| -      FixedArray::cast(instance->GetInternalField(kWasmModuleCodeTable))); | 
| -  for (int i = 0; i < functions->length(); ++i) { | 
| -    Handle<Code> function = Handle<Code>(Code::cast(functions->get(i))); | 
| +void RelocateMemoryReferencesInCode(Handle<FixedArray> code_table, | 
| +                                    Address old_start, Address start, | 
| +                                    uint32_t prev_size, uint32_t new_size) { | 
| +  for (int i = 0; i < code_table->length(); ++i) { | 
| +    DCHECK(code_table->get(i)->IsCode()); | 
| +    Handle<Code> code = Handle<Code>(Code::cast(code_table->get(i))); | 
| AllowDeferredHandleDereference embedding_raw_address; | 
| int mask = (1 << RelocInfo::WASM_MEMORY_REFERENCE) | | 
| (1 << RelocInfo::WASM_MEMORY_SIZE_REFERENCE); | 
| -    for (RelocIterator it(*function, mask); !it.done(); it.next()) { | 
| +    for (RelocIterator it(*code, mask); !it.done(); it.next()) { | 
| it.rinfo()->update_wasm_memory_reference(old_start, start, prev_size, | 
| new_size); | 
| } | 
| } | 
| } | 
|  | 
| -void RelocateGlobals(Handle<JSObject> instance, Address old_start, | 
| +void RelocateGlobals(Handle<FixedArray> code_table, Address old_start, | 
| Address globals_start) { | 
| -  Handle<FixedArray> functions = Handle<FixedArray>( | 
| -      FixedArray::cast(instance->GetInternalField(kWasmModuleCodeTable))); | 
| -  uint32_t function_count = static_cast<uint32_t>(functions->length()); | 
| -  for (uint32_t i = 0; i < function_count; ++i) { | 
| -    Handle<Code> function = Handle<Code>(Code::cast(functions->get(i))); | 
| +  for (int i = 0; i < code_table->length(); ++i) { | 
| +    DCHECK(code_table->get(i)->IsCode()); | 
| +    Handle<Code> code = Handle<Code>(Code::cast(code_table->get(i))); | 
| AllowDeferredHandleDereference embedding_raw_address; | 
| int mask = 1 << RelocInfo::WASM_GLOBAL_REFERENCE; | 
| -    for (RelocIterator it(*function, mask); !it.done(); it.next()) { | 
| +    for (RelocIterator it(*code, mask); !it.done(); it.next()) { | 
| it.rinfo()->update_wasm_global_reference(old_start, globals_start); | 
| } | 
| } | 
| @@ -265,9 +188,9 @@ bool LinkFunction(Handle<Code> unlinked, | 
| return modified; | 
| } | 
|  | 
| -void FlushICache(Isolate* isolate, Handle<FixedArray> functions) { | 
| -  for (int i = 0; i < functions->length(); ++i) { | 
| -    Handle<Code> code = functions->GetValueChecked<Code>(isolate, i); | 
| +void FlushICache(Isolate* isolate, Handle<FixedArray> code_table) { | 
| +  for (int i = 0; i < code_table->length(); ++i) { | 
| +    Handle<Code> code = code_table->GetValueChecked<Code>(isolate, i); | 
| Assembler::FlushICache(isolate, code->instruction_start(), | 
| code->instruction_size()); | 
| } | 
| @@ -356,69 +279,6 @@ Address GetGlobalStartAddressFromCodeTemplate(Object* undefined, | 
| return old_address; | 
| } | 
|  | 
| -Handle<FixedArray> EncodeImports(Factory* factory, const WasmModule* module) { | 
| -  // TODO(wasm): Encode this in one big FixedArray. | 
| -  Handle<FixedArray> ret = factory->NewFixedArray( | 
| -      static_cast<int>(module->import_table.size()), TENURED); | 
| - | 
| -  for (size_t i = 0; i < module->import_table.size(); ++i) { | 
| -    const WasmImport& import = module->import_table[i]; | 
| -    Handle<FixedArray> encoded_import = | 
| -        factory->NewFixedArray(kWasmImportDataSize, TENURED); | 
| -    encoded_import->set(kImportKind, Smi::FromInt(import.kind)); | 
| -    encoded_import->set(kImportIndex, Smi::FromInt(import.index)); | 
| - | 
| -    // Add the module and function name. | 
| -    WasmName module_name = module->GetNameOrNull(import.module_name_offset, | 
| -                                                 import.module_name_length); | 
| -    WasmName function_name = module->GetNameOrNull(import.field_name_offset, | 
| -                                                   import.field_name_length); | 
| - | 
| -    Handle<String> module_name_string = | 
| -        factory->InternalizeUtf8String(module_name); | 
| -    encoded_import->set(kModuleName, *module_name_string); | 
| -    if (!function_name.is_empty()) { | 
| -      Handle<String> function_name_string = | 
| -          factory->InternalizeUtf8String(function_name); | 
| -      encoded_import->set(kFunctionName, *function_name_string); | 
| -    } | 
| - | 
| -    switch (import.kind) { | 
| -      case kExternalFunction: { | 
| -        // Encode the signature into the import. | 
| -        FunctionSig* fsig = module->functions[import.index].sig; | 
| -        Handle<ByteArray> sig = factory->NewByteArray( | 
| -            static_cast<int>(fsig->parameter_count() + fsig->return_count()), | 
| -            TENURED); | 
| -        sig->copy_in(0, reinterpret_cast<const byte*>(fsig->raw_data()), | 
| -                     sig->length()); | 
| -        encoded_import->set( | 
| -            kOutputCount, Smi::FromInt(static_cast<int>(fsig->return_count()))); | 
| -        encoded_import->set(kSignature, *sig); | 
| -        break; | 
| -      } | 
| -      case kExternalTable: | 
| -        // Nothing extra required for imported tables. | 
| -        break; | 
| -      case kExternalMemory: | 
| -        // Nothing extra required for imported memories. | 
| -        break; | 
| -      case kExternalGlobal: { | 
| -        // Encode the offset and the global type into the import. | 
| -        const WasmGlobal& global = module->globals[import.index]; | 
| -        TRACE("import[%zu].type = %s\n", i, WasmOpcodes::TypeName(global.type)); | 
| -        encoded_import->set( | 
| -            kImportGlobalType, | 
| -            Smi::FromInt(WasmOpcodes::LocalTypeCodeFor(global.type))); | 
| -        encoded_import->set(kImportIndex, Smi::FromInt(global.offset)); | 
| -        break; | 
| -      } | 
| -    } | 
| -    ret->set(static_cast<int>(i), *encoded_import); | 
| -  } | 
| -  return ret; | 
| -} | 
| - | 
| void InitializeParallelCompilation( | 
| Isolate* isolate, const std::vector<WasmFunction>& functions, | 
| std::vector<compiler::WasmCompilationUnit*>& compilation_units, | 
| @@ -610,15 +470,22 @@ static void ResetCompiledModule(Isolate* isolate, JSObject* owner, | 
| WasmCompiledModule* compiled_module) { | 
| TRACE("Resetting %d\n", compiled_module->instance_id()); | 
| Object* undefined = *isolate->factory()->undefined_value(); | 
| -  uint32_t old_mem_size = compiled_module->has_heap() | 
| -                              ? compiled_module->mem_size() | 
| -                              : compiled_module->default_mem_size(); | 
| +  uint32_t old_mem_size = compiled_module->mem_size(); | 
| uint32_t default_mem_size = compiled_module->default_mem_size(); | 
| -  Object* mem_start = compiled_module->ptr_to_heap(); | 
| +  Object* mem_start = compiled_module->ptr_to_memory(); | 
| Address old_mem_address = nullptr; | 
| Address globals_start = | 
| GetGlobalStartAddressFromCodeTemplate(undefined, owner); | 
|  | 
| +  // Reset function tables. | 
| +  FixedArray* function_tables = nullptr; | 
| +  FixedArray* empty_function_tables = nullptr; | 
| +  if (compiled_module->has_function_tables()) { | 
| +    function_tables = compiled_module->ptr_to_function_tables(); | 
| +    empty_function_tables = compiled_module->ptr_to_empty_function_tables(); | 
| +    compiled_module->set_ptr_to_function_tables(empty_function_tables); | 
| +  } | 
| + | 
| if (old_mem_size > 0) { | 
| CHECK_NE(mem_start, undefined); | 
| old_mem_address = | 
| @@ -626,8 +493,11 @@ static void ResetCompiledModule(Isolate* isolate, JSObject* owner, | 
| } | 
| int mode_mask = RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_REFERENCE) | | 
| RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_SIZE_REFERENCE) | | 
| -                  RelocInfo::ModeMask(RelocInfo::WASM_GLOBAL_REFERENCE); | 
| +                  RelocInfo::ModeMask(RelocInfo::WASM_GLOBAL_REFERENCE) | | 
| +                  RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); | 
|  | 
| +  // Patch code to update memory references, global references, and function | 
| +  // table references. | 
| Object* fct_obj = compiled_module->ptr_to_code_table(); | 
| if (fct_obj != nullptr && fct_obj != undefined && | 
| (old_mem_size > 0 || globals_start != nullptr)) { | 
| @@ -642,10 +512,17 @@ static void ResetCompiledModule(Isolate* isolate, JSObject* owner, | 
| it.rinfo()->update_wasm_memory_reference( | 
| old_mem_address, nullptr, old_mem_size, default_mem_size); | 
| changed = true; | 
| -        } else { | 
| -          CHECK(RelocInfo::IsWasmGlobalReference(mode)); | 
| +        } else if (RelocInfo::IsWasmGlobalReference(mode)) { | 
| it.rinfo()->update_wasm_global_reference(globals_start, nullptr); | 
| changed = true; | 
| +        } else if (RelocInfo::IsEmbeddedObject(mode) && function_tables) { | 
| +          Object* old = it.rinfo()->target_object(); | 
| +          for (int i = 0; i < function_tables->length(); ++i) { | 
| +            if (function_tables->get(i) == old) { | 
| +              it.rinfo()->set_target_object(empty_function_tables->get(i)); | 
| +              changed = true; | 
| +            } | 
| +          } | 
| } | 
| } | 
| if (changed) { | 
| @@ -654,7 +531,7 @@ static void ResetCompiledModule(Isolate* isolate, JSObject* owner, | 
| } | 
| } | 
| } | 
| -  compiled_module->reset_heap(); | 
| +  compiled_module->reset_memory(); | 
| } | 
|  | 
| static void InstanceFinalizer(const v8::WeakCallbackInfo<void>& data) { | 
| @@ -663,16 +540,16 @@ static void InstanceFinalizer(const v8::WeakCallbackInfo<void>& data) { | 
| WasmCompiledModule* compiled_module = GetCompiledModule(owner); | 
| TRACE("Finalizing %d {\n", compiled_module->instance_id()); | 
| Isolate* isolate = reinterpret_cast<Isolate*>(data.GetIsolate()); | 
| -  DCHECK(compiled_module->has_weak_module_object()); | 
| -  WeakCell* weak_module_obj = compiled_module->ptr_to_weak_module_object(); | 
| +  DCHECK(compiled_module->has_weak_wasm_module()); | 
| +  WeakCell* weak_wasm_module = compiled_module->ptr_to_weak_wasm_module(); | 
|  | 
| -  // weak_module_obj may have been cleared, meaning the module object | 
| +  // weak_wasm_module may have been cleared, meaning the module object | 
| // was GC-ed. In that case, there won't be any new instances created, | 
| // and we don't need to maintain the links between instances. | 
| -  if (!weak_module_obj->cleared()) { | 
| -    JSObject* module_obj = JSObject::cast(weak_module_obj->value()); | 
| +  if (!weak_wasm_module->cleared()) { | 
| +    JSObject* wasm_module = JSObject::cast(weak_wasm_module->value()); | 
| WasmCompiledModule* current_template = | 
| -        WasmCompiledModule::cast(module_obj->GetInternalField(0)); | 
| +        WasmCompiledModule::cast(wasm_module->GetInternalField(0)); | 
|  | 
| TRACE("chain before {\n"); | 
| TRACE_CHAIN(current_template); | 
| @@ -687,7 +564,7 @@ static void InstanceFinalizer(const v8::WeakCallbackInfo<void>& data) { | 
| ResetCompiledModule(isolate, owner, compiled_module); | 
| } else { | 
| DCHECK(next->value()->IsFixedArray()); | 
| -        module_obj->SetInternalField(0, next->value()); | 
| +        wasm_module->SetInternalField(0, next->value()); | 
| DCHECK_NULL(prev); | 
| WasmCompiledModule::cast(next->value())->reset_weak_prev_instance(); | 
| } | 
| @@ -716,7 +593,7 @@ static void InstanceFinalizer(const v8::WeakCallbackInfo<void>& data) { | 
| } | 
| } | 
| TRACE("chain after {\n"); | 
| -    TRACE_CHAIN(WasmCompiledModule::cast(module_obj->GetInternalField(0))); | 
| +    TRACE_CHAIN(WasmCompiledModule::cast(wasm_module->GetInternalField(0))); | 
| TRACE("}\n"); | 
| } | 
| compiled_module->reset_weak_owning_instance(); | 
| @@ -724,36 +601,6 @@ static void InstanceFinalizer(const v8::WeakCallbackInfo<void>& data) { | 
| TRACE("}\n"); | 
| } | 
|  | 
| -Handle<FixedArray> SetupIndirectFunctionTable( | 
| -    Isolate* isolate, Handle<FixedArray> wasm_functions, | 
| -    Handle<FixedArray> indirect_table_template, | 
| -    Handle<FixedArray> tables_to_replace) { | 
| -  Factory* factory = isolate->factory(); | 
| -  Handle<FixedArray> cloned_indirect_tables = | 
| -      factory->CopyFixedArray(indirect_table_template); | 
| -  for (int i = 0; i < cloned_indirect_tables->length(); ++i) { | 
| -    Handle<FixedArray> orig_metadata = | 
| -        cloned_indirect_tables->GetValueChecked<FixedArray>(isolate, i); | 
| -    Handle<FixedArray> cloned_metadata = factory->CopyFixedArray(orig_metadata); | 
| -    cloned_indirect_tables->set(i, *cloned_metadata); | 
| - | 
| -    Handle<FixedArray> orig_table = | 
| -        cloned_metadata->GetValueChecked<FixedArray>(isolate, kTable); | 
| -    Handle<FixedArray> cloned_table = factory->CopyFixedArray(orig_table); | 
| -    cloned_metadata->set(kTable, *cloned_table); | 
| -    // Patch the cloned code to refer to the cloned kTable. | 
| -    Handle<FixedArray> table_to_replace = | 
| -        tables_to_replace->GetValueChecked<FixedArray>(isolate, i) | 
| -            ->GetValueChecked<FixedArray>(isolate, kTable); | 
| -    for (int fct_index = 0; fct_index < wasm_functions->length(); ++fct_index) { | 
| -      Handle<Code> wasm_function = | 
| -          wasm_functions->GetValueChecked<Code>(isolate, fct_index); | 
| -      PatchFunctionTable(wasm_function, table_to_replace, cloned_table); | 
| -    } | 
| -  } | 
| -  return cloned_indirect_tables; | 
| -} | 
| - | 
| }  // namespace | 
|  | 
| const char* wasm::SectionName(WasmSectionCode code) { | 
| @@ -824,10 +671,11 @@ std::ostream& wasm::operator<<(std::ostream& os, const WasmFunctionName& pair) { | 
| } | 
|  | 
| Handle<JSFunction> wasm::WrapExportCodeAsJSFunction( | 
| -    Isolate* isolate, Handle<Code> export_code, Handle<String> name, int arity, | 
| -    MaybeHandle<ByteArray> maybe_signature, Handle<JSObject> instance) { | 
| +    Isolate* isolate, Handle<Code> export_code, Handle<String> name, | 
| +    FunctionSig* sig, int func_index, Handle<JSObject> instance) { | 
| Handle<SharedFunctionInfo> shared = | 
| isolate->factory()->NewSharedFunctionInfo(name, export_code, false); | 
| +  int arity = static_cast<int>(sig->parameter_count()); | 
| shared->set_length(arity); | 
| shared->set_internal_formal_parameter_count(arity); | 
| Handle<JSFunction> function = isolate->factory()->NewFunction( | 
| @@ -835,13 +683,7 @@ Handle<JSFunction> wasm::WrapExportCodeAsJSFunction( | 
| function->set_shared(*shared); | 
|  | 
| function->SetInternalField(kInternalModuleInstance, *instance); | 
| -  // add another Internal Field as the function arity | 
| -  function->SetInternalField(kInternalArity, Smi::FromInt(arity)); | 
| -  // add another Internal Field as the signature of the foreign function | 
| -  Handle<ByteArray> signature; | 
| -  if (maybe_signature.ToHandle(&signature)) { | 
| -    function->SetInternalField(kInternalSignature, *signature); | 
| -  } | 
| +  function->SetInternalField(kInternalFunctionIndex, Smi::FromInt(func_index)); | 
| return function; | 
| } | 
|  | 
| @@ -857,78 +699,25 @@ Object* wasm::GetOwningWasmInstance(Code* code) { | 
| return cell->value(); | 
| } | 
|  | 
| -int wasm::GetNumImportedFunctions(Handle<JSObject> instance) { | 
| -  // TODO(wasm): Cache this number if it ever becomes a performance problem. | 
| +WasmModule* GetCppModule(Handle<JSObject> instance) { | 
| DCHECK(IsWasmInstance(*instance)); | 
| -  WasmCompiledModule* compiled_module = GetCompiledModule(*instance); | 
| -  Handle<FixedArray> imports = | 
| -      WasmCompiledModule::cast(compiled_module)->imports(); | 
| -  int num_imports = imports->length(); | 
| -  int num_imported_functions = 0; | 
| -  for (int i = 0; i < num_imports; ++i) { | 
| -    FixedArray* encoded_import = FixedArray::cast(imports->get(i)); | 
| -    int kind = Smi::cast(encoded_import->get(kImportKind))->value(); | 
| -    if (kind == kExternalFunction) ++num_imported_functions; | 
| -  } | 
| -  return num_imported_functions; | 
| +  return reinterpret_cast<WasmModuleWrapper*>( | 
| +             *GetCompiledModule(*instance)->module_wrapper()) | 
| +      ->get(); | 
| } | 
|  | 
| -WasmModule::WasmModule(byte* module_start) | 
| -    : module_start(module_start), | 
| -      module_end(nullptr), | 
| -      min_mem_pages(0), | 
| -      max_mem_pages(0), | 
| -      mem_export(false), | 
| -      start_function_index(-1), | 
| -      origin(kWasmOrigin), | 
| -      globals_size(0), | 
| -      num_imported_functions(0), | 
| -      num_declared_functions(0), | 
| -      num_exported_functions(0), | 
| -      pending_tasks(new base::Semaphore(0)) {} | 
| - | 
| -namespace { | 
| - | 
| -void EncodeInit(const WasmModule* module, Factory* factory, | 
| -                Handle<FixedArray> entry, int kind_index, int value_index, | 
| -                const WasmInitExpr& expr) { | 
| -  entry->set(kind_index, Smi::kZero); | 
| - | 
| -  Handle<Object> value; | 
| -  switch (expr.kind) { | 
| -    case WasmInitExpr::kGlobalIndex: { | 
| -      TRACE("  kind = 1, global index %u\n", expr.val.global_index); | 
| -      entry->set(kind_index, Smi::FromInt(1)); | 
| -      uint32_t offset = module->globals[expr.val.global_index].offset; | 
| -      entry->set(value_index, Smi::FromInt(offset)); | 
| -      return; | 
| -    } | 
| -    case WasmInitExpr::kI32Const: | 
| -      TRACE("  kind = 0, i32 = %d\n", expr.val.i32_const); | 
| -      value = factory->NewNumber(expr.val.i32_const); | 
| -      break; | 
| -    case WasmInitExpr::kI64Const: | 
| -      // TODO(titzer): implement initializers for i64 globals. | 
| -      UNREACHABLE(); | 
| -      break; | 
| -    case WasmInitExpr::kF32Const: | 
| -      TRACE("  kind = 0, f32 = %f\n", expr.val.f32_const); | 
| -      value = factory->NewNumber(expr.val.f32_const); | 
| -      break; | 
| -    case WasmInitExpr::kF64Const: | 
| -      TRACE("  kind = 0, f64 = %lf\n", expr.val.f64_const); | 
| -      value = factory->NewNumber(expr.val.f64_const); | 
| -      break; | 
| -    default: | 
| -      UNREACHABLE(); | 
| -  } | 
| -  entry->set(value_index, *value); | 
| +int wasm::GetNumImportedFunctions(Handle<JSObject> instance) { | 
| +  return static_cast<int>(GetCppModule(instance)->num_imported_functions); | 
| } | 
|  | 
| -}  // namespace | 
| +WasmModule::WasmModule(Zone* owned, const byte* module_start) | 
| +    : owned_zone(owned), | 
| +      module_start(module_start), | 
| +      pending_tasks(new base::Semaphore(0)) {} | 
|  | 
| MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions( | 
| -    Isolate* isolate, ErrorThrower* thrower) const { | 
| +    Isolate* isolate, Handle<WasmModuleWrapper> module_wrapper, | 
| +    ErrorThrower* thrower) const { | 
| Factory* factory = isolate->factory(); | 
|  | 
| MaybeHandle<WasmCompiledModule> nothing; | 
| @@ -939,20 +728,13 @@ MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions( | 
| temp_instance.mem_start = nullptr; | 
| temp_instance.globals_start = nullptr; | 
|  | 
| -  MaybeHandle<FixedArray> indirect_table = | 
| -      function_tables.size() | 
| -          ? factory->NewFixedArray(static_cast<int>(function_tables.size()), | 
| -                                   TENURED) | 
| -          : MaybeHandle<FixedArray>(); | 
| -  for (uint32_t i = 0; i < function_tables.size(); ++i) { | 
| -    Handle<FixedArray> values = wasm::BuildFunctionTable(isolate, i, this); | 
| -    temp_instance.function_tables[i] = values; | 
| - | 
| -    Handle<FixedArray> metadata = isolate->factory()->NewFixedArray( | 
| -        kWasmIndirectFunctionTableDataSize, TENURED); | 
| -    metadata->set(kSize, Smi::FromInt(function_tables[i].size)); | 
| -    metadata->set(kTable, *values); | 
| -    indirect_table.ToHandleChecked()->set(i, *metadata); | 
| +  // Initialize the indirect tables with placeholders. | 
| +  int function_table_count = static_cast<int>(this->function_tables.size()); | 
| +  Handle<FixedArray> function_tables = | 
| +      factory->NewFixedArray(function_table_count); | 
| +  for (int i = 0; i < function_table_count; ++i) { | 
| +    temp_instance.function_tables[i] = factory->NewFixedArray(0); | 
| +    function_tables->set(i, *temp_instance.function_tables[i]); | 
| } | 
|  | 
| HistogramTimerScope wasm_compile_module_time_scope( | 
| @@ -1023,122 +805,30 @@ MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions( | 
| // serializable. Instantiation may occur off a deserialized version of this | 
| // object. | 
| Handle<WasmCompiledModule> ret = | 
| -      WasmCompiledModule::New(isolate, min_mem_pages, globals_size, origin); | 
| +      WasmCompiledModule::New(isolate, module_wrapper); | 
| ret->set_code_table(code_table); | 
| -  if (!indirect_table.is_null()) { | 
| -    ret->set_indirect_function_tables(indirect_table.ToHandleChecked()); | 
| +  ret->set_min_mem_pages(min_mem_pages); | 
| +  if (function_table_count > 0) { | 
| +    ret->set_function_tables(function_tables); | 
| +    ret->set_empty_function_tables(function_tables); | 
| } | 
|  | 
| -  // Create and set import data. | 
| -  Handle<FixedArray> imports = EncodeImports(factory, this); | 
| -  ret->set_imports(imports); | 
| - | 
| -  // Create and set export data. | 
| -  int export_size = static_cast<int>(export_table.size()); | 
| -  if (export_size > 0) { | 
| -    Handle<FixedArray> exports = factory->NewFixedArray(export_size, TENURED); | 
| -    int index = 0; | 
| -    int func_index = 0; | 
| - | 
| -    for (const WasmExport& exp : export_table) { | 
| -      if (thrower->error()) return nothing; | 
| -      Handle<FixedArray> encoded_export = | 
| -          factory->NewFixedArray(kWasmExportDataSize, TENURED); | 
| -      WasmName str = GetName(exp.name_offset, exp.name_length); | 
| -      Handle<String> name = factory->InternalizeUtf8String(str); | 
| -      encoded_export->set(kExportKind, Smi::FromInt(exp.kind)); | 
| -      encoded_export->set(kExportName, *name); | 
| -      encoded_export->set(kExportIndex, | 
| -                          Smi::FromInt(static_cast<int>(exp.index))); | 
| -      exports->set(index, *encoded_export); | 
| - | 
| -      switch (exp.kind) { | 
| -        case kExternalFunction: { | 
| -          // Copy the signature and arity. | 
| -          FunctionSig* funcSig = functions[exp.index].sig; | 
| -          Handle<ByteArray> exportedSig = factory->NewByteArray( | 
| -              static_cast<int>(funcSig->parameter_count() + | 
| -                               funcSig->return_count()), | 
| -              TENURED); | 
| -          exportedSig->copy_in( | 
| -              0, reinterpret_cast<const byte*>(funcSig->raw_data()), | 
| -              exportedSig->length()); | 
| -          encoded_export->set(kExportedSignature, *exportedSig); | 
| -          encoded_export->set( | 
| -              kExportArity, | 
| -              Smi::FromInt(static_cast<int>(funcSig->parameter_count()))); | 
| - | 
| -          // Compile a wrapper for an exported function. | 
| -          Handle<Code> code = | 
| -              code_table->GetValueChecked<Code>(isolate, exp.index); | 
| -          Handle<Code> export_code = compiler::CompileJSToWasmWrapper( | 
| -              isolate, &module_env, code, exp.index); | 
| -          int code_table_index = | 
| -              static_cast<int>(functions.size() + func_index); | 
| -          code_table->set(code_table_index, *export_code); | 
| -          encoded_export->set(kExportIndex, Smi::FromInt(code_table_index)); | 
| -          ++func_index; | 
| -        } | 
| -        case kExternalTable: | 
| -          // Nothing special about exported tables. | 
| -          break; | 
| -        case kExternalMemory: | 
| -          // Nothing special about exported tables. | 
| -          break; | 
| -        case kExternalGlobal: { | 
| -          // Encode the global type and the global offset. | 
| -          const WasmGlobal& global = globals[exp.index]; | 
| -          encoded_export->set( | 
| -              kExportGlobalType, | 
| -              Smi::FromInt(WasmOpcodes::LocalTypeCodeFor(global.type))); | 
| -          encoded_export->set(kExportIndex, Smi::FromInt(global.offset)); | 
| -          break; | 
| -        } | 
| -      } | 
| -      ++index; | 
| -    } | 
| -    ret->set_exports(exports); | 
| -  } | 
| - | 
| -  // Create and set init data. | 
| -  int init_size = static_cast<int>(globals.size()); | 
| -  if (init_size > 0) { | 
| -    Handle<FixedArray> inits = factory->NewFixedArray(init_size, TENURED); | 
| -    int index = 0; | 
| -    for (const WasmGlobal& global : globals) { | 
| -      // Skip globals that have no initializer (e.g. imported ones). | 
| -      if (global.init.kind == WasmInitExpr::kNone) continue; | 
| - | 
| -      Handle<FixedArray> encoded_init = | 
| -          factory->NewFixedArray(kWasmGlobalInitDataSize, TENURED); | 
| -      inits->set(index, *encoded_init); | 
| -      TRACE("init[%d].type = %s\n", index, WasmOpcodes::TypeName(global.type)); | 
| - | 
| -      encoded_init->set( | 
| -          kGlobalInitType, | 
| -          Smi::FromInt(WasmOpcodes::LocalTypeCodeFor(global.type))); | 
| -      encoded_init->set(kGlobalInitIndex, Smi::FromInt(global.offset)); | 
| -      EncodeInit(this, factory, encoded_init, kGlobalInitKind, kGlobalInitValue, | 
| -                 global.init); | 
| -      ++index; | 
| -    } | 
| -    inits->Shrink(index); | 
| -    ret->set_inits(inits); | 
| +  // Compile JS->WASM wrappers for exported functions. | 
| +  int func_index = 0; | 
| +  for (auto exp : export_table) { | 
| +    if (exp.kind != kExternalFunction) continue; | 
| +    Handle<Code> wasm_code = | 
| +        code_table->GetValueChecked<Code>(isolate, exp.index); | 
| +    Handle<Code> wrapper_code = compiler::CompileJSToWasmWrapper( | 
| +        isolate, &module_env, wasm_code, exp.index); | 
| +    int export_index = static_cast<int>(functions.size() + func_index); | 
| +    code_table->set(export_index, *wrapper_code); | 
| +    func_index++; | 
| } | 
|  | 
| -  // Record data for startup function. | 
| -  if (start_function_index >= 0) { | 
| -    HandleScope scope(isolate); | 
| -    Handle<FixedArray> startup_data = | 
| -        factory->NewFixedArray(kWasmExportDataSize, TENURED); | 
| -    startup_data->set(kExportArity, Smi::kZero); | 
| -    startup_data->set(kExportIndex, Smi::FromInt(start_function_index)); | 
| -    ret->set_startup_function(startup_data); | 
| -  } | 
| - | 
| -  // TODO(wasm): saving the module bytes for debugging is wasteful. We should | 
| -  // consider downloading this on-demand. | 
| { | 
| +    // TODO(wasm): only save the sections necessary to deserialize a | 
| +    // {WasmModule}. E.g. function bodies could be omitted. | 
| size_t module_bytes_len = module_end - module_start; | 
| DCHECK_LE(module_bytes_len, static_cast<size_t>(kMaxInt)); | 
| Vector<const uint8_t> module_bytes_vec(module_start, | 
| @@ -1150,11 +840,6 @@ MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions( | 
| ret->set_module_bytes(Handle<SeqOneByteString>::cast(module_bytes_string)); | 
| } | 
|  | 
| -  Handle<ByteArray> function_name_table = | 
| -      BuildFunctionNamesTable(isolate, module_env.module); | 
| -  ret->set_function_names(function_name_table); | 
| -  if (data_segments.size() > 0) SaveDataSegmentInfo(factory, this, ret); | 
| -  DCHECK_EQ(ret->default_mem_size(), temp_instance.mem_size); | 
| return ret; | 
| } | 
|  | 
| @@ -1218,6 +903,8 @@ class WasmInstanceBuilder { | 
| DCHECK(!owner.is_null()); | 
| TRACE("Cloning from %d\n", original->instance_id()); | 
| compiled_module_ = WasmCompiledModule::Clone(isolate_, original); | 
| +        // Avoid creating too many handles in the outer scope. | 
| +        HandleScope scope(isolate_); | 
|  | 
| // Clone the code for WASM functions and exports. | 
| for (int i = 0; i < code_table->length(); ++i) { | 
| @@ -1246,15 +933,17 @@ class WasmInstanceBuilder { | 
| } | 
| compiled_module_->set_code_table(code_table); | 
| } | 
| +    module_ = reinterpret_cast<WasmModuleWrapper*>( | 
| +                  *compiled_module_->module_wrapper()) | 
| +                  ->get(); | 
|  | 
| //-------------------------------------------------------------------------- | 
| // Allocate the instance object. | 
| //-------------------------------------------------------------------------- | 
| Handle<Map> map = factory->NewMap( | 
| JS_OBJECT_TYPE, | 
| -        JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize); | 
| +        JSObject::kHeaderSize + kWasmInstanceInternalFieldCount * kPointerSize); | 
| Handle<JSObject> instance = factory->NewJSObjectFromMap(map, TENURED); | 
| -    instance->SetInternalField(kWasmModuleCodeTable, *code_table); | 
| instance->SetInternalField(kWasmMemObject, *factory->undefined_value()); | 
|  | 
| //-------------------------------------------------------------------------- | 
| @@ -1262,7 +951,7 @@ class WasmInstanceBuilder { | 
| //-------------------------------------------------------------------------- | 
| MaybeHandle<JSArrayBuffer> old_globals; | 
| MaybeHandle<JSArrayBuffer> globals; | 
| -    uint32_t globals_size = compiled_module_->globals_size(); | 
| +    uint32_t globals_size = module_->globals_size; | 
| if (globals_size > 0) { | 
| Handle<JSArrayBuffer> global_buffer = | 
| NewArrayBuffer(isolate_, globals_size); | 
| @@ -1276,7 +965,7 @@ class WasmInstanceBuilder { | 
| : GetGlobalStartAddressFromCodeTemplate( | 
| *factory->undefined_value(), | 
| JSObject::cast(*owner.ToHandleChecked())); | 
| -      RelocateGlobals(instance, old_address, | 
| +      RelocateGlobals(code_table, old_address, | 
| static_cast<Address>(global_buffer->backing_store())); | 
| instance->SetInternalField(kWasmGlobalsArrayBuffer, *global_buffer); | 
| } | 
| @@ -1290,15 +979,14 @@ class WasmInstanceBuilder { | 
| //-------------------------------------------------------------------------- | 
| // Process the initialization for the module's globals. | 
| //-------------------------------------------------------------------------- | 
| -    ProcessInits(globals); | 
| +    InitGlobals(globals); | 
|  | 
| //-------------------------------------------------------------------------- | 
| // Set up the memory for the new instance. | 
| //-------------------------------------------------------------------------- | 
| MaybeHandle<JSArrayBuffer> old_memory; | 
| -    // TODO(titzer): handle imported memory properly. | 
|  | 
| -    uint32_t min_mem_pages = compiled_module_->min_memory_pages(); | 
| +    uint32_t min_mem_pages = module_->min_mem_pages; | 
| isolate_->counters()->wasm_min_mem_pages_count()->AddSample(min_mem_pages); | 
| // TODO(wasm): re-enable counter for max_mem_pages when we use that field. | 
|  | 
| @@ -1314,16 +1002,15 @@ class WasmInstanceBuilder { | 
| static_cast<uint32_t>(memory_->byte_length()->Number()); | 
| LoadDataSegments(globals, mem_start, mem_size); | 
|  | 
| -      uint32_t old_mem_size = compiled_module_->has_heap() | 
| -                                  ? compiled_module_->mem_size() | 
| -                                  : compiled_module_->default_mem_size(); | 
| +      uint32_t old_mem_size = compiled_module_->mem_size(); | 
| Address old_mem_start = | 
| -          compiled_module_->has_heap() | 
| -              ? static_cast<Address>(compiled_module_->heap()->backing_store()) | 
| +          compiled_module_->has_memory() | 
| +              ? static_cast<Address>( | 
| +                    compiled_module_->memory()->backing_store()) | 
| : nullptr; | 
| -      RelocateInstanceCode(instance, old_mem_start, mem_start, old_mem_size, | 
| -                           mem_size); | 
| -      compiled_module_->set_heap(memory_); | 
| +      RelocateMemoryReferencesInCode(code_table, old_mem_start, mem_start, | 
| +                                     old_mem_size, mem_size); | 
| +      compiled_module_->set_memory(memory_); | 
| } | 
|  | 
| //-------------------------------------------------------------------------- | 
| @@ -1346,33 +1033,52 @@ class WasmInstanceBuilder { | 
| //-------------------------------------------------------------------------- | 
| // Set up the indirect function tables for the new instance. | 
| //-------------------------------------------------------------------------- | 
| -    { | 
| -      std::vector<Handle<Code>> functions( | 
| -          static_cast<size_t>(code_table->length())); | 
| -      for (int i = 0; i < code_table->length(); ++i) { | 
| -        functions[i] = code_table->GetValueChecked<Code>(isolate_, i); | 
| +    int function_table_count = | 
| +        static_cast<int>(module_->function_tables.size()); | 
| +    if (function_table_count > 0) { | 
| +      Handle<FixedArray> old_function_tables = | 
| +          compiled_module_->function_tables(); | 
| +      Handle<FixedArray> new_function_tables = | 
| +          factory->NewFixedArray(function_table_count); | 
| +      for (int index = 0; index < function_table_count; ++index) { | 
| +        WasmIndirectFunctionTable& table = module_->function_tables[index]; | 
| +        uint32_t size = table.max_size; | 
| +        Handle<FixedArray> new_table = factory->NewFixedArray(size * 2); | 
| +        for (int i = 0; i < new_table->length(); ++i) { | 
| +          static const int kInvalidSigIndex = -1; | 
| +          // Fill the table with invalid signature indexes so that uninitialized | 
| +          // entries will always fail the signature check. | 
| +          new_table->set(i, Smi::FromInt(kInvalidSigIndex)); | 
| +        } | 
| +        for (auto table_init : module_->table_inits) { | 
| +          uint32_t base = EvalUint32InitExpr(globals, table_init.offset); | 
| +          uint32_t table_size = static_cast<uint32_t>(new_table->length()); | 
| +          if (base > table_size || | 
| +              (base + table_init.entries.size() > table_size)) { | 
| +            thrower_->CompileError("table initializer is out of bounds"); | 
| +            continue; | 
| +          } | 
| +          for (size_t i = 0; i < table_init.entries.size(); ++i) { | 
| +            FunctionSig* sig = module_->functions[table_init.entries[i]].sig; | 
| +            int32_t sig_index = table.map.Find(sig); | 
| +            new_table->set(static_cast<int>(i + base), Smi::FromInt(sig_index)); | 
| +            new_table->set(static_cast<int>(i + base + size), | 
| +                           code_table->get(table_init.entries[i])); | 
| +          } | 
| +        } | 
| +        new_function_tables->set(static_cast<int>(index), *new_table); | 
| } | 
| - | 
| -      if (compiled_module_->has_indirect_function_tables()) { | 
| -        Handle<FixedArray> indirect_tables_template = | 
| -            compiled_module_->indirect_function_tables(); | 
| -        Handle<FixedArray> to_replace = | 
| -            owner.is_null() ? indirect_tables_template | 
| -                            : handle(FixedArray::cast( | 
| -                                  owner.ToHandleChecked()->GetInternalField( | 
| -                                      kWasmModuleFunctionTable))); | 
| -        Handle<FixedArray> indirect_tables = SetupIndirectFunctionTable( | 
| -            isolate_, code_table, indirect_tables_template, to_replace); | 
| -        for (int i = 0; i < indirect_tables->length(); ++i) { | 
| -          Handle<FixedArray> metadata = | 
| -              indirect_tables->GetValueChecked<FixedArray>(isolate_, i); | 
| -          uint32_t size = Smi::cast(metadata->get(kSize))->value(); | 
| -          Handle<FixedArray> table = | 
| -              metadata->GetValueChecked<FixedArray>(isolate_, kTable); | 
| -          PopulateFunctionTable(table, size, &functions); | 
| +      // Patch all code that has references to the old indirect table. | 
| +      for (int i = 0; i < code_table->length(); ++i) { | 
| +        if (!code_table->get(i)->IsCode()) continue; | 
| +        Handle<Code> code(Code::cast(code_table->get(i)), isolate_); | 
| +        for (int j = 0; j < function_table_count; ++j) { | 
| +          ReplaceReferenceInCode( | 
| +              code, Handle<Object>(old_function_tables->get(j), isolate_), | 
| +              Handle<Object>(new_function_tables->get(j), isolate_)); | 
| } | 
| -        instance->SetInternalField(kWasmModuleFunctionTable, *indirect_tables); | 
| } | 
| +      compiled_module_->set_function_tables(new_function_tables); | 
| } | 
|  | 
| //-------------------------------------------------------------------------- | 
| @@ -1413,8 +1119,8 @@ class WasmInstanceBuilder { | 
| compiled_module_->set_weak_next_instance( | 
| link_to_original.ToHandleChecked()); | 
| original.ToHandleChecked()->set_weak_prev_instance(link_to_clone); | 
| -          compiled_module_->set_weak_module_object( | 
| -              original.ToHandleChecked()->weak_module_object()); | 
| +          compiled_module_->set_weak_wasm_module( | 
| +              original.ToHandleChecked()->weak_wasm_module()); | 
| } | 
| module_object_->SetInternalField(0, *compiled_module_); | 
| instance->SetInternalField(kWasmCompiledModule, *compiled_module_); | 
| @@ -1433,19 +1139,15 @@ class WasmInstanceBuilder { | 
| //-------------------------------------------------------------------------- | 
| // Run the start function if one was specified. | 
| //-------------------------------------------------------------------------- | 
| -    if (compiled_module_->has_startup_function()) { | 
| -      Handle<FixedArray> startup_data = compiled_module_->startup_function(); | 
| +    if (module_->start_function_index >= 0) { | 
| HandleScope scope(isolate_); | 
| -      int32_t start_index = | 
| -          startup_data->GetValueChecked<Smi>(isolate_, kExportIndex)->value(); | 
| +      int start_index = module_->start_function_index; | 
| Handle<Code> startup_code = | 
| code_table->GetValueChecked<Code>(isolate_, start_index); | 
| -      int arity = Smi::cast(startup_data->get(kExportArity))->value(); | 
| -      MaybeHandle<ByteArray> startup_signature = | 
| -          startup_data->GetValue<ByteArray>(isolate_, kExportedSignature); | 
| +      FunctionSig* sig = module_->functions[start_index].sig; | 
| Handle<JSFunction> startup_fct = WrapExportCodeAsJSFunction( | 
| -          isolate_, startup_code, factory->InternalizeUtf8String("start"), | 
| -          arity, startup_signature, instance); | 
| +          isolate_, startup_code, factory->InternalizeUtf8String("start"), sig, | 
| +          start_index, instance); | 
| RecordStats(isolate_, *startup_code); | 
| // Call the JS function. | 
| Handle<Object> undefined = factory->undefined_value(); | 
| @@ -1471,6 +1173,7 @@ class WasmInstanceBuilder { | 
|  | 
| private: | 
| Isolate* isolate_; | 
| +  WasmModule* module_; | 
| ErrorThrower* thrower_; | 
| Handle<JSObject> module_object_; | 
| Handle<JSReceiver> ffi_; | 
| @@ -1534,79 +1237,65 @@ class WasmInstanceBuilder { | 
| return result; | 
| } | 
|  | 
| +  uint32_t EvalUint32InitExpr(MaybeHandle<JSArrayBuffer> globals, | 
| +                              WasmInitExpr& expr) { | 
| +    switch (expr.kind) { | 
| +      case WasmInitExpr::kI32Const: | 
| +        return expr.val.i32_const; | 
| +      case WasmInitExpr::kGlobalIndex: { | 
| +        uint32_t offset = module_->globals[expr.val.global_index].offset; | 
| +        return *reinterpret_cast<uint32_t*>(raw_buffer_ptr(globals, offset)); | 
| +      } | 
| +      default: | 
| +        UNREACHABLE(); | 
| +        return 0; | 
| +    } | 
| +  } | 
| + | 
| // Load data segments into the memory. | 
| void LoadDataSegments(MaybeHandle<JSArrayBuffer> globals, Address mem_addr, | 
| size_t mem_size) { | 
| -    CHECK(compiled_module_->has_data_segments() == | 
| -          compiled_module_->has_data_segments_info()); | 
| - | 
| -    // If we have neither, we're done. | 
| -    if (!compiled_module_->has_data_segments()) return; | 
| - | 
| -    Handle<ByteArray> data = compiled_module_->data_segments(); | 
| -    Handle<FixedArray> segments = compiled_module_->data_segments_info(); | 
| - | 
| -    uint32_t last_extraction_pos = 0; | 
| -    for (int i = 0; i < segments->length(); ++i) { | 
| -      Handle<ByteArray> segment = | 
| -          Handle<ByteArray>(ByteArray::cast(segments->get(i))); | 
| -      uint32_t dest_addr = | 
| -          static_cast<uint32_t>(segment->get_int(kDestAddrValue)); | 
| -      if (segment->get_int(kDestAddrKind) == 1) { | 
| -        // The destination address is the value of a global variable. | 
| -        dest_addr = | 
| -            *reinterpret_cast<uint32_t*>(raw_buffer_ptr(globals, dest_addr)); | 
| +    Handle<SeqOneByteString> module_bytes = compiled_module_->module_bytes(); | 
| +    for (auto segment : module_->data_segments) { | 
| +      uint32_t dest_offset = EvalUint32InitExpr(globals, segment.dest_addr); | 
| +      uint32_t source_size = segment.source_size; | 
| +      if (dest_offset >= mem_size || source_size >= mem_size || | 
| +          dest_offset >= (mem_size - source_size)) { | 
| +        thrower_->RangeError("data segment does not fit into memory"); | 
| } | 
| - | 
| -      uint32_t source_size = | 
| -          static_cast<uint32_t>(segment->get_int(kSourceSize)); | 
| -      // TODO(titzer): These should be runtime errors and not CHECKs if | 
| -      // dest_addr is global (and therefore initialized at linktime to an | 
| -      // possibly-invalid value). | 
| -      CHECK_LT(dest_addr, mem_size); | 
| -      CHECK_LE(source_size, mem_size); | 
| -      CHECK_LE(dest_addr, mem_size - source_size); | 
| -      byte* addr = mem_addr + dest_addr; | 
| -      data->copy_out(last_extraction_pos, addr, source_size); | 
| -      last_extraction_pos += source_size; | 
| +      byte* dest = mem_addr + dest_offset; | 
| +      const byte* src = reinterpret_cast<const byte*>( | 
| +          module_bytes->GetCharsAddress() + segment.source_offset); | 
| +      memcpy(dest, src, source_size); | 
| } | 
| } | 
|  | 
| -  Handle<Code> CompileImportWrapper(int index, Handle<FixedArray> data, | 
| +  Handle<Code> CompileImportWrapper(int index, const WasmImport& import, | 
| Handle<JSReceiver> target, | 
| Handle<String> module_name, | 
| MaybeHandle<String> import_name) { | 
| -    // TODO(mtrofin): this is an uint32_t, actually. We should rationalize | 
| -    // it when we rationalize signed/unsigned stuff. | 
| -    int ret_count = Smi::cast(data->get(kOutputCount))->value(); | 
| -    CHECK_GE(ret_count, 0); | 
| -    Handle<ByteArray> sig_data = | 
| -        data->GetValueChecked<ByteArray>(isolate_, kSignature); | 
| -    int sig_data_size = sig_data->length(); | 
| -    int param_count = sig_data_size - ret_count; | 
| -    CHECK(param_count >= 0); | 
| - | 
| +    FunctionSig* sig = module_->functions[import.index].sig; | 
| Handle<Code> code; | 
| -    bool isMatch = false; | 
| +    bool is_match = false; | 
| Handle<Code> export_wrapper_code; | 
| if (target->IsJSFunction()) { | 
| Handle<JSFunction> func = Handle<JSFunction>::cast(target); | 
| export_wrapper_code = handle(func->code()); | 
| if (export_wrapper_code->kind() == Code::JS_TO_WASM_FUNCTION) { | 
| -        int exported_param_count = | 
| -            Smi::cast(func->GetInternalField(kInternalArity))->value(); | 
| -        Handle<ByteArray> exportedSig = Handle<ByteArray>( | 
| -            ByteArray::cast(func->GetInternalField(kInternalSignature))); | 
| -        if (exported_param_count == param_count && | 
| -            exportedSig->length() == sig_data->length() && | 
| -            memcmp(exportedSig->GetDataStartAddress(), | 
| -                   sig_data->GetDataStartAddress(), | 
| -                   exportedSig->length()) == 0) { | 
| -          isMatch = true; | 
| -        } | 
| +        // Compare signature of other exported wasm function. | 
| +        Handle<JSObject> other_instance( | 
| +            JSObject::cast(func->GetInternalField(kInternalModuleInstance)), | 
| +            isolate_); | 
| +        int func_index = | 
| +            Smi::cast(func->GetInternalField(kInternalFunctionIndex))->value(); | 
| +        FunctionSig* other_sig = | 
| +            GetCppModule(other_instance)->functions[func_index].sig; | 
| +        is_match = sig->Equals(other_sig); | 
| } | 
| } | 
| -    if (isMatch) { | 
| +    if (is_match) { | 
| +      // Signature matched. Unwrap the JS->WASM wrapper and return the naked | 
| +      // WASM function code. | 
| int wasm_count = 0; | 
| int const mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET); | 
| for (RelocIterator it(*export_wrapper_code, mask); !it.done(); | 
| @@ -1622,22 +1311,14 @@ class WasmInstanceBuilder { | 
| DCHECK(wasm_count == 1); | 
| return code; | 
| } else { | 
| -      // Copy the signature to avoid a raw pointer into a heap object when | 
| -      // GC can happen. | 
| -      Zone zone(isolate_->allocator(), ZONE_NAME); | 
| -      MachineRepresentation* reps = | 
| -          zone.NewArray<MachineRepresentation>(sig_data_size); | 
| -      memcpy(reps, sig_data->GetDataStartAddress(), | 
| -             sizeof(MachineRepresentation) * sig_data_size); | 
| -      FunctionSig sig(ret_count, param_count, reps); | 
| - | 
| -      return compiler::CompileWasmToJSWrapper(isolate_, target, &sig, index, | 
| +      // Signature mismatch. Compile a new wrapper for the new signature. | 
| +      return compiler::CompileWasmToJSWrapper(isolate_, target, sig, index, | 
| module_name, import_name); | 
| } | 
| } | 
|  | 
| -  void WriteGlobalValue(MaybeHandle<JSArrayBuffer> globals, uint32_t offset, | 
| -                        Handle<Object> value, int type) { | 
| +  void WriteGlobalValue(WasmGlobal& global, MaybeHandle<JSArrayBuffer> globals, | 
| +                        Handle<Object> value) { | 
| double num = 0; | 
| if (value->IsSmi()) { | 
| num = Smi::cast(*value)->value(); | 
| @@ -1646,21 +1327,21 @@ class WasmInstanceBuilder { | 
| } else { | 
| UNREACHABLE(); | 
| } | 
| -    TRACE("init [globals+%u] = %lf, type = %d\n", offset, num, type); | 
| -    byte* ptr = raw_buffer_ptr(globals, offset); | 
| -    switch (type) { | 
| -      case kLocalI32: | 
| -        *reinterpret_cast<int32_t*>(ptr) = static_cast<int32_t>(num); | 
| +    TRACE("init [globals+%u] = %lf, type = %s\n", global.offset, num, | 
| +          WasmOpcodes::TypeName(global.type)); | 
| +    switch (global.type) { | 
| +      case kAstI32: | 
| +        *GetRawGlobalPtr<int32_t>(global, globals) = static_cast<int32_t>(num); | 
| break; | 
| -      case kLocalI64: | 
| +      case kAstI64: | 
| // TODO(titzer): initialization of imported i64 globals. | 
| UNREACHABLE(); | 
| break; | 
| -      case kLocalF32: | 
| -        *reinterpret_cast<float*>(ptr) = static_cast<float>(num); | 
| +      case kAstF32: | 
| +        *GetRawGlobalPtr<float>(global, globals) = static_cast<float>(num); | 
| break; | 
| -      case kLocalF64: | 
| -        *reinterpret_cast<double*>(ptr) = num; | 
| +      case kAstF64: | 
| +        *GetRawGlobalPtr<double>(global, globals) = static_cast<double>(num); | 
| break; | 
| default: | 
| UNREACHABLE(); | 
| @@ -1673,25 +1354,27 @@ class WasmInstanceBuilder { | 
| int ProcessImports(MaybeHandle<JSArrayBuffer> globals, | 
| Handle<FixedArray> code_table, Handle<JSObject> instance) { | 
| int num_imported_functions = 0; | 
| -    if (!compiled_module_->has_imports()) return num_imported_functions; | 
| - | 
| -    Handle<FixedArray> imports = compiled_module_->imports(); | 
| -    for (int index = 0; index < imports->length(); ++index) { | 
| -      Handle<FixedArray> data = | 
| -          imports->GetValueChecked<FixedArray>(isolate_, index); | 
| - | 
| +    for (int index = 0; index < static_cast<int>(module_->import_table.size()); | 
| +         ++index) { | 
| +      WasmImport& import = module_->import_table[index]; | 
| Handle<String> module_name = | 
| -          data->GetValueChecked<String>(isolate_, kModuleName); | 
| -      MaybeHandle<String> function_name = | 
| -          data->GetValue<String>(isolate_, kFunctionName); | 
| +          ExtractStringFromModuleBytes(isolate_, compiled_module_, | 
| +                                       import.module_name_offset, | 
| +                                       import.module_name_length) | 
| +              .ToHandleChecked(); | 
| +      Handle<String> function_name = Handle<String>::null(); | 
| +      if (import.field_name_length > 0) { | 
| +        function_name = ExtractStringFromModuleBytes(isolate_, compiled_module_, | 
| +                                                     import.field_name_offset, | 
| +                                                     import.field_name_length) | 
| +                            .ToHandleChecked(); | 
| +      } | 
|  | 
| MaybeHandle<Object> result = | 
| LookupImport(index, module_name, function_name); | 
| if (thrower_->error()) return -1; | 
|  | 
| -      WasmExternalKind kind = static_cast<WasmExternalKind>( | 
| -          Smi::cast(data->get(kImportKind))->value()); | 
| -      switch (kind) { | 
| +      switch (import.kind) { | 
| case kExternalFunction: { | 
| // Function imports must be callable. | 
| Handle<Object> function = result.ToHandleChecked(); | 
| @@ -1702,10 +1385,9 @@ class WasmInstanceBuilder { | 
| } | 
|  | 
| Handle<Code> import_wrapper = CompileImportWrapper( | 
| -              index, data, Handle<JSReceiver>::cast(function), module_name, | 
| +              index, import, Handle<JSReceiver>::cast(function), module_name, | 
| function_name); | 
| -          int func_index = Smi::cast(data->get(kImportIndex))->value(); | 
| -          code_table->set(func_index, *import_wrapper); | 
| +          code_table->set(num_imported_functions, *import_wrapper); | 
| RecordStats(isolate_, *import_wrapper); | 
| num_imported_functions++; | 
| break; | 
| @@ -1735,9 +1417,7 @@ class WasmInstanceBuilder { | 
| return -1; | 
| } | 
| Handle<Object> val = number.ToHandleChecked(); | 
| -          int offset = Smi::cast(data->get(kImportIndex))->value(); | 
| -          int type = Smi::cast(data->get(kImportGlobalType))->value(); | 
| -          WriteGlobalValue(globals, offset, val, type); | 
| +          WriteGlobalValue(module_->globals[import.index], globals, val); | 
| break; | 
| } | 
| default: | 
| @@ -1748,29 +1428,49 @@ class WasmInstanceBuilder { | 
| return num_imported_functions; | 
| } | 
|  | 
| +  template <typename T> | 
| +  T* GetRawGlobalPtr(WasmGlobal& global, MaybeHandle<JSArrayBuffer> globals) { | 
| +    return reinterpret_cast<T*>(raw_buffer_ptr(globals, global.offset)); | 
| +  } | 
| + | 
| // Process initialization of globals. | 
| -  void ProcessInits(MaybeHandle<JSArrayBuffer> globals) { | 
| -    if (!compiled_module_->has_inits()) return; | 
| - | 
| -    Handle<FixedArray> inits = compiled_module_->inits(); | 
| -    for (int index = 0; index < inits->length(); ++index) { | 
| -      Handle<FixedArray> data = | 
| -          inits->GetValueChecked<FixedArray>(isolate_, index); | 
| - | 
| -      int offset = Smi::cast(data->get(kGlobalInitIndex))->value(); | 
| -      Handle<Object> val(data->get(kGlobalInitValue), isolate_); | 
| -      int type = Smi::cast(data->get(kGlobalInitType))->value(); | 
| -      if (Smi::cast(data->get(kGlobalInitKind))->value() == 0) { | 
| -        // Initialize with a constant. | 
| -        WriteGlobalValue(globals, offset, val, type); | 
| -      } else { | 
| -        // Initialize with another global. | 
| -        int old_offset = Smi::cast(*val)->value(); | 
| -        TRACE("init [globals+%u] = [globals+%d]\n", offset, old_offset); | 
| -        int size = sizeof(int32_t); | 
| -        if (type == kLocalI64 || type == kLocalF64) size = sizeof(double); | 
| -        memcpy(raw_buffer_ptr(globals, offset), | 
| -               raw_buffer_ptr(globals, old_offset), size); | 
| +  void InitGlobals(MaybeHandle<JSArrayBuffer> globals) { | 
| +    for (auto global : module_->globals) { | 
| +      switch (global.init.kind) { | 
| +        case WasmInitExpr::kI32Const: | 
| +          *GetRawGlobalPtr<int32_t>(global, globals) = | 
| +              global.init.val.i32_const; | 
| +          break; | 
| +        case WasmInitExpr::kI64Const: | 
| +          *GetRawGlobalPtr<int64_t>(global, globals) = | 
| +              global.init.val.i64_const; | 
| +          break; | 
| +        case WasmInitExpr::kF32Const: | 
| +          *GetRawGlobalPtr<float>(global, globals) = global.init.val.f32_const; | 
| +          break; | 
| +        case WasmInitExpr::kF64Const: | 
| +          *GetRawGlobalPtr<double>(global, globals) = global.init.val.f64_const; | 
| +          break; | 
| +        case WasmInitExpr::kGlobalIndex: { | 
| +          // Initialize with another global. | 
| +          uint32_t new_offset = global.offset; | 
| +          uint32_t old_offset = | 
| +              module_->globals[global.init.val.global_index].offset; | 
| +          TRACE("init [globals+%u] = [globals+%d]\n", global.offset, | 
| +                old_offset); | 
| +          size_t size = (global.type == kAstI64 || global.type == kAstF64) | 
| +                            ? size = sizeof(double) | 
| +                            : sizeof(int32_t); | 
| +          memcpy(raw_buffer_ptr(globals, new_offset), | 
| +                 raw_buffer_ptr(globals, old_offset), size); | 
| +          break; | 
| +        } | 
| +        case WasmInitExpr::kNone: | 
| +          // Happens with imported globals. | 
| +          break; | 
| +        default: | 
| +          UNREACHABLE(); | 
| +          break; | 
| } | 
| } | 
| } | 
| @@ -1795,10 +1495,10 @@ class WasmInstanceBuilder { | 
| void ProcessExports(MaybeHandle<JSArrayBuffer> globals, | 
| Handle<FixedArray> code_table, | 
| Handle<JSObject> instance) { | 
| -    if (!compiled_module_->has_exports()) return; | 
| +    if (module_->export_table.size() == 0) return; | 
|  | 
| Handle<JSObject> exports_object = instance; | 
| -    if (compiled_module_->origin() == kWasmOrigin) { | 
| +    if (module_->origin == kWasmOrigin) { | 
| // Create the "exports" object. | 
| Handle<JSFunction> object_function = Handle<JSFunction>( | 
| isolate_->native_context()->object_function(), isolate_); | 
| @@ -1812,27 +1512,23 @@ class WasmInstanceBuilder { | 
| PropertyDescriptor desc; | 
| desc.set_writable(false); | 
|  | 
| -    Handle<FixedArray> exports = compiled_module_->exports(); | 
| - | 
| -    for (int i = 0; i < exports->length(); ++i) { | 
| -      Handle<FixedArray> export_data = | 
| -          exports->GetValueChecked<FixedArray>(isolate_, i); | 
| +    int func_index = 0; | 
| +    for (auto exp : module_->export_table) { | 
| Handle<String> name = | 
| -          export_data->GetValueChecked<String>(isolate_, kExportName); | 
| -      WasmExternalKind kind = static_cast<WasmExternalKind>( | 
| -          Smi::cast(export_data->get(kExportKind))->value()); | 
| -      switch (kind) { | 
| +          ExtractStringFromModuleBytes(isolate_, compiled_module_, | 
| +                                       exp.name_offset, exp.name_length) | 
| +              .ToHandleChecked(); | 
| +      switch (exp.kind) { | 
| case kExternalFunction: { | 
| // Wrap and export the code as a JSFunction. | 
| -          int code_table_index = | 
| -              Smi::cast(export_data->get(kExportIndex))->value(); | 
| +          WasmFunction& function = module_->functions[exp.index]; | 
| +          int export_index = | 
| +              static_cast<int>(module_->functions.size() + func_index); | 
| Handle<Code> export_code = | 
| -              code_table->GetValueChecked<Code>(isolate_, code_table_index); | 
| -          int arity = Smi::cast(export_data->get(kExportArity))->value(); | 
| -          MaybeHandle<ByteArray> signature = | 
| -              export_data->GetValue<ByteArray>(isolate_, kExportedSignature); | 
| +              code_table->GetValueChecked<Code>(isolate_, export_index); | 
| desc.set_value(WrapExportCodeAsJSFunction( | 
| -              isolate_, export_code, name, arity, signature, instance)); | 
| +              isolate_, export_code, name, function.sig, func_index, instance)); | 
| +          func_index++; | 
| break; | 
| } | 
| case kExternalTable: | 
| @@ -1859,18 +1555,17 @@ class WasmInstanceBuilder { | 
| } | 
| case kExternalGlobal: { | 
| // Export the value of the global variable as a number. | 
| -          int offset = Smi::cast(export_data->get(kExportIndex))->value(); | 
| -          byte* ptr = raw_buffer_ptr(globals, offset); | 
| +          WasmGlobal& global = module_->globals[exp.index]; | 
| double num = 0; | 
| -          switch (Smi::cast(export_data->get(kExportGlobalType))->value()) { | 
| -            case kLocalI32: | 
| -              num = *reinterpret_cast<int32_t*>(ptr); | 
| +          switch (global.type) { | 
| +            case kAstI32: | 
| +              num = *GetRawGlobalPtr<int32_t>(global, globals); | 
| break; | 
| -            case kLocalF32: | 
| -              num = *reinterpret_cast<float*>(ptr); | 
| +            case kAstF32: | 
| +              num = *GetRawGlobalPtr<float>(global, globals); | 
| break; | 
| -            case kLocalF64: | 
| -              num = *reinterpret_cast<double*>(ptr); | 
| +            case kAstF64: | 
| +              num = *GetRawGlobalPtr<double>(global, globals); | 
| break; | 
| default: | 
| UNREACHABLE(); | 
| @@ -1898,37 +1593,26 @@ class WasmInstanceBuilder { | 
| // WebAssembly.Module. | 
| MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate, | 
| ErrorThrower* thrower, | 
| -                                              Handle<JSObject> module_object, | 
| +                                              Handle<JSObject> wasm_module, | 
| Handle<JSReceiver> ffi, | 
| Handle<JSArrayBuffer> memory) { | 
| -  WasmInstanceBuilder builder(isolate, thrower, module_object, ffi, memory); | 
| +  WasmInstanceBuilder builder(isolate, thrower, wasm_module, ffi, memory); | 
| return builder.Build(); | 
| } | 
|  | 
| -Handle<WasmCompiledModule> WasmCompiledModule::New(Isolate* isolate, | 
| -                                                   uint32_t min_memory_pages, | 
| -                                                   uint32_t globals_size, | 
| -                                                   ModuleOrigin origin) { | 
| +Handle<WasmCompiledModule> WasmCompiledModule::New( | 
| +    Isolate* isolate, Handle<WasmModuleWrapper> module_wrapper) { | 
| Handle<FixedArray> ret = | 
| isolate->factory()->NewFixedArray(PropertyIndices::Count, TENURED); | 
| -  // Globals size is expected to fit into an int without overflow. This is not | 
| -  // supported by the spec at the moment, however, we don't support array | 
| -  // buffer sizes over 1g, so, for now, we avoid alocating a HeapNumber for | 
| -  // the globals size. The CHECK guards this assumption. | 
| -  CHECK_GE(static_cast<int>(globals_size), 0); | 
| -  ret->set(kID_min_memory_pages, | 
| -           Smi::FromInt(static_cast<int>(min_memory_pages))); | 
| -  ret->set(kID_globals_size, Smi::FromInt(static_cast<int>(globals_size))); | 
| -  ret->set(kID_origin, Smi::FromInt(static_cast<int>(origin))); | 
| - | 
| // WasmCompiledModule::cast would fail since module bytes are not set yet. | 
| -  Handle<WasmCompiledModule> module(reinterpret_cast<WasmCompiledModule*>(*ret), | 
| -                                    isolate); | 
| -  module->Init(); | 
| -  return module; | 
| +  Handle<WasmCompiledModule> compiled_module( | 
| +      reinterpret_cast<WasmCompiledModule*>(*ret), isolate); | 
| +  compiled_module->InitId(); | 
| +  compiled_module->set_module_wrapper(module_wrapper); | 
| +  return compiled_module; | 
| } | 
|  | 
| -void WasmCompiledModule::Init() { | 
| +void WasmCompiledModule::InitId() { | 
| #if DEBUG | 
| static uint32_t instance_id_counter = 0; | 
| set(kID_instance_id, Smi::FromInt(instance_id_counter++)); | 
| @@ -1972,27 +1656,26 @@ void WasmCompiledModule::PrintInstancesChain() { | 
| } | 
|  | 
| Handle<Object> wasm::GetWasmFunctionNameOrNull(Isolate* isolate, | 
| -                                               Handle<Object> wasm, | 
| +                                               Handle<Object> instance, | 
| uint32_t func_index) { | 
| -  if (!wasm->IsUndefined(isolate)) { | 
| -    DCHECK(IsWasmInstance(*wasm)); | 
| -    WasmCompiledModule* compiled_module = | 
| -        GetCompiledModule(JSObject::cast(*wasm)); | 
| -    Handle<ByteArray> func_names = compiled_module->function_names(); | 
| -    // TODO(clemens): Extract this from the module bytes; skip whole function | 
| -    // name table. | 
| -    Handle<Object> name; | 
| -    if (GetWasmFunctionNameFromTable(func_names, func_index).ToHandle(&name)) { | 
| -      return name; | 
| -    } | 
| +  if (!instance->IsUndefined(isolate)) { | 
| +    DCHECK(IsWasmInstance(*instance)); | 
| +    WasmModule* module = GetCppModule(Handle<JSObject>::cast(instance)); | 
| +    WasmFunction& function = module->functions[func_index]; | 
| +    Handle<WasmCompiledModule> compiled_module(GetCompiledModule(*instance), | 
| +                                               isolate); | 
| +    MaybeHandle<String> string = ExtractStringFromModuleBytes( | 
| +        isolate, compiled_module, function.name_offset, function.name_length); | 
| +    if (!string.is_null()) return string.ToHandleChecked(); | 
| } | 
| return isolate->factory()->null_value(); | 
| } | 
|  | 
| -Handle<String> wasm::GetWasmFunctionName(Isolate* isolate, Handle<Object> wasm, | 
| +Handle<String> wasm::GetWasmFunctionName(Isolate* isolate, | 
| +                                         Handle<Object> instance, | 
| uint32_t func_index) { | 
| Handle<Object> name_or_null = | 
| -      GetWasmFunctionNameOrNull(isolate, wasm, func_index); | 
| +      GetWasmFunctionNameOrNull(isolate, instance, func_index); | 
| if (!name_or_null->IsNull(isolate)) { | 
| return Handle<String>::cast(name_or_null); | 
| } | 
| @@ -2004,13 +1687,12 @@ bool wasm::IsWasmInstance(Object* object) { | 
|  | 
| JSObject* obj = JSObject::cast(object); | 
| Isolate* isolate = obj->GetIsolate(); | 
| -  if (obj->GetInternalFieldCount() != kWasmModuleInternalFieldCount) { | 
| +  if (obj->GetInternalFieldCount() != kWasmInstanceInternalFieldCount) { | 
| return false; | 
| } | 
|  | 
| Object* mem = obj->GetInternalField(kWasmMemArrayBuffer); | 
| -  if (!obj->GetInternalField(kWasmModuleCodeTable)->IsFixedArray() || | 
| -      !(mem->IsUndefined(isolate) || mem->IsJSArrayBuffer()) || | 
| +  if (!(mem->IsUndefined(isolate) || mem->IsJSArrayBuffer()) || | 
| !WasmCompiledModule::IsWasmCompiledModule( | 
| obj->GetInternalField(kWasmCompiledModule))) { | 
| return false; | 
| @@ -2020,27 +1702,27 @@ bool wasm::IsWasmInstance(Object* object) { | 
| return true; | 
| } | 
|  | 
| -WasmCompiledModule* wasm::GetCompiledModule(JSObject* wasm) { | 
| -  return WasmCompiledModule::cast(wasm->GetInternalField(kWasmCompiledModule)); | 
| +WasmCompiledModule* wasm::GetCompiledModule(Object* instance) { | 
| +  DCHECK(IsWasmInstance(instance)); | 
| +  return WasmCompiledModule::cast( | 
| +      JSObject::cast(instance)->GetInternalField(kWasmCompiledModule)); | 
| } | 
|  | 
| -bool wasm::WasmIsAsmJs(Object* wasm, Isolate* isolate) { | 
| -  if (wasm->IsUndefined(isolate)) return false; | 
| -  DCHECK(IsWasmInstance(wasm)); | 
| -  WasmCompiledModule* compiled_module = GetCompiledModule(JSObject::cast(wasm)); | 
| -  return compiled_module->has_asm_js_script(); | 
| +bool wasm::WasmIsAsmJs(Object* instance, Isolate* isolate) { | 
| +  return IsWasmInstance(instance) && | 
| +         GetCompiledModule(JSObject::cast(instance))->has_asm_js_script(); | 
| } | 
|  | 
| -Handle<Script> wasm::GetAsmWasmScript(Handle<JSObject> wasm) { | 
| -  DCHECK(IsWasmInstance(*wasm)); | 
| -  WasmCompiledModule* compiled_module = GetCompiledModule(*wasm); | 
| +Handle<Script> wasm::GetAsmWasmScript(Handle<JSObject> instance) { | 
| +  DCHECK(IsWasmInstance(*instance)); | 
| +  WasmCompiledModule* compiled_module = GetCompiledModule(*instance); | 
| return compiled_module->asm_js_script(); | 
| } | 
|  | 
| -int wasm::GetAsmWasmSourcePosition(Handle<JSObject> wasm, int func_index, | 
| +int wasm::GetAsmWasmSourcePosition(Handle<JSObject> instance, int func_index, | 
| int byte_offset) { | 
| -  return WasmDebugInfo::GetAsmJsSourcePosition(GetDebugInfo(wasm), func_index, | 
| -                                               byte_offset); | 
| +  return WasmDebugInfo::GetAsmJsSourcePosition(GetDebugInfo(instance), | 
| +                                               func_index, byte_offset); | 
| } | 
|  | 
| Handle<SeqOneByteString> wasm::GetWasmBytes(Handle<JSObject> instance) { | 
| @@ -2059,72 +1741,33 @@ Handle<WasmDebugInfo> wasm::GetDebugInfo(Handle<JSObject> instance) { | 
| return new_info; | 
| } | 
|  | 
| -Handle<FixedArray> wasm::BuildFunctionTable(Isolate* isolate, uint32_t index, | 
| -                                            const WasmModule* module) { | 
| -  const WasmIndirectFunctionTable* table = &module->function_tables[index]; | 
| -  DCHECK_EQ(table->size, table->values.size()); | 
| -  DCHECK_GE(table->max_size, table->size); | 
| -  Handle<FixedArray> values = | 
| -      isolate->factory()->NewFixedArray(2 * table->max_size, TENURED); | 
| -  for (uint32_t i = 0; i < table->size; ++i) { | 
| -    const WasmFunction* function = &module->functions[table->values[i]]; | 
| -    int32_t index = table->map.Find(function->sig); | 
| -    DCHECK_GE(index, 0); | 
| -    values->set(i, Smi::FromInt(index)); | 
| -    values->set(i + table->max_size, Smi::FromInt(table->values[i])); | 
| -  } | 
| -  // Set the remaining elements to -1 (instead of "undefined"). These | 
| -  // elements are accessed directly as SMIs (without a check). On 64-bit | 
| -  // platforms, it is possible to have the top bits of "undefined" take | 
| -  // small integer values (or zero), which are more likely to be equal to | 
| -  // the signature index we check against. | 
| -  for (uint32_t i = table->size; i < table->max_size; ++i) { | 
| -    values->set(i, Smi::FromInt(-1)); | 
| -  } | 
| -  return values; | 
| -} | 
| - | 
| -void wasm::PopulateFunctionTable(Handle<FixedArray> table, uint32_t table_size, | 
| -                                 const std::vector<Handle<Code>>* code_table) { | 
| -  uint32_t max_size = table->length() / 2; | 
| -  for (uint32_t i = max_size; i < max_size + table_size; ++i) { | 
| -    int index = Smi::cast(table->get(static_cast<int>(i)))->value(); | 
| -    DCHECK_GE(index, 0); | 
| -    DCHECK_LT(static_cast<size_t>(index), code_table->size()); | 
| -    table->set(static_cast<int>(i), *(*code_table)[index]); | 
| -  } | 
| -} | 
| - | 
| int wasm::GetNumberOfFunctions(Handle<JSObject> instance) { | 
| -  DCHECK(IsWasmInstance(*instance)); | 
| -  WasmCompiledModule* compiled_module = GetCompiledModule(*instance); | 
| -  ByteArray* func_names_arr = compiled_module->ptr_to_function_names(); | 
| -  // TODO(clemensh): this looks inside an array constructed elsewhere. Refactor. | 
| -  return func_names_arr->get_int(0); | 
| +  return static_cast<int>(GetCppModule(instance)->functions.size()); | 
| } | 
|  | 
| -Handle<JSObject> wasm::CreateCompiledModuleObject( | 
| +Handle<JSObject> wasm::CreateWasmModuleObject( | 
| Isolate* isolate, Handle<WasmCompiledModule> compiled_module, | 
| ModuleOrigin origin) { | 
| -  Handle<JSObject> module_obj; | 
| +  Handle<JSObject> wasm_module; | 
| if (origin == ModuleOrigin::kWasmOrigin) { | 
| Handle<JSFunction> module_cons( | 
| isolate->native_context()->wasm_module_constructor()); | 
| -    module_obj = isolate->factory()->NewJSObject(module_cons); | 
| +    wasm_module = isolate->factory()->NewJSObject(module_cons); | 
| } else { | 
| DCHECK(origin == ModuleOrigin::kAsmJsOrigin); | 
| Handle<Map> map = isolate->factory()->NewMap( | 
| JS_OBJECT_TYPE, JSObject::kHeaderSize + kPointerSize); | 
| -    module_obj = isolate->factory()->NewJSObjectFromMap(map, TENURED); | 
| +    wasm_module = isolate->factory()->NewJSObjectFromMap(map, TENURED); | 
| } | 
| -  module_obj->SetInternalField(0, *compiled_module); | 
| +  wasm_module->SetInternalField(0, *compiled_module); | 
| if (origin == ModuleOrigin::kWasmOrigin) { | 
| Handle<Symbol> module_sym(isolate->native_context()->wasm_module_sym()); | 
| -    Object::SetProperty(module_obj, module_sym, module_obj, STRICT).Check(); | 
| +    Object::SetProperty(wasm_module, module_sym, wasm_module, STRICT).Check(); | 
| } | 
| -  Handle<WeakCell> link_to_module = isolate->factory()->NewWeakCell(module_obj); | 
| -  compiled_module->set_weak_module_object(link_to_module); | 
| -  return module_obj; | 
| +  Handle<WeakCell> link_to_module = | 
| +      isolate->factory()->NewWeakCell(wasm_module); | 
| +  compiled_module->set_weak_wasm_module(link_to_module); | 
| +  return wasm_module; | 
| } | 
|  | 
| // TODO(clemensh): origin can be inferred from asm_js_script; remove it. | 
| @@ -2134,17 +1777,23 @@ MaybeHandle<JSObject> wasm::CreateModuleObjectFromBytes( | 
| const byte* asm_js_offset_tables_start, | 
| const byte* asm_js_offset_tables_end) { | 
| MaybeHandle<JSObject> nothing; | 
| -  Zone zone(isolate->allocator(), ZONE_NAME); | 
| -  ModuleResult result = | 
| -      DecodeWasmModule(isolate, &zone, start, end, false, origin); | 
| -  std::unique_ptr<const WasmModule> decoded_module(result.val); | 
| +  ModuleResult result = DecodeWasmModule(isolate, start, end, false, origin); | 
| if (result.failed()) { | 
| +    if (result.val) delete result.val; | 
| thrower->CompileFailed("Wasm decoding failed", result); | 
| return nothing; | 
| } | 
| +  // The {module_wrapper} will take ownership of the {WasmModule} object, | 
| +  // and it will be destroyed when the GC reclaims the wrapper object. | 
| +  Handle<WasmModuleWrapper> module_wrapper = | 
| +      WasmModuleWrapper::New(isolate, const_cast<WasmModule*>(result.val)); | 
| + | 
| +  // Compile the functions of the module, producing a compiled module. | 
| MaybeHandle<WasmCompiledModule> maybe_compiled_module = | 
| -      decoded_module->CompileFunctions(isolate, thrower); | 
| +      result.val->CompileFunctions(isolate, module_wrapper, thrower); | 
| + | 
| if (maybe_compiled_module.is_null()) return nothing; | 
| + | 
| Handle<WasmCompiledModule> compiled_module = | 
| maybe_compiled_module.ToHandleChecked(); | 
|  | 
| @@ -2163,15 +1812,13 @@ MaybeHandle<JSObject> wasm::CreateModuleObjectFromBytes( | 
| compiled_module->set_asm_js_offset_tables(offset_tables); | 
| } | 
|  | 
| -  return CreateCompiledModuleObject(isolate, compiled_module, origin); | 
| +  return CreateWasmModuleObject(isolate, compiled_module, origin); | 
| } | 
|  | 
| bool wasm::ValidateModuleBytes(Isolate* isolate, const byte* start, | 
| const byte* end, ErrorThrower* thrower, | 
| ModuleOrigin origin) { | 
| -  Zone zone(isolate->allocator(), ZONE_NAME); | 
| -  ModuleResult result = | 
| -      DecodeWasmModule(isolate, &zone, start, end, false, origin); | 
| +  ModuleResult result = DecodeWasmModule(isolate, start, end, false, origin); | 
| if (result.ok()) { | 
| DCHECK_NOT_NULL(result.val); | 
| delete result.val; | 
| @@ -2193,7 +1840,7 @@ void SetInstanceMemory(Handle<JSObject> instance, JSArrayBuffer* buffer) { | 
| DCHECK(IsWasmInstance(*instance)); | 
| instance->SetInternalField(kWasmMemArrayBuffer, buffer); | 
| WasmCompiledModule* compiled_module = GetCompiledModule(*instance); | 
| -  compiled_module->set_ptr_to_heap(buffer); | 
| +  compiled_module->set_ptr_to_memory(buffer); | 
| } | 
|  | 
| int32_t wasm::GetInstanceMemorySize(Isolate* isolate, | 
| @@ -2256,30 +1903,30 @@ int32_t wasm::GrowInstanceMemory(Isolate* isolate, Handle<JSObject> instance, | 
| memcpy(new_mem_start, old_mem_start, old_size); | 
| } | 
| SetInstanceMemory(instance, *buffer); | 
| -  RelocateInstanceCode(instance, old_mem_start, new_mem_start, old_size, | 
| -                       new_size); | 
| +  Handle<FixedArray> code_table = GetCompiledModule(*instance)->code_table(); | 
| +  RelocateMemoryReferencesInCode(code_table, old_mem_start, new_mem_start, | 
| +                                 old_size, new_size); | 
| DCHECK(old_size % WasmModule::kPageSize == 0); | 
| return (old_size / WasmModule::kPageSize); | 
| } | 
|  | 
| void testing::ValidateInstancesChain(Isolate* isolate, | 
| -                                     Handle<JSObject> module_obj, | 
| +                                     Handle<JSObject> wasm_module, | 
| int instance_count) { | 
| CHECK_GE(instance_count, 0); | 
| DisallowHeapAllocation no_gc; | 
| WasmCompiledModule* compiled_module = | 
| -      WasmCompiledModule::cast(module_obj->GetInternalField(0)); | 
| -  CHECK_EQ( | 
| -      JSObject::cast(compiled_module->ptr_to_weak_module_object()->value()), | 
| -      *module_obj); | 
| +      WasmCompiledModule::cast(wasm_module->GetInternalField(0)); | 
| +  CHECK_EQ(JSObject::cast(compiled_module->ptr_to_weak_wasm_module()->value()), | 
| +           *wasm_module); | 
| Object* prev = nullptr; | 
| int found_instances = compiled_module->has_weak_owning_instance() ? 1 : 0; | 
| WasmCompiledModule* current_instance = compiled_module; | 
| while (current_instance->has_weak_next_instance()) { | 
| CHECK((prev == nullptr && !current_instance->has_weak_prev_instance()) || | 
| current_instance->ptr_to_weak_prev_instance()->value() == prev); | 
| -    CHECK_EQ(current_instance->ptr_to_weak_module_object()->value(), | 
| -             *module_obj); | 
| +    CHECK_EQ(current_instance->ptr_to_weak_wasm_module()->value(), | 
| +             *wasm_module); | 
| CHECK(IsWasmInstance( | 
| current_instance->ptr_to_weak_owning_instance()->value())); | 
| prev = current_instance; | 
| @@ -2292,22 +1939,52 @@ void testing::ValidateInstancesChain(Isolate* isolate, | 
| } | 
|  | 
| void testing::ValidateModuleState(Isolate* isolate, | 
| -                                  Handle<JSObject> module_obj) { | 
| +                                  Handle<JSObject> wasm_module) { | 
| DisallowHeapAllocation no_gc; | 
| WasmCompiledModule* compiled_module = | 
| -      WasmCompiledModule::cast(module_obj->GetInternalField(0)); | 
| -  CHECK(compiled_module->has_weak_module_object()); | 
| -  CHECK_EQ(compiled_module->ptr_to_weak_module_object()->value(), *module_obj); | 
| +      WasmCompiledModule::cast(wasm_module->GetInternalField(0)); | 
| +  CHECK(compiled_module->has_weak_wasm_module()); | 
| +  CHECK_EQ(compiled_module->ptr_to_weak_wasm_module()->value(), *wasm_module); | 
| CHECK(!compiled_module->has_weak_prev_instance()); | 
| CHECK(!compiled_module->has_weak_next_instance()); | 
| CHECK(!compiled_module->has_weak_owning_instance()); | 
| } | 
|  | 
| void testing::ValidateOrphanedInstance(Isolate* isolate, | 
| -                                       Handle<JSObject> instance) { | 
| +                                       Handle<JSObject> wasm_module) { | 
| DisallowHeapAllocation no_gc; | 
| -  CHECK(IsWasmInstance(*instance)); | 
| -  WasmCompiledModule* compiled_module = GetCompiledModule(*instance); | 
| -  CHECK(compiled_module->has_weak_module_object()); | 
| -  CHECK(compiled_module->ptr_to_weak_module_object()->cleared()); | 
| +  CHECK(IsWasmInstance(*wasm_module)); | 
| +  WasmCompiledModule* compiled_module = GetCompiledModule(*wasm_module); | 
| +  CHECK(compiled_module->has_weak_wasm_module()); | 
| +  CHECK(compiled_module->ptr_to_weak_wasm_module()->cleared()); | 
| +} | 
| + | 
| +void WasmCompiledModule::RecreateModuleWrapper(Isolate* isolate, | 
| +                                               Handle<FixedArray> array) { | 
| +  Handle<WasmCompiledModule> compiled_module( | 
| +      reinterpret_cast<WasmCompiledModule*>(*array), isolate); | 
| + | 
| +  WasmModule* module = nullptr; | 
| +  { | 
| +    Handle<SeqOneByteString> module_bytes = compiled_module->module_bytes(); | 
| +    // We parse the module again directly from the module bytes, so | 
| +    // the underlying storage must not be moved meanwhile. | 
| +    DisallowHeapAllocation no_allocation; | 
| +    const byte* start = | 
| +        reinterpret_cast<const byte*>(module_bytes->GetCharsAddress()); | 
| +    const byte* end = start + module_bytes->length(); | 
| +    // TODO(titzer): remember the module origin in the compiled_module | 
| +    // For now, we assume serialized modules did not originate from asm.js. | 
| +    ModuleResult result = | 
| +        DecodeWasmModule(isolate, start, end, false, kWasmOrigin); | 
| +    CHECK(result.ok()); | 
| +    CHECK_NOT_NULL(result.val); | 
| +    module = const_cast<WasmModule*>(result.val); | 
| +  } | 
| + | 
| +  Handle<WasmModuleWrapper> module_wrapper = | 
| +      WasmModuleWrapper::New(isolate, module); | 
| + | 
| +  compiled_module->set_module_wrapper(module_wrapper); | 
| +  DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module)); | 
| } | 
|  |