OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |