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 159231 : WireBytesRef WasmModule::LookupFunctionName(const ModuleWireBytes& wire_bytes,
31 : uint32_t function_index) const {
32 159231 : if (!function_names) {
33 250562 : function_names.reset(new std::unordered_map<uint32_t, WireBytesRef>());
34 : DecodeFunctionNames(wire_bytes.start(), wire_bytes.end(),
35 125281 : function_names.get());
36 : }
37 : auto it = function_names->find(function_index);
38 159231 : if (it == function_names->end()) return WireBytesRef();
39 10822 : return it->second;
40 : }
41 :
42 1093668 : void WasmModule::AddFunctionNameForTesting(int function_index,
43 : WireBytesRef name) {
44 1093668 : if (!function_names) {
45 2187224 : function_names.reset(new std::unordered_map<uint32_t, WireBytesRef>());
46 : }
47 2187336 : function_names->insert(std::make_pair(function_index, name));
48 1093668 : }
49 :
50 : // Get a string stored in the module bytes representing a name.
51 135979 : WasmName ModuleWireBytes::GetNameOrNull(WireBytesRef ref) const {
52 135979 : if (!ref.is_set()) return {nullptr, 0}; // no name.
53 372 : CHECK(BoundsCheck(ref.offset(), ref.length()));
54 : return WasmName::cast(
55 372 : module_bytes_.SubVector(ref.offset(), ref.end_offset()));
56 : }
57 :
58 : // Get a string stored in the module bytes representing a function name.
59 135691 : WasmName ModuleWireBytes::GetNameOrNull(const WasmFunction* function,
60 : const WasmModule* module) const {
61 135691 : return GetNameOrNull(module->LookupFunctionName(*this, function->func_index));
62 : }
63 :
64 6729 : std::ostream& operator<<(std::ostream& os, const WasmFunctionName& name) {
65 6729 : os << "#" << name.function_->func_index;
66 6729 : 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 6729 : os << "?";
73 : }
74 6729 : return os;
75 : }
76 :
77 1377345 : WasmModule::WasmModule(std::unique_ptr<Zone> signature_zone)
78 5509378 : : signature_zone(std::move(signature_zone)) {}
79 :
80 305138 : 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 152617 : if (auto wasm_codegen_callback = isolate->allow_wasm_code_gen_callback()) {
86 : return wasm_codegen_callback(
87 : v8::Utils::ToLocal(context),
88 96 : v8::Utils::ToLocal(isolate->factory()->empty_string()));
89 : }
90 : auto codegen_callback = isolate->allow_code_gen_callback();
91 152569 : return codegen_callback == nullptr ||
92 : codegen_callback(
93 : v8::Utils::ToLocal(context),
94 152569 : v8::Utils::ToLocal(isolate->factory()->empty_string()));
95 : }
96 :
97 144 : Handle<JSArray> GetImports(Isolate* isolate,
98 : Handle<WasmModuleObject> module_object) {
99 : Factory* factory = isolate->factory();
100 :
101 144 : Handle<String> module_string = factory->InternalizeUtf8String("module");
102 144 : Handle<String> name_string = factory->InternalizeUtf8String("name");
103 144 : Handle<String> kind_string = factory->InternalizeUtf8String("kind");
104 :
105 144 : Handle<String> function_string = factory->InternalizeUtf8String("function");
106 144 : Handle<String> table_string = factory->InternalizeUtf8String("table");
107 144 : Handle<String> memory_string = factory->InternalizeUtf8String("memory");
108 144 : Handle<String> global_string = factory->InternalizeUtf8String("global");
109 144 : Handle<String> exception_string = factory->InternalizeUtf8String("exception");
110 :
111 : // Create the result array.
112 288 : const WasmModule* module = module_object->module();
113 360 : int num_imports = static_cast<int>(module->import_table.size());
114 144 : Handle<JSArray> array_object = factory->NewJSArray(PACKED_ELEMENTS, 0, 0);
115 144 : Handle<FixedArray> storage = factory->NewFixedArray(num_imports);
116 144 : JSArray::SetContent(array_object, storage);
117 288 : array_object->set_length(Smi::FromInt(num_imports));
118 :
119 : Handle<JSFunction> object_function =
120 432 : Handle<JSFunction>(isolate->native_context()->object_function(), isolate);
121 :
122 : // Populate the result array.
123 216 : for (int index = 0; index < num_imports; ++index) {
124 72 : const WasmImport& import = module->import_table[index];
125 :
126 72 : Handle<JSObject> entry = factory->NewJSObject(object_function);
127 :
128 : Handle<String> import_kind;
129 72 : switch (import.kind) {
130 : case kExternalFunction:
131 16 : import_kind = function_string;
132 16 : break;
133 : case kExternalTable:
134 16 : import_kind = table_string;
135 16 : break;
136 : case kExternalMemory:
137 16 : import_kind = memory_string;
138 16 : break;
139 : case kExternalGlobal:
140 16 : import_kind = global_string;
141 16 : break;
142 : case kExternalException:
143 8 : import_kind = exception_string;
144 8 : break;
145 : default:
146 0 : UNREACHABLE();
147 : }
148 :
149 : MaybeHandle<String> import_module =
150 : WasmModuleObject::ExtractUtf8StringFromModuleBytes(
151 72 : isolate, module_object, import.module_name);
152 :
153 : MaybeHandle<String> import_name =
154 : WasmModuleObject::ExtractUtf8StringFromModuleBytes(
155 72 : isolate, module_object, import.field_name);
156 :
157 : JSObject::AddProperty(isolate, entry, module_string,
158 72 : import_module.ToHandleChecked(), NONE);
159 : JSObject::AddProperty(isolate, entry, name_string,
160 72 : import_name.ToHandleChecked(), NONE);
161 72 : JSObject::AddProperty(isolate, entry, kind_string, import_kind, NONE);
162 :
163 144 : storage->set(index, *entry);
164 : }
165 :
166 144 : return array_object;
167 : }
168 :
169 136 : Handle<JSArray> GetExports(Isolate* isolate,
170 : Handle<WasmModuleObject> module_object) {
171 : Factory* factory = isolate->factory();
172 :
173 136 : Handle<String> name_string = factory->InternalizeUtf8String("name");
174 136 : Handle<String> kind_string = factory->InternalizeUtf8String("kind");
175 :
176 136 : Handle<String> function_string = factory->InternalizeUtf8String("function");
177 136 : Handle<String> table_string = factory->InternalizeUtf8String("table");
178 136 : Handle<String> memory_string = factory->InternalizeUtf8String("memory");
179 136 : Handle<String> global_string = factory->InternalizeUtf8String("global");
180 136 : Handle<String> exception_string = factory->InternalizeUtf8String("exception");
181 :
182 : // Create the result array.
183 272 : const WasmModule* module = module_object->module();
184 360 : int num_exports = static_cast<int>(module->export_table.size());
185 136 : Handle<JSArray> array_object = factory->NewJSArray(PACKED_ELEMENTS, 0, 0);
186 136 : Handle<FixedArray> storage = factory->NewFixedArray(num_exports);
187 136 : JSArray::SetContent(array_object, storage);
188 272 : array_object->set_length(Smi::FromInt(num_exports));
189 :
190 : Handle<JSFunction> object_function =
191 408 : Handle<JSFunction>(isolate->native_context()->object_function(), isolate);
192 :
193 : // Populate the result array.
194 224 : for (int index = 0; index < num_exports; ++index) {
195 88 : const WasmExport& exp = module->export_table[index];
196 :
197 : Handle<String> export_kind;
198 88 : switch (exp.kind) {
199 : case kExternalFunction:
200 24 : export_kind = function_string;
201 24 : break;
202 : case kExternalTable:
203 16 : export_kind = table_string;
204 16 : break;
205 : case kExternalMemory:
206 16 : export_kind = memory_string;
207 16 : break;
208 : case kExternalGlobal:
209 24 : export_kind = global_string;
210 24 : break;
211 : case kExternalException:
212 8 : export_kind = exception_string;
213 8 : break;
214 : default:
215 0 : UNREACHABLE();
216 : }
217 :
218 88 : Handle<JSObject> entry = factory->NewJSObject(object_function);
219 :
220 : MaybeHandle<String> export_name =
221 : WasmModuleObject::ExtractUtf8StringFromModuleBytes(
222 88 : isolate, module_object, exp.name);
223 :
224 : JSObject::AddProperty(isolate, entry, name_string,
225 88 : export_name.ToHandleChecked(), NONE);
226 88 : JSObject::AddProperty(isolate, entry, kind_string, export_kind, NONE);
227 :
228 176 : storage->set(index, *entry);
229 : }
230 :
231 136 : return array_object;
232 : }
233 :
234 328 : 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 496 : module_object->native_module()->wire_bytes();
241 : std::vector<CustomSectionOffset> custom_sections =
242 248 : DecodeCustomSections(wire_bytes.start(), wire_bytes.end());
243 :
244 : std::vector<Handle<Object>> matching_sections;
245 :
246 : // Gather matching sections.
247 816 : for (auto& section : custom_sections) {
248 : MaybeHandle<String> section_name =
249 : WasmModuleObject::ExtractUtf8StringFromModuleBytes(
250 320 : isolate, module_object, section.name);
251 :
252 560 : if (!name->Equals(*section_name.ToHandleChecked())) continue;
253 :
254 : // Make a copy of the payload data in the section.
255 240 : size_t size = section.payload.length();
256 : void* memory =
257 160 : size == 0 ? nullptr : isolate->array_buffer_allocator()->Allocate(size);
258 :
259 80 : 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 80 : isolate->factory()->NewJSArrayBuffer(SharedFlag::kNotShared);
265 : constexpr bool is_external = false;
266 80 : JSArrayBuffer::Setup(buffer, isolate, is_external, memory, size);
267 80 : memcpy(memory, wire_bytes.start() + section.payload.offset(),
268 160 : section.payload.length());
269 :
270 80 : matching_sections.push_back(buffer);
271 : }
272 :
273 496 : int num_custom_sections = static_cast<int>(matching_sections.size());
274 248 : Handle<JSArray> array_object = factory->NewJSArray(PACKED_ELEMENTS, 0, 0);
275 248 : Handle<FixedArray> storage = factory->NewFixedArray(num_custom_sections);
276 248 : JSArray::SetContent(array_object, storage);
277 496 : array_object->set_length(Smi::FromInt(num_custom_sections));
278 :
279 328 : for (int i = 0; i < num_custom_sections; i++) {
280 160 : storage->set(i, *matching_sections[i]);
281 : }
282 :
283 248 : return array_object;
284 : }
285 :
286 20 : Handle<FixedArray> DecodeLocalNames(Isolate* isolate,
287 : Handle<WasmModuleObject> module_object) {
288 : Vector<const uint8_t> wire_bytes =
289 40 : module_object->native_module()->wire_bytes();
290 : LocalNames decoded_locals;
291 20 : DecodeLocalNames(wire_bytes.start(), wire_bytes.end(), &decoded_locals);
292 : Handle<FixedArray> locals_names =
293 20 : isolate->factory()->NewFixedArray(decoded_locals.max_function_index + 1);
294 44 : for (LocalNamesPerFunction& func : decoded_locals.names) {
295 : Handle<FixedArray> func_locals_names =
296 4 : isolate->factory()->NewFixedArray(func.max_local_index + 1);
297 8 : locals_names->set(func.function_index, *func_locals_names);
298 20 : for (LocalName& name : func.names) {
299 : Handle<String> name_str =
300 : WasmModuleObject::ExtractUtf8StringFromModuleBytes(
301 : isolate, module_object, name.name)
302 24 : .ToHandleChecked();
303 24 : func_locals_names->set(name.local_index, *name_str);
304 : }
305 : }
306 40 : return locals_names;
307 : }
308 :
309 : namespace {
310 : template <typename T>
311 12376090 : inline size_t VectorSize(const std::vector<T>& vector) {
312 12376090 : return sizeof(T) * vector.size();
313 : }
314 : } // namespace
315 :
316 1237609 : size_t EstimateStoredSize(const WasmModule* module) {
317 3712827 : return sizeof(WasmModule) + VectorSize(module->globals) +
318 : (module->signature_zone ? module->signature_zone->allocation_size()
319 1237609 : : 0) +
320 2475218 : VectorSize(module->signatures) + VectorSize(module->signature_ids) +
321 2475218 : VectorSize(module->functions) + VectorSize(module->data_segments) +
322 2475218 : VectorSize(module->tables) + VectorSize(module->import_table) +
323 1237609 : VectorSize(module->export_table) + VectorSize(module->exceptions) +
324 1237609 : VectorSize(module->elem_segments);
325 : }
326 : } // namespace wasm
327 : } // namespace internal
328 178779 : } // namespace v8
|