Chromium Code Reviews| 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 |