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