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  * 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 frontend_PropOpEmitter_h
8 #define frontend_PropOpEmitter_h
9 
10 #include "mozilla/Attributes.h"
11 
12 #include <stdint.h>
13 
14 #include "frontend/ParserAtom.h"  // TaggedParserAtomIndex
15 #include "js/TypeDecls.h"
16 #include "vm/SharedStencil.h"  // GCThingIndex
17 
18 namespace js {
19 namespace frontend {
20 
21 struct BytecodeEmitter;
22 
23 // Class for emitting bytecode for property operation.
24 //
25 // Usage: (check for the return value is omitted for simplicity)
26 //
27 //   `obj.prop;`
28 //     PropOpEmitter poe(this,
29 //                       PropOpEmitter::Kind::Get,
30 //                       PropOpEmitter::ObjKind::Other);
31 //     poe.prepareForObj();
32 //     emit(obj);
33 //     poe.emitGet(atom_of_prop);
34 //
35 //   `super.prop;`
36 //     PropOpEmitter poe(this,
37 //                       PropOpEmitter::Kind::Get,
38 //                       PropOpEmitter::ObjKind::Super);
39 //     poe.prepareForObj();
40 //     emit(obj);
41 //     poe.emitGet(atom_of_prop);
42 //
43 //   `obj.prop();`
44 //     PropOpEmitter poe(this,
45 //                       PropOpEmitter::Kind::Call,
46 //                       PropOpEmitter::ObjKind::Other);
47 //     poe.prepareForObj();
48 //     emit(obj);
49 //     poe.emitGet(atom_of_prop);
50 //     emit_call_here();
51 //
52 //   `new obj.prop();`
53 //     PropOpEmitter poe(this,
54 //                       PropOpEmitter::Kind::Call,
55 //                       PropOpEmitter::ObjKind::Other);
56 //     poe.prepareForObj();
57 //     emit(obj);
58 //     poe.emitGet(atom_of_prop);
59 //     emit_call_here();
60 //
61 //   `delete obj.prop;`
62 //     PropOpEmitter poe(this,
63 //                       PropOpEmitter::Kind::Delete,
64 //                       PropOpEmitter::ObjKind::Other);
65 //     poe.prepareForObj();
66 //     emit(obj);
67 //     poe.emitDelete(atom_of_prop);
68 //
69 //   `delete super.prop;`
70 //     PropOpEmitter poe(this,
71 //                       PropOpEmitter::Kind::Delete,
72 //                       PropOpEmitter::ObjKind::Other);
73 //     poe.emitDelete(atom_of_prop);
74 //
75 //   `obj.prop++;`
76 //     PropOpEmitter poe(this,
77 //                       PropOpEmitter::Kind::PostIncrement,
78 //                       PropOpEmitter::ObjKind::Other);
79 //     poe.prepareForObj();
80 //     emit(obj);
81 //     poe.emitIncDec(atom_of_prop);
82 //
83 //   `obj.prop = value;`
84 //     PropOpEmitter poe(this,
85 //                       PropOpEmitter::Kind::SimpleAssignment,
86 //                       PropOpEmitter::ObjKind::Other);
87 //     poe.prepareForObj();
88 //     emit(obj);
89 //     poe.prepareForRhs();
90 //     emit(value);
91 //     poe.emitAssignment(atom_of_prop);
92 //
93 //   `obj.prop += value;`
94 //     PropOpEmitter poe(this,
95 //                       PropOpEmitter::Kind::CompoundAssignment,
96 //                       PropOpEmitter::ObjKind::Other);
97 //     poe.prepareForObj();
98 //     emit(obj);
99 //     poe.emitGet(atom_of_prop);
100 //     poe.prepareForRhs();
101 //     emit(value);
102 //     emit_add_op_here();
103 //     poe.emitAssignment(nullptr); // nullptr for CompoundAssignment
104 //
105 class MOZ_STACK_CLASS PropOpEmitter {
106  public:
107   enum class Kind {
108     Get,
109     Call,
110     Delete,
111     PostIncrement,
112     PreIncrement,
113     PostDecrement,
114     PreDecrement,
115     SimpleAssignment,
116     PropInit,
117     CompoundAssignment
118   };
119   enum class ObjKind { Super, Other };
120 
121  private:
122   BytecodeEmitter* bce_;
123 
124   Kind kind_;
125   ObjKind objKind_;
126 
127   // The index for the property name's atom.
128   GCThingIndex propAtomIndex_;
129 
130 #ifdef DEBUG
131   // The state of this emitter.
132   //
133   //             skipObjAndRhs
134   //           +----------------------------+
135   //           |                            |
136   // +-------+ | prepareForObj +-----+      |
137   // | Start |-+-------------->| Obj |-+    |
138   // +-------+                 +-----+ |    |
139   //                                   |    |
140   // +---------------------------------+    |
141   // |                                      |
142   // |                                      |
143   // | [Get]                                |
144   // | [Call]                               |
145   // |   emitGet +-----+                    |
146   // +---------->| Get |                    |
147   // |           +-----+                    |
148   // |                                      |
149   // | [Delete]                             |
150   // |   emitDelete +--------+              |
151   // +------------->| Delete |              |
152   // |              +--------+              |
153   // |                                      |
154   // | [PostIncrement]                      |
155   // | [PreIncrement]                       |
156   // | [PostDecrement]                      |
157   // | [PreDecrement]                       |
158   // |   emitIncDec +--------+              |
159   // +------------->| IncDec |              |
160   // |              +--------+              |
161   // |                                      |
162   // | [SimpleAssignment]                   |
163   // | [PropInit]                           |
164   // |                        prepareForRhs |  +-----+
165   // +--------------------->+-------------->+->| Rhs |-+
166   // |                      ^                  +-----+ |
167   // |                      |                          |
168   // |                      |                +---------+
169   // | [CompoundAssignment] |                |
170   // |   emitGet +-----+    |                | emitAssignment +------------+
171   // +---------->| Get |----+                + -------------->| Assignment |
172   //             +-----+                                      +------------+
173   enum class State {
174     // The initial state.
175     Start,
176 
177     // After calling prepareForObj.
178     Obj,
179 
180     // After calling emitGet.
181     Get,
182 
183     // After calling emitDelete.
184     Delete,
185 
186     // After calling emitIncDec.
187     IncDec,
188 
189     // After calling prepareForRhs or skipObjAndRhs.
190     Rhs,
191 
192     // After calling emitAssignment.
193     Assignment,
194   };
195   State state_ = State::Start;
196 #endif
197 
198  public:
199   PropOpEmitter(BytecodeEmitter* bce, Kind kind, ObjKind objKind);
200 
201  private:
isCall()202   [[nodiscard]] bool isCall() const { return kind_ == Kind::Call; }
203 
isSuper()204   [[nodiscard]] bool isSuper() const { return objKind_ == ObjKind::Super; }
205 
isSimpleAssignment()206   [[nodiscard]] bool isSimpleAssignment() const {
207     return kind_ == Kind::SimpleAssignment;
208   }
209 
isPropInit()210   [[nodiscard]] bool isPropInit() const { return kind_ == Kind::PropInit; }
211 
isDelete()212   [[nodiscard]] bool isDelete() const { return kind_ == Kind::Delete; }
213 
isCompoundAssignment()214   [[nodiscard]] bool isCompoundAssignment() const {
215     return kind_ == Kind::CompoundAssignment;
216   }
217 
isIncDec()218   [[nodiscard]] bool isIncDec() const {
219     return isPostIncDec() || isPreIncDec();
220   }
221 
isPostIncDec()222   [[nodiscard]] bool isPostIncDec() const {
223     return kind_ == Kind::PostIncrement || kind_ == Kind::PostDecrement;
224   }
225 
isPreIncDec()226   [[nodiscard]] bool isPreIncDec() const {
227     return kind_ == Kind::PreIncrement || kind_ == Kind::PreDecrement;
228   }
229 
isInc()230   [[nodiscard]] bool isInc() const {
231     return kind_ == Kind::PostIncrement || kind_ == Kind::PreIncrement;
232   }
233 
234   [[nodiscard]] bool prepareAtomIndex(TaggedParserAtomIndex prop);
235 
236  public:
237   [[nodiscard]] bool prepareForObj();
238 
239   [[nodiscard]] bool emitGet(TaggedParserAtomIndex prop);
240 
241   [[nodiscard]] bool prepareForRhs();
242   [[nodiscard]] bool skipObjAndRhs();
243 
244   [[nodiscard]] bool emitDelete(TaggedParserAtomIndex prop);
245 
246   // `prop` can be nullptr for CompoundAssignment.
247   [[nodiscard]] bool emitAssignment(TaggedParserAtomIndex prop);
248 
249   [[nodiscard]] bool emitIncDec(TaggedParserAtomIndex prop);
250 };
251 
252 } /* namespace frontend */
253 } /* namespace js */
254 
255 #endif /* frontend_PropOpEmitter_h */
256