1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * 4 * Copyright 2016 Mozilla Foundation 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 #ifndef wasm_instance_h 20 #define wasm_instance_h 21 22 #include "builtin/TypedObject.h" 23 #include "gc/Barrier.h" 24 #include "gc/Zone.h" 25 #include "vm/SharedMem.h" 26 #include "wasm/WasmCode.h" 27 #include "wasm/WasmDebug.h" 28 #include "wasm/WasmFrameIter.h" // js::wasm::WasmFrameIter 29 #include "wasm/WasmProcess.h" 30 #include "wasm/WasmTable.h" 31 32 namespace js { 33 namespace wasm { 34 35 // Instance represents a wasm instance and provides all the support for runtime 36 // execution of code in the instance. Instances share various immutable data 37 // structures with the Module from which they were instantiated and other 38 // instances instantiated from the same Module. However, an Instance has no 39 // direct reference to its source Module which allows a Module to be destroyed 40 // while it still has live Instances. 41 // 42 // The instance's code may be shared among multiple instances provided none of 43 // those instances are being debugged. Instances that are being debugged own 44 // their code. 45 46 class Instance { 47 JS::Realm* const realm_; 48 WeakHeapPtrWasmInstanceObject object_; 49 void* jsJitArgsRectifier_; 50 void* jsJitExceptionHandler_; 51 void* preBarrierCode_; 52 const SharedCode code_; 53 const UniqueTlsData tlsData_; 54 const GCPtrWasmMemoryObject memory_; 55 const SharedTableVector tables_; 56 DataSegmentVector passiveDataSegments_; 57 ElemSegmentVector passiveElemSegments_; 58 const UniqueDebugState maybeDebug_; 59 StructTypeDescrVector structTypeDescrs_; 60 61 // Internal helpers: 62 const void** addressOfFuncTypeId(const FuncTypeIdDesc& funcTypeId) const; 63 FuncImportTls& funcImportTls(const FuncImport& fi); 64 TableTls& tableTls(const TableDesc& td) const; 65 66 // Only WasmInstanceObject can call the private trace function. 67 friend class js::WasmInstanceObject; 68 void tracePrivate(JSTracer* trc); 69 70 bool callImport(JSContext* cx, uint32_t funcImportIndex, unsigned argc, 71 const uint64_t* argv, MutableHandleValue rval); 72 73 public: 74 Instance(JSContext* cx, HandleWasmInstanceObject object, SharedCode code, 75 UniqueTlsData tlsData, HandleWasmMemoryObject memory, 76 SharedTableVector&& tables, StructTypeDescrVector&& structTypeDescrs, 77 UniqueDebugState maybeDebug); 78 ~Instance(); 79 bool init(JSContext* cx, const JSFunctionVector& funcImports, 80 const ValVector& globalImportValues, 81 const WasmGlobalObjectVector& globalObjs, 82 const DataSegmentVector& dataSegments, 83 const ElemSegmentVector& elemSegments); 84 void trace(JSTracer* trc); 85 86 // Trace any GC roots on the stack, for the frame associated with |wfi|, 87 // whose next instruction to execute is |nextPC|. 88 // 89 // For consistency checking of StackMap sizes in debug builds, this also 90 // takes |highestByteVisitedInPrevFrame|, which is the address of the 91 // highest byte scanned in the frame below this one on the stack, and in 92 // turn it returns the address of the highest byte scanned in this frame. 93 uintptr_t traceFrame(JSTracer* trc, const wasm::WasmFrameIter& wfi, 94 uint8_t* nextPC, 95 uintptr_t highestByteVisitedInPrevFrame); 96 realm()97 JS::Realm* realm() const { return realm_; } code()98 const Code& code() const { return *code_; } code(Tier t)99 const CodeTier& code(Tier t) const { return code_->codeTier(t); } debugEnabled()100 bool debugEnabled() const { return !!maybeDebug_; } debug()101 DebugState& debug() { return *maybeDebug_; } moduleSegment(Tier t)102 const ModuleSegment& moduleSegment(Tier t) const { return code_->segment(t); } tlsData()103 TlsData* tlsData() const { return tlsData_.get(); } globalData()104 uint8_t* globalData() const { return (uint8_t*)&tlsData_->globalArea; } codeBase(Tier t)105 uint8_t* codeBase(Tier t) const { return code_->segment(t).base(); } metadata(Tier t)106 const MetadataTier& metadata(Tier t) const { return code_->metadata(t); } metadata()107 const Metadata& metadata() const { return code_->metadata(); } isAsmJS()108 bool isAsmJS() const { return metadata().isAsmJS(); } tables()109 const SharedTableVector& tables() const { return tables_; } 110 SharedMem<uint8_t*> memoryBase() const; 111 WasmMemoryObject* memory() const; 112 size_t memoryMappedSize() const; 113 SharedArrayRawBuffer* sharedMemoryBuffer() const; // never null 114 bool memoryAccessInGuardRegion(uint8_t* addr, unsigned numBytes) const; 115 bool memoryAccessInBounds(uint8_t* addr, unsigned numBytes) const; structTypes()116 const StructTypeVector& structTypes() const { return code_->structTypes(); } 117 offsetOfJSJitArgsRectifier()118 static constexpr size_t offsetOfJSJitArgsRectifier() { 119 return offsetof(Instance, jsJitArgsRectifier_); 120 } offsetOfJSJitExceptionHandler()121 static constexpr size_t offsetOfJSJitExceptionHandler() { 122 return offsetof(Instance, jsJitExceptionHandler_); 123 } offsetOfPreBarrierCode()124 static constexpr size_t offsetOfPreBarrierCode() { 125 return offsetof(Instance, preBarrierCode_); 126 } 127 128 // This method returns a pointer to the GC object that owns this Instance. 129 // Instances may be reached via weak edges (e.g., Realm::instances_) 130 // so this perform a read-barrier on the returned object unless the barrier 131 // is explicitly waived. 132 133 WasmInstanceObject* object() const; 134 WasmInstanceObject* objectUnbarriered() const; 135 136 // Execute the given export given the JS call arguments, storing the return 137 // value in args.rval. 138 139 MOZ_MUST_USE bool callExport(JSContext* cx, uint32_t funcIndex, 140 CallArgs args); 141 142 // Return the name associated with a given function index, or generate one 143 // if none was given by the module. 144 145 JSAtom* getFuncDisplayAtom(JSContext* cx, uint32_t funcIndex) const; 146 void ensureProfilingLabels(bool profilingEnabled) const; 147 148 // Initially, calls to imports in wasm code call out through the generic 149 // callImport method. If the imported callee gets JIT compiled and the types 150 // match up, callImport will patch the code to instead call through a thunk 151 // directly into the JIT code. If the JIT code is released, the Instance must 152 // be notified so it can go back to the generic callImport. 153 154 void deoptimizeImportExit(uint32_t funcImportIndex); 155 156 // Called by Wasm(Memory|Table)Object when a moving resize occurs: 157 158 void onMovingGrowMemory(); 159 void onMovingGrowTable(const Table* theTable); 160 161 // Called to apply a single ElemSegment at a given offset, assuming 162 // that all bounds validation has already been performed. 163 164 MOZ_MUST_USE bool initElems(uint32_t tableIndex, const ElemSegment& seg, 165 uint32_t dstOffset, uint32_t srcOffset, 166 uint32_t len); 167 168 // Debugger support: 169 170 JSString* createDisplayURL(JSContext* cx); 171 WasmBreakpointSite* getOrCreateBreakpointSite(JSContext* cx, uint32_t offset); 172 void destroyBreakpointSite(JSFreeOp* fop, uint32_t offset); 173 174 // about:memory reporting: 175 176 void addSizeOfMisc(MallocSizeOf mallocSizeOf, Metadata::SeenSet* seenMetadata, 177 Code::SeenSet* seenCode, Table::SeenSet* seenTables, 178 size_t* code, size_t* data) const; 179 180 // Wasm disassembly support 181 182 void disassembleExport(JSContext* cx, uint32_t funcIndex, Tier tier, 183 PrintCallback callback) const; 184 185 public: 186 // Functions to be called directly from wasm code. 187 static int32_t callImport_void(Instance*, int32_t, int32_t, uint64_t*); 188 static int32_t callImport_i32(Instance*, int32_t, int32_t, uint64_t*); 189 static int32_t callImport_i64(Instance*, int32_t, int32_t, uint64_t*); 190 static int32_t callImport_v128(Instance*, int32_t, int32_t, uint64_t*); 191 static int32_t callImport_f64(Instance*, int32_t, int32_t, uint64_t*); 192 static int32_t callImport_anyref(Instance*, int32_t, int32_t, uint64_t*); 193 static int32_t callImport_funcref(Instance*, int32_t, int32_t, uint64_t*); 194 static uint32_t memoryGrow_i32(Instance* instance, uint32_t delta); 195 static uint32_t memorySize_i32(Instance* instance); 196 static int32_t wait_i32(Instance* instance, uint32_t byteOffset, 197 int32_t value, int64_t timeout); 198 static int32_t wait_i64(Instance* instance, uint32_t byteOffset, 199 int64_t value, int64_t timeout); 200 static int32_t wake(Instance* instance, uint32_t byteOffset, int32_t count); 201 static int32_t memCopy(Instance* instance, uint32_t destByteOffset, 202 uint32_t srcByteOffset, uint32_t len, 203 uint8_t* memBase); 204 static int32_t memCopyShared(Instance* instance, uint32_t destByteOffset, 205 uint32_t srcByteOffset, uint32_t len, 206 uint8_t* memBase); 207 static int32_t dataDrop(Instance* instance, uint32_t segIndex); 208 static int32_t memFill(Instance* instance, uint32_t byteOffset, 209 uint32_t value, uint32_t len, uint8_t* memBase); 210 static int32_t memFillShared(Instance* instance, uint32_t byteOffset, 211 uint32_t value, uint32_t len, uint8_t* memBase); 212 static int32_t memInit(Instance* instance, uint32_t dstOffset, 213 uint32_t srcOffset, uint32_t len, uint32_t segIndex); 214 static int32_t tableCopy(Instance* instance, uint32_t dstOffset, 215 uint32_t srcOffset, uint32_t len, 216 uint32_t dstTableIndex, uint32_t srcTableIndex); 217 static int32_t elemDrop(Instance* instance, uint32_t segIndex); 218 static int32_t tableFill(Instance* instance, uint32_t start, void* value, 219 uint32_t len, uint32_t tableIndex); 220 static void* tableGet(Instance* instance, uint32_t index, 221 uint32_t tableIndex); 222 static uint32_t tableGrow(Instance* instance, void* initValue, uint32_t delta, 223 uint32_t tableIndex); 224 static int32_t tableSet(Instance* instance, uint32_t index, void* value, 225 uint32_t tableIndex); 226 static uint32_t tableSize(Instance* instance, uint32_t tableIndex); 227 static int32_t tableInit(Instance* instance, uint32_t dstOffset, 228 uint32_t srcOffset, uint32_t len, uint32_t segIndex, 229 uint32_t tableIndex); 230 static void* refFunc(Instance* instance, uint32_t funcIndex); 231 static void preBarrierFiltering(Instance* instance, gc::Cell** location); 232 static void postBarrier(Instance* instance, gc::Cell** location); 233 static void postBarrierFiltering(Instance* instance, gc::Cell** location); 234 static void* structNew(Instance* instance, uint32_t typeIndex); 235 static void* structNarrow(Instance* instance, uint32_t mustUnboxAnyref, 236 uint32_t outputTypeIndex, void* maybeNullPtr); 237 }; 238 239 using UniqueInstance = UniquePtr<Instance>; 240 241 bool ResultsToJSValue(JSContext* cx, ResultType type, void* registerResultLoc, 242 Maybe<char*> stackResultsLoc, MutableHandleValue rval); 243 244 } // namespace wasm 245 } // namespace js 246 247 #endif // wasm_instance_h 248