1 // Copyright 2016 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 #ifndef V8_WASM_OBJECTS_H_ 6 #define V8_WASM_OBJECTS_H_ 7 8 #include "src/debug/debug.h" 9 #include "src/debug/interface-types.h" 10 #include "src/objects.h" 11 #include "src/trap-handler/trap-handler.h" 12 #include "src/wasm/wasm-limits.h" 13 14 namespace v8 { 15 namespace internal { 16 namespace wasm { 17 class InterpretedFrame; 18 struct WasmModule; 19 } 20 21 class WasmCompiledModule; 22 class WasmDebugInfo; 23 class WasmInstanceObject; 24 class WasmInstanceWrapper; 25 26 #define DECLARE_CASTS(name) \ 27 static bool Is##name(Object* object); \ 28 static name* cast(Object* object) 29 30 #define DECLARE_GETTER(name, type) type* name() 31 32 #define DECLARE_ACCESSORS(name, type) \ 33 void set_##name(type* value); \ 34 DECLARE_GETTER(name, type) 35 36 #define DECLARE_OPTIONAL_ACCESSORS(name, type) \ 37 bool has_##name(); \ 38 DECLARE_ACCESSORS(name, type) 39 40 #define DECLARE_OPTIONAL_GETTER(name, type) \ 41 bool has_##name(); \ 42 DECLARE_GETTER(name, type) 43 44 // Representation of a WebAssembly.Module JavaScript-level object. 45 class WasmModuleObject : public JSObject { 46 public: 47 // TODO(titzer): add the brand as an internal field instead of a property. 48 enum Fields { kCompiledModule, kFieldCount }; 49 50 DECLARE_CASTS(WasmModuleObject); 51 52 WasmCompiledModule* compiled_module(); 53 54 static Handle<WasmModuleObject> New( 55 Isolate* isolate, Handle<WasmCompiledModule> compiled_module); 56 }; 57 58 // Representation of a WebAssembly.Table JavaScript-level object. 59 class WasmTableObject : public JSObject { 60 public: 61 // TODO(titzer): add the brand as an internal field instead of a property. 62 enum Fields { kFunctions, kMaximum, kDispatchTables, kFieldCount }; 63 64 DECLARE_CASTS(WasmTableObject); 65 DECLARE_ACCESSORS(functions, FixedArray); 66 67 FixedArray* dispatch_tables(); 68 uint32_t current_length(); 69 bool has_maximum_length(); 70 int64_t maximum_length(); // Returns < 0 if no maximum. 71 72 static Handle<WasmTableObject> New(Isolate* isolate, uint32_t initial, 73 int64_t maximum, 74 Handle<FixedArray>* js_functions); 75 static void Grow(Isolate* isolate, Handle<WasmTableObject> table, 76 uint32_t count); 77 static Handle<FixedArray> AddDispatchTable( 78 Isolate* isolate, Handle<WasmTableObject> table, 79 Handle<WasmInstanceObject> instance, int table_index, 80 Handle<FixedArray> function_table, Handle<FixedArray> signature_table); 81 }; 82 83 // Representation of a WebAssembly.Memory JavaScript-level object. 84 class WasmMemoryObject : public JSObject { 85 public: 86 // TODO(titzer): add the brand as an internal field instead of a property. 87 enum Fields : uint8_t { kArrayBuffer, kMaximum, kInstancesLink, kFieldCount }; 88 89 DECLARE_CASTS(WasmMemoryObject); 90 DECLARE_ACCESSORS(buffer, JSArrayBuffer); 91 DECLARE_OPTIONAL_ACCESSORS(instances_link, WasmInstanceWrapper); 92 93 void AddInstance(Isolate* isolate, Handle<WasmInstanceObject> object); 94 void ResetInstancesLink(Isolate* isolate); 95 uint32_t current_pages(); 96 bool has_maximum_pages(); 97 int32_t maximum_pages(); // Returns < 0 if there is no maximum. 98 99 static Handle<WasmMemoryObject> New(Isolate* isolate, 100 Handle<JSArrayBuffer> buffer, 101 int32_t maximum); 102 103 static bool Grow(Isolate* isolate, Handle<WasmMemoryObject> memory, 104 uint32_t count); 105 }; 106 107 // Representation of a WebAssembly.Instance JavaScript-level object. 108 class WasmInstanceObject : public JSObject { 109 public: 110 // TODO(titzer): add the brand as an internal field instead of a property. 111 enum Fields { 112 kCompiledModule, 113 kMemoryObject, 114 kMemoryArrayBuffer, 115 kGlobalsArrayBuffer, 116 kDebugInfo, 117 kWasmMemInstanceWrapper, 118 kFieldCount 119 }; 120 121 DECLARE_CASTS(WasmInstanceObject); 122 123 DECLARE_ACCESSORS(compiled_module, WasmCompiledModule); 124 DECLARE_OPTIONAL_ACCESSORS(globals_buffer, JSArrayBuffer); 125 DECLARE_OPTIONAL_ACCESSORS(memory_buffer, JSArrayBuffer); 126 DECLARE_OPTIONAL_ACCESSORS(memory_object, WasmMemoryObject); 127 DECLARE_OPTIONAL_ACCESSORS(debug_info, WasmDebugInfo); 128 DECLARE_OPTIONAL_ACCESSORS(instance_wrapper, WasmInstanceWrapper); 129 130 WasmModuleObject* module_object(); 131 wasm::WasmModule* module(); 132 133 // Get the debug info associated with the given wasm object. 134 // If no debug info exists yet, it is created automatically. 135 static Handle<WasmDebugInfo> GetOrCreateDebugInfo( 136 Handle<WasmInstanceObject> instance); 137 138 static Handle<WasmInstanceObject> New( 139 Isolate* isolate, Handle<WasmCompiledModule> compiled_module); 140 }; 141 142 // Representation of an exported WASM function. 143 class WasmExportedFunction : public JSFunction { 144 public: 145 enum Fields { kInstance, kIndex, kFieldCount }; 146 147 DECLARE_CASTS(WasmExportedFunction); 148 149 WasmInstanceObject* instance(); 150 int function_index(); 151 152 static Handle<WasmExportedFunction> New(Isolate* isolate, 153 Handle<WasmInstanceObject> instance, 154 MaybeHandle<String> maybe_name, 155 int func_index, int arity, 156 Handle<Code> export_wrapper); 157 }; 158 159 // Information shared by all WasmCompiledModule objects for the same module. 160 class WasmSharedModuleData : public FixedArray { 161 enum Fields { 162 kModuleWrapper, 163 kModuleBytes, 164 kScript, 165 kAsmJsOffsetTable, 166 kBreakPointInfos, 167 kFieldCount 168 }; 169 170 public: 171 DECLARE_CASTS(WasmSharedModuleData); 172 173 DECLARE_GETTER(module, wasm::WasmModule); 174 DECLARE_OPTIONAL_ACCESSORS(module_bytes, SeqOneByteString); 175 DECLARE_GETTER(script, Script); 176 DECLARE_OPTIONAL_ACCESSORS(asm_js_offset_table, ByteArray); 177 DECLARE_OPTIONAL_GETTER(breakpoint_infos, FixedArray); 178 179 static Handle<WasmSharedModuleData> New( 180 Isolate* isolate, Handle<Foreign> module_wrapper, 181 Handle<SeqOneByteString> module_bytes, Handle<Script> script, 182 Handle<ByteArray> asm_js_offset_table); 183 184 // Check whether this module was generated from asm.js source. 185 bool is_asm_js(); 186 187 static void ReinitializeAfterDeserialization(Isolate*, 188 Handle<WasmSharedModuleData>); 189 190 static void AddBreakpoint(Handle<WasmSharedModuleData>, int position, 191 Handle<Object> break_point_object); 192 193 static void SetBreakpointsOnNewInstance(Handle<WasmSharedModuleData>, 194 Handle<WasmInstanceObject>); 195 }; 196 197 class WasmCompiledModule : public FixedArray { 198 public: 199 enum Fields { kFieldCount }; 200 cast(Object * fixed_array)201 static WasmCompiledModule* cast(Object* fixed_array) { 202 SLOW_DCHECK(IsWasmCompiledModule(fixed_array)); 203 return reinterpret_cast<WasmCompiledModule*>(fixed_array); 204 } 205 206 #define WCM_OBJECT_OR_WEAK(TYPE, NAME, ID, TYPE_CHECK) \ 207 Handle<TYPE> NAME() const { return handle(ptr_to_##NAME()); } \ 208 \ 209 MaybeHandle<TYPE> maybe_##NAME() const { \ 210 if (has_##NAME()) return NAME(); \ 211 return MaybeHandle<TYPE>(); \ 212 } \ 213 \ 214 TYPE* maybe_ptr_to_##NAME() const { \ 215 Object* obj = get(ID); \ 216 if (!(TYPE_CHECK)) return nullptr; \ 217 return TYPE::cast(obj); \ 218 } \ 219 \ 220 TYPE* ptr_to_##NAME() const { \ 221 Object* obj = get(ID); \ 222 DCHECK(TYPE_CHECK); \ 223 return TYPE::cast(obj); \ 224 } \ 225 \ 226 void set_##NAME(Handle<TYPE> value) { set_ptr_to_##NAME(*value); } \ 227 \ 228 void set_ptr_to_##NAME(TYPE* value) { set(ID, value); } \ 229 \ 230 bool has_##NAME() const { \ 231 Object* obj = get(ID); \ 232 return TYPE_CHECK; \ 233 } \ 234 \ 235 void reset_##NAME() { set_undefined(ID); } 236 237 #define WCM_OBJECT(TYPE, NAME) \ 238 WCM_OBJECT_OR_WEAK(TYPE, NAME, kID_##NAME, obj->Is##TYPE()) 239 240 #define WCM_WASM_OBJECT(TYPE, NAME) \ 241 WCM_OBJECT_OR_WEAK(TYPE, NAME, kID_##NAME, TYPE::Is##TYPE(obj)) 242 243 #define WCM_SMALL_NUMBER(TYPE, NAME) \ 244 TYPE NAME() const { \ 245 return static_cast<TYPE>(Smi::cast(get(kID_##NAME))->value()); \ 246 } \ 247 void set_##NAME(TYPE value) { set(kID_##NAME, Smi::FromInt(value)); } 248 249 #define WCM_WEAK_LINK(TYPE, NAME) \ 250 WCM_OBJECT_OR_WEAK(WeakCell, weak_##NAME, kID_##NAME, obj->IsWeakCell()); \ 251 \ 252 Handle<TYPE> NAME() const { \ 253 return handle(TYPE::cast(weak_##NAME()->value())); \ 254 } 255 256 #define CORE_WCM_PROPERTY_TABLE(MACRO) \ 257 MACRO(WASM_OBJECT, WasmSharedModuleData, shared) \ 258 MACRO(OBJECT, Context, native_context) \ 259 MACRO(SMALL_NUMBER, uint32_t, num_imported_functions) \ 260 MACRO(OBJECT, FixedArray, code_table) \ 261 MACRO(OBJECT, FixedArray, weak_exported_functions) \ 262 MACRO(OBJECT, FixedArray, function_tables) \ 263 MACRO(OBJECT, FixedArray, signature_tables) \ 264 MACRO(OBJECT, FixedArray, empty_function_tables) \ 265 MACRO(OBJECT, JSArrayBuffer, memory) \ 266 MACRO(SMALL_NUMBER, uint32_t, min_mem_pages) \ 267 MACRO(SMALL_NUMBER, uint32_t, max_mem_pages) \ 268 MACRO(WEAK_LINK, WasmCompiledModule, next_instance) \ 269 MACRO(WEAK_LINK, WasmCompiledModule, prev_instance) \ 270 MACRO(WEAK_LINK, JSObject, owning_instance) \ 271 MACRO(WEAK_LINK, WasmModuleObject, wasm_module) 272 273 #if DEBUG 274 #define DEBUG_ONLY_TABLE(MACRO) MACRO(SMALL_NUMBER, uint32_t, instance_id) 275 #else 276 #define DEBUG_ONLY_TABLE(IGNORE) instance_id()277 uint32_t instance_id() const { return -1; } 278 #endif 279 280 #define WCM_PROPERTY_TABLE(MACRO) \ 281 CORE_WCM_PROPERTY_TABLE(MACRO) \ 282 DEBUG_ONLY_TABLE(MACRO) 283 284 private: 285 enum PropertyIndices { 286 #define INDICES(IGNORE1, IGNORE2, NAME) kID_##NAME, 287 WCM_PROPERTY_TABLE(INDICES) Count 288 #undef INDICES 289 }; 290 291 public: 292 static Handle<WasmCompiledModule> New(Isolate* isolate, 293 Handle<WasmSharedModuleData> shared); 294 Clone(Isolate * isolate,Handle<WasmCompiledModule> module)295 static Handle<WasmCompiledModule> Clone(Isolate* isolate, 296 Handle<WasmCompiledModule> module) { 297 Handle<WasmCompiledModule> ret = Handle<WasmCompiledModule>::cast( 298 isolate->factory()->CopyFixedArray(module)); 299 ret->InitId(); 300 ret->reset_weak_owning_instance(); 301 ret->reset_weak_next_instance(); 302 ret->reset_weak_prev_instance(); 303 ret->reset_weak_exported_functions(); 304 return ret; 305 } 306 307 uint32_t mem_size() const; 308 uint32_t default_mem_size() const; 309 310 #define DECLARATION(KIND, TYPE, NAME) WCM_##KIND(TYPE, NAME) 311 WCM_PROPERTY_TABLE(DECLARATION) 312 #undef DECLARATION 313 314 // Allow to call method on WasmSharedModuleData also on this object. 315 #define FORWARD_SHARED(type, name) \ 316 type name() { return shared()->name(); } 317 FORWARD_SHARED(SeqOneByteString*, module_bytes) 318 FORWARD_SHARED(wasm::WasmModule*, module) 319 FORWARD_SHARED(Script*, script) 320 FORWARD_SHARED(bool, is_asm_js) 321 #undef FORWARD_SHARED 322 323 static bool IsWasmCompiledModule(Object* obj); 324 325 void PrintInstancesChain(); 326 327 static void ReinitializeAfterDeserialization(Isolate*, 328 Handle<WasmCompiledModule>); 329 330 // Get the function name of the function identified by the given index. 331 // Returns a null handle if the function is unnamed or the name is not a valid 332 // UTF-8 string. 333 static MaybeHandle<String> GetFunctionNameOrNull( 334 Isolate* isolate, Handle<WasmCompiledModule> compiled_module, 335 uint32_t func_index); 336 337 // Get the function name of the function identified by the given index. 338 // Returns "<WASM UNNAMED>" if the function is unnamed or the name is not a 339 // valid UTF-8 string. 340 static Handle<String> GetFunctionName( 341 Isolate* isolate, Handle<WasmCompiledModule> compiled_module, 342 uint32_t func_index); 343 344 // Get the raw bytes of the function name of the function identified by the 345 // given index. 346 // Meant to be used for debugging or frame printing. 347 // Does not allocate, hence gc-safe. 348 Vector<const uint8_t> GetRawFunctionName(uint32_t func_index); 349 350 // Return the byte offset of the function identified by the given index. 351 // The offset will be relative to the start of the module bytes. 352 // Returns -1 if the function index is invalid. 353 int GetFunctionOffset(uint32_t func_index); 354 355 // Returns the function containing the given byte offset. 356 // Returns -1 if the byte offset is not contained in any function of this 357 // module. 358 int GetContainingFunction(uint32_t byte_offset); 359 360 // Translate from byte offset in the module to function number and byte offset 361 // within that function, encoded as line and column in the position info. 362 // Returns true if the position is valid inside this module, false otherwise. 363 bool GetPositionInfo(uint32_t position, Script::PositionInfo* info); 364 365 // Get the asm.js source position from a byte offset. 366 // Must only be called if the associated wasm object was created from asm.js. 367 static int GetAsmJsSourcePosition(Handle<WasmCompiledModule> compiled_module, 368 uint32_t func_index, uint32_t byte_offset, 369 bool is_at_number_conversion); 370 371 // Compute the disassembly of a wasm function. 372 // Returns the disassembly string and a list of <byte_offset, line, column> 373 // entries, mapping wasm byte offsets to line and column in the disassembly. 374 // The list is guaranteed to be ordered by the byte_offset. 375 // Returns an empty string and empty vector if the function index is invalid. 376 debug::WasmDisassembly DisassembleFunction(int func_index); 377 378 // Extract a portion of the wire bytes as UTF-8 string. 379 // Returns a null handle if the respective bytes do not form a valid UTF-8 380 // string. 381 static MaybeHandle<String> ExtractUtf8StringFromModuleBytes( 382 Isolate* isolate, Handle<WasmCompiledModule> compiled_module, 383 uint32_t offset, uint32_t size); 384 385 // Get a list of all possible breakpoints within a given range of this module. 386 bool GetPossibleBreakpoints(const debug::Location& start, 387 const debug::Location& end, 388 std::vector<debug::Location>* locations); 389 390 // Set a breakpoint on the given byte position inside the given module. 391 // This will affect all live and future instances of the module. 392 // The passed position might be modified to point to the next breakable 393 // location inside the same function. 394 // If it points outside a function, or behind the last breakable location, 395 // this function returns false and does not set any breakpoint. 396 static bool SetBreakPoint(Handle<WasmCompiledModule>, int* position, 397 Handle<Object> break_point_object); 398 399 // Return an empty handle if no breakpoint is hit at that location, or a 400 // FixedArray with all hit breakpoint objects. 401 MaybeHandle<FixedArray> CheckBreakPoints(int position); 402 403 private: 404 void InitId(); 405 406 DISALLOW_IMPLICIT_CONSTRUCTORS(WasmCompiledModule); 407 }; 408 409 class WasmDebugInfo : public FixedArray { 410 public: 411 enum Fields { 412 kInstance, 413 kInterpreterHandle, 414 kInterpretedFunctions, 415 kFieldCount 416 }; 417 418 static Handle<WasmDebugInfo> New(Handle<WasmInstanceObject>); 419 420 static bool IsDebugInfo(Object*); 421 static WasmDebugInfo* cast(Object*); 422 423 // Set a breakpoint in the given function at the given byte offset within that 424 // function. This will redirect all future calls to this function to the 425 // interpreter and will always pause at the given offset. 426 static void SetBreakpoint(Handle<WasmDebugInfo>, int func_index, int offset); 427 428 // Make a function always execute in the interpreter without setting a 429 // breakpoints. 430 static void RedirectToInterpreter(Handle<WasmDebugInfo>, int func_index); 431 432 void PrepareStep(StepAction); 433 434 void RunInterpreter(int func_index, uint8_t* arg_buffer); 435 436 // Get the stack of the wasm interpreter as pairs of <function index, byte 437 // offset>. The list is ordered bottom-to-top, i.e. caller before callee. 438 std::vector<std::pair<uint32_t, int>> GetInterpretedStack( 439 Address frame_pointer); 440 441 std::unique_ptr<wasm::InterpretedFrame> GetInterpretedFrame( 442 Address frame_pointer, int idx); 443 444 // Returns the number of calls / function frames executed in the interpreter. 445 uint64_t NumInterpretedCalls(); 446 447 DECLARE_GETTER(wasm_instance, WasmInstanceObject); 448 }; 449 450 class WasmInstanceWrapper : public FixedArray { 451 public: 452 static Handle<WasmInstanceWrapper> New(Isolate* isolate, 453 Handle<WasmInstanceObject> instance); cast(Object * fixed_array)454 static WasmInstanceWrapper* cast(Object* fixed_array) { 455 SLOW_DCHECK(IsWasmInstanceWrapper(fixed_array)); 456 return reinterpret_cast<WasmInstanceWrapper*>(fixed_array); 457 } 458 static bool IsWasmInstanceWrapper(Object* obj); has_instance()459 bool has_instance() { return get(kWrapperInstanceObject)->IsWeakCell(); } instance_object()460 Handle<WasmInstanceObject> instance_object() { 461 Object* obj = get(kWrapperInstanceObject); 462 DCHECK(obj->IsWeakCell()); 463 WeakCell* cell = WeakCell::cast(obj); 464 DCHECK(cell->value()->IsJSObject()); 465 return handle(WasmInstanceObject::cast(cell->value())); 466 } has_next()467 bool has_next() { return IsWasmInstanceWrapper(get(kNextInstanceWrapper)); } has_previous()468 bool has_previous() { 469 return IsWasmInstanceWrapper(get(kPreviousInstanceWrapper)); 470 } set_next_wrapper(Object * obj)471 void set_next_wrapper(Object* obj) { 472 DCHECK(IsWasmInstanceWrapper(obj)); 473 set(kNextInstanceWrapper, obj); 474 } set_previous_wrapper(Object * obj)475 void set_previous_wrapper(Object* obj) { 476 DCHECK(IsWasmInstanceWrapper(obj)); 477 set(kPreviousInstanceWrapper, obj); 478 } next_wrapper()479 Handle<WasmInstanceWrapper> next_wrapper() { 480 Object* obj = get(kNextInstanceWrapper); 481 DCHECK(IsWasmInstanceWrapper(obj)); 482 return handle(WasmInstanceWrapper::cast(obj)); 483 } previous_wrapper()484 Handle<WasmInstanceWrapper> previous_wrapper() { 485 Object* obj = get(kPreviousInstanceWrapper); 486 DCHECK(IsWasmInstanceWrapper(obj)); 487 return handle(WasmInstanceWrapper::cast(obj)); 488 } reset_next_wrapper()489 void reset_next_wrapper() { set_undefined(kNextInstanceWrapper); } reset_previous_wrapper()490 void reset_previous_wrapper() { set_undefined(kPreviousInstanceWrapper); } reset()491 void reset() { 492 for (int kID = 0; kID < kWrapperPropertyCount; kID++) set_undefined(kID); 493 } 494 495 private: 496 enum { 497 kWrapperInstanceObject, 498 kNextInstanceWrapper, 499 kPreviousInstanceWrapper, 500 kWrapperPropertyCount 501 }; 502 }; 503 504 #undef DECLARE_ACCESSORS 505 #undef DECLARE_OPTIONAL_ACCESSORS 506 507 } // namespace internal 508 } // namespace v8 509 510 #endif // V8_WASM_OBJECTS_H_ 511