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(), | |
bradnelson
2016/10/25 07:33:39
There will be one by default correct?
titzer
2016/10/25 08:27:37
This code handles any number of tables with any si
| |
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 // If there are any exported tables, cache the JSFunctions created | |
rossberg
2016/10/25 08:19:20
Don't you need to do that anyway, in case the same
titzer
2016/10/25 08:23:13
I don't think we've spec'd that case yet.
As it is
rossberg
2016/10/25 08:28:59
Actually, JS.md explicitly requires it. ;)
| |
1528 // for export to reuse in the exported tables. | |
1529 Handle<FixedArray> exported_functions; | |
1530 for (auto table : module_->function_tables) { | |
1531 if (table.exported) { | |
1532 exported_functions = isolate_->factory()->NewFixedArray( | |
1533 static_cast<int>(module_->functions.size())); | |
1534 break; | |
1535 } | |
1536 } | |
1537 | |
1503 Handle<JSObject> exports_object = instance; | 1538 Handle<JSObject> exports_object = instance; |
1504 if (module_->origin == kWasmOrigin) { | 1539 if (module_->origin == kWasmOrigin) { |
1505 // Create the "exports" object. | 1540 // Create the "exports" object. |
1506 Handle<JSFunction> object_function = Handle<JSFunction>( | 1541 Handle<JSFunction> object_function = Handle<JSFunction>( |
1507 isolate_->native_context()->object_function(), isolate_); | 1542 isolate_->native_context()->object_function(), isolate_); |
1508 exports_object = | 1543 exports_object = |
1509 isolate_->factory()->NewJSObject(object_function, TENURED); | 1544 isolate_->factory()->NewJSObject(object_function, TENURED); |
1510 Handle<String> exports_name = | 1545 Handle<String> exports_name = |
1511 isolate_->factory()->InternalizeUtf8String("exports"); | 1546 isolate_->factory()->InternalizeUtf8String("exports"); |
1512 JSObject::AddProperty(instance, exports_name, exports_object, READ_ONLY); | 1547 JSObject::AddProperty(instance, exports_name, exports_object, READ_ONLY); |
1513 } | 1548 } |
1514 | 1549 |
1515 PropertyDescriptor desc; | 1550 PropertyDescriptor desc; |
1516 desc.set_writable(false); | 1551 desc.set_writable(false); |
1517 | 1552 |
1518 int func_index = 0; | 1553 int func_index = 0; |
1519 for (auto exp : module_->export_table) { | 1554 for (auto exp : module_->export_table) { |
1520 Handle<String> name = | 1555 Handle<String> name = |
1521 ExtractStringFromModuleBytes(isolate_, compiled_module_, | 1556 ExtractStringFromModuleBytes(isolate_, compiled_module_, |
1522 exp.name_offset, exp.name_length) | 1557 exp.name_offset, exp.name_length) |
1523 .ToHandleChecked(); | 1558 .ToHandleChecked(); |
1524 switch (exp.kind) { | 1559 switch (exp.kind) { |
1525 case kExternalFunction: { | 1560 case kExternalFunction: { |
1526 // Wrap and export the code as a JSFunction. | 1561 // Wrap and export the code as a JSFunction. |
1527 WasmFunction& function = module_->functions[exp.index]; | 1562 WasmFunction& function = module_->functions[exp.index]; |
1528 int export_index = | 1563 int export_index = |
1529 static_cast<int>(module_->functions.size() + func_index); | 1564 static_cast<int>(module_->functions.size() + func_index); |
1530 Handle<Code> export_code = | 1565 Handle<Code> export_code = |
rossberg
2016/10/25 08:19:20
Like here, you should first check whether exported
titzer
2016/10/25 08:23:13
That would mean that there would be only one expor
| |
1531 code_table->GetValueChecked<Code>(isolate_, export_index); | 1566 code_table->GetValueChecked<Code>(isolate_, export_index); |
1532 desc.set_value(WrapExportCodeAsJSFunction( | 1567 Handle<JSFunction> js_function = WrapExportCodeAsJSFunction( |
1533 isolate_, export_code, name, function.sig, func_index, instance)); | 1568 isolate_, export_code, name, function.sig, func_index, instance); |
1569 if (!exported_functions.is_null()) { | |
1570 exported_functions->set(exp.index, *js_function); | |
1571 } | |
1572 desc.set_value(js_function); | |
1534 func_index++; | 1573 func_index++; |
1535 break; | 1574 break; |
1536 } | 1575 } |
1537 case kExternalTable: | 1576 case kExternalTable: { |
1538 // TODO(titzer): create a WebAssembly.Table instance. | 1577 InitializedTable& init_table = inited_tables[exp.index]; |
1539 // TODO(titzer): should it have the same identity as an import? | 1578 WasmIndirectFunctionTable& table = |
1579 module_->function_tables[exp.index]; | |
1580 if (init_table.table_object.is_null()) { | |
1581 init_table.table_object = WasmJs::CreateWasmTableObject( | |
1582 isolate_, table.size, table.max_size != 0, table.max_size, | |
1583 &init_table.js_functions); | |
1584 } | |
1585 desc.set_value(init_table.table_object); | |
1540 break; | 1586 break; |
1587 } | |
1541 case kExternalMemory: { | 1588 case kExternalMemory: { |
1542 // Export the memory as a WebAssembly.Memory object. | 1589 // Export the memory as a WebAssembly.Memory object. |
1543 Handle<Object> memory_object( | 1590 Handle<Object> memory_object( |
1544 instance->GetInternalField(kWasmMemObject), isolate_); | 1591 instance->GetInternalField(kWasmMemObject), isolate_); |
1545 if (memory_object->IsUndefined(isolate_)) { | 1592 if (memory_object->IsUndefined(isolate_)) { |
1546 // If there was no imported WebAssembly.Memory object, create one. | 1593 // If there was no imported WebAssembly.Memory object, create one. |
1547 Handle<JSArrayBuffer> buffer( | 1594 Handle<JSArrayBuffer> buffer( |
1548 JSArrayBuffer::cast( | 1595 JSArrayBuffer::cast( |
1549 instance->GetInternalField(kWasmMemArrayBuffer)), | 1596 instance->GetInternalField(kWasmMemArrayBuffer)), |
1550 isolate_); | 1597 isolate_); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1582 } | 1629 } |
1583 | 1630 |
1584 v8::Maybe<bool> status = JSReceiver::DefineOwnProperty( | 1631 v8::Maybe<bool> status = JSReceiver::DefineOwnProperty( |
1585 isolate_, exports_object, name, &desc, Object::THROW_ON_ERROR); | 1632 isolate_, exports_object, name, &desc, Object::THROW_ON_ERROR); |
1586 if (!status.IsJust()) { | 1633 if (!status.IsJust()) { |
1587 thrower_->TypeError("export of %.*s failed.", name->length(), | 1634 thrower_->TypeError("export of %.*s failed.", name->length(), |
1588 name->ToCString().get()); | 1635 name->ToCString().get()); |
1589 return; | 1636 return; |
1590 } | 1637 } |
1591 } | 1638 } |
1639 | |
1640 // Fill out the contents of WebAssembly.Table instances. | |
1641 if (!exported_functions.is_null()) { | |
1642 // TODO(titzer): We compile JS->WASM wrappers for any function that is a | |
1643 // member of an exported indirect table that is not itself exported. This | |
1644 // could be done at compile time and cached instead. | |
1645 WasmInstance temp_instance(module_); | |
1646 temp_instance.context = isolate_->native_context(); | |
1647 temp_instance.mem_size = 0; | |
1648 temp_instance.mem_start = nullptr; | |
1649 temp_instance.globals_start = nullptr; | |
1650 | |
1651 ModuleEnv module_env; | |
1652 module_env.module = module_; | |
1653 module_env.instance = &temp_instance; | |
1654 module_env.origin = module_->origin; | |
1655 | |
1656 // Fill the exported tables with JSFunctions. | |
1657 for (auto inited_table : inited_tables) { | |
1658 if (inited_table.js_functions.is_null()) continue; | |
1659 for (int i = 0; i < static_cast<int>(inited_table.new_entries.size()); | |
1660 i++) { | |
1661 if (inited_table.new_entries[i] == nullptr) continue; | |
1662 int func_index = | |
1663 static_cast<int>(inited_table.new_entries[i]->func_index); | |
bradnelson
2016/10/25 07:33:39
These can only be in bounds correct? DCHECK?
titzer
2016/10/25 08:27:37
The loop iterates over the inited_table.new_entrie
| |
1664 if (!exported_functions->get(func_index)->IsJSFunction()) { | |
1665 // No JSFunction entry yet exists for this function. Create one. | |
1666 Handle<Code> wasm_code(Code::cast(code_table->get(func_index)), | |
1667 isolate_); | |
1668 Handle<Code> wrapper_code = compiler::CompileJSToWasmWrapper( | |
1669 isolate_, &module_env, wasm_code, func_index); | |
1670 Handle<JSFunction> js_function = WrapExportCodeAsJSFunction( | |
1671 isolate_, wrapper_code, isolate_->factory()->empty_string(), | |
1672 module_->functions[func_index].sig, func_index, instance); | |
1673 exported_functions->set(func_index, *js_function); | |
1674 } | |
1675 inited_table.js_functions->set(i, | |
1676 exported_functions->get(func_index)); | |
1677 } | |
1678 } | |
1679 } | |
1592 } | 1680 } |
1593 }; | 1681 }; |
1594 | 1682 |
1595 // Instantiates a WASM module, creating a WebAssembly.Instance from a | 1683 // Instantiates a WASM module, creating a WebAssembly.Instance from a |
1596 // WebAssembly.Module. | 1684 // WebAssembly.Module. |
1597 MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate, | 1685 MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate, |
1598 ErrorThrower* thrower, | 1686 ErrorThrower* thrower, |
1599 Handle<JSObject> wasm_module, | 1687 Handle<JSObject> wasm_module, |
1600 Handle<JSReceiver> ffi, | 1688 Handle<JSReceiver> ffi, |
1601 Handle<JSArrayBuffer> memory) { | 1689 Handle<JSArrayBuffer> memory) { |
(...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1990 CHECK_NOT_NULL(result.val); | 2078 CHECK_NOT_NULL(result.val); |
1991 module = const_cast<WasmModule*>(result.val); | 2079 module = const_cast<WasmModule*>(result.val); |
1992 } | 2080 } |
1993 | 2081 |
1994 Handle<WasmModuleWrapper> module_wrapper = | 2082 Handle<WasmModuleWrapper> module_wrapper = |
1995 WasmModuleWrapper::New(isolate, module); | 2083 WasmModuleWrapper::New(isolate, module); |
1996 | 2084 |
1997 compiled_module->set_module_wrapper(module_wrapper); | 2085 compiled_module->set_module_wrapper(module_wrapper); |
1998 DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module)); | 2086 DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module)); |
1999 } | 2087 } |
OLD | NEW |