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