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.h"
9 : #include "src/assembler-inl.h"
10 : #include "src/code-stubs.h"
11 : #include "src/debug/interface-types.h"
12 : #include "src/frames-inl.h"
13 : #include "src/objects.h"
14 : #include "src/property-descriptor.h"
15 : #include "src/simulator.h"
16 : #include "src/snapshot/snapshot.h"
17 : #include "src/v8.h"
18 :
19 : #include "src/compiler/wasm-compiler.h"
20 : #include "src/wasm/compilation-manager.h"
21 : #include "src/wasm/module-compiler.h"
22 : #include "src/wasm/module-decoder.h"
23 : #include "src/wasm/wasm-code-specialization.h"
24 : #include "src/wasm/wasm-js.h"
25 : #include "src/wasm/wasm-module.h"
26 : #include "src/wasm/wasm-objects-inl.h"
27 : #include "src/wasm/wasm-result.h"
28 :
29 : namespace v8 {
30 : namespace internal {
31 : namespace wasm {
32 :
33 : #define TRACE(...) \
34 : do { \
35 : if (FLAG_trace_wasm_instances) PrintF(__VA_ARGS__); \
36 : } while (false)
37 :
38 : #define TRACE_CHAIN(instance) \
39 : do { \
40 : instance->PrintInstancesChain(); \
41 : } while (false)
42 :
43 : #define TRACE_COMPILE(...) \
44 : do { \
45 : if (FLAG_trace_wasm_compiler) PrintF(__VA_ARGS__); \
46 : } while (false)
47 :
48 : // static
49 : const WasmExceptionSig WasmException::empty_sig_(0, 0, nullptr);
50 :
51 : // static
52 : constexpr const char* WasmException::kRuntimeIdStr;
53 :
54 : // static
55 : constexpr const char* WasmException::kRuntimeValuesStr;
56 :
57 21386 : void UnpackAndRegisterProtectedInstructions(Isolate* isolate,
58 : Handle<FixedArray> code_table) {
59 : DisallowHeapAllocation no_gc;
60 : std::vector<trap_handler::ProtectedInstructionData> unpacked;
61 :
62 129054 : for (int i = 0; i < code_table->length(); ++i) {
63 : Object* maybe_code = code_table->get(i);
64 : // This is sometimes undefined when we're called from cctests.
65 43141 : if (maybe_code->IsUndefined(isolate)) continue;
66 : Code* code = Code::cast(maybe_code);
67 :
68 41492 : if (code->kind() != Code::WASM_FUNCTION) {
69 : continue;
70 : }
71 :
72 37848 : if (code->trap_handler_index()->value() != trap_handler::kInvalidIndex) {
73 : // This function has already been registered.
74 : continue;
75 : }
76 :
77 37844 : byte* base = code->entry();
78 :
79 : const int mode_mask =
80 : RelocInfo::ModeMask(RelocInfo::WASM_PROTECTED_INSTRUCTION_LANDING);
81 43175 : for (RelocIterator it(code, mode_mask); !it.done(); it.next()) {
82 : trap_handler::ProtectedInstructionData data;
83 5331 : data.instr_offset = static_cast<uint32_t>(it.rinfo()->data());
84 5331 : data.landing_offset = static_cast<uint32_t>(it.rinfo()->pc() - base);
85 : // Check that now over-/underflow happened.
86 : DCHECK_EQ(it.rinfo()->data(), data.instr_offset);
87 : DCHECK_EQ(it.rinfo()->pc() - base, data.landing_offset);
88 5331 : unpacked.emplace_back(data);
89 : }
90 37844 : if (unpacked.empty()) continue;
91 :
92 : const int index = RegisterHandlerData(base, code->instruction_size(),
93 743 : unpacked.size(), &unpacked[0]);
94 : unpacked.clear();
95 : // TODO(eholk): if index is negative, fail.
96 : DCHECK_LE(0, index);
97 743 : code->set_trap_handler_index(Smi::FromInt(index));
98 : }
99 21386 : }
100 :
101 5901 : std::ostream& operator<<(std::ostream& os, const WasmFunctionName& name) {
102 5901 : os << "#" << name.function_->func_index;
103 5901 : if (name.function_->name.is_set()) {
104 0 : if (name.name_.start()) {
105 0 : os << ":";
106 0 : os.write(name.name_.start(), name.name_.length());
107 : }
108 : } else {
109 5901 : os << "?";
110 : }
111 5901 : return os;
112 : }
113 :
114 345897 : WasmModule::WasmModule(std::unique_ptr<Zone> owned)
115 1037691 : : signature_zone(std::move(owned)) {}
116 :
117 2230 : WasmFunction* GetWasmFunctionForExport(Isolate* isolate,
118 : Handle<Object> target) {
119 2230 : if (target->IsJSFunction()) {
120 : Handle<JSFunction> func = Handle<JSFunction>::cast(target);
121 2230 : if (func->code()->kind() == Code::JS_TO_WASM_FUNCTION) {
122 : auto exported = Handle<WasmExportedFunction>::cast(func);
123 2230 : Handle<WasmInstanceObject> other_instance(exported->instance(), isolate);
124 2230 : int func_index = exported->function_index();
125 4460 : return &other_instance->module()->functions[func_index];
126 : }
127 : }
128 : return nullptr;
129 : }
130 :
131 5340 : void UpdateDispatchTables(Isolate* isolate, Handle<FixedArray> dispatch_tables,
132 : int index, WasmFunction* function,
133 : Handle<Code> code) {
134 : DCHECK_EQ(0, dispatch_tables->length() % 4);
135 23060 : for (int i = 0; i < dispatch_tables->length(); i += 4) {
136 : Handle<FixedArray> function_table(
137 6190 : FixedArray::cast(dispatch_tables->get(i + 2)), isolate);
138 : Handle<FixedArray> signature_table(
139 6190 : FixedArray::cast(dispatch_tables->get(i + 3)), isolate);
140 6190 : if (function) {
141 : Handle<WasmInstanceObject> instance(
142 : WasmInstanceObject::cast(dispatch_tables->get(i)), isolate);
143 : // Note that {SignatureMap::Find} may return {-1} if the signature is
144 : // not found; it will simply never match any check.
145 10180 : auto sig_index = instance->module()->signature_map.Find(function->sig);
146 : signature_table->set(index, Smi::FromInt(sig_index));
147 5090 : function_table->set(index, *code);
148 : } else {
149 : signature_table->set(index, Smi::FromInt(-1));
150 : function_table->set(index, Smi::kZero);
151 : }
152 : }
153 5340 : }
154 :
155 157337 : bool IsWasmCodegenAllowed(Isolate* isolate, Handle<Context> context) {
156 : // TODO(wasm): Once wasm has its own CSP policy, we should introduce a
157 : // separate callback that includes information about the module about to be
158 : // compiled. For the time being, pass an empty string as placeholder for the
159 : // sources.
160 157369 : return isolate->allow_code_gen_callback() == nullptr ||
161 32 : isolate->allow_code_gen_callback()(
162 : v8::Utils::ToLocal(context),
163 157337 : v8::Utils::ToLocal(isolate->factory()->empty_string()));
164 : }
165 :
166 40 : Handle<JSArray> GetImports(Isolate* isolate,
167 : Handle<WasmModuleObject> module_object) {
168 : Handle<WasmCompiledModule> compiled_module(module_object->compiled_module(),
169 : isolate);
170 : Factory* factory = isolate->factory();
171 :
172 40 : Handle<String> module_string = factory->InternalizeUtf8String("module");
173 40 : Handle<String> name_string = factory->InternalizeUtf8String("name");
174 40 : Handle<String> kind_string = factory->InternalizeUtf8String("kind");
175 :
176 40 : Handle<String> function_string = factory->InternalizeUtf8String("function");
177 40 : Handle<String> table_string = factory->InternalizeUtf8String("table");
178 40 : Handle<String> memory_string = factory->InternalizeUtf8String("memory");
179 40 : Handle<String> global_string = factory->InternalizeUtf8String("global");
180 :
181 : // Create the result array.
182 40 : WasmModule* module = compiled_module->module();
183 160 : int num_imports = static_cast<int>(module->import_table.size());
184 40 : Handle<JSArray> array_object = factory->NewJSArray(PACKED_ELEMENTS, 0, 0);
185 40 : Handle<FixedArray> storage = factory->NewFixedArray(num_imports);
186 40 : JSArray::SetContent(array_object, storage);
187 : array_object->set_length(Smi::FromInt(num_imports));
188 :
189 : Handle<JSFunction> object_function =
190 80 : Handle<JSFunction>(isolate->native_context()->object_function(), isolate);
191 :
192 : // Populate the result array.
193 120 : for (int index = 0; index < num_imports; ++index) {
194 80 : WasmImport& import = module->import_table[index];
195 :
196 80 : Handle<JSObject> entry = factory->NewJSObject(object_function);
197 :
198 : Handle<String> import_kind;
199 80 : switch (import.kind) {
200 : case kExternalFunction:
201 20 : import_kind = function_string;
202 20 : break;
203 : case kExternalTable:
204 20 : import_kind = table_string;
205 20 : break;
206 : case kExternalMemory:
207 20 : import_kind = memory_string;
208 20 : break;
209 : case kExternalGlobal:
210 20 : import_kind = global_string;
211 20 : break;
212 : default:
213 0 : UNREACHABLE();
214 : }
215 :
216 : MaybeHandle<String> import_module =
217 : WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
218 80 : isolate, compiled_module, import.module_name);
219 :
220 : MaybeHandle<String> import_name =
221 : WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
222 80 : isolate, compiled_module, import.field_name);
223 :
224 : JSObject::AddProperty(entry, module_string, import_module.ToHandleChecked(),
225 80 : NONE);
226 : JSObject::AddProperty(entry, name_string, import_name.ToHandleChecked(),
227 80 : NONE);
228 80 : JSObject::AddProperty(entry, kind_string, import_kind, NONE);
229 :
230 80 : storage->set(index, *entry);
231 : }
232 :
233 40 : return array_object;
234 : }
235 :
236 40 : Handle<JSArray> GetExports(Isolate* isolate,
237 : Handle<WasmModuleObject> module_object) {
238 : Handle<WasmCompiledModule> compiled_module(module_object->compiled_module(),
239 : isolate);
240 : Factory* factory = isolate->factory();
241 :
242 40 : Handle<String> name_string = factory->InternalizeUtf8String("name");
243 40 : Handle<String> kind_string = factory->InternalizeUtf8String("kind");
244 :
245 40 : Handle<String> function_string = factory->InternalizeUtf8String("function");
246 40 : Handle<String> table_string = factory->InternalizeUtf8String("table");
247 40 : Handle<String> memory_string = factory->InternalizeUtf8String("memory");
248 40 : Handle<String> global_string = factory->InternalizeUtf8String("global");
249 :
250 : // Create the result array.
251 40 : WasmModule* module = compiled_module->module();
252 160 : int num_exports = static_cast<int>(module->export_table.size());
253 40 : Handle<JSArray> array_object = factory->NewJSArray(PACKED_ELEMENTS, 0, 0);
254 40 : Handle<FixedArray> storage = factory->NewFixedArray(num_exports);
255 40 : JSArray::SetContent(array_object, storage);
256 : array_object->set_length(Smi::FromInt(num_exports));
257 :
258 : Handle<JSFunction> object_function =
259 80 : Handle<JSFunction>(isolate->native_context()->object_function(), isolate);
260 :
261 : // Populate the result array.
262 120 : for (int index = 0; index < num_exports; ++index) {
263 80 : WasmExport& exp = module->export_table[index];
264 :
265 : Handle<String> export_kind;
266 80 : switch (exp.kind) {
267 : case kExternalFunction:
268 20 : export_kind = function_string;
269 20 : break;
270 : case kExternalTable:
271 20 : export_kind = table_string;
272 20 : break;
273 : case kExternalMemory:
274 20 : export_kind = memory_string;
275 20 : break;
276 : case kExternalGlobal:
277 20 : export_kind = global_string;
278 20 : break;
279 : default:
280 0 : UNREACHABLE();
281 : }
282 :
283 80 : Handle<JSObject> entry = factory->NewJSObject(object_function);
284 :
285 : MaybeHandle<String> export_name =
286 : WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
287 80 : isolate, compiled_module, exp.name);
288 :
289 : JSObject::AddProperty(entry, name_string, export_name.ToHandleChecked(),
290 80 : NONE);
291 80 : JSObject::AddProperty(entry, kind_string, export_kind, NONE);
292 :
293 80 : storage->set(index, *entry);
294 : }
295 :
296 40 : return array_object;
297 : }
298 :
299 110 : Handle<JSArray> GetCustomSections(Isolate* isolate,
300 : Handle<WasmModuleObject> module_object,
301 : Handle<String> name, ErrorThrower* thrower) {
302 : Handle<WasmCompiledModule> compiled_module(module_object->compiled_module(),
303 : isolate);
304 : Factory* factory = isolate->factory();
305 :
306 : std::vector<CustomSectionOffset> custom_sections;
307 : {
308 : DisallowHeapAllocation no_gc; // for raw access to string bytes.
309 : Handle<SeqOneByteString> module_bytes(compiled_module->module_bytes(),
310 : isolate);
311 : const byte* start =
312 60 : reinterpret_cast<const byte*>(module_bytes->GetCharsAddress());
313 60 : const byte* end = start + module_bytes->length();
314 120 : custom_sections = DecodeCustomSections(start, end);
315 : }
316 :
317 : std::vector<Handle<Object>> matching_sections;
318 :
319 : // Gather matching sections.
320 280 : for (auto& section : custom_sections) {
321 : MaybeHandle<String> section_name =
322 : WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
323 160 : isolate, compiled_module, section.name);
324 :
325 270 : if (!name->Equals(*section_name.ToHandleChecked())) continue;
326 :
327 : // Make a copy of the payload data in the section.
328 150 : size_t size = section.payload.length();
329 : void* memory =
330 100 : size == 0 ? nullptr : isolate->array_buffer_allocator()->Allocate(size);
331 :
332 50 : if (size && !memory) {
333 0 : thrower->RangeError("out of memory allocating custom section data");
334 0 : return Handle<JSArray>();
335 : }
336 50 : Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
337 : constexpr bool is_external = false;
338 : JSArrayBuffer::Setup(buffer, isolate, is_external, memory, size, memory,
339 50 : size);
340 : DisallowHeapAllocation no_gc; // for raw access to string bytes.
341 : Handle<SeqOneByteString> module_bytes(compiled_module->module_bytes(),
342 : isolate);
343 : const byte* start =
344 50 : reinterpret_cast<const byte*>(module_bytes->GetCharsAddress());
345 100 : memcpy(memory, start + section.payload.offset(), section.payload.length());
346 :
347 50 : matching_sections.push_back(buffer);
348 : }
349 :
350 120 : int num_custom_sections = static_cast<int>(matching_sections.size());
351 60 : Handle<JSArray> array_object = factory->NewJSArray(PACKED_ELEMENTS, 0, 0);
352 60 : Handle<FixedArray> storage = factory->NewFixedArray(num_custom_sections);
353 60 : JSArray::SetContent(array_object, storage);
354 : array_object->set_length(Smi::FromInt(num_custom_sections));
355 :
356 110 : for (int i = 0; i < num_custom_sections; i++) {
357 100 : storage->set(i, *matching_sections[i]);
358 : }
359 :
360 60 : return array_object;
361 : }
362 :
363 15 : Handle<FixedArray> DecodeLocalNames(
364 : Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
365 : Handle<SeqOneByteString> wire_bytes(compiled_module->module_bytes(), isolate);
366 : LocalNames decoded_locals;
367 : {
368 : DisallowHeapAllocation no_gc;
369 : DecodeLocalNames(wire_bytes->GetChars(),
370 15 : wire_bytes->GetChars() + wire_bytes->length(),
371 15 : &decoded_locals);
372 : }
373 : Handle<FixedArray> locals_names =
374 15 : isolate->factory()->NewFixedArray(decoded_locals.max_function_index + 1);
375 35 : for (LocalNamesPerFunction& func : decoded_locals.names) {
376 : Handle<FixedArray> func_locals_names =
377 5 : isolate->factory()->NewFixedArray(func.max_local_index + 1);
378 10 : locals_names->set(func.function_index, *func_locals_names);
379 20 : for (LocalName& name : func.names) {
380 : Handle<String> name_str =
381 : WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
382 : isolate, compiled_module, name.name)
383 20 : .ToHandleChecked();
384 20 : func_locals_names->set(name.local_index, *name_str);
385 : }
386 : }
387 30 : return locals_names;
388 : }
389 :
390 800 : const char* ExternalKindName(WasmExternalKind kind) {
391 800 : switch (kind) {
392 : case kExternalFunction:
393 : return "function";
394 : case kExternalTable:
395 160 : return "table";
396 : case kExternalMemory:
397 160 : return "memory";
398 : case kExternalGlobal:
399 250 : return "global";
400 : }
401 0 : return "unknown";
402 : }
403 :
404 : #undef TRACE
405 : #undef TRACE_CHAIN
406 : #undef TRACE_COMPILE
407 :
408 : } // namespace wasm
409 : } // namespace internal
410 : } // namespace v8
|