Line data Source code
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
3 : // found in the LICENSE file.
4 :
5 : #include <functional>
6 : #include <memory>
7 :
8 : #include "src/api-inl.h"
9 : #include "src/assembler-inl.h"
10 : #include "src/compiler/wasm-compiler.h"
11 : #include "src/debug/interface-types.h"
12 : #include "src/frames-inl.h"
13 : #include "src/objects.h"
14 : #include "src/objects/js-array-inl.h"
15 : #include "src/property-descriptor.h"
16 : #include "src/simulator.h"
17 : #include "src/snapshot/snapshot.h"
18 : #include "src/v8.h"
19 : #include "src/wasm/module-decoder.h"
20 : #include "src/wasm/wasm-code-manager.h"
21 : #include "src/wasm/wasm-js.h"
22 : #include "src/wasm/wasm-module.h"
23 : #include "src/wasm/wasm-objects-inl.h"
24 : #include "src/wasm/wasm-result.h"
25 :
26 : namespace v8 {
27 : namespace internal {
28 : namespace wasm {
29 :
30 177198 : WireBytesRef WasmModule::LookupFunctionName(const ModuleWireBytes& wire_bytes,
31 : uint32_t function_index) const {
32 177198 : if (!function_names) {
33 279500 : function_names.reset(new std::unordered_map<uint32_t, WireBytesRef>());
34 : DecodeFunctionNames(wire_bytes.start(), wire_bytes.end(),
35 139750 : function_names.get());
36 : }
37 : auto it = function_names->find(function_index);
38 177198 : if (it == function_names->end()) return WireBytesRef();
39 12340 : return it->second;
40 : }
41 :
42 1366815 : void WasmModule::AddFunctionNameForTesting(int function_index,
43 : WireBytesRef name) {
44 1366815 : if (!function_names) {
45 2733460 : function_names.reset(new std::unordered_map<uint32_t, WireBytesRef>());
46 : }
47 2733630 : function_names->insert(std::make_pair(function_index, name));
48 1366815 : }
49 :
50 : // Get a string stored in the module bytes representing a name.
51 152137 : WasmName ModuleWireBytes::GetNameOrNull(WireBytesRef ref) const {
52 152137 : if (!ref.is_set()) return {nullptr, 0}; // no name.
53 398 : CHECK(BoundsCheck(ref.offset(), ref.length()));
54 : return WasmName::cast(
55 398 : module_bytes_.SubVector(ref.offset(), ref.end_offset()));
56 : }
57 :
58 : // Get a string stored in the module bytes representing a function name.
59 151840 : WasmName ModuleWireBytes::GetNameOrNull(const WasmFunction* function,
60 : const WasmModule* module) const {
61 151840 : return GetNameOrNull(module->LookupFunctionName(*this, function->func_index));
62 : }
63 :
64 6859 : std::ostream& operator<<(std::ostream& os, const WasmFunctionName& name) {
65 6859 : os << "#" << name.function_->func_index;
66 6859 : if (!name.name_.is_empty()) {
67 0 : if (name.name_.start()) {
68 0 : os << ":";
69 0 : os.write(name.name_.start(), name.name_.length());
70 : }
71 : } else {
72 6859 : os << "?";
73 : }
74 6859 : return os;
75 : }
76 :
77 1684194 : WasmModule::WasmModule(std::unique_ptr<Zone> signature_zone)
78 6736770 : : signature_zone(std::move(signature_zone)) {}
79 :
80 340720 : bool IsWasmCodegenAllowed(Isolate* isolate, Handle<Context> context) {
81 : // TODO(wasm): Once wasm has its own CSP policy, we should introduce a
82 : // separate callback that includes information about the module about to be
83 : // compiled. For the time being, pass an empty string as placeholder for the
84 : // sources.
85 170417 : if (auto wasm_codegen_callback = isolate->allow_wasm_code_gen_callback()) {
86 : return wasm_codegen_callback(
87 : v8::Utils::ToLocal(context),
88 114 : v8::Utils::ToLocal(isolate->factory()->empty_string()));
89 : }
90 : auto codegen_callback = isolate->allow_code_gen_callback();
91 170360 : return codegen_callback == nullptr ||
92 : codegen_callback(
93 : v8::Utils::ToLocal(context),
94 170360 : v8::Utils::ToLocal(isolate->factory()->empty_string()));
95 : }
96 :
97 162 : Handle<JSArray> GetImports(Isolate* isolate,
98 : Handle<WasmModuleObject> module_object) {
99 : Factory* factory = isolate->factory();
100 :
101 162 : Handle<String> module_string = factory->InternalizeUtf8String("module");
102 162 : Handle<String> name_string = factory->InternalizeUtf8String("name");
103 162 : Handle<String> kind_string = factory->InternalizeUtf8String("kind");
104 :
105 162 : Handle<String> function_string = factory->InternalizeUtf8String("function");
106 162 : Handle<String> table_string = factory->InternalizeUtf8String("table");
107 162 : Handle<String> memory_string = factory->InternalizeUtf8String("memory");
108 162 : Handle<String> global_string = factory->InternalizeUtf8String("global");
109 162 : Handle<String> exception_string = factory->InternalizeUtf8String("exception");
110 :
111 : // Create the result array.
112 324 : const WasmModule* module = module_object->module();
113 405 : int num_imports = static_cast<int>(module->import_table.size());
114 162 : Handle<JSArray> array_object = factory->NewJSArray(PACKED_ELEMENTS, 0, 0);
115 162 : Handle<FixedArray> storage = factory->NewFixedArray(num_imports);
116 162 : JSArray::SetContent(array_object, storage);
117 324 : array_object->set_length(Smi::FromInt(num_imports));
118 :
119 : Handle<JSFunction> object_function =
120 486 : Handle<JSFunction>(isolate->native_context()->object_function(), isolate);
121 :
122 : // Populate the result array.
123 243 : for (int index = 0; index < num_imports; ++index) {
124 81 : const WasmImport& import = module->import_table[index];
125 :
126 81 : Handle<JSObject> entry = factory->NewJSObject(object_function);
127 :
128 : Handle<String> import_kind;
129 81 : switch (import.kind) {
130 : case kExternalFunction:
131 18 : import_kind = function_string;
132 18 : break;
133 : case kExternalTable:
134 18 : import_kind = table_string;
135 18 : break;
136 : case kExternalMemory:
137 18 : import_kind = memory_string;
138 18 : break;
139 : case kExternalGlobal:
140 18 : import_kind = global_string;
141 18 : break;
142 : case kExternalException:
143 9 : import_kind = exception_string;
144 9 : break;
145 : default:
146 0 : UNREACHABLE();
147 : }
148 :
149 : MaybeHandle<String> import_module =
150 : WasmModuleObject::ExtractUtf8StringFromModuleBytes(
151 81 : isolate, module_object, import.module_name);
152 :
153 : MaybeHandle<String> import_name =
154 : WasmModuleObject::ExtractUtf8StringFromModuleBytes(
155 81 : isolate, module_object, import.field_name);
156 :
157 : JSObject::AddProperty(isolate, entry, module_string,
158 81 : import_module.ToHandleChecked(), NONE);
159 : JSObject::AddProperty(isolate, entry, name_string,
160 81 : import_name.ToHandleChecked(), NONE);
161 81 : JSObject::AddProperty(isolate, entry, kind_string, import_kind, NONE);
162 :
163 162 : storage->set(index, *entry);
164 : }
165 :
166 162 : return array_object;
167 : }
168 :
169 153 : Handle<JSArray> GetExports(Isolate* isolate,
170 : Handle<WasmModuleObject> module_object) {
171 : Factory* factory = isolate->factory();
172 :
173 153 : Handle<String> name_string = factory->InternalizeUtf8String("name");
174 153 : Handle<String> kind_string = factory->InternalizeUtf8String("kind");
175 :
176 153 : Handle<String> function_string = factory->InternalizeUtf8String("function");
177 153 : Handle<String> table_string = factory->InternalizeUtf8String("table");
178 153 : Handle<String> memory_string = factory->InternalizeUtf8String("memory");
179 153 : Handle<String> global_string = factory->InternalizeUtf8String("global");
180 153 : Handle<String> exception_string = factory->InternalizeUtf8String("exception");
181 :
182 : // Create the result array.
183 306 : const WasmModule* module = module_object->module();
184 405 : int num_exports = static_cast<int>(module->export_table.size());
185 153 : Handle<JSArray> array_object = factory->NewJSArray(PACKED_ELEMENTS, 0, 0);
186 153 : Handle<FixedArray> storage = factory->NewFixedArray(num_exports);
187 153 : JSArray::SetContent(array_object, storage);
188 306 : array_object->set_length(Smi::FromInt(num_exports));
189 :
190 : Handle<JSFunction> object_function =
191 459 : Handle<JSFunction>(isolate->native_context()->object_function(), isolate);
192 :
193 : // Populate the result array.
194 252 : for (int index = 0; index < num_exports; ++index) {
195 99 : const WasmExport& exp = module->export_table[index];
196 :
197 : Handle<String> export_kind;
198 99 : switch (exp.kind) {
199 : case kExternalFunction:
200 27 : export_kind = function_string;
201 27 : break;
202 : case kExternalTable:
203 18 : export_kind = table_string;
204 18 : break;
205 : case kExternalMemory:
206 18 : export_kind = memory_string;
207 18 : break;
208 : case kExternalGlobal:
209 27 : export_kind = global_string;
210 27 : break;
211 : case kExternalException:
212 9 : export_kind = exception_string;
213 9 : break;
214 : default:
215 0 : UNREACHABLE();
216 : }
217 :
218 99 : Handle<JSObject> entry = factory->NewJSObject(object_function);
219 :
220 : MaybeHandle<String> export_name =
221 : WasmModuleObject::ExtractUtf8StringFromModuleBytes(
222 99 : isolate, module_object, exp.name);
223 :
224 : JSObject::AddProperty(isolate, entry, name_string,
225 99 : export_name.ToHandleChecked(), NONE);
226 99 : JSObject::AddProperty(isolate, entry, kind_string, export_kind, NONE);
227 :
228 198 : storage->set(index, *entry);
229 : }
230 :
231 153 : return array_object;
232 : }
233 :
234 99 : Handle<JSArray> GetCustomSections(Isolate* isolate,
235 : Handle<WasmModuleObject> module_object,
236 : Handle<String> name, ErrorThrower* thrower) {
237 : Factory* factory = isolate->factory();
238 :
239 : Vector<const uint8_t> wire_bytes =
240 108 : module_object->native_module()->wire_bytes();
241 : std::vector<CustomSectionOffset> custom_sections =
242 54 : DecodeCustomSections(wire_bytes.start(), wire_bytes.end());
243 :
244 : std::vector<Handle<Object>> matching_sections;
245 :
246 : // Gather matching sections.
247 252 : for (auto& section : custom_sections) {
248 : MaybeHandle<String> section_name =
249 : WasmModuleObject::ExtractUtf8StringFromModuleBytes(
250 144 : isolate, module_object, section.name);
251 :
252 243 : if (!name->Equals(*section_name.ToHandleChecked())) continue;
253 :
254 : // Make a copy of the payload data in the section.
255 135 : size_t size = section.payload.length();
256 : void* memory =
257 90 : size == 0 ? nullptr : isolate->array_buffer_allocator()->Allocate(size);
258 :
259 45 : if (size && !memory) {
260 0 : thrower->RangeError("out of memory allocating custom section data");
261 0 : return Handle<JSArray>();
262 : }
263 : Handle<JSArrayBuffer> buffer =
264 45 : isolate->factory()->NewJSArrayBuffer(SharedFlag::kNotShared);
265 : constexpr bool is_external = false;
266 45 : JSArrayBuffer::Setup(buffer, isolate, is_external, memory, size);
267 45 : memcpy(memory, wire_bytes.start() + section.payload.offset(),
268 90 : section.payload.length());
269 :
270 45 : matching_sections.push_back(buffer);
271 : }
272 :
273 108 : int num_custom_sections = static_cast<int>(matching_sections.size());
274 54 : Handle<JSArray> array_object = factory->NewJSArray(PACKED_ELEMENTS, 0, 0);
275 54 : Handle<FixedArray> storage = factory->NewFixedArray(num_custom_sections);
276 54 : JSArray::SetContent(array_object, storage);
277 108 : array_object->set_length(Smi::FromInt(num_custom_sections));
278 :
279 99 : for (int i = 0; i < num_custom_sections; i++) {
280 90 : storage->set(i, *matching_sections[i]);
281 : }
282 :
283 54 : return array_object;
284 : }
285 :
286 25 : Handle<FixedArray> DecodeLocalNames(Isolate* isolate,
287 : Handle<WasmModuleObject> module_object) {
288 : Vector<const uint8_t> wire_bytes =
289 50 : module_object->native_module()->wire_bytes();
290 : LocalNames decoded_locals;
291 25 : DecodeLocalNames(wire_bytes.start(), wire_bytes.end(), &decoded_locals);
292 : Handle<FixedArray> locals_names =
293 25 : isolate->factory()->NewFixedArray(decoded_locals.max_function_index + 1);
294 55 : for (LocalNamesPerFunction& func : decoded_locals.names) {
295 : Handle<FixedArray> func_locals_names =
296 5 : isolate->factory()->NewFixedArray(func.max_local_index + 1);
297 10 : locals_names->set(func.function_index, *func_locals_names);
298 25 : for (LocalName& name : func.names) {
299 : Handle<String> name_str =
300 : WasmModuleObject::ExtractUtf8StringFromModuleBytes(
301 : isolate, module_object, name.name)
302 30 : .ToHandleChecked();
303 30 : func_locals_names->set(name.local_index, *name_str);
304 : }
305 : }
306 50 : return locals_names;
307 : }
308 :
309 : namespace {
310 : template <typename T>
311 15285680 : inline size_t VectorSize(const std::vector<T>& vector) {
312 15285680 : return sizeof(T) * vector.size();
313 : }
314 : } // namespace
315 :
316 1528568 : size_t EstimateStoredSize(const WasmModule* module) {
317 4585704 : return sizeof(WasmModule) + VectorSize(module->globals) +
318 : (module->signature_zone ? module->signature_zone->allocation_size()
319 1528568 : : 0) +
320 3057136 : VectorSize(module->signatures) + VectorSize(module->signature_ids) +
321 3057136 : VectorSize(module->functions) + VectorSize(module->data_segments) +
322 3057136 : VectorSize(module->tables) + VectorSize(module->import_table) +
323 1528568 : VectorSize(module->export_table) + VectorSize(module->exceptions) +
324 1528568 : VectorSize(module->elem_segments);
325 : }
326 : } // namespace wasm
327 : } // namespace internal
328 183867 : } // namespace v8
|