1/*
2 * Copyright (C) 2015-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#if ENABLE(B3_JIT)
29
30#include "AirGenerationContext.h"
31#include "B3ValueRep.h"
32#include "CCallHelpers.h"
33#include "RegisterSet.h"
34#include <wtf/Box.h>
35
36namespace JSC { namespace B3 {
37
38class CheckSpecial;
39class PatchpointSpecial;
40class Procedure;
41class StackmapValue;
42
43// NOTE: It's possible to capture StackmapGenerationParams by value, but not all of the methods will
44// work if you do that.
45class StackmapGenerationParams {
46public:
47 // This is the stackmap value that we're generating.
48 StackmapValue* value() const { return m_value; }
49
50 // This tells you the actual value representations that were chosen. This is usually different
51 // from the constraints we supplied.
52 const Vector<ValueRep>& reps() const { return m_reps; };
53
54 // Usually we wish to access the reps. We make this easy by making ourselves appear to be a
55 // collection of reps.
56 unsigned size() const { return m_reps.size(); }
57 const ValueRep& at(unsigned index) const { return m_reps[index]; }
58 const ValueRep& operator[](unsigned index) const { return at(index); }
59 Vector<ValueRep>::const_iterator begin() const { return m_reps.begin(); }
60 Vector<ValueRep>::const_iterator end() const { return m_reps.end(); }
61
62 // This tells you the registers that were used.
63 // NOTE: This will report bogus information if you did proc.setNeedsUsedRegisters(false).
64 const RegisterSet& usedRegisters() const;
65
66 // This is a useful helper if you want to do register allocation inside of a patchpoint. The
67 // usedRegisters() set is not directly useful for this purpose because:
68 //
69 // - You can only use callee-save registers for scratch if they were saved in the prologue. So,
70 // if a register is callee-save, it's not enough that it's not in usedRegisters().
71 //
72 // - Scratch registers are going to be in usedRegisters() at the patchpoint. So, if you want to
73 // find one of your requested scratch registers using usedRegisters(), you'll have a bad time.
74 //
75 // This gives you the used register set that's useful for allocating scratch registers. This set
76 // is defined as:
77 //
78 // (usedRegisters() | (RegisterSet::calleeSaveRegisters() - proc.calleeSaveRegisters()))
79 // - gpScratchRegisters - fpScratchRegisters
80 //
81 // I.e. it is like usedRegisters() but also includes unsaved callee-saves and excludes scratch
82 // registers.
83 //
84 // NOTE: This will report bogus information if you did proc.setNeedsUsedRegisters(false).
85 JS_EXPORT_PRIVATE RegisterSet unavailableRegisters() const;
86
87 GPRReg gpScratch(unsigned index) const { return m_gpScratch[index]; }
88 FPRReg fpScratch(unsigned index) const { return m_fpScratch[index]; }
89
90 // This is computed lazily, so it won't work if you capture StackmapGenerationParams by value.
91 // These labels will get populated before any late paths or link tasks execute.
92 JS_EXPORT_PRIVATE Vector<Box<CCallHelpers::Label>> successorLabels() const;
93
94 // This is computed lazily, so it won't work if you capture StackmapGenerationParams by value.
95 // Returns true if the successor at the given index is going to be emitted right after the
96 // patchpoint.
97 JS_EXPORT_PRIVATE bool fallsThroughToSuccessor(unsigned successorIndex) const;
98
99 // This is provided for convenience; it means that you don't have to capture it if you don't want to.
100 JS_EXPORT_PRIVATE Procedure& proc() const;
101
102 // The Air::GenerationContext gives you even more power.
103 Air::GenerationContext& context() const { return m_context; };
104
105 template<typename Functor>
106 void addLatePath(const Functor& functor) const
107 {
108 context().latePaths.append(
109 createSharedTask<Air::GenerationContext::LatePathFunction>(
110 [=] (CCallHelpers& jit, Air::GenerationContext&) {
111 functor(jit);
112 }));
113 }
114
115private:
116 friend class CheckSpecial;
117 friend class PatchpointSpecial;
118
119 StackmapGenerationParams(StackmapValue*, const Vector<ValueRep>& reps, Air::GenerationContext&);
120
121 StackmapValue* m_value;
122 Vector<ValueRep> m_reps;
123 Vector<GPRReg> m_gpScratch;
124 Vector<FPRReg> m_fpScratch;
125 Air::GenerationContext& m_context;
126};
127
128} } // namespace JSC::B3
129
130#endif // ENABLE(B3_JIT)
131