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