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