Home | History | Annotate | Download | only in wasm
      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 
    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)
    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 
    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);
    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);
    459   bool has_instance() { return get(kWrapperInstanceObject)->IsWeakCell(); }
    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   }
    467   bool has_next() { return IsWasmInstanceWrapper(get(kNextInstanceWrapper)); }
    468   bool has_previous() {
    469     return IsWasmInstanceWrapper(get(kPreviousInstanceWrapper));
    470   }
    471   void set_next_wrapper(Object* obj) {
    472     DCHECK(IsWasmInstanceWrapper(obj));
    473     set(kNextInstanceWrapper, obj);
    474   }
    475   void set_previous_wrapper(Object* obj) {
    476     DCHECK(IsWasmInstanceWrapper(obj));
    477     set(kPreviousInstanceWrapper, obj);
    478   }
    479   Handle<WasmInstanceWrapper> next_wrapper() {
    480     Object* obj = get(kNextInstanceWrapper);
    481     DCHECK(IsWasmInstanceWrapper(obj));
    482     return handle(WasmInstanceWrapper::cast(obj));
    483   }
    484   Handle<WasmInstanceWrapper> previous_wrapper() {
    485     Object* obj = get(kPreviousInstanceWrapper);
    486     DCHECK(IsWasmInstanceWrapper(obj));
    487     return handle(WasmInstanceWrapper::cast(obj));
    488   }
    489   void reset_next_wrapper() { set_undefined(kNextInstanceWrapper); }
    490   void reset_previous_wrapper() { set_undefined(kPreviousInstanceWrapper); }
    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