CallOrNewEmitter.h (12806B)
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_CallOrNewEmitter_h 8 #define frontend_CallOrNewEmitter_h 9 10 #include "mozilla/Attributes.h" 11 #include "mozilla/Maybe.h" 12 13 #include <stdint.h> 14 15 #include "frontend/ElemOpEmitter.h" 16 #include "frontend/IfEmitter.h" 17 #include "frontend/PrivateOpEmitter.h" 18 #include "frontend/PropOpEmitter.h" 19 #include "frontend/ValueUsage.h" 20 #include "vm/BytecodeUtil.h" 21 #include "vm/Opcodes.h" 22 23 namespace js { 24 namespace frontend { 25 26 struct BytecodeEmitter; 27 class TaggedParserAtomIndex; 28 29 // Class for emitting bytecode for call or new expression. 30 // 31 // Usage: (check for the return value is omitted for simplicity) 32 // 33 // `print(arg);` 34 // CallOrNewEmitter cone(this, JSOp::Call, 35 // CallOrNewEmitter::ArgumentsKind::Other, 36 // ValueUsage::WantValue); 37 // cone.emitNameCallee(print); 38 // cone.emitThis(); 39 // cone.prepareForNonSpreadArguments(); 40 // emit(arg); 41 // cone.emitEnd(1, offset_of_callee); 42 // 43 // `callee.prop(arg1, arg2);` 44 // CallOrNewEmitter cone(this, JSOp::Call, 45 // CallOrNewEmitter::ArgumentsKind::Other, 46 // ValueUsage::WantValue); 47 // PropOpEmitter& poe = cone.prepareForPropCallee(false); 48 // ... emit `callee.prop` with `poe` here... 49 // cone.emitThis(); 50 // cone.prepareForNonSpreadArguments(); 51 // emit(arg1); 52 // emit(arg2); 53 // cone.emitEnd(2, offset_of_callee); 54 // 55 // `callee[key](arg);` 56 // CallOrNewEmitter cone(this, JSOp::Call, 57 // CallOrNewEmitter::ArgumentsKind::Other, 58 // ValueUsage::WantValue); 59 // ElemOpEmitter& eoe = cone.prepareForElemCallee(false); 60 // ... emit `callee[key]` with `eoe` here... 61 // cone.emitThis(); 62 // cone.prepareForNonSpreadArguments(); 63 // emit(arg); 64 // cone.emitEnd(1, offset_of_callee); 65 // 66 // `callee.#method(arg);` 67 // CallOrNewEmitter cone(this, JSOp::Call, 68 // CallOrNewEmitter::ArgumentsKind::Other, 69 // ValueUsage::WantValue); 70 // PrivateOpEmitter& xoe = cone.prepareForPrivateCallee(); 71 // ... emit `callee.#method` with `xoe` here... 72 // cone.prepareForNonSpreadArguments(); 73 // emit(arg); 74 // cone.emitEnd(1, offset_of_callee); 75 // 76 // `(function() { ... })(arg);` 77 // CallOrNewEmitter cone(this, JSOp::Call, 78 // CallOrNewEmitter::ArgumentsKind::Other, 79 // ValueUsage::WantValue); 80 // cone.prepareForFunctionCallee(); 81 // emit(function); 82 // cone.emitThis(); 83 // cone.prepareForNonSpreadArguments(); 84 // emit(arg); 85 // cone.emitEnd(1, offset_of_callee); 86 // 87 // `super(arg);` 88 // CallOrNewEmitter cone(this, JSOp::Call, 89 // CallOrNewEmitter::ArgumentsKind::Other, 90 // ValueUsage::WantValue); 91 // cone.emitSuperCallee(); 92 // cone.emitThis(); 93 // cone.prepareForNonSpreadArguments(); 94 // emit(arg); 95 // cone.emitEnd(1, offset_of_callee); 96 // 97 // `(some_other_expression)(arg);` 98 // CallOrNewEmitter cone(this, JSOp::Call, 99 // CallOrNewEmitter::ArgumentsKind::Other, 100 // ValueUsage::WantValue); 101 // cone.prepareForOtherCallee(); 102 // emit(some_other_expression); 103 // cone.emitThis(); 104 // cone.prepareForNonSpreadArguments(); 105 // emit(arg); 106 // cone.emitEnd(1, offset_of_callee); 107 // 108 // `print(...arg);` 109 // CallOrNewEmitter cone(this, JSOp::SpreadCall, 110 // CallOrNewEmitter::ArgumentsKind::SingleSpread, 111 // ValueUsage::WantValue); 112 // cone.emitNameCallee(print); 113 // cone.emitThis(); 114 // if (cone.wantSpreadOperand()) { 115 // emit(arg) 116 // } 117 // cone.emitSpreadArgumentsTest(); 118 // emit([...arg]); 119 // cone.emitEnd(1, offset_of_callee); 120 // 121 // `new f(arg);` 122 // CallOrNewEmitter cone(this, JSOp::New, 123 // CallOrNewEmitter::ArgumentsKind::Other, 124 // ValueUsage::WantValue); 125 // cone.emitNameCallee(f); 126 // cone.emitThis(); 127 // cone.prepareForNonSpreadArguments(); 128 // emit(arg); 129 // cone.emitEnd(1, offset_of_callee); 130 // 131 class MOZ_STACK_CLASS CallOrNewEmitter { 132 public: 133 enum class ArgumentsKind { 134 Other, 135 136 // Specify this for the following case: 137 // 138 // g(...input); 139 // 140 // This enables optimization to avoid allocating an intermediate array 141 // for spread operation. 142 // 143 // wantSpreadOperand() returns true when this is specified. 144 SingleSpread, 145 146 // Used for default derived class constructors: 147 // 148 // constructor(...args) { 149 // super(...args); 150 // } 151 // 152 // The rest-parameter is directly passed through to the `super` call without 153 // using the iteration protocol. 154 PassthroughRest, 155 }; 156 157 private: 158 BytecodeEmitter* bce_; 159 160 // The opcode for the call or new. 161 JSOp op_; 162 163 // Whether the call is a spread call with single parameter or not. 164 // See the comment in emitSpreadArgumentsTest for more details. 165 ArgumentsKind argumentsKind_; 166 167 // The branch for spread call optimization. 168 mozilla::Maybe<InternalIfEmitter> ifNotOptimizable_; 169 170 mozilla::Maybe<PropOpEmitter> poe_; 171 mozilla::Maybe<ElemOpEmitter> eoe_; 172 mozilla::Maybe<PrivateOpEmitter> xoe_; 173 174 // The state of this emitter. 175 // 176 // +-------+ emitNameCallee +------------+ 177 // | Start |-+------------------------->| NameCallee |------+ 178 // +-------+ | +------------+ | 179 // | | 180 // | prepareForPropCallee +------------+ v 181 // +------------------------->| PropCallee |----->+ 182 // | +------------+ | 183 // | | 184 // | prepareForElemCallee +------------+ v 185 // +------------------------->| ElemCallee |----->+ 186 // | +------------+ | 187 // | | 188 // | prepareForPrivateCallee +---------------+ v 189 // +------------------------->| PrivateCallee |-->+ 190 // | +---------------+ | 191 // | | 192 // | prepareForFunctionCallee +----------------+ v 193 // +------------------------->| FunctionCallee |->+ 194 // | +----------------+ | 195 // | | 196 // | emitSuperCallee +-------------+ v 197 // +------------------------->| SuperCallee |---->+ 198 // | +-------------+ | 199 // | | 200 // | prepareForOtherCallee +-------------+ v 201 // +------------------------->| OtherCallee |---->+ 202 // +-------------+ | 203 // | 204 // +--------------------------------------------------------+ 205 // | 206 // | emitThis +------+ 207 // +--------->| This |-+ 208 // +------+ | 209 // | 210 // +-------------------+ 211 // | 212 // | [!isSpread] 213 // | prepareForNonSpreadArguments +-----------+ emitEnd +-----+ 214 // +------------------------------->+->| Arguments |-------->| End | 215 // | ^ +-----------+ +-----+ 216 // | | 217 // | +<------------------------------------+ 218 // | | | 219 // | | emitSpreadArgumentsTestEnd | 220 // | | | 221 // | | +-----------------+ | 222 // | +---------| SpreadIteration |------+ | 223 // | +-----------------+ | | 224 // | +----------------------------------+ | 225 // | | | 226 // | | wantSpreadIteration | 227 // | | | 228 // | | +---------------------+ | 229 // | +---------| SpreadArgumentsTest |--+ | 230 // | +---------------------+ | | 231 // | [isSpread] | | 232 // | wantSpreadOperand +-------------------+ emitSpreadArgumentsTest | | 233 // +-------------------->| WantSpreadOperand |-------------------------+ | 234 // | +-------------------+ | 235 // | | 236 // | | 237 // | | 238 // | [isSpread] | 239 // | prepareForSpreadArguments | 240 // +----------------------------------------------------------------------+ 241 enum class State { 242 // The initial state. 243 Start, 244 245 // After calling emitNameCallee. 246 NameCallee, 247 248 // After calling prepareForPropCallee. 249 PropCallee, 250 251 // After calling prepareForElemCallee. 252 ElemCallee, 253 254 // After calling prepareForPrivateCallee. 255 PrivateCallee, 256 257 // After calling prepareForFunctionCallee. 258 FunctionCallee, 259 260 // After calling emitSuperCallee. 261 SuperCallee, 262 263 // After calling prepareForOtherCallee. 264 OtherCallee, 265 266 // After calling emitThis. 267 This, 268 269 // After calling wantSpreadOperand. 270 WantSpreadOperand, 271 272 // After calling emitSpreadArgumentsTest. 273 SpreadArgumentsTest, 274 275 // After calling wantSpreadIteration. 276 SpreadIteration, 277 278 // After calling prepareForNonSpreadArguments. 279 Arguments, 280 281 // After calling emitEnd. 282 End 283 }; 284 State state_ = State::Start; 285 286 public: 287 CallOrNewEmitter(BytecodeEmitter* bce, JSOp op, ArgumentsKind argumentsKind, 288 ValueUsage valueUsage); 289 290 private: 291 [[nodiscard]] bool isCall() const { 292 return op_ == JSOp::Call || op_ == JSOp::CallIgnoresRv || 293 op_ == JSOp::SpreadCall || isEval(); 294 } 295 296 [[nodiscard]] bool isNew() const { 297 return op_ == JSOp::New || op_ == JSOp::SpreadNew; 298 } 299 300 [[nodiscard]] bool isSuperCall() const { 301 return op_ == JSOp::SuperCall || op_ == JSOp::SpreadSuperCall; 302 } 303 304 [[nodiscard]] bool isEval() const { 305 return op_ == JSOp::Eval || op_ == JSOp::StrictEval || 306 op_ == JSOp::SpreadEval || op_ == JSOp::StrictSpreadEval; 307 } 308 309 [[nodiscard]] bool isSpread() const { return IsSpreadOp(op_); } 310 311 [[nodiscard]] bool isSingleSpread() const { 312 return argumentsKind_ == ArgumentsKind::SingleSpread; 313 } 314 315 [[nodiscard]] bool isPassthroughRest() const { 316 return argumentsKind_ == ArgumentsKind::PassthroughRest; 317 } 318 319 public: 320 [[nodiscard]] bool emitNameCallee(TaggedParserAtomIndex name); 321 [[nodiscard]] PropOpEmitter& prepareForPropCallee(bool isSuperProp); 322 [[nodiscard]] ElemOpEmitter& prepareForElemCallee(bool isSuperElem); 323 [[nodiscard]] PrivateOpEmitter& prepareForPrivateCallee( 324 TaggedParserAtomIndex privateName); 325 [[nodiscard]] bool prepareForFunctionCallee(); 326 [[nodiscard]] bool emitSuperCallee(); 327 [[nodiscard]] bool prepareForOtherCallee(); 328 329 [[nodiscard]] bool emitThis(); 330 331 [[nodiscard]] bool prepareForNonSpreadArguments(); 332 [[nodiscard]] bool prepareForSpreadArguments(); 333 334 // See the usage in the comment at the top of the class. 335 [[nodiscard]] bool wantSpreadOperand(); 336 [[nodiscard]] bool emitSpreadArgumentsTest(); 337 [[nodiscard]] bool emitSpreadArgumentsTestEnd(); 338 [[nodiscard]] bool wantSpreadIteration(); 339 340 // Parameters are the offset in the source code for each character below: 341 // 342 // callee(arg); 343 // ^ 344 // | 345 // beginPos 346 [[nodiscard]] bool emitEnd(uint32_t argc, uint32_t beginPos); 347 }; 348 349 } /* namespace frontend */ 350 } /* namespace js */ 351 352 #endif /* frontend_CallOrNewEmitter_h */