Harden how the compiler references GC objects
[WebKit.git] / Source / JavaScriptCore / ftl / FTLOutput.h
1 /*
2  * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #pragma once
27
28 #include "DFGCommon.h"
29
30 #if ENABLE(FTL_JIT)
31
32 #include "B3BasicBlockInlines.h"
33 #include "B3CCallValue.h"
34 #include "B3Compilation.h"
35 #include "B3FrequentedBlock.h"
36 #include "B3Procedure.h"
37 #include "B3SwitchValue.h"
38 #include "FTLAbbreviatedTypes.h"
39 #include "FTLAbstractHeapRepository.h"
40 #include "FTLCommonValues.h"
41 #include "FTLState.h"
42 #include "FTLSwitchCase.h"
43 #include "FTLTypedPointer.h"
44 #include "FTLValueFromBlock.h"
45 #include "FTLWeight.h"
46 #include "FTLWeightedTarget.h"
47 #include "HeapCell.h"
48 #include <wtf/OrderMaker.h>
49 #include <wtf/StringPrintStream.h>
50
51 // FIXME: remove this once everything can be generated through B3.
52 #if COMPILER(GCC_OR_CLANG)
53 #pragma GCC diagnostic push
54 #pragma GCC diagnostic ignored "-Wmissing-noreturn"
55 #pragma GCC diagnostic ignored "-Wunused-parameter"
56 #endif // COMPILER(GCC_OR_CLANG)
57
58 namespace JSC {
59
60 namespace DFG {
61 struct Node;
62 } // namespace DFG
63
64 namespace B3 {
65 class FenceValue;
66 class SlotBaseValue;
67 } // namespace B3
68
69 namespace FTL {
70
71 enum Scale { ScaleOne, ScaleTwo, ScaleFour, ScaleEight, ScalePtr };
72
73 class Output : public CommonValues {
74 public:
75     Output(State&);
76     ~Output();
77
78     void initialize(AbstractHeapRepository&);
79
80     void setFrequency(double value)
81     {
82         m_frequency = value;
83     }
84
85     LBasicBlock newBlock();
86
87     LBasicBlock insertNewBlocksBefore(LBasicBlock nextBlock)
88     {
89         LBasicBlock lastNextBlock = m_nextBlock;
90         m_nextBlock = nextBlock;
91         return lastNextBlock;
92     }
93
94     void applyBlockOrder();
95
96     LBasicBlock appendTo(LBasicBlock, LBasicBlock nextBlock);
97     void appendTo(LBasicBlock);
98
99     void setOrigin(DFG::Node* node) { m_origin = node; }
100     B3::Origin origin() { return B3::Origin(m_origin); }
101
102     LValue framePointer();
103
104     B3::SlotBaseValue* lockedStackSlot(size_t bytes);
105
106     LValue constBool(bool value);
107     LValue constInt32(int32_t value);
108
109     LValue weakPointer(DFG::Graph& graph, JSCell* cell)
110     {
111         ASSERT(graph.m_plan.weakReferences.contains(cell));
112
113         if (sizeof(void*) == 8)
114             return constInt64(bitwise_cast<intptr_t>(cell));
115         return constInt32(bitwise_cast<intptr_t>(cell));
116     }
117
118     LValue weakPointer(DFG::FrozenValue* value)
119     {
120         RELEASE_ASSERT(value->value().isCell());
121
122         if (sizeof(void*) == 8)
123             return constInt64(bitwise_cast<intptr_t>(value->cell()));
124         return constInt32(bitwise_cast<intptr_t>(value->cell()));
125     }
126
127     template<typename T>
128     LValue constIntPtr(T* value)
129     {
130         static_assert(!std::is_base_of<HeapCell, T>::value, "To use a GC pointer, the graph must be aware of it. Use gcPointer instead and make sure the graph is aware of this reference.");
131         if (sizeof(void*) == 8)
132             return constInt64(bitwise_cast<intptr_t>(value));
133         return constInt32(bitwise_cast<intptr_t>(value));
134     }
135     template<typename T>
136     LValue constIntPtr(T value)
137     {
138         if (sizeof(void*) == 8)
139             return constInt64(static_cast<intptr_t>(value));
140         return constInt32(static_cast<intptr_t>(value));
141     }
142     LValue constInt64(int64_t value);
143     LValue constDouble(double value);
144
145     LValue phi(LType);
146     template<typename... Params>
147     LValue phi(LType, ValueFromBlock, Params... theRest);
148     template<typename VectorType>
149     LValue phi(LType, const VectorType&);
150     void addIncomingToPhi(LValue phi, ValueFromBlock);
151     template<typename... Params>
152     void addIncomingToPhi(LValue phi, ValueFromBlock, Params... theRest);
153
154     LValue add(LValue, LValue);
155     LValue sub(LValue, LValue);
156     LValue mul(LValue, LValue);
157     LValue div(LValue, LValue);
158     LValue chillDiv(LValue, LValue);
159     LValue mod(LValue, LValue);
160     LValue chillMod(LValue, LValue);
161     LValue neg(LValue);
162
163     LValue doubleAdd(LValue, LValue);
164     LValue doubleSub(LValue, LValue);
165     LValue doubleMul(LValue, LValue);
166     LValue doubleDiv(LValue, LValue);
167     LValue doubleMod(LValue, LValue);
168     LValue doubleNeg(LValue value) { return neg(value); }
169
170     LValue bitAnd(LValue, LValue);
171     LValue bitOr(LValue, LValue);
172     LValue bitXor(LValue, LValue);
173     LValue shl(LValue, LValue shiftAmount);
174     LValue aShr(LValue, LValue shiftAmount);
175     LValue lShr(LValue, LValue shiftAmount);
176     LValue bitNot(LValue);
177     LValue logicalNot(LValue);
178
179     LValue ctlz32(LValue);
180     LValue doubleAbs(LValue);
181     LValue doubleCeil(LValue);
182     LValue doubleFloor(LValue);
183     LValue doubleTrunc(LValue);
184
185     LValue doubleSin(LValue);
186     LValue doubleCos(LValue);
187     LValue doubleTan(LValue);
188
189     LValue doublePow(LValue base, LValue exponent);
190     LValue doublePowi(LValue base, LValue exponent);
191
192     LValue doubleSqrt(LValue);
193
194     LValue doubleLog(LValue);
195
196     static bool hasSensibleDoubleToInt();
197     LValue doubleToInt(LValue);
198     LValue doubleToUInt(LValue);
199
200     LValue signExt32To64(LValue);
201     LValue signExt32ToPtr(LValue);
202     LValue zeroExt(LValue, LType);
203     LValue zeroExtPtr(LValue value) { return zeroExt(value, B3::Int64); }
204     LValue intToDouble(LValue);
205     LValue unsignedToDouble(LValue);
206     LValue castToInt32(LValue);
207     LValue doubleToFloat(LValue);
208     LValue floatToDouble(LValue);
209     LValue bitCast(LValue, LType);
210     LValue fround(LValue);
211
212     LValue load(TypedPointer, LType);
213     void store(LValue, TypedPointer);
214     B3::FenceValue* fence(const AbstractHeap* read, const AbstractHeap* write);
215
216     LValue load8SignExt32(TypedPointer);
217     LValue load8ZeroExt32(TypedPointer);
218     LValue load16SignExt32(TypedPointer);
219     LValue load16ZeroExt32(TypedPointer);
220     LValue load32(TypedPointer pointer) { return load(pointer, B3::Int32); }
221     LValue load64(TypedPointer pointer) { return load(pointer, B3::Int64); }
222     LValue loadPtr(TypedPointer pointer) { return load(pointer, B3::pointerType()); }
223     LValue loadFloat(TypedPointer pointer) { return load(pointer, B3::Float); }
224     LValue loadDouble(TypedPointer pointer) { return load(pointer, B3::Double); }
225     void store32As8(LValue, TypedPointer);
226     void store32As16(LValue, TypedPointer);
227     void store32(LValue value, TypedPointer pointer)
228     {
229         ASSERT(value->type() == B3::Int32);
230         store(value, pointer);
231     }
232     void store64(LValue value, TypedPointer pointer)
233     {
234         ASSERT(value->type() == B3::Int64);
235         store(value, pointer);
236     }
237     void storePtr(LValue value, TypedPointer pointer)
238     {
239         ASSERT(value->type() == B3::pointerType());
240         store(value, pointer);
241     }
242     void storeFloat(LValue value, TypedPointer pointer)
243     {
244         ASSERT(value->type() == B3::Float);
245         store(value, pointer);
246     }
247     void storeDouble(LValue value, TypedPointer pointer)
248     {
249         ASSERT(value->type() == B3::Double);
250         store(value, pointer);
251     }
252
253     enum LoadType {
254         Load8SignExt32,
255         Load8ZeroExt32,
256         Load16SignExt32,
257         Load16ZeroExt32,
258         Load32,
259         Load64,
260         LoadPtr,
261         LoadFloat,
262         LoadDouble
263     };
264
265     LValue load(TypedPointer, LoadType);
266     
267     enum StoreType {
268         Store32As8,
269         Store32As16,
270         Store32,
271         Store64,
272         StorePtr,
273         StoreFloat,
274         StoreDouble
275     };
276
277     void store(LValue, TypedPointer, StoreType);
278
279     LValue addPtr(LValue value, ptrdiff_t immediate = 0)
280     {
281         if (!immediate)
282             return value;
283         return add(value, constIntPtr(immediate));
284     }
285
286     // Construct an address by offsetting base by the requested amount and ascribing
287     // the requested abstract heap to it.
288     TypedPointer address(const AbstractHeap& heap, LValue base, ptrdiff_t offset = 0)
289     {
290         return TypedPointer(heap, addPtr(base, offset));
291     }
292     // Construct an address by offsetting base by the amount specified by the field,
293     // and optionally an additional amount (use this with care), and then creating
294     // a TypedPointer with the given field as the heap.
295     TypedPointer address(LValue base, const AbstractHeap& field, ptrdiff_t offset = 0)
296     {
297         return address(field, base, offset + field.offset());
298     }
299
300     LValue baseIndex(LValue base, LValue index, Scale, ptrdiff_t offset = 0);
301
302     TypedPointer baseIndex(const AbstractHeap& heap, LValue base, LValue index, Scale scale, ptrdiff_t offset = 0)
303     {
304         return TypedPointer(heap, baseIndex(base, index, scale, offset));
305     }
306     TypedPointer baseIndex(IndexedAbstractHeap& heap, LValue base, LValue index, JSValue indexAsConstant = JSValue(), ptrdiff_t offset = 0)
307     {
308         return heap.baseIndex(*this, base, index, indexAsConstant, offset);
309     }
310
311     TypedPointer absolute(const void* address);
312
313     LValue load8SignExt32(LValue base, const AbstractHeap& field) { return load8SignExt32(address(base, field)); }
314     LValue load8ZeroExt32(LValue base, const AbstractHeap& field) { return load8ZeroExt32(address(base, field)); }
315     LValue load16SignExt32(LValue base, const AbstractHeap& field) { return load16SignExt32(address(base, field)); }
316     LValue load16ZeroExt32(LValue base, const AbstractHeap& field) { return load16ZeroExt32(address(base, field)); }
317     LValue load32(LValue base, const AbstractHeap& field) { return load32(address(base, field)); }
318     LValue load64(LValue base, const AbstractHeap& field) { return load64(address(base, field)); }
319     LValue loadPtr(LValue base, const AbstractHeap& field) { return loadPtr(address(base, field)); }
320     LValue loadDouble(LValue base, const AbstractHeap& field) { return loadDouble(address(base, field)); }
321     void store32(LValue value, LValue base, const AbstractHeap& field) { store32(value, address(base, field)); }
322     void store64(LValue value, LValue base, const AbstractHeap& field) { store64(value, address(base, field)); }
323     void storePtr(LValue value, LValue base, const AbstractHeap& field) { storePtr(value, address(base, field)); }
324     void storeDouble(LValue value, LValue base, const AbstractHeap& field) { storeDouble(value, address(base, field)); }
325
326     // FIXME: Explore adding support for value range constraints to B3. Maybe it could be as simple as having
327     // a load instruction that guarantees that its result is non-negative.
328     // https://bugs.webkit.org/show_bug.cgi?id=151458
329     void ascribeRange(LValue, const ValueRange&) { }
330     LValue nonNegative32(LValue loadInstruction) { return loadInstruction; }
331     LValue load32NonNegative(TypedPointer pointer) { return load32(pointer); }
332     LValue load32NonNegative(LValue base, const AbstractHeap& field) { return load32(base, field); }
333
334     LValue equal(LValue, LValue);
335     LValue notEqual(LValue, LValue);
336     LValue above(LValue, LValue);
337     LValue aboveOrEqual(LValue, LValue);
338     LValue below(LValue, LValue);
339     LValue belowOrEqual(LValue, LValue);
340     LValue greaterThan(LValue, LValue);
341     LValue greaterThanOrEqual(LValue, LValue);
342     LValue lessThan(LValue, LValue);
343     LValue lessThanOrEqual(LValue, LValue);
344
345     LValue doubleEqual(LValue, LValue);
346     LValue doubleEqualOrUnordered(LValue, LValue);
347     LValue doubleNotEqualOrUnordered(LValue, LValue);
348     LValue doubleLessThan(LValue, LValue);
349     LValue doubleLessThanOrEqual(LValue, LValue);
350     LValue doubleGreaterThan(LValue, LValue);
351     LValue doubleGreaterThanOrEqual(LValue, LValue);
352     LValue doubleNotEqualAndOrdered(LValue, LValue);
353     LValue doubleLessThanOrUnordered(LValue, LValue);
354     LValue doubleLessThanOrEqualOrUnordered(LValue, LValue);
355     LValue doubleGreaterThanOrUnordered(LValue, LValue);
356     LValue doubleGreaterThanOrEqualOrUnordered(LValue, LValue);
357
358     LValue isZero32(LValue);
359     LValue notZero32(LValue);
360     LValue isZero64(LValue);
361     LValue notZero64(LValue);
362     LValue isNull(LValue value) { return isZero64(value); }
363     LValue notNull(LValue value) { return notZero64(value); }
364
365     LValue testIsZero32(LValue value, LValue mask) { return isZero32(bitAnd(value, mask)); }
366     LValue testNonZero32(LValue value, LValue mask) { return notZero32(bitAnd(value, mask)); }
367     LValue testIsZero64(LValue value, LValue mask) { return isZero64(bitAnd(value, mask)); }
368     LValue testNonZero64(LValue value, LValue mask) { return notZero64(bitAnd(value, mask)); }
369     LValue testIsZeroPtr(LValue value, LValue mask) { return isNull(bitAnd(value, mask)); }
370     LValue testNonZeroPtr(LValue value, LValue mask) { return notNull(bitAnd(value, mask)); }
371
372     LValue select(LValue value, LValue taken, LValue notTaken);
373
374     template<typename VectorType>
375     LValue call(LType type, LValue function, const VectorType& vector)
376     {
377         B3::CCallValue* result = m_block->appendNew<B3::CCallValue>(m_proc, type, origin(), function);
378         result->children().appendVector(vector);
379         return result;
380     }
381     LValue call(LType type, LValue function) { return m_block->appendNew<B3::CCallValue>(m_proc, type, origin(), function); }
382     LValue call(LType type, LValue function, LValue arg1) { return m_block->appendNew<B3::CCallValue>(m_proc, type, origin(), function, arg1); }
383     template<typename... Args>
384     LValue call(LType type, LValue function, LValue arg1, Args... args) { return m_block->appendNew<B3::CCallValue>(m_proc, type, origin(), function, arg1, args...); }
385
386     template<typename Function, typename... Args>
387     LValue callWithoutSideEffects(B3::Type type, Function function, LValue arg1, Args... args)
388     {
389         return m_block->appendNew<B3::CCallValue>(m_proc, type, origin(), B3::Effects::none(),
390             constIntPtr(bitwise_cast<void*>(function)), arg1, args...);
391     }
392
393     template<typename FunctionType>
394     LValue operation(FunctionType function) { return constIntPtr(bitwise_cast<void*>(function)); }
395
396     void jump(LBasicBlock);
397     void branch(LValue condition, LBasicBlock taken, Weight takenWeight, LBasicBlock notTaken, Weight notTakenWeight);
398     void branch(LValue condition, WeightedTarget taken, WeightedTarget notTaken)
399     {
400         branch(condition, taken.target(), taken.weight(), notTaken.target(), notTaken.weight());
401     }
402
403     // Branches to an already-created handler if true, "falls through" if false. Fall-through is
404     // simulated by creating a continuation for you.
405     void check(LValue condition, WeightedTarget taken, Weight notTakenWeight);
406     
407     // Same as check(), but uses Weight::inverse() to compute the notTakenWeight.
408     void check(LValue condition, WeightedTarget taken);
409     
410     template<typename VectorType>
411     void switchInstruction(LValue value, const VectorType& cases, LBasicBlock fallThrough, Weight fallThroughWeight)
412     {
413         B3::SwitchValue* switchValue = m_block->appendNew<B3::SwitchValue>(m_proc, origin(), value);
414         switchValue->setFallThrough(B3::FrequentedBlock(fallThrough));
415         for (const SwitchCase& switchCase : cases) {
416             int64_t value = switchCase.value()->asInt();
417             B3::FrequentedBlock target(switchCase.target(), switchCase.weight().frequencyClass());
418             switchValue->appendCase(B3::SwitchCase(value, target));
419         }
420     }
421
422     void ret(LValue);
423
424     void unreachable();
425     
426     void appendSuccessor(WeightedTarget);
427
428     B3::CheckValue* speculate(LValue);
429     B3::CheckValue* speculateAdd(LValue, LValue);
430     B3::CheckValue* speculateSub(LValue, LValue);
431     B3::CheckValue* speculateMul(LValue, LValue);
432
433     B3::PatchpointValue* patchpoint(LType);
434
435     void trap();
436
437     ValueFromBlock anchor(LValue);
438
439     void incrementSuperSamplerCount();
440     void decrementSuperSamplerCount();
441
442 #if PLATFORM(COCOA)
443 #pragma mark - States
444 #endif
445     B3::Procedure& m_proc;
446
447     DFG::Node* m_origin { nullptr };
448     LBasicBlock m_block { nullptr };
449     LBasicBlock m_nextBlock { nullptr };
450
451     AbstractHeapRepository* m_heaps;
452
453     double m_frequency { 1 };
454
455 private:
456     OrderMaker<LBasicBlock> m_blockOrder;
457 };
458
459 template<typename... Params>
460 inline LValue Output::phi(LType type, ValueFromBlock value, Params... theRest)
461 {
462     LValue phiNode = phi(type);
463     addIncomingToPhi(phiNode, value, theRest...);
464     return phiNode;
465 }
466
467 template<typename VectorType>
468 inline LValue Output::phi(LType type, const VectorType& vector)
469 {
470     LValue phiNode = phi(type);
471     for (const ValueFromBlock& valueFromBlock : vector)
472         addIncomingToPhi(phiNode, valueFromBlock);
473     return phiNode;
474 }
475
476 template<typename... Params>
477 inline void Output::addIncomingToPhi(LValue phi, ValueFromBlock value, Params... theRest)
478 {
479     addIncomingToPhi(phi, value);
480     addIncomingToPhi(phi, theRest...);
481 }
482
483 #if COMPILER(GCC_OR_CLANG)
484 #pragma GCC diagnostic pop
485 #endif // COMPILER(GCC_OR_CLANG)
486
487 } } // namespace JSC::FTL
488
489 #endif // ENABLE(FTL_JIT)