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