PrivateOpEmitter.h (6972B)
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_PrivateOpEmitter_h 8 #define frontend_PrivateOpEmitter_h 9 10 #include "mozilla/Attributes.h" 11 #include "mozilla/Maybe.h" 12 13 #include <stddef.h> 14 15 #include "frontend/NameAnalysisTypes.h" // NameLocation 16 #include "frontend/ParserAtom.h" // TaggedParserAtomIndex 17 18 namespace js { 19 namespace frontend { 20 21 struct BytecodeEmitter; 22 enum class ValueUsage; 23 24 // Class for emitting bytecode for operations on private members of objects. 25 // 26 // Usage is similar to PropOpEmitter, but the name of the private member must 27 // be passed to the constructor; prepare*() methods aren't necessary; and 28 // `delete obj.#member` and `super.#member` aren't supported because both are 29 // SyntaxErrors. 30 // 31 // Usage: (error checking is omitted for simplicity) 32 // 33 // `obj.#member;` 34 // PrivateOpEmitter xoe(this, 35 // privateName, 36 // PrivateOpEmitter::Kind::Get); 37 // emit(obj); 38 // xoe.emitReference(); 39 // xoe.emitGet(); 40 // 41 // `obj.#member();` 42 // PrivateOpEmitter xoe(this, 43 // privateName, 44 // PrivateOpEmitter::Kind::Call); 45 // emit(obj); 46 // xoe.emitReference(); 47 // xoe.emitGet(); 48 // emit_call_here(); 49 // 50 // `new obj.#member();` 51 // The same, but use PrivateOpEmitter::Kind::Get. 52 // 53 // `obj.#field++;` 54 // PrivateOpEmitter xoe(this, 55 // privateName, 56 // PrivateOpEmitter::Kind::PostIncrement); 57 // emit(obj); 58 // xoe.emitReference(); 59 // xoe.emitIncDec(); 60 // 61 // `obj.#field = value;` 62 // PrivateOpEmitter xoe(this, 63 // privateName, 64 // PrivateOpEmitter::Kind::SimpleAssignment); 65 // emit(obj); 66 // xoe.emitReference(); 67 // emit(value); 68 // xoe.emitAssignment(); 69 // 70 // `obj.#field += value;` 71 // PrivateOpEmitter xoe(this, 72 // privateName, 73 // PrivateOpEmitter::Kind::CompoundAssignment); 74 // emit(obj); 75 // xoe.emitReference(); 76 // emit(JSOp::Dup2); 77 // xoe.emitGet(); 78 // emit(value); 79 // emit_add_op_here(); 80 // xoe.emitAssignment(); 81 // 82 class MOZ_STACK_CLASS PrivateOpEmitter { 83 public: 84 enum class Kind { 85 Get, 86 Call, 87 Delete, 88 PostIncrement, 89 PreIncrement, 90 PostDecrement, 91 PreDecrement, 92 SimpleAssignment, 93 PropInit, 94 CompoundAssignment, 95 ErgonomicBrandCheck, 96 }; 97 98 private: 99 BytecodeEmitter* bce_; 100 101 Kind kind_; 102 103 // Name of the private member, e.g. "#field". 104 TaggedParserAtomIndex name_; 105 106 // Location of the slot containing the private name symbol; or, for a 107 // non-static private method, the slot containing the method. 108 mozilla::Maybe<NameLocation> loc_; 109 110 // For non-static private method accesses, the location of the relevant 111 // `.privateBrand` binding. Otherwise, `Nothing`. 112 mozilla::Maybe<NameLocation> brandLoc_{}; 113 114 #ifdef DEBUG 115 // The state of this emitter. 116 // 117 // +-------+ emitReference +-----------+ 118 // | Start |---------------->| Reference | 119 // +-------+ +-----+-----+ 120 // | 121 // +---------------------------+ 122 // | 123 // | 124 // | [Get] 125 // | emitGet 126 // | [Call] [Get] [CompoundAssignment] 127 // | emitGetForCallOrNew +-----+ emitAssignment 128 // +---------------------->| Get |-------------------+ 129 // | +-----+ | 130 // | [PostIncrement] | 131 // | [PreIncrement] | 132 // | [PostDecrement] | 133 // | [PreDecrement] | 134 // | emitIncDec | 135 // +------------------------------------------------>+ 136 // | | 137 // | [SimpleAssignment] | 138 // | [PropInit] V 139 // | emitAssignment +------------+ 140 // +------------------------------------------>| Assignment | 141 // +------------+ 142 enum class State { 143 // The initial state. 144 Start, 145 146 // After calling emitReference. 147 Reference, 148 149 // After calling emitGet. 150 Get, 151 152 // After calling emitAssignment or emitIncDec. 153 Assignment, 154 }; 155 State state_ = State::Start; 156 #endif 157 158 public: 159 PrivateOpEmitter(BytecodeEmitter* bce, Kind kind, TaggedParserAtomIndex name); 160 161 private: 162 [[nodiscard]] bool isCall() const { return kind_ == Kind::Call; } 163 164 [[nodiscard]] bool isSimpleAssignment() const { 165 return kind_ == Kind::SimpleAssignment; 166 } 167 168 [[nodiscard]] bool isFieldInit() const { return kind_ == Kind::PropInit; } 169 170 [[nodiscard]] bool isBrandCheck() const { 171 return kind_ == Kind::ErgonomicBrandCheck; 172 } 173 174 [[nodiscard]] bool isCompoundAssignment() const { 175 return kind_ == Kind::CompoundAssignment; 176 } 177 178 [[nodiscard]] bool isIncDec() const { 179 return isPostIncDec() || isPreIncDec(); 180 } 181 182 [[nodiscard]] bool isPostIncDec() const { 183 return kind_ == Kind::PostIncrement || kind_ == Kind::PostDecrement; 184 } 185 186 [[nodiscard]] bool isPreIncDec() const { 187 return kind_ == Kind::PreIncrement || kind_ == Kind::PreDecrement; 188 } 189 190 [[nodiscard]] bool isInc() const { 191 return kind_ == Kind::PostIncrement || kind_ == Kind::PreIncrement; 192 } 193 194 [[nodiscard]] bool init(); 195 196 // Emit a GetAliasedLexical or similar instruction. 197 [[nodiscard]] bool emitLoad(TaggedParserAtomIndex name, 198 const NameLocation& loc); 199 200 [[nodiscard]] bool emitLoadPrivateBrand(); 201 202 public: 203 // Emit bytecode to check for the presence/absence of a private field/brand. 204 // 205 // Given OBJ KEY on the stack, where KEY is a private name symbol, the 206 // emitted code will throw if OBJ does not have the given KEY. 207 // 208 // If `isFieldInit()`, the check is reversed: the code will throw if OBJ 209 // already has the KEY. 210 // 211 // If `isBrandCheck()`, the check verifies RHS is an object (throwing if not). 212 // 213 // The bytecode leaves OBJ KEY BOOL on the stack. Caller is responsible for 214 // consuming or popping it. 215 [[nodiscard]] bool emitBrandCheck(); 216 217 [[nodiscard]] bool emitReference(); 218 [[nodiscard]] bool emitGet(); 219 [[nodiscard]] bool emitGetForCallOrNew(); 220 [[nodiscard]] bool emitAssignment(); 221 [[nodiscard]] bool emitIncDec(ValueUsage valueUsage); 222 223 size_t numReferenceSlots() const { return 2; } 224 }; 225 226 } /* namespace frontend */ 227 } /* namespace js */ 228 229 #endif /* frontend_PrivateOpEmitter_h */