OLD | NEW |
---|---|
1 // Copyright 2015 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_WASM_MODULE_H_ | 5 #ifndef V8_WASM_MODULE_H_ |
6 #define V8_WASM_MODULE_H_ | 6 #define V8_WASM_MODULE_H_ |
7 | 7 |
8 #include <memory> | 8 #include <memory> |
9 | 9 |
10 #include "src/api.h" | 10 #include "src/api.h" |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
170 | 170 |
171 // Static representation of a WASM export. | 171 // Static representation of a WASM export. |
172 struct WasmExport { | 172 struct WasmExport { |
173 uint32_t name_length; // length in bytes of the exported name. | 173 uint32_t name_length; // length in bytes of the exported name. |
174 uint32_t name_offset; // offset in module bytes of the name to export. | 174 uint32_t name_offset; // offset in module bytes of the name to export. |
175 WasmExternalKind kind; // kind of the export. | 175 WasmExternalKind kind; // kind of the export. |
176 uint32_t index; // index into the respective space. | 176 uint32_t index; // index into the respective space. |
177 }; | 177 }; |
178 | 178 |
179 enum ModuleOrigin { kWasmOrigin, kAsmJsOrigin }; | 179 enum ModuleOrigin { kWasmOrigin, kAsmJsOrigin }; |
180 struct ModuleStorage; | |
titzer
2016/11/30 13:13:42
Can we call this ModuleWireBytes? or ModuleRawByte
Clemens Hammacher
2016/11/30 14:28:45
I renamed ModuleStorage to ModuleWireBytes and Mod
| |
180 | 181 |
181 // Static representation of a module. | 182 // Static representation of a module. |
182 struct V8_EXPORT_PRIVATE WasmModule { | 183 struct V8_EXPORT_PRIVATE WasmModule { |
183 static const uint32_t kPageSize = 0x10000; // Page size, 64kb. | 184 static const uint32_t kPageSize = 0x10000; // Page size, 64kb. |
184 static const uint32_t kMinMemPages = 1; // Minimum memory size = 64kb | 185 static const uint32_t kMinMemPages = 1; // Minimum memory size = 64kb |
185 static const size_t kV8MaxPages = 16384; // Maximum memory size = 1gb | 186 static const size_t kV8MaxPages = 16384; // Maximum memory size = 1gb |
186 static const size_t kSpecMaxPages = 65536; // Maximum according to the spec | 187 static const size_t kSpecMaxPages = 65536; // Maximum according to the spec |
187 static const size_t kV8MaxTableSize = 16 * 1024 * 1024; | 188 static const size_t kV8MaxTableSize = 16 * 1024 * 1024; |
188 | 189 |
189 Zone* owned_zone; | 190 Zone* owned_zone; |
190 const byte* module_start = nullptr; // starting address for the module bytes | |
191 const byte* module_end = nullptr; // end address for the module bytes | |
192 uint32_t min_mem_pages = 0; // minimum size of the memory in 64k pages | 191 uint32_t min_mem_pages = 0; // minimum size of the memory in 64k pages |
193 uint32_t max_mem_pages = 0; // maximum size of the memory in 64k pages | 192 uint32_t max_mem_pages = 0; // maximum size of the memory in 64k pages |
194 bool has_memory = false; // true if the memory was defined or imported | 193 bool has_memory = false; // true if the memory was defined or imported |
195 bool mem_export = false; // true if the memory is exported | 194 bool mem_export = false; // true if the memory is exported |
196 // TODO(wasm): reconcile start function index being an int with | 195 // TODO(wasm): reconcile start function index being an int with |
197 // the fact that we index on uint32_t, so we may technically not be | 196 // the fact that we index on uint32_t, so we may technically not be |
198 // able to represent some start_function_index -es. | 197 // able to represent some start_function_index -es. |
199 int start_function_index = -1; // start function, if any | 198 int start_function_index = -1; // start function, if any |
200 ModuleOrigin origin = kWasmOrigin; // origin of the module | 199 ModuleOrigin origin = kWasmOrigin; // origin of the module |
201 | 200 |
(...skipping 11 matching lines...) Expand all Loading... | |
213 std::vector<WasmTableInit> table_inits; // initializations of tables | 212 std::vector<WasmTableInit> table_inits; // initializations of tables |
214 // We store the semaphore here to extend its lifetime. In <libc-2.21, which we | 213 // We store the semaphore here to extend its lifetime. In <libc-2.21, which we |
215 // use on the try bots, semaphore::Wait() can return while some compilation | 214 // use on the try bots, semaphore::Wait() can return while some compilation |
216 // tasks are still executing semaphore::Signal(). If the semaphore is cleaned | 215 // tasks are still executing semaphore::Signal(). If the semaphore is cleaned |
217 // up right after semaphore::Wait() returns, then this can cause an | 216 // up right after semaphore::Wait() returns, then this can cause an |
218 // invalid-semaphore error in the compilation tasks. | 217 // invalid-semaphore error in the compilation tasks. |
219 // TODO(wasm): Move this semaphore back to CompileInParallel when the try bots | 218 // TODO(wasm): Move this semaphore back to CompileInParallel when the try bots |
220 // switch to libc-2.21 or higher. | 219 // switch to libc-2.21 or higher. |
221 std::unique_ptr<base::Semaphore> pending_tasks; | 220 std::unique_ptr<base::Semaphore> pending_tasks; |
222 | 221 |
223 WasmModule() : WasmModule(nullptr, nullptr) {} | 222 WasmModule() : WasmModule(nullptr) {} |
224 WasmModule(Zone* owned_zone, const byte* module_start); | 223 WasmModule(Zone* owned_zone); |
225 ~WasmModule() { | 224 ~WasmModule() { |
226 if (owned_zone) delete owned_zone; | 225 if (owned_zone) delete owned_zone; |
227 } | 226 } |
228 | 227 |
229 // Get a string stored in the module bytes representing a name. | |
230 WasmName GetName(uint32_t offset, uint32_t length) const { | |
231 if (length == 0) return {"<?>", 3}; // no name. | |
232 CHECK(BoundsCheck(offset, offset + length)); | |
233 DCHECK_GE(static_cast<int>(length), 0); | |
234 return {reinterpret_cast<const char*>(module_start + offset), | |
235 static_cast<int>(length)}; | |
236 } | |
237 | |
238 // Get a string stored in the module bytes representing a function name. | |
239 WasmName GetName(WasmFunction* function) const { | |
240 return GetName(function->name_offset, function->name_length); | |
241 } | |
242 | |
243 // Get a string stored in the module bytes representing a name. | |
244 WasmName GetNameOrNull(uint32_t offset, uint32_t length) const { | |
245 if (offset == 0 && length == 0) return {NULL, 0}; // no name. | |
246 CHECK(BoundsCheck(offset, offset + length)); | |
247 DCHECK_GE(static_cast<int>(length), 0); | |
248 return {reinterpret_cast<const char*>(module_start + offset), | |
249 static_cast<int>(length)}; | |
250 } | |
251 | |
252 // Get a string stored in the module bytes representing a function name. | |
253 WasmName GetNameOrNull(const WasmFunction* function) const { | |
254 return GetNameOrNull(function->name_offset, function->name_length); | |
255 } | |
256 | |
257 // Checks the given offset range is contained within the module bytes. | |
258 bool BoundsCheck(uint32_t start, uint32_t end) const { | |
259 size_t size = module_end - module_start; | |
260 return start <= size && end <= size; | |
261 } | |
262 | |
263 // Creates a new instantiation of the module in the given isolate. | 228 // Creates a new instantiation of the module in the given isolate. |
264 static MaybeHandle<WasmInstanceObject> Instantiate( | 229 static MaybeHandle<WasmInstanceObject> Instantiate( |
265 Isolate* isolate, ErrorThrower* thrower, Handle<JSObject> wasm_module, | 230 Isolate* isolate, ErrorThrower* thrower, Handle<JSObject> wasm_module, |
266 Handle<JSReceiver> ffi, Handle<JSArrayBuffer> memory); | 231 Handle<JSReceiver> ffi, Handle<JSArrayBuffer> memory); |
267 | 232 |
268 MaybeHandle<WasmCompiledModule> CompileFunctions( | 233 MaybeHandle<WasmCompiledModule> CompileFunctions( |
269 Isolate* isolate, Handle<Managed<WasmModule>> module_wrapper, | 234 Isolate* isolate, Handle<Managed<WasmModule>> module_wrapper, |
270 ErrorThrower* thrower) const; | 235 ErrorThrower* thrower, const ModuleStorage& storage) const; |
271 }; | 236 }; |
272 | 237 |
273 typedef Managed<WasmModule> WasmModuleWrapper; | 238 typedef Managed<WasmModule> WasmModuleWrapper; |
274 | 239 |
275 // An instantiated WASM module, including memory, function table, etc. | 240 // An instantiated WASM module, including memory, function table, etc. |
276 struct WasmInstance { | 241 struct WasmInstance { |
277 const WasmModule* module; // static representation of the module. | 242 const WasmModule* module; // static representation of the module. |
278 // -- Heap allocated -------------------------------------------------------- | 243 // -- Heap allocated -------------------------------------------------------- |
279 Handle<JSObject> js_object; // JavaScript module object. | 244 Handle<JSObject> js_object; // JavaScript module object. |
280 Handle<Context> context; // JavaScript native context. | 245 Handle<Context> context; // JavaScript native context. |
281 Handle<JSArrayBuffer> mem_buffer; // Handle to array buffer of memory. | 246 Handle<JSArrayBuffer> mem_buffer; // Handle to array buffer of memory. |
282 Handle<JSArrayBuffer> globals_buffer; // Handle to array buffer of globals. | 247 Handle<JSArrayBuffer> globals_buffer; // Handle to array buffer of globals. |
283 std::vector<Handle<FixedArray>> function_tables; // indirect function tables. | 248 std::vector<Handle<FixedArray>> function_tables; // indirect function tables. |
284 std::vector<Handle<Code>> function_code; // code objects for each function. | 249 std::vector<Handle<Code>> function_code; // code objects for each function. |
285 // -- raw memory ------------------------------------------------------------ | 250 // -- raw memory ------------------------------------------------------------ |
286 byte* mem_start = nullptr; // start of linear memory. | 251 byte* mem_start = nullptr; // start of linear memory. |
287 uint32_t mem_size = 0; // size of the linear memory. | 252 uint32_t mem_size = 0; // size of the linear memory. |
288 // -- raw globals ----------------------------------------------------------- | 253 // -- raw globals ----------------------------------------------------------- |
289 byte* globals_start = nullptr; // start of the globals area. | 254 byte* globals_start = nullptr; // start of the globals area. |
290 | 255 |
291 explicit WasmInstance(const WasmModule* m) | 256 explicit WasmInstance(const WasmModule* m) |
292 : module(m), | 257 : module(m), |
293 function_tables(m->function_tables.size()), | 258 function_tables(m->function_tables.size()), |
294 function_code(m->functions.size()) {} | 259 function_code(m->functions.size()) {} |
295 }; | 260 }; |
296 | 261 |
262 // Interface to the storage (wire bytes) of a wasm module. | |
263 // It is illegal for anyone receiving a ModuleStorage to store pointers based on | |
264 // module_bytes, as this storage is only guaranteed to be alive as long as this | |
265 // struct is alive. | |
266 struct V8_EXPORT_PRIVATE ModuleStorage { | |
267 ModuleStorage(Vector<const byte> module_bytes) : module_bytes(module_bytes) {} | |
268 ModuleStorage(const byte* start, const byte* end) | |
269 : module_bytes(start, static_cast<int>(end - start)) { | |
270 DCHECK_GE(kMaxInt, end - start); | |
271 } | |
272 | |
273 const Vector<const byte> module_bytes; | |
274 | |
275 // Get a string stored in the module bytes representing a name. | |
276 WasmName GetName(uint32_t offset, uint32_t length) const { | |
277 if (length == 0) return {"<?>", 3}; // no name. | |
278 CHECK(BoundsCheck(offset, length)); | |
279 DCHECK_GE(static_cast<int>(length), 0); | |
280 return Vector<const char>::cast( | |
281 module_bytes.SubVector(offset, offset + length)); | |
282 } | |
283 | |
284 // Get a string stored in the module bytes representing a function name. | |
285 WasmName GetName(const WasmFunction* function) const { | |
286 return GetName(function->name_offset, function->name_length); | |
287 } | |
288 | |
289 // Get a string stored in the module bytes representing a name. | |
290 WasmName GetNameOrNull(uint32_t offset, uint32_t length) const { | |
291 if (offset == 0 && length == 0) return {NULL, 0}; // no name. | |
292 CHECK(BoundsCheck(offset, length)); | |
293 DCHECK_GE(static_cast<int>(length), 0); | |
294 return Vector<const char>::cast( | |
295 module_bytes.SubVector(offset, offset + length)); | |
296 } | |
297 | |
298 // Get a string stored in the module bytes representing a function name. | |
299 WasmName GetNameOrNull(const WasmFunction* function) const { | |
300 return GetNameOrNull(function->name_offset, function->name_length); | |
301 } | |
302 | |
303 // Checks the given offset range is contained within the module bytes. | |
304 bool BoundsCheck(uint32_t offset, uint32_t length) const { | |
305 uint32_t size = static_cast<uint32_t>(module_bytes.length()); | |
306 return offset <= size && length <= size - offset; | |
307 } | |
308 }; | |
309 | |
297 // Interface provided to the decoder/graph builder which contains only | 310 // Interface provided to the decoder/graph builder which contains only |
298 // minimal information about the globals, functions, and function tables. | 311 // minimal information about the globals, functions, and function tables. |
299 struct V8_EXPORT_PRIVATE ModuleEnv { | 312 struct V8_EXPORT_PRIVATE ModuleEnv { |
313 ModuleEnv(const WasmModule* module, WasmInstance* instance) | |
314 : module(module), instance(instance) {} | |
315 | |
300 const WasmModule* module; | 316 const WasmModule* module; |
301 WasmInstance* instance; | 317 WasmInstance* instance; |
302 ModuleOrigin origin; | |
303 | 318 |
304 bool IsValidGlobal(uint32_t index) const { | 319 bool IsValidGlobal(uint32_t index) const { |
305 return module && index < module->globals.size(); | 320 return module && index < module->globals.size(); |
306 } | 321 } |
307 bool IsValidFunction(uint32_t index) const { | 322 bool IsValidFunction(uint32_t index) const { |
308 return module && index < module->functions.size(); | 323 return module && index < module->functions.size(); |
309 } | 324 } |
310 bool IsValidSignature(uint32_t index) const { | 325 bool IsValidSignature(uint32_t index) const { |
311 return module && index < module->signatures.size(); | 326 return module && index < module->signatures.size(); |
312 } | 327 } |
(...skipping 10 matching lines...) Expand all Loading... | |
323 } | 338 } |
324 FunctionSig* GetSignature(uint32_t index) { | 339 FunctionSig* GetSignature(uint32_t index) { |
325 DCHECK(IsValidSignature(index)); | 340 DCHECK(IsValidSignature(index)); |
326 return module->signatures[index]; | 341 return module->signatures[index]; |
327 } | 342 } |
328 const WasmIndirectFunctionTable* GetTable(uint32_t index) const { | 343 const WasmIndirectFunctionTable* GetTable(uint32_t index) const { |
329 DCHECK(IsValidTable(index)); | 344 DCHECK(IsValidTable(index)); |
330 return &module->function_tables[index]; | 345 return &module->function_tables[index]; |
331 } | 346 } |
332 | 347 |
333 bool asm_js() { return origin == kAsmJsOrigin; } | 348 bool asm_js() { return module->origin == kAsmJsOrigin; } |
334 | 349 |
335 Handle<Code> GetFunctionCode(uint32_t index) { | 350 Handle<Code> GetFunctionCode(uint32_t index) { |
336 DCHECK_NOT_NULL(instance); | 351 DCHECK_NOT_NULL(instance); |
337 return instance->function_code[index]; | 352 return instance->function_code[index]; |
338 } | 353 } |
339 | 354 |
340 static compiler::CallDescriptor* GetWasmCallDescriptor(Zone* zone, | 355 static compiler::CallDescriptor* GetWasmCallDescriptor(Zone* zone, |
341 FunctionSig* sig); | 356 FunctionSig* sig); |
342 static compiler::CallDescriptor* GetI32WasmCallDescriptor( | 357 static compiler::CallDescriptor* GetI32WasmCallDescriptor( |
343 Zone* zone, compiler::CallDescriptor* descriptor); | 358 Zone* zone, compiler::CallDescriptor* descriptor); |
344 static compiler::CallDescriptor* GetI32WasmCallDescriptorForSimd( | 359 static compiler::CallDescriptor* GetI32WasmCallDescriptorForSimd( |
345 Zone* zone, compiler::CallDescriptor* descriptor); | 360 Zone* zone, compiler::CallDescriptor* descriptor); |
346 }; | 361 }; |
347 | 362 |
363 // A ModuleEnv together with ModuleStorage. | |
364 struct ModuleStorageEnv : public ModuleEnv, public ModuleStorage { | |
365 ModuleStorageEnv(const WasmModule* module, WasmInstance* instance, | |
366 Vector<const byte> module_bytes) | |
367 : ModuleEnv(module, instance), ModuleStorage(module_bytes) {} | |
368 ModuleStorageEnv(const WasmModule* module, WasmInstance* instance, | |
369 const ModuleStorage& storage) | |
370 : ModuleEnv(module, instance), ModuleStorage(storage) {} | |
371 }; | |
372 | |
348 // A helper for printing out the names of functions. | 373 // A helper for printing out the names of functions. |
349 struct WasmFunctionName { | 374 struct WasmFunctionName { |
375 WasmFunctionName(const WasmFunction* function, ModuleStorageEnv* module_env) | |
376 : function_(function), name_(module_env->GetNameOrNull(function)) {} | |
377 | |
350 const WasmFunction* function_; | 378 const WasmFunction* function_; |
351 const WasmModule* module_; | 379 WasmName name_; |
352 WasmFunctionName(const WasmFunction* function, const ModuleEnv* menv) | |
353 : function_(function), module_(menv ? menv->module : nullptr) {} | |
354 }; | 380 }; |
355 | 381 |
356 std::ostream& operator<<(std::ostream& os, const WasmModule& module); | 382 std::ostream& operator<<(std::ostream& os, const WasmModule& module); |
357 std::ostream& operator<<(std::ostream& os, const WasmFunction& function); | 383 std::ostream& operator<<(std::ostream& os, const WasmFunction& function); |
358 std::ostream& operator<<(std::ostream& os, const WasmFunctionName& name); | 384 std::ostream& operator<<(std::ostream& os, const WasmFunctionName& name); |
359 | 385 |
360 // Extract a function name from the given wasm instance. | 386 // Extract a function name from the given wasm instance. |
361 // Returns "<WASM UNNAMED>" if no instance is passed, the function is unnamed or | 387 // Returns "<WASM UNNAMED>" if no instance is passed, the function is unnamed or |
362 // the name is not a valid UTF-8 string. | 388 // the name is not a valid UTF-8 string. |
363 // TODO(5620): Refactor once we always get a wasm instance. | 389 // TODO(5620): Refactor once we always get a wasm instance. |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
439 void ValidateModuleState(Isolate* isolate, Handle<WasmModuleObject> module_obj); | 465 void ValidateModuleState(Isolate* isolate, Handle<WasmModuleObject> module_obj); |
440 void ValidateOrphanedInstance(Isolate* isolate, | 466 void ValidateOrphanedInstance(Isolate* isolate, |
441 Handle<WasmInstanceObject> instance); | 467 Handle<WasmInstanceObject> instance); |
442 | 468 |
443 } // namespace testing | 469 } // namespace testing |
444 } // namespace wasm | 470 } // namespace wasm |
445 } // namespace internal | 471 } // namespace internal |
446 } // namespace v8 | 472 } // namespace v8 |
447 | 473 |
448 #endif // V8_WASM_MODULE_H_ | 474 #endif // V8_WASM_MODULE_H_ |
OLD | NEW |