Chromium Code Reviews| 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 |