/src/mozilla-central/js/src/jit/IonBuilder.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 | | * vim: set ts=8 sts=4 et sw=4 tw=99: |
3 | | * This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #ifndef jit_IonBuilder_h |
8 | | #define jit_IonBuilder_h |
9 | | |
10 | | // This file declares the data structures for building a MIRGraph from a |
11 | | // JSScript. |
12 | | |
13 | | #include "mozilla/LinkedList.h" |
14 | | #include "mozilla/Maybe.h" |
15 | | |
16 | | #include "jit/BaselineInspector.h" |
17 | | #include "jit/BytecodeAnalysis.h" |
18 | | #include "jit/IonAnalysis.h" |
19 | | #include "jit/IonControlFlow.h" |
20 | | #include "jit/IonOptimizationLevels.h" |
21 | | #include "jit/MIR.h" |
22 | | #include "jit/MIRGenerator.h" |
23 | | #include "jit/MIRGraph.h" |
24 | | #include "jit/OptimizationTracking.h" |
25 | | |
26 | | namespace js { |
27 | | namespace jit { |
28 | | |
29 | | class CodeGenerator; |
30 | | class CallInfo; |
31 | | class BaselineFrameInspector; |
32 | | |
33 | | enum class InlinableNative : uint16_t; |
34 | | |
35 | | // Records information about a baseline frame for compilation that is stable |
36 | | // when later used off thread. |
37 | | BaselineFrameInspector* |
38 | | NewBaselineFrameInspector(TempAllocator* temp, BaselineFrame* frame); |
39 | | |
40 | | using CallTargets = Vector<JSFunction*, 6, JitAllocPolicy>; |
41 | | |
42 | | class IonBuilder |
43 | | : public MIRGenerator, |
44 | | public mozilla::LinkedListElement<IonBuilder> |
45 | | { |
46 | | |
47 | | public: |
48 | | IonBuilder(JSContext* analysisContext, CompileRealm* realm, |
49 | | const JitCompileOptions& options, TempAllocator* temp, |
50 | | MIRGraph* graph, CompilerConstraintList* constraints, |
51 | | BaselineInspector* inspector, CompileInfo* info, |
52 | | const OptimizationInfo* optimizationInfo, BaselineFrameInspector* baselineFrame, |
53 | | size_t inliningDepth = 0, uint32_t loopDepth = 0); |
54 | | |
55 | | // Callers of build() and buildInline() should always check whether the |
56 | | // call overrecursed, if false is returned. Overrecursion is not |
57 | | // signaled as OOM and will not in general be caught by OOM paths. |
58 | | AbortReasonOr<Ok> build(); |
59 | | AbortReasonOr<Ok> buildInline(IonBuilder* callerBuilder, MResumePoint* callerResumePoint, |
60 | | CallInfo& callInfo); |
61 | | |
62 | | mozilla::GenericErrorResult<AbortReason> abort(AbortReason r); |
63 | | mozilla::GenericErrorResult<AbortReason> |
64 | | abort(AbortReason r, const char* message, ...) MOZ_FORMAT_PRINTF(3, 4); |
65 | | |
66 | | private: |
67 | | AbortReasonOr<Ok> traverseBytecode(); |
68 | | AbortReasonOr<Ok> processIterators(); |
69 | | AbortReasonOr<Ok> inspectOpcode(JSOp op); |
70 | | uint32_t readIndex(jsbytecode* pc); |
71 | | JSAtom* readAtom(jsbytecode* pc); |
72 | | |
73 | | void trackActionableAbort(const char* message); |
74 | | void spew(const char* message); |
75 | | |
76 | | JSFunction* getSingleCallTarget(TemporaryTypeSet* calleeTypes); |
77 | | AbortReasonOr<Ok> getPolyCallTargets(TemporaryTypeSet* calleeTypes, bool constructing, |
78 | | InliningTargets& targets, uint32_t maxTargets); |
79 | | |
80 | | AbortReasonOr<Ok> analyzeNewLoopTypes(const CFGBlock* loopEntryBlock); |
81 | | |
82 | | AbortReasonOr<MBasicBlock*> newBlock(size_t stackDepth, jsbytecode* pc, |
83 | | MBasicBlock* maybePredecessor = nullptr); |
84 | | AbortReasonOr<MBasicBlock*> newBlock(MBasicBlock* predecessor, jsbytecode* pc, |
85 | | MResumePoint* priorResumePoint); |
86 | | AbortReasonOr<MBasicBlock*> newBlockPopN(MBasicBlock* predecessor, jsbytecode* pc, |
87 | | uint32_t popped); |
88 | | AbortReasonOr<MBasicBlock*> newBlockAfter(MBasicBlock* at, size_t stackDepth, |
89 | | jsbytecode* pc, MBasicBlock* maybePredecessor = nullptr); |
90 | | AbortReasonOr<MBasicBlock*> newOsrPreheader(MBasicBlock* header, jsbytecode* loopEntry, |
91 | | jsbytecode* beforeLoopEntry); |
92 | | AbortReasonOr<MBasicBlock*> newPendingLoopHeader(MBasicBlock* predecessor, jsbytecode* pc, |
93 | | bool osr, bool canOsr, unsigned stackPhiCount); |
94 | | |
95 | 56 | AbortReasonOr<MBasicBlock*> newBlock(MBasicBlock* predecessor, jsbytecode* pc) { |
96 | 56 | return newBlock(predecessor->stackDepth(), pc, predecessor); |
97 | 56 | } |
98 | | |
99 | | AbortReasonOr<Ok> visitBlock(const CFGBlock* hblock, MBasicBlock* mblock); |
100 | | AbortReasonOr<Ok> visitControlInstruction(CFGControlInstruction* ins, bool* restarted); |
101 | | AbortReasonOr<Ok> visitTest(CFGTest* test); |
102 | | AbortReasonOr<Ok> visitCompare(CFGCompare* compare); |
103 | | AbortReasonOr<Ok> visitLoopEntry(CFGLoopEntry* loopEntry); |
104 | | AbortReasonOr<Ok> visitReturn(CFGControlInstruction* ins); |
105 | | AbortReasonOr<Ok> visitGoto(CFGGoto* ins); |
106 | | AbortReasonOr<Ok> visitBackEdge(CFGBackEdge* ins, bool* restarted); |
107 | | AbortReasonOr<Ok> visitTry(CFGTry* test); |
108 | | AbortReasonOr<Ok> visitThrow(CFGThrow* ins); |
109 | | AbortReasonOr<Ok> visitTableSwitch(CFGTableSwitch* ins); |
110 | | |
111 | | // We want to make sure that our MTest instructions all check whether the |
112 | | // thing being tested might emulate undefined. So we funnel their creation |
113 | | // through this method, to make sure that happens. We don't want to just do |
114 | | // the check in MTest::New, because that can run on background compilation |
115 | | // threads, and we're not sure it's safe to touch that part of the typeset |
116 | | // from a background thread. |
117 | | MTest* newTest(MDefinition* ins, MBasicBlock* ifTrue, MBasicBlock* ifFalse); |
118 | | |
119 | | // Incorporates a type/typeSet into an OSR value for a loop, after the loop |
120 | | // body has been processed. |
121 | | AbortReasonOr<Ok> addOsrValueTypeBarrier(uint32_t slot, MInstruction** def, |
122 | | MIRType type, TemporaryTypeSet* typeSet); |
123 | | AbortReasonOr<Ok> maybeAddOsrTypeBarriers(); |
124 | | |
125 | | // Restarts processing of a loop if the type information at its header was |
126 | | // incomplete. |
127 | | AbortReasonOr<Ok> restartLoop(const CFGBlock* header); |
128 | | |
129 | | // Please see the Big Honkin' Comment about how resume points work in |
130 | | // IonBuilder.cpp, near the definition for this function. |
131 | | AbortReasonOr<Ok> resume(MInstruction* ins, jsbytecode* pc, MResumePoint::Mode mode); |
132 | | AbortReasonOr<Ok> resumeAt(MInstruction* ins, jsbytecode* pc); |
133 | | AbortReasonOr<Ok> resumeAfter(MInstruction* ins); |
134 | | AbortReasonOr<Ok> maybeInsertResume(); |
135 | | |
136 | | bool blockIsOSREntry(const CFGBlock* block, const CFGBlock* predecessor); |
137 | | |
138 | | void insertRecompileCheck(); |
139 | | |
140 | | bool usesEnvironmentChain(); |
141 | | |
142 | | AbortReasonOr<Ok> initParameters(); |
143 | | void initLocals(); |
144 | | void rewriteParameter(uint32_t slotIdx, MDefinition* param); |
145 | | AbortReasonOr<Ok> rewriteParameters(); |
146 | | AbortReasonOr<Ok> initEnvironmentChain(MDefinition* callee = nullptr); |
147 | | void initArgumentsObject(); |
148 | | void pushConstant(const Value& v); |
149 | | |
150 | | MConstant* constant(const Value& v); |
151 | | MConstant* constantInt(int32_t i); |
152 | | MInstruction* initializedLength(MDefinition* elements); |
153 | | MInstruction* setInitializedLength(MDefinition* obj, size_t count); |
154 | | |
155 | | // Improve the type information at tests |
156 | | AbortReasonOr<Ok> improveTypesAtTest(MDefinition* ins, bool trueBranch, MTest* test); |
157 | | AbortReasonOr<Ok> improveTypesAtCompare(MCompare* ins, bool trueBranch, MTest* test); |
158 | | AbortReasonOr<Ok> improveTypesAtNullOrUndefinedCompare(MCompare* ins, bool trueBranch, |
159 | | MTest* test); |
160 | | AbortReasonOr<Ok> improveTypesAtTypeOfCompare(MCompare* ins, bool trueBranch, MTest* test); |
161 | | |
162 | | // Used to detect triangular structure at test. |
163 | | bool detectAndOrStructure(MPhi* ins, bool* branchIsTrue); |
164 | | AbortReasonOr<Ok> replaceTypeSet(MDefinition* subject, TemporaryTypeSet* type, MTest* test); |
165 | | |
166 | | // Add a guard which ensure that the set of type which goes through this |
167 | | // generated code correspond to the observed types for the bytecode. |
168 | | MDefinition* addTypeBarrier(MDefinition* def, TemporaryTypeSet* observed, |
169 | | BarrierKind kind, MTypeBarrier** pbarrier = nullptr); |
170 | | AbortReasonOr<Ok> pushTypeBarrier(MDefinition* def, TemporaryTypeSet* observed, |
171 | | BarrierKind kind); |
172 | | |
173 | | // As pushTypeBarrier, but will compute the needBarrier boolean itself based |
174 | | // on observed and the JSFunction that we're planning to call. The |
175 | | // JSFunction must be a DOM method or getter. |
176 | | AbortReasonOr<Ok> pushDOMTypeBarrier(MInstruction* ins, TemporaryTypeSet* observed, |
177 | | JSFunction* func); |
178 | | |
179 | | // If definiteType is not known or def already has the right type, just |
180 | | // returns def. Otherwise, returns an MInstruction that has that definite |
181 | | // type, infallibly unboxing ins as needed. The new instruction will be |
182 | | // added to |current| in this case. |
183 | | MDefinition* ensureDefiniteType(MDefinition* def, MIRType definiteType); |
184 | | |
185 | | void maybeMarkEmpty(MDefinition* ins); |
186 | | |
187 | | JSObject* getSingletonPrototype(JSFunction* target); |
188 | | |
189 | | MDefinition* createThisScripted(MDefinition* callee, MDefinition* newTarget); |
190 | | MDefinition* createThisScriptedSingleton(JSFunction* target); |
191 | | MDefinition* createThisScriptedBaseline(MDefinition* callee); |
192 | | MDefinition* createThis(JSFunction* target, MDefinition* callee, MDefinition* newTarget); |
193 | | MInstruction* createNamedLambdaObject(MDefinition* callee, MDefinition* envObj); |
194 | | AbortReasonOr<MInstruction*> createCallObject(MDefinition* callee, MDefinition* envObj); |
195 | | |
196 | | MDefinition* walkEnvironmentChain(unsigned hops); |
197 | | |
198 | | MInstruction* addConvertElementsToDoubles(MDefinition* elements); |
199 | | MDefinition* addMaybeCopyElementsForWrite(MDefinition* object, bool checkNative); |
200 | | |
201 | | MInstruction* addBoundsCheck(MDefinition* index, MDefinition* length); |
202 | | |
203 | | MInstruction* addShapeGuard(MDefinition* obj, Shape* const shape, BailoutKind bailoutKind); |
204 | | MInstruction* addGroupGuard(MDefinition* obj, ObjectGroup* group, BailoutKind bailoutKind); |
205 | | MInstruction* addUnboxedExpandoGuard(MDefinition* obj, bool hasExpando, BailoutKind bailoutKind); |
206 | | MInstruction* addSharedTypedArrayGuard(MDefinition* obj); |
207 | | |
208 | | MInstruction* |
209 | | addGuardReceiverPolymorphic(MDefinition* obj, const BaselineInspector::ReceiverVector& receivers); |
210 | | |
211 | | bool invalidatedIdempotentCache(); |
212 | | |
213 | | bool hasStaticEnvironmentObject(JSObject** pcall); |
214 | | AbortReasonOr<Ok> loadSlot(MDefinition* obj, size_t slot, size_t nfixed, MIRType rvalType, |
215 | | BarrierKind barrier, TemporaryTypeSet* types); |
216 | | AbortReasonOr<Ok> loadSlot(MDefinition* obj, Shape* shape, MIRType rvalType, |
217 | | BarrierKind barrier, TemporaryTypeSet* types); |
218 | | AbortReasonOr<Ok> storeSlot(MDefinition* obj, size_t slot, size_t nfixed, MDefinition* value, |
219 | | bool needsBarrier, MIRType slotType = MIRType::None); |
220 | | AbortReasonOr<Ok> storeSlot(MDefinition* obj, Shape* shape, MDefinition* value, |
221 | | bool needsBarrier, MIRType slotType = MIRType::None); |
222 | | bool shouldAbortOnPreliminaryGroups(MDefinition *obj); |
223 | | |
224 | | MDefinition* tryInnerizeWindow(MDefinition* obj); |
225 | | MDefinition* maybeUnboxForPropertyAccess(MDefinition* def); |
226 | | |
227 | | // jsop_getprop() helpers. |
228 | | AbortReasonOr<Ok> checkIsDefinitelyOptimizedArguments(MDefinition* obj, bool* isOptimizedArgs); |
229 | | AbortReasonOr<Ok> getPropTryInferredConstant(bool* emitted, MDefinition* obj, |
230 | | PropertyName* name, TemporaryTypeSet* types); |
231 | | AbortReasonOr<Ok> getPropTryArgumentsLength(bool* emitted, MDefinition* obj); |
232 | | AbortReasonOr<Ok> getPropTryArgumentsCallee(bool* emitted, MDefinition* obj, |
233 | | PropertyName* name); |
234 | | AbortReasonOr<Ok> getPropTryConstant(bool* emitted, MDefinition* obj, jsid id, |
235 | | TemporaryTypeSet* types); |
236 | | AbortReasonOr<Ok> getPropTryNotDefined(bool* emitted, MDefinition* obj, jsid id, |
237 | | TemporaryTypeSet* types); |
238 | | AbortReasonOr<Ok> getPropTryDefiniteSlot(bool* emitted, MDefinition* obj, PropertyName* name, |
239 | | BarrierKind barrier, TemporaryTypeSet* types); |
240 | | AbortReasonOr<Ok> getPropTryModuleNamespace(bool* emitted, MDefinition* obj, PropertyName* name, |
241 | | BarrierKind barrier, TemporaryTypeSet* types); |
242 | | AbortReasonOr<Ok> getPropTryUnboxed(bool* emitted, MDefinition* obj, PropertyName* name, |
243 | | BarrierKind barrier, TemporaryTypeSet* types); |
244 | | AbortReasonOr<Ok> getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName* name, |
245 | | TemporaryTypeSet* types, bool innerized = false); |
246 | | AbortReasonOr<Ok> getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName* name, |
247 | | BarrierKind barrier, TemporaryTypeSet* types); |
248 | | AbortReasonOr<Ok> getPropTryInlineProtoAccess(bool* emitted, MDefinition* obj, PropertyName* name, |
249 | | TemporaryTypeSet* types); |
250 | | AbortReasonOr<Ok> getPropTryTypedObject(bool* emitted, MDefinition* obj, PropertyName* name); |
251 | | AbortReasonOr<Ok> getPropTryScalarPropOfTypedObject(bool* emitted, MDefinition* typedObj, |
252 | | int32_t fieldOffset, |
253 | | TypedObjectPrediction fieldTypeReprs); |
254 | | AbortReasonOr<Ok> getPropTryReferencePropOfTypedObject(bool* emitted, MDefinition* typedObj, |
255 | | int32_t fieldOffset, |
256 | | TypedObjectPrediction fieldPrediction, |
257 | | PropertyName* name); |
258 | | AbortReasonOr<Ok> getPropTryComplexPropOfTypedObject(bool* emitted, MDefinition* typedObj, |
259 | | int32_t fieldOffset, |
260 | | TypedObjectPrediction fieldTypeReprs, |
261 | | size_t fieldIndex); |
262 | | AbortReasonOr<Ok> getPropTryInnerize(bool* emitted, MDefinition* obj, PropertyName* name, |
263 | | TemporaryTypeSet* types); |
264 | | AbortReasonOr<Ok> getPropAddCache(MDefinition* obj, PropertyName* name, |
265 | | BarrierKind barrier, TemporaryTypeSet* types); |
266 | | |
267 | | // jsop_setprop() helpers. |
268 | | AbortReasonOr<Ok> setPropTryCommonSetter(bool* emitted, MDefinition* obj, |
269 | | PropertyName* name, MDefinition* value); |
270 | | AbortReasonOr<Ok> setPropTryCommonDOMSetter(bool* emitted, MDefinition* obj, |
271 | | MDefinition* value, JSFunction* setter, |
272 | | TemporaryTypeSet* objTypes); |
273 | | AbortReasonOr<Ok> setPropTryDefiniteSlot(bool* emitted, MDefinition* obj, |
274 | | PropertyName* name, MDefinition* value, |
275 | | bool barrier); |
276 | | AbortReasonOr<Ok> setPropTryUnboxed(bool* emitted, MDefinition* obj, |
277 | | PropertyName* name, MDefinition* value, |
278 | | bool barrier); |
279 | | AbortReasonOr<Ok> setPropTryInlineAccess(bool* emitted, MDefinition* obj, |
280 | | PropertyName* name, MDefinition* value, |
281 | | bool barrier, TemporaryTypeSet* objTypes); |
282 | | AbortReasonOr<Ok> setPropTryTypedObject(bool* emitted, MDefinition* obj, |
283 | | PropertyName* name, MDefinition* value); |
284 | | AbortReasonOr<Ok> setPropTryReferencePropOfTypedObject(bool* emitted, MDefinition* obj, |
285 | | int32_t fieldOffset, MDefinition* value, |
286 | | TypedObjectPrediction fieldPrediction, |
287 | | PropertyName* name); |
288 | | AbortReasonOr<Ok> setPropTryReferenceTypedObjectValue(bool* emitted, |
289 | | MDefinition* typedObj, |
290 | | const LinearSum& byteOffset, |
291 | | ReferenceType type, |
292 | | MDefinition* value, |
293 | | PropertyName* name); |
294 | | AbortReasonOr<Ok> setPropTryScalarPropOfTypedObject(bool* emitted, |
295 | | MDefinition* obj, |
296 | | int32_t fieldOffset, |
297 | | MDefinition* value, |
298 | | TypedObjectPrediction fieldTypeReprs); |
299 | | AbortReasonOr<Ok> setPropTryScalarTypedObjectValue(bool* emitted, |
300 | | MDefinition* typedObj, |
301 | | const LinearSum& byteOffset, |
302 | | ScalarTypeDescr::Type type, |
303 | | MDefinition* value); |
304 | | AbortReasonOr<Ok> setPropTryCache(bool* emitted, MDefinition* obj, |
305 | | PropertyName* name, MDefinition* value, |
306 | | bool barrier); |
307 | | |
308 | | // jsop_binary_arith helpers. |
309 | | MBinaryArithInstruction* binaryArithInstruction(JSOp op, MDefinition* left, MDefinition* right); |
310 | | AbortReasonOr<Ok> binaryArithTryConcat(bool* emitted, JSOp op, MDefinition* left, |
311 | | MDefinition* right); |
312 | | AbortReasonOr<Ok> binaryArithTrySpecialized(bool* emitted, JSOp op, MDefinition* left, |
313 | | MDefinition* right); |
314 | | AbortReasonOr<Ok> binaryArithTrySpecializedOnBaselineInspector(bool* emitted, JSOp op, |
315 | | MDefinition* left, |
316 | | MDefinition* right); |
317 | | AbortReasonOr<Ok> arithTryBinaryStub(bool* emitted, JSOp op, MDefinition* left, |
318 | | MDefinition* right); |
319 | | |
320 | | // jsop_bitnot helpers. |
321 | | AbortReasonOr<Ok> bitnotTrySpecialized(bool* emitted, MDefinition* input); |
322 | | |
323 | | // jsop_pow helpers. |
324 | | AbortReasonOr<Ok> powTrySpecialized(bool* emitted, MDefinition* base, MDefinition* power, |
325 | | MIRType outputType); |
326 | | |
327 | | // jsop_compare helpers. |
328 | | AbortReasonOr<Ok> compareTrySpecialized(bool* emitted, JSOp op, MDefinition* left, |
329 | | MDefinition* right); |
330 | | AbortReasonOr<Ok> compareTryBitwise(bool* emitted, JSOp op, MDefinition* left, |
331 | | MDefinition* right); |
332 | | AbortReasonOr<Ok> compareTrySpecializedOnBaselineInspector(bool* emitted, JSOp op, |
333 | | MDefinition* left, |
334 | | MDefinition* right); |
335 | | AbortReasonOr<Ok> compareTryBinaryStub(bool* emitted, MDefinition* left, MDefinition* right); |
336 | | AbortReasonOr<Ok> compareTryCharacter(bool* emitted, JSOp op, MDefinition* left, |
337 | | MDefinition* right); |
338 | | |
339 | | // jsop_newarray helpers. |
340 | | AbortReasonOr<Ok> newArrayTryTemplateObject(bool* emitted, JSObject* templateObject, |
341 | | uint32_t length); |
342 | | AbortReasonOr<Ok> newArrayTryVM(bool* emitted, JSObject* templateObject, uint32_t length); |
343 | | |
344 | | // jsop_newobject helpers. |
345 | | AbortReasonOr<Ok> newObjectTryTemplateObject(bool* emitted, JSObject* templateObject); |
346 | | AbortReasonOr<Ok> newObjectTryVM(bool* emitted, JSObject* templateObject); |
347 | | |
348 | | // jsop_in/jsop_hasown helpers. |
349 | | AbortReasonOr<Ok> inTryDense(bool* emitted, MDefinition* obj, MDefinition* id); |
350 | | AbortReasonOr<Ok> hasTryNotDefined(bool* emitted, MDefinition* obj, MDefinition* id, bool ownProperty); |
351 | | AbortReasonOr<Ok> hasTryDefiniteSlotOrUnboxed(bool* emitted, MDefinition* obj, MDefinition* id); |
352 | | |
353 | | // binary data lookup helpers. |
354 | | TypedObjectPrediction typedObjectPrediction(MDefinition* typedObj); |
355 | | TypedObjectPrediction typedObjectPrediction(TemporaryTypeSet* types); |
356 | | bool typedObjectHasField(MDefinition* typedObj, |
357 | | PropertyName* name, |
358 | | size_t* fieldOffset, |
359 | | TypedObjectPrediction* fieldTypeReprs, |
360 | | size_t* fieldIndex, |
361 | | bool* fieldMutable); |
362 | | MDefinition* loadTypedObjectType(MDefinition* value); |
363 | | AbortReasonOr<Ok> loadTypedObjectData(MDefinition* typedObj, |
364 | | MDefinition** owner, |
365 | | LinearSum* ownerOffset); |
366 | | AbortReasonOr<Ok> loadTypedObjectElements(MDefinition* typedObj, |
367 | | const LinearSum& byteOffset, |
368 | | uint32_t scale, |
369 | | MDefinition** ownerElements, |
370 | | MDefinition** ownerScaledOffset, |
371 | | int32_t* ownerByteAdjustment); |
372 | | MDefinition* typeObjectForElementFromArrayStructType(MDefinition* typedObj); |
373 | | MDefinition* typeObjectForFieldFromStructType(MDefinition* type, |
374 | | size_t fieldIndex); |
375 | | bool checkTypedObjectIndexInBounds(uint32_t elemSize, |
376 | | MDefinition* index, |
377 | | TypedObjectPrediction objTypeDescrs, |
378 | | LinearSum* indexAsByteOffset); |
379 | | AbortReasonOr<Ok> pushDerivedTypedObject(bool* emitted, |
380 | | MDefinition* obj, |
381 | | const LinearSum& byteOffset, |
382 | | TypedObjectPrediction derivedTypeDescrs, |
383 | | MDefinition* derivedTypeObj); |
384 | | AbortReasonOr<Ok> pushScalarLoadFromTypedObject(MDefinition* obj, |
385 | | const LinearSum& byteoffset, |
386 | | ScalarTypeDescr::Type type); |
387 | | AbortReasonOr<Ok> pushReferenceLoadFromTypedObject(MDefinition* typedObj, |
388 | | const LinearSum& byteOffset, |
389 | | ReferenceType type, |
390 | | PropertyName* name); |
391 | | |
392 | | // jsop_setelem() helpers. |
393 | | AbortReasonOr<Ok> setElemTryTypedArray(bool* emitted, MDefinition* object, |
394 | | MDefinition* index, MDefinition* value); |
395 | | AbortReasonOr<Ok> setElemTryTypedObject(bool* emitted, MDefinition* obj, |
396 | | MDefinition* index, MDefinition* value); |
397 | | AbortReasonOr<Ok> initOrSetElemTryDense(bool* emitted, MDefinition* object, |
398 | | MDefinition* index, MDefinition* value, |
399 | | bool writeHole); |
400 | | AbortReasonOr<Ok> setElemTryArguments(bool* emitted, MDefinition* object); |
401 | | AbortReasonOr<Ok> initOrSetElemTryCache(bool* emitted, MDefinition* object, |
402 | | MDefinition* index, MDefinition* value); |
403 | | AbortReasonOr<Ok> setElemTryReferenceElemOfTypedObject(bool* emitted, |
404 | | MDefinition* obj, |
405 | | MDefinition* index, |
406 | | TypedObjectPrediction objPrediction, |
407 | | MDefinition* value, |
408 | | TypedObjectPrediction elemPrediction); |
409 | | AbortReasonOr<Ok> setElemTryScalarElemOfTypedObject(bool* emitted, |
410 | | MDefinition* obj, |
411 | | MDefinition* index, |
412 | | TypedObjectPrediction objTypeReprs, |
413 | | MDefinition* value, |
414 | | TypedObjectPrediction elemTypeReprs, |
415 | | uint32_t elemSize); |
416 | | AbortReasonOr<Ok> initializeArrayElement(MDefinition* obj, size_t index, MDefinition* value, |
417 | | bool addResumePointAndIncrementInitializedLength); |
418 | | |
419 | | // jsop_getelem() helpers. |
420 | | AbortReasonOr<Ok> getElemTryDense(bool* emitted, MDefinition* obj, MDefinition* index); |
421 | | AbortReasonOr<Ok> getElemTryGetProp(bool* emitted, MDefinition* obj, MDefinition* index); |
422 | | AbortReasonOr<Ok> getElemTryTypedArray(bool* emitted, MDefinition* obj, MDefinition* index); |
423 | | AbortReasonOr<Ok> getElemTryCallSiteObject(bool* emitted, MDefinition* obj, MDefinition* index); |
424 | | AbortReasonOr<Ok> getElemTryTypedObject(bool* emitted, MDefinition* obj, MDefinition* index); |
425 | | AbortReasonOr<Ok> getElemTryString(bool* emitted, MDefinition* obj, MDefinition* index); |
426 | | AbortReasonOr<Ok> getElemTryArguments(bool* emitted, MDefinition* obj, MDefinition* index); |
427 | | AbortReasonOr<Ok> getElemTryArgumentsInlinedConstant(bool* emitted, MDefinition* obj, |
428 | | MDefinition* index); |
429 | | AbortReasonOr<Ok> getElemTryArgumentsInlinedIndex(bool* emitted, MDefinition* obj, |
430 | | MDefinition* index); |
431 | | AbortReasonOr<Ok> getElemAddCache(MDefinition* obj, MDefinition* index); |
432 | | AbortReasonOr<Ok> getElemTryScalarElemOfTypedObject(bool* emitted, |
433 | | MDefinition* obj, |
434 | | MDefinition* index, |
435 | | TypedObjectPrediction objTypeReprs, |
436 | | TypedObjectPrediction elemTypeReprs, |
437 | | uint32_t elemSize); |
438 | | AbortReasonOr<Ok> getElemTryReferenceElemOfTypedObject(bool* emitted, |
439 | | MDefinition* obj, |
440 | | MDefinition* index, |
441 | | TypedObjectPrediction objPrediction, |
442 | | TypedObjectPrediction elemPrediction); |
443 | | AbortReasonOr<Ok> getElemTryComplexElemOfTypedObject(bool* emitted, |
444 | | MDefinition* obj, |
445 | | MDefinition* index, |
446 | | TypedObjectPrediction objTypeReprs, |
447 | | TypedObjectPrediction elemTypeReprs, |
448 | | uint32_t elemSize); |
449 | | TemporaryTypeSet* computeHeapType(const TemporaryTypeSet* objTypes, const jsid id); |
450 | | |
451 | | enum BoundsChecking { DoBoundsCheck, SkipBoundsCheck }; |
452 | | |
453 | | MInstruction* addArrayBufferByteLength(MDefinition* obj); |
454 | | |
455 | | // Add instructions to compute a typed array's length and data. Also |
456 | | // optionally convert |*index| into a bounds-checked definition, if |
457 | | // requested. |
458 | | // |
459 | | // If you only need the array's length, use addTypedArrayLength below. |
460 | | void addTypedArrayLengthAndData(MDefinition* obj, |
461 | | BoundsChecking checking, |
462 | | MDefinition** index, |
463 | | MInstruction** length, MInstruction** elements); |
464 | | |
465 | | // Add an instruction to compute a typed array's length to the current |
466 | | // block. If you also need the typed array's data, use the above method |
467 | | // instead. |
468 | 0 | MInstruction* addTypedArrayLength(MDefinition* obj) { |
469 | 0 | MInstruction* length; |
470 | 0 | addTypedArrayLengthAndData(obj, SkipBoundsCheck, nullptr, &length, nullptr); |
471 | 0 | return length; |
472 | 0 | } |
473 | | |
474 | | AbortReasonOr<Ok> improveThisTypesForCall(); |
475 | | |
476 | | MDefinition* getCallee(); |
477 | | MDefinition* getAliasedVar(EnvironmentCoordinate ec); |
478 | | AbortReasonOr<MDefinition*> addLexicalCheck(MDefinition* input); |
479 | | |
480 | | MDefinition* convertToBoolean(MDefinition* input); |
481 | | |
482 | | AbortReasonOr<Ok> tryFoldInstanceOf(bool* emitted, MDefinition* lhs, JSObject* protoObject); |
483 | | AbortReasonOr<bool> hasOnProtoChain(TypeSet::ObjectKey* key, JSObject* protoObject, bool* onProto); |
484 | | |
485 | | AbortReasonOr<Ok> jsop_add(MDefinition* left, MDefinition* right); |
486 | | AbortReasonOr<Ok> jsop_bitnot(); |
487 | | AbortReasonOr<Ok> jsop_bitop(JSOp op); |
488 | | AbortReasonOr<Ok> jsop_binary_arith(JSOp op); |
489 | | AbortReasonOr<Ok> jsop_binary_arith(JSOp op, MDefinition* left, MDefinition* right); |
490 | | AbortReasonOr<Ok> jsop_pow(); |
491 | | AbortReasonOr<Ok> jsop_pos(); |
492 | | AbortReasonOr<Ok> jsop_neg(); |
493 | | AbortReasonOr<Ok> jsop_tostring(); |
494 | | AbortReasonOr<Ok> jsop_setarg(uint32_t arg); |
495 | | AbortReasonOr<Ok> jsop_defvar(uint32_t index); |
496 | | AbortReasonOr<Ok> jsop_deflexical(uint32_t index); |
497 | | AbortReasonOr<Ok> jsop_deffun(); |
498 | | AbortReasonOr<Ok> jsop_notearg(); |
499 | | AbortReasonOr<Ok> jsop_throwsetconst(); |
500 | | AbortReasonOr<Ok> jsop_checklexical(); |
501 | | AbortReasonOr<Ok> jsop_checkaliasedlexical(EnvironmentCoordinate ec); |
502 | | AbortReasonOr<Ok> jsop_funcall(uint32_t argc); |
503 | | AbortReasonOr<Ok> jsop_funapply(uint32_t argc); |
504 | | AbortReasonOr<Ok> jsop_funapplyarguments(uint32_t argc); |
505 | | AbortReasonOr<Ok> jsop_funapplyarray(uint32_t argc); |
506 | | AbortReasonOr<Ok> jsop_spreadcall(); |
507 | | AbortReasonOr<Ok> jsop_call(uint32_t argc, bool constructing, bool ignoresReturnValue); |
508 | | AbortReasonOr<Ok> jsop_eval(uint32_t argc); |
509 | | AbortReasonOr<Ok> jsop_label(); |
510 | | AbortReasonOr<Ok> jsop_andor(JSOp op); |
511 | | AbortReasonOr<Ok> jsop_dup2(); |
512 | | AbortReasonOr<Ok> jsop_loopentry(); |
513 | | AbortReasonOr<Ok> jsop_loophead(jsbytecode* pc); |
514 | | AbortReasonOr<Ok> jsop_compare(JSOp op); |
515 | | AbortReasonOr<Ok> jsop_compare(JSOp op, MDefinition* left, MDefinition* right); |
516 | | AbortReasonOr<Ok> getStaticName(bool* emitted, JSObject* staticObject, PropertyName* name, |
517 | | MDefinition* lexicalCheck = nullptr); |
518 | | AbortReasonOr<Ok> loadStaticSlot(JSObject* staticObject, BarrierKind barrier, |
519 | | TemporaryTypeSet* types, uint32_t slot); |
520 | | AbortReasonOr<Ok> setStaticName(JSObject* staticObject, PropertyName* name); |
521 | | AbortReasonOr<Ok> jsop_getgname(PropertyName* name); |
522 | | AbortReasonOr<Ok> jsop_getname(PropertyName* name); |
523 | | AbortReasonOr<Ok> jsop_intrinsic(PropertyName* name); |
524 | | AbortReasonOr<Ok> jsop_getimport(PropertyName* name); |
525 | | AbortReasonOr<Ok> jsop_bindname(PropertyName* name); |
526 | | AbortReasonOr<Ok> jsop_bindvar(); |
527 | | AbortReasonOr<Ok> jsop_getelem(); |
528 | | AbortReasonOr<Ok> jsop_getelem_dense(MDefinition* obj, MDefinition* index); |
529 | | AbortReasonOr<Ok> jsop_getelem_typed(MDefinition* obj, MDefinition* index, |
530 | | ScalarTypeDescr::Type arrayType); |
531 | | AbortReasonOr<Ok> jsop_setelem(); |
532 | | AbortReasonOr<Ok> initOrSetElemDense(TemporaryTypeSet::DoubleConversion conversion, |
533 | | MDefinition* object, MDefinition* index, |
534 | | MDefinition* value, bool writeHole, bool* emitted); |
535 | | AbortReasonOr<Ok> jsop_setelem_typed(ScalarTypeDescr::Type arrayType, |
536 | | MDefinition* object, MDefinition* index, |
537 | | MDefinition* value); |
538 | | AbortReasonOr<Ok> jsop_length(); |
539 | | bool jsop_length_fastPath(); |
540 | | AbortReasonOr<Ok> jsop_arguments(); |
541 | | AbortReasonOr<Ok> jsop_arguments_getelem(); |
542 | | AbortReasonOr<Ok> jsop_runonce(); |
543 | | AbortReasonOr<Ok> jsop_rest(); |
544 | | AbortReasonOr<Ok> jsop_not(); |
545 | | AbortReasonOr<Ok> jsop_superbase(); |
546 | | AbortReasonOr<Ok> jsop_getprop_super(PropertyName* name); |
547 | | AbortReasonOr<Ok> jsop_getelem_super(); |
548 | | AbortReasonOr<Ok> jsop_getprop(PropertyName* name); |
549 | | AbortReasonOr<Ok> jsop_setprop(PropertyName* name); |
550 | | AbortReasonOr<Ok> jsop_delprop(PropertyName* name); |
551 | | AbortReasonOr<Ok> jsop_delelem(); |
552 | | AbortReasonOr<Ok> jsop_newarray(uint32_t length); |
553 | | AbortReasonOr<Ok> jsop_newarray(JSObject* templateObject, uint32_t length); |
554 | | AbortReasonOr<Ok> jsop_newarray_copyonwrite(); |
555 | | AbortReasonOr<Ok> jsop_newobject(); |
556 | | AbortReasonOr<Ok> jsop_initelem(); |
557 | | AbortReasonOr<Ok> jsop_initelem_inc(); |
558 | | AbortReasonOr<Ok> jsop_initelem_array(); |
559 | | AbortReasonOr<Ok> jsop_initelem_getter_setter(); |
560 | | AbortReasonOr<Ok> jsop_mutateproto(); |
561 | | AbortReasonOr<Ok> jsop_initprop(PropertyName* name); |
562 | | AbortReasonOr<Ok> jsop_initprop_getter_setter(PropertyName* name); |
563 | | AbortReasonOr<Ok> jsop_regexp(RegExpObject* reobj); |
564 | | AbortReasonOr<Ok> jsop_object(JSObject* obj); |
565 | | AbortReasonOr<Ok> jsop_classconstructor(); |
566 | | AbortReasonOr<Ok> jsop_lambda(JSFunction* fun); |
567 | | AbortReasonOr<Ok> jsop_lambda_arrow(JSFunction* fun); |
568 | | AbortReasonOr<Ok> jsop_setfunname(uint8_t prefixKind); |
569 | | AbortReasonOr<Ok> jsop_pushlexicalenv(uint32_t index); |
570 | | AbortReasonOr<Ok> jsop_copylexicalenv(bool copySlots); |
571 | | AbortReasonOr<Ok> jsop_functionthis(); |
572 | | AbortReasonOr<Ok> jsop_globalthis(); |
573 | | AbortReasonOr<Ok> jsop_typeof(); |
574 | | AbortReasonOr<Ok> jsop_toasync(); |
575 | | AbortReasonOr<Ok> jsop_toasyncgen(); |
576 | | AbortReasonOr<Ok> jsop_toasynciter(); |
577 | | AbortReasonOr<Ok> jsop_toid(); |
578 | | AbortReasonOr<Ok> jsop_iter(); |
579 | | AbortReasonOr<Ok> jsop_itermore(); |
580 | | AbortReasonOr<Ok> jsop_isnoiter(); |
581 | | AbortReasonOr<Ok> jsop_iterend(); |
582 | | AbortReasonOr<Ok> jsop_iternext(); |
583 | | AbortReasonOr<Ok> jsop_in(); |
584 | | AbortReasonOr<Ok> jsop_hasown(); |
585 | | AbortReasonOr<Ok> jsop_instanceof(); |
586 | | AbortReasonOr<Ok> jsop_getaliasedvar(EnvironmentCoordinate ec); |
587 | | AbortReasonOr<Ok> jsop_setaliasedvar(EnvironmentCoordinate ec); |
588 | | AbortReasonOr<Ok> jsop_debugger(); |
589 | | AbortReasonOr<Ok> jsop_newtarget(); |
590 | | AbortReasonOr<Ok> jsop_checkisobj(uint8_t kind); |
591 | | AbortReasonOr<Ok> jsop_checkiscallable(uint8_t kind); |
592 | | AbortReasonOr<Ok> jsop_checkobjcoercible(); |
593 | | AbortReasonOr<Ok> jsop_pushcallobj(); |
594 | | AbortReasonOr<Ok> jsop_implicitthis(PropertyName* name); |
595 | | AbortReasonOr<Ok> jsop_importmeta(); |
596 | | |
597 | | /* Inlining. */ |
598 | | |
599 | | enum InliningStatus |
600 | | { |
601 | | InliningStatus_NotInlined, |
602 | | InliningStatus_WarmUpCountTooLow, |
603 | | InliningStatus_Inlined |
604 | | }; |
605 | | using InliningResult = AbortReasonOr<InliningStatus>; |
606 | | |
607 | | enum InliningDecision |
608 | | { |
609 | | InliningDecision_Error, |
610 | | InliningDecision_Inline, |
611 | | InliningDecision_DontInline, |
612 | | InliningDecision_WarmUpCountTooLow |
613 | | }; |
614 | | |
615 | | static InliningDecision DontInline(JSScript* targetScript, const char* reason); |
616 | | |
617 | | // Helper function for canInlineTarget |
618 | | bool hasCommonInliningPath(const JSScript* scriptToInline); |
619 | | |
620 | | // Oracles. |
621 | | InliningDecision canInlineTarget(JSFunction* target, CallInfo& callInfo); |
622 | | InliningDecision makeInliningDecision(JSObject* target, CallInfo& callInfo); |
623 | | AbortReasonOr<Ok> selectInliningTargets(const InliningTargets& targets, CallInfo& callInfo, |
624 | | BoolVector& choiceSet, uint32_t* numInlineable); |
625 | | |
626 | | // Native inlining helpers. |
627 | | // The typeset for the return value of our function. These are |
628 | | // the types it's been observed returning in the past. |
629 | | TemporaryTypeSet* getInlineReturnTypeSet(); |
630 | | // The known MIR type of getInlineReturnTypeSet. |
631 | | MIRType getInlineReturnType(); |
632 | | |
633 | | // Array natives. |
634 | | InliningResult inlineArray(CallInfo& callInfo); |
635 | | InliningResult inlineArrayIsArray(CallInfo& callInfo); |
636 | | InliningResult inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode); |
637 | | InliningResult inlineArrayPush(CallInfo& callInfo); |
638 | | InliningResult inlineArraySlice(CallInfo& callInfo); |
639 | | InliningResult inlineArrayJoin(CallInfo& callInfo); |
640 | | |
641 | | // Boolean natives. |
642 | | InliningResult inlineBoolean(CallInfo& callInfo); |
643 | | |
644 | | // Iterator intrinsics. |
645 | | InliningResult inlineNewIterator(CallInfo& callInfo, MNewIterator::Type type); |
646 | | |
647 | | // Math natives. |
648 | | InliningResult inlineMathAbs(CallInfo& callInfo); |
649 | | InliningResult inlineMathFloor(CallInfo& callInfo); |
650 | | InliningResult inlineMathCeil(CallInfo& callInfo); |
651 | | InliningResult inlineMathClz32(CallInfo& callInfo); |
652 | | InliningResult inlineMathRound(CallInfo& callInfo); |
653 | | InliningResult inlineMathSqrt(CallInfo& callInfo); |
654 | | InliningResult inlineMathAtan2(CallInfo& callInfo); |
655 | | InliningResult inlineMathHypot(CallInfo& callInfo); |
656 | | InliningResult inlineMathMinMax(CallInfo& callInfo, bool max); |
657 | | InliningResult inlineMathPow(CallInfo& callInfo); |
658 | | InliningResult inlineMathRandom(CallInfo& callInfo); |
659 | | InliningResult inlineMathImul(CallInfo& callInfo); |
660 | | InliningResult inlineMathFRound(CallInfo& callInfo); |
661 | | InliningResult inlineMathTrunc(CallInfo& callInfo); |
662 | | InliningResult inlineMathSign(CallInfo& callInfo); |
663 | | InliningResult inlineMathFunction(CallInfo& callInfo, MMathFunction::Function function); |
664 | | |
665 | | // String natives. |
666 | | InliningResult inlineStringObject(CallInfo& callInfo); |
667 | | InliningResult inlineStrCharCodeAt(CallInfo& callInfo); |
668 | | InliningResult inlineConstantCharCodeAt(CallInfo& callInfo); |
669 | | InliningResult inlineStrFromCharCode(CallInfo& callInfo); |
670 | | InliningResult inlineStrFromCodePoint(CallInfo& callInfo); |
671 | | InliningResult inlineStrCharAt(CallInfo& callInfo); |
672 | | InliningResult inlineStringConvertCase(CallInfo& callInfo, MStringConvertCase::Mode mode); |
673 | | |
674 | | // String intrinsics. |
675 | | InliningResult inlineStringReplaceString(CallInfo& callInfo); |
676 | | InliningResult inlineConstantStringSplitString(CallInfo& callInfo); |
677 | | InliningResult inlineStringSplitString(CallInfo& callInfo); |
678 | | |
679 | | // Reflect natives. |
680 | | InliningResult inlineReflectGetPrototypeOf(CallInfo& callInfo); |
681 | | |
682 | | // RegExp intrinsics. |
683 | | InliningResult inlineRegExpMatcher(CallInfo& callInfo); |
684 | | InliningResult inlineRegExpSearcher(CallInfo& callInfo); |
685 | | InliningResult inlineRegExpTester(CallInfo& callInfo); |
686 | | InliningResult inlineIsRegExpObject(CallInfo& callInfo); |
687 | | InliningResult inlineRegExpPrototypeOptimizable(CallInfo& callInfo); |
688 | | InliningResult inlineRegExpInstanceOptimizable(CallInfo& callInfo); |
689 | | InliningResult inlineGetFirstDollarIndex(CallInfo& callInfo); |
690 | | |
691 | | // Object natives and intrinsics. |
692 | | InliningResult inlineObject(CallInfo& callInfo); |
693 | | InliningResult inlineObjectCreate(CallInfo& callInfo); |
694 | | InliningResult inlineObjectIs(CallInfo& callInfo); |
695 | | InliningResult inlineObjectToString(CallInfo& callInfo); |
696 | | InliningResult inlineDefineDataProperty(CallInfo& callInfo); |
697 | | |
698 | | // Atomics natives. |
699 | | InliningResult inlineAtomicsCompareExchange(CallInfo& callInfo); |
700 | | InliningResult inlineAtomicsExchange(CallInfo& callInfo); |
701 | | InliningResult inlineAtomicsLoad(CallInfo& callInfo); |
702 | | InliningResult inlineAtomicsStore(CallInfo& callInfo); |
703 | | InliningResult inlineAtomicsBinop(CallInfo& callInfo, InlinableNative target); |
704 | | InliningResult inlineAtomicsIsLockFree(CallInfo& callInfo); |
705 | | |
706 | | // Slot intrinsics. |
707 | | InliningResult inlineUnsafeSetReservedSlot(CallInfo& callInfo); |
708 | | InliningResult inlineUnsafeGetReservedSlot(CallInfo& callInfo, |
709 | | MIRType knownValueType); |
710 | | |
711 | | // Map and Set intrinsics. |
712 | | InliningResult inlineGetNextEntryForIterator(CallInfo& callInfo, |
713 | | MGetNextEntryForIterator::Mode mode); |
714 | | |
715 | | // ArrayBuffer intrinsics. |
716 | | InliningResult inlineArrayBufferByteLength(CallInfo& callInfo); |
717 | | InliningResult inlinePossiblyWrappedArrayBufferByteLength(CallInfo& callInfo); |
718 | | |
719 | | // TypedArray intrinsics. |
720 | | enum WrappingBehavior { AllowWrappedTypedArrays, RejectWrappedTypedArrays }; |
721 | | InliningResult inlineTypedArray(CallInfo& callInfo, Native native); |
722 | | InliningResult inlineIsTypedArrayHelper(CallInfo& callInfo, WrappingBehavior wrappingBehavior); |
723 | | InliningResult inlineIsTypedArray(CallInfo& callInfo); |
724 | | InliningResult inlineIsPossiblyWrappedTypedArray(CallInfo& callInfo); |
725 | | InliningResult inlineTypedArrayLength(CallInfo& callInfo); |
726 | | InliningResult inlinePossiblyWrappedTypedArrayLength(CallInfo& callInfo); |
727 | | InliningResult inlineSetDisjointTypedElements(CallInfo& callInfo); |
728 | | |
729 | | // TypedObject intrinsics and natives. |
730 | | InliningResult inlineObjectIsTypeDescr(CallInfo& callInfo); |
731 | | InliningResult inlineSetTypedObjectOffset(CallInfo& callInfo); |
732 | | InliningResult inlineConstructTypedObject(CallInfo& callInfo, TypeDescr* target); |
733 | | |
734 | | // Utility intrinsics. |
735 | | InliningResult inlineIsCallable(CallInfo& callInfo); |
736 | | InliningResult inlineIsConstructor(CallInfo& callInfo); |
737 | | InliningResult inlineIsObject(CallInfo& callInfo); |
738 | | InliningResult inlineToObject(CallInfo& callInfo); |
739 | | InliningResult inlineIsCrossRealmArrayConstructor(CallInfo& callInfo); |
740 | | InliningResult inlineToInteger(CallInfo& callInfo); |
741 | | InliningResult inlineToString(CallInfo& callInfo); |
742 | | InliningResult inlineDump(CallInfo& callInfo); |
743 | | InliningResult inlineHasClass(CallInfo& callInfo, const Class* clasp, |
744 | | const Class* clasp2 = nullptr, |
745 | | const Class* clasp3 = nullptr, |
746 | | const Class* clasp4 = nullptr); |
747 | | InliningResult inlineGuardToClass(CallInfo& callInfo, const Class* clasp); |
748 | | InliningResult inlineIsConstructing(CallInfo& callInfo); |
749 | | InliningResult inlineSubstringKernel(CallInfo& callInfo); |
750 | | InliningResult inlineObjectHasPrototype(CallInfo& callInfo); |
751 | | InliningResult inlineFinishBoundFunctionInit(CallInfo& callInfo); |
752 | | InliningResult inlineIsPackedArray(CallInfo& callInfo); |
753 | | InliningResult inlineWasmCall(CallInfo& callInfo, JSFunction* target); |
754 | | |
755 | | // Testing functions. |
756 | | InliningResult inlineBailout(CallInfo& callInfo); |
757 | | InliningResult inlineAssertFloat32(CallInfo& callInfo); |
758 | | InliningResult inlineAssertRecoveredOnBailout(CallInfo& callInfo); |
759 | | |
760 | | // Bind function. |
761 | | InliningResult inlineBoundFunction(CallInfo& callInfo, JSFunction* target); |
762 | | |
763 | | // Main inlining functions |
764 | | InliningResult inlineNativeCall(CallInfo& callInfo, JSFunction* target); |
765 | | InliningResult inlineNativeGetter(CallInfo& callInfo, JSFunction* target); |
766 | | InliningResult inlineNonFunctionCall(CallInfo& callInfo, JSObject* target); |
767 | | InliningResult inlineScriptedCall(CallInfo& callInfo, JSFunction* target); |
768 | | InliningResult inlineSingleCall(CallInfo& callInfo, JSObject* target); |
769 | | |
770 | | // Call functions |
771 | | InliningResult inlineCallsite(const InliningTargets& targets, CallInfo& callInfo); |
772 | | AbortReasonOr<Ok> inlineCalls(CallInfo& callInfo, const InliningTargets& targets, |
773 | | BoolVector& choiceSet, MGetPropertyCache* maybeCache); |
774 | | |
775 | | // Inlining helpers. |
776 | | AbortReasonOr<Ok> inlineGenericFallback(const mozilla::Maybe<CallTargets>& targets, |
777 | | CallInfo& callInfo, |
778 | | MBasicBlock* dispatchBlock); |
779 | | AbortReasonOr<Ok> inlineObjectGroupFallback(const mozilla::Maybe<CallTargets>& targets, |
780 | | CallInfo& callInfo, MBasicBlock* dispatchBlock, |
781 | | MObjectGroupDispatch* dispatch, |
782 | | MGetPropertyCache* cache, |
783 | | MBasicBlock** fallbackTarget); |
784 | | |
785 | | enum AtomicCheckResult { |
786 | | DontCheckAtomicResult, |
787 | | DoCheckAtomicResult |
788 | | }; |
789 | | |
790 | | bool atomicsMeetsPreconditions(CallInfo& callInfo, Scalar::Type* arrayElementType, |
791 | | bool* requiresDynamicCheck, |
792 | | AtomicCheckResult checkResult=DoCheckAtomicResult); |
793 | | void atomicsCheckBounds(CallInfo& callInfo, MInstruction** elements, MDefinition** index); |
794 | | |
795 | | bool testNeedsArgumentCheck(JSFunction* target, CallInfo& callInfo); |
796 | | |
797 | | AbortReasonOr<MCall*> makeCallHelper(const mozilla::Maybe<CallTargets>& targets, |
798 | | CallInfo& callInfo); |
799 | | AbortReasonOr<Ok> makeCall(const mozilla::Maybe<CallTargets>& targets, CallInfo& callInfo); |
800 | | AbortReasonOr<Ok> makeCall(JSFunction* target, CallInfo& callInfo); |
801 | | |
802 | | MDefinition* patchInlinedReturn(CallInfo& callInfo, MBasicBlock* exit, MBasicBlock* bottom); |
803 | | MDefinition* patchInlinedReturns(CallInfo& callInfo, MIRGraphReturns& returns, |
804 | | MBasicBlock* bottom); |
805 | | MDefinition* specializeInlinedReturn(MDefinition* rdef, MBasicBlock* exit); |
806 | | |
807 | | NativeObject* commonPrototypeWithGetterSetter(TemporaryTypeSet* types, PropertyName* name, |
808 | | bool isGetter, JSFunction* getterOrSetter, |
809 | | bool* guardGlobal); |
810 | | void freezePropertiesForCommonPrototype(TemporaryTypeSet* types, PropertyName* name, |
811 | | JSObject* foundProto, bool allowEmptyTypesForGlobal = false); |
812 | | /* |
813 | | * Callers must pass a non-null globalGuard if they pass a non-null globalShape. |
814 | | */ |
815 | | bool testCommonGetterSetter(TemporaryTypeSet* types, PropertyName* name, |
816 | | bool isGetter, JSFunction* getterOrSetter, |
817 | | MDefinition** guard, Shape* globalShape = nullptr, |
818 | | MDefinition** globalGuard = nullptr); |
819 | | AbortReasonOr<bool> testShouldDOMCall(TypeSet* inTypes, |
820 | | JSFunction* func, JSJitInfo::OpType opType); |
821 | | |
822 | | MDefinition* |
823 | | addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Shape* holderShape, |
824 | | const BaselineInspector::ReceiverVector& receivers, |
825 | | const BaselineInspector::ObjectGroupVector& convertUnboxedGroups, |
826 | | bool isOwnProperty); |
827 | | |
828 | | AbortReasonOr<Ok> annotateGetPropertyCache(MDefinition* obj, PropertyName* name, |
829 | | MGetPropertyCache* getPropCache, |
830 | | TemporaryTypeSet* objTypes, |
831 | | TemporaryTypeSet* pushedTypes); |
832 | | |
833 | | MGetPropertyCache* getInlineableGetPropertyCache(CallInfo& callInfo); |
834 | | |
835 | | JSObject* testGlobalLexicalBinding(PropertyName* name); |
836 | | |
837 | | JSObject* testSingletonProperty(JSObject* obj, jsid id); |
838 | | JSObject* testSingletonPropertyTypes(MDefinition* obj, jsid id); |
839 | | |
840 | | AbortReasonOr<bool> testNotDefinedProperty(MDefinition* obj, jsid id, bool ownProperty = false); |
841 | | |
842 | | uint32_t getDefiniteSlot(TemporaryTypeSet* types, jsid id, uint32_t* pnfixed); |
843 | | MDefinition* convertUnboxedObjects(MDefinition* obj); |
844 | | MDefinition* convertUnboxedObjects(MDefinition* obj, |
845 | | const BaselineInspector::ObjectGroupVector& list); |
846 | | uint32_t getUnboxedOffset(TemporaryTypeSet* types, jsid id, |
847 | | JSValueType* punboxedType); |
848 | | MInstruction* loadUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType, |
849 | | BarrierKind barrier, TemporaryTypeSet* types); |
850 | | MInstruction* loadUnboxedValue(MDefinition* elements, size_t elementsOffset, |
851 | | MDefinition* scaledOffset, JSValueType unboxedType, |
852 | | BarrierKind barrier, TemporaryTypeSet* types); |
853 | | MInstruction* storeUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType, |
854 | | MDefinition* value); |
855 | | MInstruction* storeUnboxedValue(MDefinition* obj, |
856 | | MDefinition* elements, int32_t elementsOffset, |
857 | | MDefinition* scaledOffset, JSValueType unboxedType, |
858 | | MDefinition* value, bool preBarrier = true); |
859 | | AbortReasonOr<Ok> checkPreliminaryGroups(MDefinition *obj); |
860 | | AbortReasonOr<Ok> freezePropTypeSets(TemporaryTypeSet* types, |
861 | | JSObject* foundProto, PropertyName* name); |
862 | | bool canInlinePropertyOpShapes(const BaselineInspector::ReceiverVector& receivers); |
863 | | |
864 | | TemporaryTypeSet* bytecodeTypes(jsbytecode* pc); |
865 | | |
866 | | // Use one of the below methods for updating the current block, rather than |
867 | | // updating |current| directly. setCurrent() should only be used in cases |
868 | | // where the block cannot have phis whose type needs to be computed. |
869 | | |
870 | 98 | AbortReasonOr<Ok> setCurrentAndSpecializePhis(MBasicBlock* block) { |
871 | 98 | if (block) { |
872 | 98 | if (!block->specializePhis(alloc())) { |
873 | 0 | return abort(AbortReason::Alloc); |
874 | 0 | } |
875 | 98 | } |
876 | 98 | setCurrent(block); |
877 | 98 | return Ok(); |
878 | 98 | } |
879 | | |
880 | 112 | void setCurrent(MBasicBlock* block) { |
881 | 112 | current = block; |
882 | 112 | } |
883 | | |
884 | | // A builder is inextricably tied to a particular script. |
885 | | JSScript* script_; |
886 | | |
887 | | // script->hasIonScript() at the start of the compilation. Used to avoid |
888 | | // calling hasIonScript() from background compilation threads. |
889 | | bool scriptHasIonScript_; |
890 | | |
891 | | // If off thread compilation is successful, the final code generator is |
892 | | // attached here. Code has been generated, but not linked (there is not yet |
893 | | // an IonScript). This is heap allocated, and must be explicitly destroyed, |
894 | | // performed by FinishOffThreadBuilder(). |
895 | | CodeGenerator* backgroundCodegen_; |
896 | | |
897 | | // Some aborts are actionable (e.g., using an unsupported bytecode). When |
898 | | // optimization tracking is enabled, the location and message of the abort |
899 | | // are recorded here so they may be propagated to the script's |
900 | | // corresponding JitcodeGlobalEntry::BaselineEntry. |
901 | | JSScript* actionableAbortScript_; |
902 | | jsbytecode* actionableAbortPc_; |
903 | | const char* actionableAbortMessage_; |
904 | | |
905 | | MRootList* rootList_; |
906 | | |
907 | | public: |
908 | 14 | void setRootList(MRootList& rootList) { |
909 | 14 | MOZ_ASSERT(!rootList_); |
910 | 14 | rootList_ = &rootList; |
911 | 14 | } |
912 | | void clearForBackEnd(); |
913 | | JSObject* checkNurseryObject(JSObject* obj); |
914 | | |
915 | 764 | JSScript* script() const { return script_; } |
916 | 0 | bool scriptHasIonScript() const { return scriptHasIonScript_; } |
917 | | |
918 | 28 | CodeGenerator* backgroundCodegen() const { return backgroundCodegen_; } |
919 | 14 | void setBackgroundCodegen(CodeGenerator* codegen) { backgroundCodegen_ = codegen; } |
920 | | |
921 | 339 | CompilerConstraintList* constraints() { |
922 | 339 | return constraints_; |
923 | 339 | } |
924 | | |
925 | 0 | bool isInlineBuilder() const { |
926 | 0 | return callerBuilder_ != nullptr; |
927 | 0 | } |
928 | | |
929 | 98 | const JSAtomState& names() { return realm->runtime()->names(); } |
930 | | |
931 | 0 | bool hadActionableAbort() const { |
932 | 0 | MOZ_ASSERT(!actionableAbortScript_ || |
933 | 0 | (actionableAbortPc_ && actionableAbortMessage_)); |
934 | 0 | return actionableAbortScript_ != nullptr; |
935 | 0 | } |
936 | | |
937 | 0 | TraceLoggerThread *traceLogger() { |
938 | 0 | return TraceLoggerForCurrentThread(); |
939 | 0 | } |
940 | | |
941 | | void actionableAbortLocationAndMessage(JSScript** abortScript, jsbytecode** abortPc, |
942 | | const char** abortMessage) |
943 | 0 | { |
944 | 0 | MOZ_ASSERT(hadActionableAbort()); |
945 | 0 | *abortScript = actionableAbortScript_; |
946 | 0 | *abortPc = actionableAbortPc_; |
947 | 0 | *abortMessage = actionableAbortMessage_; |
948 | 0 | } |
949 | | |
950 | | void trace(JSTracer* trc); |
951 | | |
952 | | private: |
953 | | AbortReasonOr<Ok> init(); |
954 | | |
955 | | JSContext* analysisContext; |
956 | | BaselineFrameInspector* baselineFrame_; |
957 | | |
958 | | // Constraints for recording dependencies on type information. |
959 | | CompilerConstraintList* constraints_; |
960 | | |
961 | | TemporaryTypeSet* thisTypes; |
962 | | TemporaryTypeSet* argTypes; |
963 | | TemporaryTypeSet* typeArray; |
964 | | uint32_t typeArrayHint; |
965 | | uint32_t* bytecodeTypeMap; |
966 | | |
967 | | EnvironmentCoordinateNameCache envCoordinateNameCache; |
968 | | |
969 | | jsbytecode* pc; |
970 | | MBasicBlock* current; |
971 | | uint32_t loopDepth_; |
972 | | Vector<MBasicBlock*, 0, JitAllocPolicy> blockWorklist; |
973 | | const CFGBlock* cfgCurrent; |
974 | | const ControlFlowGraph* cfg; |
975 | | |
976 | | Vector<BytecodeSite*, 0, JitAllocPolicy> trackedOptimizationSites_; |
977 | | |
978 | 672 | BytecodeSite* bytecodeSite(jsbytecode* pc) { |
979 | 672 | MOZ_ASSERT(info().inlineScriptTree()->script()->containsPC(pc)); |
980 | 672 | // See comment in maybeTrackedOptimizationSite. |
981 | 672 | if (isOptimizationTrackingEnabled()) { |
982 | 0 | if (BytecodeSite* site = maybeTrackedOptimizationSite(pc)) { |
983 | 0 | return site; |
984 | 0 | } |
985 | 672 | } |
986 | 672 | return new(alloc()) BytecodeSite(info().inlineScriptTree(), pc); |
987 | 672 | } |
988 | | |
989 | | BytecodeSite* maybeTrackedOptimizationSite(jsbytecode* pc); |
990 | | |
991 | | MDefinition* lexicalCheck_; |
992 | | |
993 | 0 | void setLexicalCheck(MDefinition* lexical) { |
994 | 0 | MOZ_ASSERT(!lexicalCheck_); |
995 | 0 | lexicalCheck_ = lexical; |
996 | 0 | } |
997 | 0 | MDefinition* takeLexicalCheck() { |
998 | 0 | MDefinition* lexical = lexicalCheck_; |
999 | 0 | lexicalCheck_ = nullptr; |
1000 | 0 | return lexical; |
1001 | 0 | } |
1002 | | |
1003 | | /* Information used for inline-call builders. */ |
1004 | | MResumePoint* callerResumePoint_; |
1005 | 0 | jsbytecode* callerPC() { |
1006 | 0 | return callerResumePoint_ ? callerResumePoint_->pc() : nullptr; |
1007 | 0 | } |
1008 | | IonBuilder* callerBuilder_; |
1009 | | |
1010 | | IonBuilder* outermostBuilder(); |
1011 | | |
1012 | | struct LoopHeader { |
1013 | | jsbytecode* pc; |
1014 | | MBasicBlock* header; |
1015 | | |
1016 | | LoopHeader(jsbytecode* pc, MBasicBlock* header) |
1017 | | : pc(pc), header(header) |
1018 | 0 | {} |
1019 | | }; |
1020 | | |
1021 | | Vector<MDefinition*, 2, JitAllocPolicy> iterators_; |
1022 | | Vector<LoopHeader, 0, JitAllocPolicy> loopHeaders_; |
1023 | | Vector<MBasicBlock*, 0, JitAllocPolicy> loopHeaderStack_; |
1024 | | #ifdef DEBUG |
1025 | | Vector<const CFGBlock*, 0, JitAllocPolicy> cfgLoopHeaderStack_; |
1026 | | #endif |
1027 | | |
1028 | | BaselineInspector* inspector; |
1029 | | |
1030 | | size_t inliningDepth_; |
1031 | | |
1032 | | // Total bytecode length of all inlined scripts. Only tracked for the |
1033 | | // outermost builder. |
1034 | | size_t inlinedBytecodeLength_; |
1035 | | |
1036 | | // Cutoff to disable compilation if excessive time is spent reanalyzing |
1037 | | // loop bodies to compute a fixpoint of the types for loop variables. |
1038 | | static const size_t MAX_LOOP_RESTARTS = 40; |
1039 | | size_t numLoopRestarts_; |
1040 | | |
1041 | | // True if script->failedBoundsCheck is set for the current script or |
1042 | | // an outer script. |
1043 | | bool failedBoundsCheck_; |
1044 | | |
1045 | | // True if script->failedShapeGuard is set for the current script or |
1046 | | // an outer script. |
1047 | | bool failedShapeGuard_; |
1048 | | |
1049 | | // True if script->failedLexicalCheck_ is set for the current script or |
1050 | | // an outer script. |
1051 | | bool failedLexicalCheck_; |
1052 | | |
1053 | | #ifdef DEBUG |
1054 | | // If this script uses the lazy arguments object. |
1055 | | bool hasLazyArguments_; |
1056 | | #endif |
1057 | | |
1058 | | // If this is an inline builder, the call info for the builder. |
1059 | | const CallInfo* inlineCallInfo_; |
1060 | | |
1061 | | // When compiling a call with multiple targets, we are first creating a |
1062 | | // MGetPropertyCache. This MGetPropertyCache is following the bytecode, and |
1063 | | // is used to recover the JSFunction. In some cases, the Type of the object |
1064 | | // which own the property is enough for dispatching to the right function. |
1065 | | // In such cases we do not have read the property, except when the type |
1066 | | // object is unknown. |
1067 | | // |
1068 | | // As an optimization, we can dispatch a call based on the object group, |
1069 | | // without doing the MGetPropertyCache. This is what is achieved by |
1070 | | // |IonBuilder::inlineCalls|. As we might not know all the functions, we |
1071 | | // are adding a fallback path, where this MGetPropertyCache would be moved |
1072 | | // into. |
1073 | | // |
1074 | | // In order to build the fallback path, we have to capture a resume point |
1075 | | // ahead, for the potential fallback path. This resume point is captured |
1076 | | // while building MGetPropertyCache. It is capturing the state of Baseline |
1077 | | // before the execution of the MGetPropertyCache, such as we can safely do |
1078 | | // it in the fallback path. |
1079 | | // |
1080 | | // This field is used to discard the resume point if it is not used for |
1081 | | // building a fallback path. |
1082 | | |
1083 | | // Discard the prior resume point while setting a new MGetPropertyCache. |
1084 | | void replaceMaybeFallbackFunctionGetter(MGetPropertyCache* cache); |
1085 | | |
1086 | | // Discard the MGetPropertyCache if it is handled by WrapMGetPropertyCache. |
1087 | 14 | void keepFallbackFunctionGetter(MGetPropertyCache* cache) { |
1088 | 14 | if (cache == maybeFallbackFunctionGetter_) { |
1089 | 14 | maybeFallbackFunctionGetter_ = nullptr; |
1090 | 14 | } |
1091 | 14 | } |
1092 | | |
1093 | | MGetPropertyCache* maybeFallbackFunctionGetter_; |
1094 | | |
1095 | | bool needsPostBarrier(MDefinition* value); |
1096 | | |
1097 | | // Used in tracking outcomes of optimization strategies for devtools. |
1098 | | void startTrackingOptimizations(); |
1099 | | |
1100 | | // The track* methods below are called often. Do not combine them with the |
1101 | | // unchecked variants, despite the unchecked variants having no other |
1102 | | // callers. |
1103 | | void trackTypeInfo(JS::TrackedTypeSite site, MIRType mirType, |
1104 | | TemporaryTypeSet* typeSet) |
1105 | 98 | { |
1106 | 98 | if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations())) { |
1107 | 0 | trackTypeInfoUnchecked(site, mirType, typeSet); |
1108 | 0 | } |
1109 | 98 | } |
1110 | 14 | void trackTypeInfo(JS::TrackedTypeSite site, JSObject* obj) { |
1111 | 14 | if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations())) { |
1112 | 0 | trackTypeInfoUnchecked(site, obj); |
1113 | 0 | } |
1114 | 14 | } |
1115 | 0 | void trackTypeInfo(CallInfo& callInfo) { |
1116 | 0 | if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations())) { |
1117 | 0 | trackTypeInfoUnchecked(callInfo); |
1118 | 0 | } |
1119 | 0 | } |
1120 | 1.17k | void trackOptimizationAttempt(JS::TrackedStrategy strategy) { |
1121 | 1.17k | if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations())) { |
1122 | 0 | trackOptimizationAttemptUnchecked(strategy); |
1123 | 0 | } |
1124 | 1.17k | } |
1125 | 0 | void amendOptimizationAttempt(uint32_t index) { |
1126 | 0 | if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations())) { |
1127 | 0 | amendOptimizationAttemptUnchecked(index); |
1128 | 0 | } |
1129 | 0 | } |
1130 | 755 | void trackOptimizationOutcome(JS::TrackedOutcome outcome) { |
1131 | 755 | if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations())) { |
1132 | 0 | trackOptimizationOutcomeUnchecked(outcome); |
1133 | 0 | } |
1134 | 755 | } |
1135 | 51 | void trackOptimizationSuccess() { |
1136 | 51 | if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations())) { |
1137 | 0 | trackOptimizationSuccessUnchecked(); |
1138 | 0 | } |
1139 | 51 | } |
1140 | 14 | void trackInlineSuccess(InliningStatus status = InliningStatus_Inlined) { |
1141 | 14 | if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations())) { |
1142 | 0 | trackInlineSuccessUnchecked(status); |
1143 | 0 | } |
1144 | 14 | } |
1145 | | |
1146 | 84 | bool forceInlineCaches() { |
1147 | 84 | return MOZ_UNLIKELY(JitOptions.forceInlineCaches); |
1148 | 84 | } |
1149 | | |
1150 | | // Out-of-line variants that don't check if optimization tracking is |
1151 | | // enabled. |
1152 | | void trackTypeInfoUnchecked(JS::TrackedTypeSite site, MIRType mirType, |
1153 | | TemporaryTypeSet* typeSet); |
1154 | | void trackTypeInfoUnchecked(JS::TrackedTypeSite site, JSObject* obj); |
1155 | | void trackTypeInfoUnchecked(CallInfo& callInfo); |
1156 | | void trackOptimizationAttemptUnchecked(JS::TrackedStrategy strategy); |
1157 | | void amendOptimizationAttemptUnchecked(uint32_t index); |
1158 | | void trackOptimizationOutcomeUnchecked(JS::TrackedOutcome outcome); |
1159 | | void trackOptimizationSuccessUnchecked(); |
1160 | | void trackInlineSuccessUnchecked(InliningStatus status); |
1161 | | |
1162 | | public: |
1163 | | |
1164 | | // This is only valid for IonBuilders that have moved to background |
1165 | | size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; |
1166 | | }; |
1167 | | |
1168 | | class CallInfo |
1169 | | { |
1170 | | MDefinition* fun_; |
1171 | | MDefinition* thisArg_; |
1172 | | MDefinition* newTargetArg_; |
1173 | | MDefinitionVector args_; |
1174 | | // If non-empty, this corresponds to the stack prior any implicit inlining |
1175 | | // such as before JSOP_FUNAPPLY. |
1176 | | MDefinitionVector priorArgs_; |
1177 | | |
1178 | | bool constructing_:1; |
1179 | | |
1180 | | // True if the caller does not use the return value. |
1181 | | bool ignoresReturnValue_:1; |
1182 | | |
1183 | | bool setter_:1; |
1184 | | bool apply_:1; |
1185 | | |
1186 | | public: |
1187 | | CallInfo(TempAllocator& alloc, jsbytecode* pc, bool constructing, bool ignoresReturnValue) |
1188 | | : fun_(nullptr), |
1189 | | thisArg_(nullptr), |
1190 | | newTargetArg_(nullptr), |
1191 | | args_(alloc), |
1192 | | priorArgs_(alloc), |
1193 | | constructing_(constructing), |
1194 | | ignoresReturnValue_(ignoresReturnValue), |
1195 | | setter_(false), |
1196 | | apply_(JSOp(*pc) == JSOP_FUNAPPLY) |
1197 | 70 | { } |
1198 | | |
1199 | 0 | MOZ_MUST_USE bool init(CallInfo& callInfo) { |
1200 | 0 | MOZ_ASSERT(constructing_ == callInfo.constructing()); |
1201 | 0 |
|
1202 | 0 | fun_ = callInfo.fun(); |
1203 | 0 | thisArg_ = callInfo.thisArg(); |
1204 | 0 | ignoresReturnValue_ = callInfo.ignoresReturnValue(); |
1205 | 0 |
|
1206 | 0 | if (constructing()) { |
1207 | 0 | newTargetArg_ = callInfo.getNewTarget(); |
1208 | 0 | } |
1209 | 0 |
|
1210 | 0 | if (!args_.appendAll(callInfo.argv())) { |
1211 | 0 | return false; |
1212 | 0 | } |
1213 | 0 | |
1214 | 0 | return true; |
1215 | 0 | } |
1216 | | |
1217 | 70 | MOZ_MUST_USE bool init(MBasicBlock* current, uint32_t argc) { |
1218 | 70 | MOZ_ASSERT(args_.empty()); |
1219 | 70 | |
1220 | 70 | // Get the arguments in the right order |
1221 | 70 | if (!args_.reserve(argc)) { |
1222 | 0 | return false; |
1223 | 0 | } |
1224 | 70 | |
1225 | 70 | if (constructing()) { |
1226 | 0 | setNewTarget(current->pop()); |
1227 | 0 | } |
1228 | 70 | |
1229 | 126 | for (int32_t i = argc; i > 0; i--) { |
1230 | 56 | args_.infallibleAppend(current->peek(-i)); |
1231 | 56 | } |
1232 | 70 | current->popn(argc); |
1233 | 70 | |
1234 | 70 | // Get |this| and |fun| |
1235 | 70 | setThis(current->pop()); |
1236 | 70 | setFun(current->pop()); |
1237 | 70 | |
1238 | 70 | return true; |
1239 | 70 | } |
1240 | | |
1241 | | // Before doing any pop to the stack, capture whatever flows into the |
1242 | | // instruction, such that we can restore it later. |
1243 | | AbortReasonOr<Ok> savePriorCallStack(MIRGenerator* mir, MBasicBlock* current, size_t peekDepth); |
1244 | | |
1245 | 0 | void popPriorCallStack(MBasicBlock* current) { |
1246 | 0 | if (priorArgs_.empty()) { |
1247 | 0 | popCallStack(current); |
1248 | 0 | } else { |
1249 | 0 | current->popn(priorArgs_.length()); |
1250 | 0 | } |
1251 | 0 | } |
1252 | | |
1253 | 0 | AbortReasonOr<Ok> pushPriorCallStack(MIRGenerator* mir, MBasicBlock* current) { |
1254 | 0 | if (priorArgs_.empty()) { |
1255 | 0 | return pushCallStack(mir, current); |
1256 | 0 | } |
1257 | 0 | for (MDefinition* def : priorArgs_) { |
1258 | 0 | current->push(def); |
1259 | 0 | } |
1260 | 0 | return Ok(); |
1261 | 0 | } |
1262 | | |
1263 | 0 | void popCallStack(MBasicBlock* current) { |
1264 | 0 | current->popn(numFormals()); |
1265 | 0 | } |
1266 | | |
1267 | 0 | AbortReasonOr<Ok> pushCallStack(MIRGenerator* mir, MBasicBlock* current) { |
1268 | 0 | // Ensure sufficient space in the slots: needed for inlining from FUNAPPLY. |
1269 | 0 | if (apply_) { |
1270 | 0 | uint32_t depth = current->stackDepth() + numFormals(); |
1271 | 0 | if (depth > current->nslots()) { |
1272 | 0 | if (!current->increaseSlots(depth - current->nslots())) { |
1273 | 0 | return mir->abort(AbortReason::Alloc); |
1274 | 0 | } |
1275 | 0 | } |
1276 | 0 | } |
1277 | 0 | |
1278 | 0 | current->push(fun()); |
1279 | 0 | current->push(thisArg()); |
1280 | 0 |
|
1281 | 0 | for (uint32_t i = 0; i < argc(); i++) { |
1282 | 0 | current->push(getArg(i)); |
1283 | 0 | } |
1284 | 0 |
|
1285 | 0 | if (constructing()) { |
1286 | 0 | current->push(getNewTarget()); |
1287 | 0 | } |
1288 | 0 |
|
1289 | 0 | return Ok(); |
1290 | 0 | } |
1291 | | |
1292 | 280 | uint32_t argc() const { |
1293 | 280 | return args_.length(); |
1294 | 280 | } |
1295 | 0 | uint32_t numFormals() const { |
1296 | 0 | return argc() + 2 + constructing(); |
1297 | 0 | } |
1298 | | |
1299 | 0 | MOZ_MUST_USE bool setArgs(const MDefinitionVector& args) { |
1300 | 0 | MOZ_ASSERT(args_.empty()); |
1301 | 0 | return args_.appendAll(args); |
1302 | 0 | } |
1303 | | |
1304 | 0 | MDefinitionVector& argv() { |
1305 | 0 | return args_; |
1306 | 0 | } |
1307 | | |
1308 | 0 | const MDefinitionVector& argv() const { |
1309 | 0 | return args_; |
1310 | 0 | } |
1311 | | |
1312 | 56 | MDefinition* getArg(uint32_t i) const { |
1313 | 56 | MOZ_ASSERT(i < argc()); |
1314 | 56 | return args_[i]; |
1315 | 56 | } |
1316 | | |
1317 | 0 | MDefinition* getArgWithDefault(uint32_t i, MDefinition* defaultValue) const { |
1318 | 0 | if (i < argc()) { |
1319 | 0 | return args_[i]; |
1320 | 0 | } |
1321 | 0 |
|
1322 | 0 | return defaultValue; |
1323 | 0 | } |
1324 | | |
1325 | 0 | void setArg(uint32_t i, MDefinition* def) { |
1326 | 0 | MOZ_ASSERT(i < argc()); |
1327 | 0 | args_[i] = def; |
1328 | 0 | } |
1329 | | |
1330 | 98 | MDefinition* thisArg() const { |
1331 | 98 | MOZ_ASSERT(thisArg_); |
1332 | 98 | return thisArg_; |
1333 | 98 | } |
1334 | | |
1335 | 70 | void setThis(MDefinition* thisArg) { |
1336 | 70 | thisArg_ = thisArg; |
1337 | 70 | } |
1338 | | |
1339 | 392 | bool constructing() const { |
1340 | 392 | return constructing_; |
1341 | 392 | } |
1342 | | |
1343 | 70 | bool ignoresReturnValue() const { |
1344 | 70 | return ignoresReturnValue_; |
1345 | 70 | } |
1346 | | |
1347 | 0 | void setNewTarget(MDefinition* newTarget) { |
1348 | 0 | MOZ_ASSERT(constructing()); |
1349 | 0 | newTargetArg_ = newTarget; |
1350 | 0 | } |
1351 | 0 | MDefinition* getNewTarget() const { |
1352 | 0 | MOZ_ASSERT(newTargetArg_); |
1353 | 0 | return newTargetArg_; |
1354 | 0 | } |
1355 | | |
1356 | 0 | bool isSetter() const { |
1357 | 0 | return setter_; |
1358 | 0 | } |
1359 | 0 | void markAsSetter() { |
1360 | 0 | setter_ = true; |
1361 | 0 | } |
1362 | | |
1363 | 98 | MDefinition* fun() const { |
1364 | 98 | MOZ_ASSERT(fun_); |
1365 | 98 | return fun_; |
1366 | 98 | } |
1367 | | |
1368 | 84 | void setFun(MDefinition* fun) { |
1369 | 84 | fun_ = fun; |
1370 | 84 | } |
1371 | | |
1372 | 0 | void setImplicitlyUsedUnchecked() { |
1373 | 0 | fun_->setImplicitlyUsedUnchecked(); |
1374 | 0 | thisArg_->setImplicitlyUsedUnchecked(); |
1375 | 0 | if (newTargetArg_) { |
1376 | 0 | newTargetArg_->setImplicitlyUsedUnchecked(); |
1377 | 0 | } |
1378 | 0 | for (uint32_t i = 0; i < argc(); i++) { |
1379 | 0 | getArg(i)->setImplicitlyUsedUnchecked(); |
1380 | 0 | } |
1381 | 0 | } |
1382 | | }; |
1383 | | |
1384 | | } // namespace jit |
1385 | | } // namespace js |
1386 | | |
1387 | | #endif /* jit_IonBuilder_h */ |