Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(183)

Side by Side Diff: src/wasm/wasm-module.cc

Issue 2443353002: [wasm] Add support for exporting WebAssembly.Table instances. (Closed)
Patch Set: Fix identity of exported JSFunctions Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/wasm/wasm-js.cc ('k') | test/mjsunit/wasm/export-table.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <memory> 5 #include <memory>
6 6
7 #include "src/base/atomic-utils.h" 7 #include "src/base/atomic-utils.h"
8 #include "src/code-stubs.h" 8 #include "src/code-stubs.h"
9 9
10 #include "src/macro-assembler.h" 10 #include "src/macro-assembler.h"
(...skipping 1020 matching lines...) Expand 10 before | Expand all | Expand 10 after
1031 deopt_data->set_length(2); 1031 deopt_data->set_length(2);
1032 code->set_deoptimization_data(*deopt_data); 1032 code->set_deoptimization_data(*deopt_data);
1033 } 1033 }
1034 } 1034 }
1035 1035
1036 //-------------------------------------------------------------------------- 1036 //--------------------------------------------------------------------------
1037 // Set up the indirect function tables for the new instance. 1037 // Set up the indirect function tables for the new instance.
1038 //-------------------------------------------------------------------------- 1038 //--------------------------------------------------------------------------
1039 int function_table_count = 1039 int function_table_count =
1040 static_cast<int>(module_->function_tables.size()); 1040 static_cast<int>(module_->function_tables.size());
1041 std::vector<InitializedTable> inited_tables;
1042 inited_tables.reserve(module_->function_tables.size());
1041 if (function_table_count > 0) { 1043 if (function_table_count > 0) {
1042 Handle<FixedArray> old_function_tables = 1044 Handle<FixedArray> old_function_tables =
1043 compiled_module_->function_tables(); 1045 compiled_module_->function_tables();
1044 Handle<FixedArray> new_function_tables = 1046 Handle<FixedArray> new_function_tables =
1045 factory->NewFixedArray(function_table_count); 1047 factory->NewFixedArray(function_table_count);
1046 for (int index = 0; index < function_table_count; ++index) { 1048 for (int index = 0; index < function_table_count; ++index) {
1047 WasmIndirectFunctionTable& table = module_->function_tables[index]; 1049 WasmIndirectFunctionTable& table = module_->function_tables[index];
1048 uint32_t size = table.max_size > 0 ? table.max_size : table.size; 1050 uint32_t table_size = table.size;
1049 Handle<FixedArray> new_table = factory->NewFixedArray(size * 2); 1051 Handle<FixedArray> new_table = factory->NewFixedArray(table_size * 2);
1052
1053 inited_tables.push_back({Handle<JSObject>::null(),
1054 Handle<FixedArray>::null(), new_table,
1055 std::vector<WasmFunction*>()});
1056 InitializedTable& init_table = inited_tables.back();
1057 if (table.exported) {
1058 init_table.new_entries.insert(init_table.new_entries.begin(),
1059 table_size, nullptr);
1060 }
1061
1050 for (int i = 0; i < new_table->length(); ++i) { 1062 for (int i = 0; i < new_table->length(); ++i) {
1051 static const int kInvalidSigIndex = -1; 1063 static const int kInvalidSigIndex = -1;
1052 // Fill the table with invalid signature indexes so that uninitialized 1064 // Fill the table with invalid signature indexes so that uninitialized
1053 // entries will always fail the signature check. 1065 // entries will always fail the signature check.
1054 new_table->set(i, Smi::FromInt(kInvalidSigIndex)); 1066 new_table->set(i, Smi::FromInt(kInvalidSigIndex));
1055 } 1067 }
1056 for (auto table_init : module_->table_inits) { 1068 for (auto table_init : module_->table_inits) {
1057 uint32_t base = EvalUint32InitExpr(globals, table_init.offset); 1069 uint32_t base = EvalUint32InitExpr(globals, table_init.offset);
1058 uint32_t table_size = static_cast<uint32_t>(new_table->length());
1059 if (base > table_size || 1070 if (base > table_size ||
1060 (base + table_init.entries.size() > table_size)) { 1071 (base + table_init.entries.size() > table_size)) {
1061 thrower_->CompileError("table initializer is out of bounds"); 1072 thrower_->CompileError("table initializer is out of bounds");
1062 continue; 1073 continue;
1063 } 1074 }
1064 for (size_t i = 0; i < table_init.entries.size(); ++i) { 1075 for (size_t i = 0; i < table_init.entries.size(); ++i) {
1065 FunctionSig* sig = module_->functions[table_init.entries[i]].sig; 1076 WasmFunction* func = &module_->functions[table_init.entries[i]];
1077 if (table.exported) {
1078 init_table.new_entries[i + base] = func;
1079 }
1080 FunctionSig* sig = func->sig;
1066 int32_t sig_index = table.map.Find(sig); 1081 int32_t sig_index = table.map.Find(sig);
1067 new_table->set(static_cast<int>(i + base), Smi::FromInt(sig_index)); 1082 new_table->set(static_cast<int>(i + base), Smi::FromInt(sig_index));
1068 new_table->set(static_cast<int>(i + base + size), 1083 new_table->set(static_cast<int>(i + base + table_size),
1069 code_table->get(table_init.entries[i])); 1084 code_table->get(table_init.entries[i]));
1070 } 1085 }
1071 } 1086 }
1072 new_function_tables->set(static_cast<int>(index), *new_table); 1087 new_function_tables->set(static_cast<int>(index), *new_table);
1073 } 1088 }
1074 // Patch all code that has references to the old indirect table. 1089 // Patch all code that has references to the old indirect table.
1075 for (int i = 0; i < code_table->length(); ++i) { 1090 for (int i = 0; i < code_table->length(); ++i) {
1076 if (!code_table->get(i)->IsCode()) continue; 1091 if (!code_table->get(i)->IsCode()) continue;
1077 Handle<Code> code(Code::cast(code_table->get(i)), isolate_); 1092 Handle<Code> code(Code::cast(code_table->get(i)), isolate_);
1078 for (int j = 0; j < function_table_count; ++j) { 1093 for (int j = 0; j < function_table_count; ++j) {
1079 ReplaceReferenceInCode( 1094 ReplaceReferenceInCode(
1080 code, Handle<Object>(old_function_tables->get(j), isolate_), 1095 code, Handle<Object>(old_function_tables->get(j), isolate_),
1081 Handle<Object>(new_function_tables->get(j), isolate_)); 1096 Handle<Object>(new_function_tables->get(j), isolate_));
1082 } 1097 }
1083 } 1098 }
1084 compiled_module_->set_function_tables(new_function_tables); 1099 compiled_module_->set_function_tables(new_function_tables);
1085 } 1100 }
1086 1101
1087 //-------------------------------------------------------------------------- 1102 //--------------------------------------------------------------------------
1088 // Set up the exports object for the new instance. 1103 // Set up the exports object for the new instance.
1089 //-------------------------------------------------------------------------- 1104 //--------------------------------------------------------------------------
1090 ProcessExports(globals, code_table, instance); 1105 ProcessExports(globals, inited_tables, code_table, instance);
1091 1106
1092 if (num_imported_functions > 0 || !owner.is_null()) { 1107 if (num_imported_functions > 0 || !owner.is_null()) {
1093 // If the code was cloned, or new imports were compiled, patch. 1108 // If the code was cloned, or new imports were compiled, patch.
1094 PatchDirectCalls(old_code_table, code_table, num_imported_functions); 1109 PatchDirectCalls(old_code_table, code_table, num_imported_functions);
1095 } 1110 }
1096 1111
1097 FlushICache(isolate_, code_table); 1112 FlushICache(isolate_, code_table);
1098 1113
1099 //-------------------------------------------------------------------------- 1114 //--------------------------------------------------------------------------
1100 // Set up and link the new instance. 1115 // Set up and link the new instance.
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
1168 } 1183 }
1169 } 1184 }
1170 1185
1171 DCHECK(!isolate_->has_pending_exception()); 1186 DCHECK(!isolate_->has_pending_exception());
1172 TRACE("Finishing instance %d\n", compiled_module_->instance_id()); 1187 TRACE("Finishing instance %d\n", compiled_module_->instance_id());
1173 TRACE_CHAIN(WasmCompiledModule::cast(module_object_->GetInternalField(0))); 1188 TRACE_CHAIN(WasmCompiledModule::cast(module_object_->GetInternalField(0)));
1174 return instance; 1189 return instance;
1175 } 1190 }
1176 1191
1177 private: 1192 private:
1193 // Represents the initialized state of a table.
1194 struct InitializedTable {
1195 Handle<JSObject> table_object; // WebAssembly.Table instance
1196 Handle<FixedArray> js_functions; // JSFunctions exported
1197 Handle<FixedArray> dispatch_table; // internal (code, sig) pairs
1198 std::vector<WasmFunction*> new_entries; // overwriting entries
1199 };
1200
1178 Isolate* isolate_; 1201 Isolate* isolate_;
1179 WasmModule* module_; 1202 WasmModule* module_;
1180 ErrorThrower* thrower_; 1203 ErrorThrower* thrower_;
1181 Handle<JSObject> module_object_; 1204 Handle<JSObject> module_object_;
1182 Handle<JSReceiver> ffi_; 1205 Handle<JSReceiver> ffi_;
1183 Handle<JSArrayBuffer> memory_; 1206 Handle<JSArrayBuffer> memory_;
1184 Handle<WasmCompiledModule> compiled_module_; 1207 Handle<WasmCompiledModule> compiled_module_;
1185 1208
1186 // Helper routine to print out errors with imports (FFI). 1209 // Helper routine to print out errors with imports (FFI).
1187 MaybeHandle<JSFunction> ReportFFIError(const char* error, uint32_t index, 1210 MaybeHandle<JSFunction> ReportFFIError(const char* error, uint32_t index,
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after
1489 1512
1490 if (mem_buffer.is_null()) { 1513 if (mem_buffer.is_null()) {
1491 thrower_->RangeError("Out of memory: wasm memory"); 1514 thrower_->RangeError("Out of memory: wasm memory");
1492 } 1515 }
1493 return mem_buffer; 1516 return mem_buffer;
1494 } 1517 }
1495 1518
1496 // Process the exports, creating wrappers for functions, tables, memories, 1519 // Process the exports, creating wrappers for functions, tables, memories,
1497 // and globals. 1520 // and globals.
1498 void ProcessExports(MaybeHandle<JSArrayBuffer> globals, 1521 void ProcessExports(MaybeHandle<JSArrayBuffer> globals,
1522 std::vector<InitializedTable>& inited_tables,
1499 Handle<FixedArray> code_table, 1523 Handle<FixedArray> code_table,
1500 Handle<JSObject> instance) { 1524 Handle<JSObject> instance) {
1501 if (module_->export_table.size() == 0) return; 1525 if (module_->export_table.size() == 0) return;
1502 1526
1527 // Allocate a table to cache the exported JSFunctions if needed.
1528 bool has_exported_functions = module_->num_exported_functions > 0;
1529 if (!has_exported_functions) {
1530 for (auto table : module_->function_tables) {
1531 if (table.exported) {
1532 has_exported_functions = true;
1533 break;
1534 }
1535 }
1536 }
1537 Handle<FixedArray> exported_functions =
1538 has_exported_functions
1539 ? isolate_->factory()->NewFixedArray(
1540 static_cast<int>(module_->functions.size()))
1541 : Handle<FixedArray>::null();
1542
1503 Handle<JSObject> exports_object = instance; 1543 Handle<JSObject> exports_object = instance;
1504 if (module_->origin == kWasmOrigin) { 1544 if (module_->origin == kWasmOrigin) {
1505 // Create the "exports" object. 1545 // Create the "exports" object.
1506 Handle<JSFunction> object_function = Handle<JSFunction>( 1546 Handle<JSFunction> object_function = Handle<JSFunction>(
1507 isolate_->native_context()->object_function(), isolate_); 1547 isolate_->native_context()->object_function(), isolate_);
1508 exports_object = 1548 exports_object =
1509 isolate_->factory()->NewJSObject(object_function, TENURED); 1549 isolate_->factory()->NewJSObject(object_function, TENURED);
1510 Handle<String> exports_name = 1550 Handle<String> exports_name =
1511 isolate_->factory()->InternalizeUtf8String("exports"); 1551 isolate_->factory()->InternalizeUtf8String("exports");
1512 JSObject::AddProperty(instance, exports_name, exports_object, READ_ONLY); 1552 JSObject::AddProperty(instance, exports_name, exports_object, READ_ONLY);
1513 } 1553 }
1514 1554
1515 PropertyDescriptor desc; 1555 PropertyDescriptor desc;
1516 desc.set_writable(false); 1556 desc.set_writable(false);
1517 1557
1518 int func_index = 0; 1558 int func_index = 0;
1519 for (auto exp : module_->export_table) { 1559 for (auto exp : module_->export_table) {
1520 Handle<String> name = 1560 Handle<String> name =
1521 ExtractStringFromModuleBytes(isolate_, compiled_module_, 1561 ExtractStringFromModuleBytes(isolate_, compiled_module_,
1522 exp.name_offset, exp.name_length) 1562 exp.name_offset, exp.name_length)
1523 .ToHandleChecked(); 1563 .ToHandleChecked();
1524 switch (exp.kind) { 1564 switch (exp.kind) {
1525 case kExternalFunction: { 1565 case kExternalFunction: {
1526 // Wrap and export the code as a JSFunction. 1566 // Wrap and export the code as a JSFunction.
1527 WasmFunction& function = module_->functions[exp.index]; 1567 WasmFunction& function = module_->functions[exp.index];
1528 int export_index = 1568 int export_index =
1529 static_cast<int>(module_->functions.size() + func_index); 1569 static_cast<int>(module_->functions.size() + func_index);
1530 Handle<Code> export_code = 1570 Handle<Object> value(exported_functions->get(exp.index), isolate_);
1531 code_table->GetValueChecked<Code>(isolate_, export_index); 1571 Handle<JSFunction> js_function;
1532 desc.set_value(WrapExportCodeAsJSFunction( 1572 if (value->IsJSFunction()) {
1533 isolate_, export_code, name, function.sig, func_index, instance)); 1573 // There already is a JSFunction for this WASM function.
1574 js_function = Handle<JSFunction>::cast(value);
1575 } else {
1576 // Wrap the exported code as a JSFunction.
1577 Handle<Code> export_code =
1578 code_table->GetValueChecked<Code>(isolate_, export_index);
1579 js_function =
1580 WrapExportCodeAsJSFunction(isolate_, export_code, name,
1581 function.sig, func_index, instance);
1582 exported_functions->set(exp.index, *js_function);
1583 }
1584 desc.set_value(js_function);
1534 func_index++; 1585 func_index++;
1535 break; 1586 break;
1536 } 1587 }
1537 case kExternalTable: 1588 case kExternalTable: {
1538 // TODO(titzer): create a WebAssembly.Table instance. 1589 InitializedTable& init_table = inited_tables[exp.index];
1539 // TODO(titzer): should it have the same identity as an import? 1590 WasmIndirectFunctionTable& table =
1591 module_->function_tables[exp.index];
1592 if (init_table.table_object.is_null()) {
1593 init_table.table_object = WasmJs::CreateWasmTableObject(
1594 isolate_, table.size, table.max_size != 0, table.max_size,
1595 &init_table.js_functions);
1596 }
1597 desc.set_value(init_table.table_object);
1540 break; 1598 break;
1599 }
1541 case kExternalMemory: { 1600 case kExternalMemory: {
1542 // Export the memory as a WebAssembly.Memory object. 1601 // Export the memory as a WebAssembly.Memory object.
1543 Handle<Object> memory_object( 1602 Handle<Object> memory_object(
1544 instance->GetInternalField(kWasmMemObject), isolate_); 1603 instance->GetInternalField(kWasmMemObject), isolate_);
1545 if (memory_object->IsUndefined(isolate_)) { 1604 if (memory_object->IsUndefined(isolate_)) {
1546 // If there was no imported WebAssembly.Memory object, create one. 1605 // If there was no imported WebAssembly.Memory object, create one.
1547 Handle<JSArrayBuffer> buffer( 1606 Handle<JSArrayBuffer> buffer(
1548 JSArrayBuffer::cast( 1607 JSArrayBuffer::cast(
1549 instance->GetInternalField(kWasmMemArrayBuffer)), 1608 instance->GetInternalField(kWasmMemArrayBuffer)),
1550 isolate_); 1609 isolate_);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1582 } 1641 }
1583 1642
1584 v8::Maybe<bool> status = JSReceiver::DefineOwnProperty( 1643 v8::Maybe<bool> status = JSReceiver::DefineOwnProperty(
1585 isolate_, exports_object, name, &desc, Object::THROW_ON_ERROR); 1644 isolate_, exports_object, name, &desc, Object::THROW_ON_ERROR);
1586 if (!status.IsJust()) { 1645 if (!status.IsJust()) {
1587 thrower_->TypeError("export of %.*s failed.", name->length(), 1646 thrower_->TypeError("export of %.*s failed.", name->length(),
1588 name->ToCString().get()); 1647 name->ToCString().get());
1589 return; 1648 return;
1590 } 1649 }
1591 } 1650 }
1651
1652 // Fill out the contents of WebAssembly.Table instances.
1653 if (!exported_functions.is_null()) {
1654 // TODO(titzer): We compile JS->WASM wrappers for any function that is a
1655 // member of an exported indirect table that is not itself exported. This
1656 // should be done at compile time and cached instead.
1657 WasmInstance temp_instance(module_);
1658 temp_instance.context = isolate_->native_context();
1659 temp_instance.mem_size = 0;
1660 temp_instance.mem_start = nullptr;
1661 temp_instance.globals_start = nullptr;
1662
1663 ModuleEnv module_env;
1664 module_env.module = module_;
1665 module_env.instance = &temp_instance;
1666 module_env.origin = module_->origin;
1667
1668 // Fill the exported tables with JSFunctions.
1669 for (auto inited_table : inited_tables) {
1670 if (inited_table.js_functions.is_null()) continue;
1671 for (int i = 0; i < static_cast<int>(inited_table.new_entries.size());
1672 i++) {
1673 if (inited_table.new_entries[i] == nullptr) continue;
1674 int func_index =
1675 static_cast<int>(inited_table.new_entries[i]->func_index);
1676 if (!exported_functions->get(func_index)->IsJSFunction()) {
1677 // No JSFunction entry yet exists for this function. Create one.
1678 Handle<Code> wasm_code(Code::cast(code_table->get(func_index)),
1679 isolate_);
1680 Handle<Code> wrapper_code = compiler::CompileJSToWasmWrapper(
1681 isolate_, &module_env, wasm_code, func_index);
1682 Handle<JSFunction> js_function = WrapExportCodeAsJSFunction(
1683 isolate_, wrapper_code, isolate_->factory()->empty_string(),
1684 module_->functions[func_index].sig, func_index, instance);
1685 exported_functions->set(func_index, *js_function);
1686 }
1687 inited_table.js_functions->set(i,
1688 exported_functions->get(func_index));
1689 }
1690 }
1691 }
1592 } 1692 }
1593 }; 1693 };
1594 1694
1595 // Instantiates a WASM module, creating a WebAssembly.Instance from a 1695 // Instantiates a WASM module, creating a WebAssembly.Instance from a
1596 // WebAssembly.Module. 1696 // WebAssembly.Module.
1597 MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate, 1697 MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
1598 ErrorThrower* thrower, 1698 ErrorThrower* thrower,
1599 Handle<JSObject> wasm_module, 1699 Handle<JSObject> wasm_module,
1600 Handle<JSReceiver> ffi, 1700 Handle<JSReceiver> ffi,
1601 Handle<JSArrayBuffer> memory) { 1701 Handle<JSArrayBuffer> memory) {
(...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after
1990 CHECK_NOT_NULL(result.val); 2090 CHECK_NOT_NULL(result.val);
1991 module = const_cast<WasmModule*>(result.val); 2091 module = const_cast<WasmModule*>(result.val);
1992 } 2092 }
1993 2093
1994 Handle<WasmModuleWrapper> module_wrapper = 2094 Handle<WasmModuleWrapper> module_wrapper =
1995 WasmModuleWrapper::New(isolate, module); 2095 WasmModuleWrapper::New(isolate, module);
1996 2096
1997 compiled_module->set_module_wrapper(module_wrapper); 2097 compiled_module->set_module_wrapper(module_wrapper);
1998 DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module)); 2098 DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module));
1999 } 2099 }
OLDNEW
« no previous file with comments | « src/wasm/wasm-js.cc ('k') | test/mjsunit/wasm/export-table.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698