NameOpEmitter.h (5164B)
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_NameOpEmitter_h 8 #define frontend_NameOpEmitter_h 9 10 #include "mozilla/Attributes.h" 11 12 #include <stddef.h> 13 14 #include "frontend/NameAnalysisTypes.h" 15 #include "frontend/ParserAtom.h" // TaggedParserAtomIndex 16 #include "vm/SharedStencil.h" // GCThingIndex 17 18 namespace js { 19 namespace frontend { 20 21 struct BytecodeEmitter; 22 enum class ValueUsage; 23 24 // Class for emitting bytecode for name operation. 25 // 26 // Usage: (check for the return value is omitted for simplicity) 27 // 28 // `name;` 29 // NameOpEmitter noe(this, atom_of_name 30 // NameOpEmitter::Kind::Get); 31 // noe.emitGet(); 32 // 33 // `name();` 34 // this is handled in CallOrNewEmitter 35 // 36 // `name++;` 37 // NameOpEmitter noe(this, atom_of_name 38 // NameOpEmitter::Kind::PostIncrement); 39 // noe.emitIncDec(); 40 // 41 // `name = 10;` 42 // NameOpEmitter noe(this, atom_of_name 43 // NameOpEmitter::Kind::SimpleAssignment); 44 // noe.prepareForRhs(); 45 // emit(10); 46 // noe.emitAssignment(); 47 // 48 // `name += 10;` 49 // NameOpEmitter noe(this, atom_of_name 50 // NameOpEmitter::Kind::CompoundAssignment); 51 // noe.prepareForRhs(); 52 // emit(10); 53 // emit_add_op_here(); 54 // noe.emitAssignment(); 55 // 56 // `name = 10;` part of `let name = 10;` 57 // NameOpEmitter noe(this, atom_of_name 58 // NameOpEmitter::Kind::Initialize); 59 // noe.prepareForRhs(); 60 // emit(10); 61 // noe.emitAssignment(); 62 // 63 class MOZ_STACK_CLASS NameOpEmitter { 64 public: 65 enum class Kind { 66 Get, 67 Call, 68 PostIncrement, 69 PreIncrement, 70 PostDecrement, 71 PreDecrement, 72 SimpleAssignment, 73 CompoundAssignment, 74 Initialize 75 }; 76 77 private: 78 BytecodeEmitter* bce_; 79 80 Kind kind_; 81 82 bool emittedBindOp_ = false; 83 84 TaggedParserAtomIndex name_; 85 86 GCThingIndex atomIndex_; 87 88 NameLocation loc_; 89 90 #ifdef DEBUG 91 // The state of this emitter. 92 // 93 // [Get] 94 // [Call] 95 // +-------+ emitGet +-----+ 96 // | Start |-+-+--------->| Get | 97 // +-------+ | +-----+ 98 // | 99 // | [PostIncrement] 100 // | [PreIncrement] 101 // | [PostDecrement] 102 // | [PreDecrement] 103 // | emitIncDec +--------+ 104 // +------------->| IncDec | 105 // | +--------+ 106 // | 107 // | [SimpleAssignment] 108 // | prepareForRhs +-----+ 109 // +--------------------->+-------------->| Rhs |-+ 110 // | ^ +-----+ | 111 // | | | 112 // | | +------------------+ 113 // | [CompoundAssignment] | | 114 // | emitGet +-----+ | | emitAssignment +------------+ 115 // +---------->| Get |----+ + -------------->| Assignment | 116 // +-----+ +------------+ 117 enum class State { 118 // The initial state. 119 Start, 120 121 // After calling emitGet. 122 Get, 123 124 // After calling emitIncDec. 125 IncDec, 126 127 // After calling prepareForRhs. 128 Rhs, 129 130 // After calling emitAssignment. 131 Assignment, 132 }; 133 State state_ = State::Start; 134 #endif 135 136 public: 137 NameOpEmitter(BytecodeEmitter* bce, TaggedParserAtomIndex name, Kind kind); 138 NameOpEmitter(BytecodeEmitter* bce, TaggedParserAtomIndex name, 139 const NameLocation& loc, Kind kind); 140 141 private: 142 [[nodiscard]] bool isCall() const { return kind_ == Kind::Call; } 143 144 [[nodiscard]] bool isSimpleAssignment() const { 145 return kind_ == Kind::SimpleAssignment; 146 } 147 148 [[nodiscard]] bool isCompoundAssignment() const { 149 return kind_ == Kind::CompoundAssignment; 150 } 151 152 [[nodiscard]] bool isIncDec() const { 153 return isPostIncDec() || isPreIncDec(); 154 } 155 156 [[nodiscard]] bool isPostIncDec() const { 157 return kind_ == Kind::PostIncrement || kind_ == Kind::PostDecrement; 158 } 159 160 [[nodiscard]] bool isPreIncDec() const { 161 return kind_ == Kind::PreIncrement || kind_ == Kind::PreDecrement; 162 } 163 164 [[nodiscard]] bool isInc() const { 165 return kind_ == Kind::PostIncrement || kind_ == Kind::PreIncrement; 166 } 167 168 [[nodiscard]] bool isInitialize() const { return kind_ == Kind::Initialize; } 169 170 JSOp strictifySetNameOp(JSOp op) const; 171 172 public: 173 [[nodiscard]] bool emittedBindOp() const { return emittedBindOp_; } 174 175 [[nodiscard]] const NameLocation& loc() const { return loc_; } 176 177 [[nodiscard]] bool emitGet(); 178 [[nodiscard]] bool prepareForRhs(); 179 [[nodiscard]] bool emitAssignment(); 180 [[nodiscard]] bool emitIncDec(ValueUsage valueUsage); 181 182 size_t numReferenceSlots() const { return emittedBindOp(); } 183 }; 184 185 } /* namespace frontend */ 186 } /* namespace js */ 187 188 #endif /* frontend_NameOpEmitter_h */