OptionalEmitter.cpp (3885B)
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 #include "frontend/OptionalEmitter.h" 8 9 #include "frontend/BytecodeEmitter.h" 10 #include "frontend/IfEmitter.h" // IfEmitter, InternalIfEmitter, CondEmitter 11 #include "vm/Opcodes.h" 12 13 using namespace js; 14 using namespace js::frontend; 15 16 OptionalEmitter::OptionalEmitter(BytecodeEmitter* bce, int32_t initialDepth) 17 : bce_(bce), tdzCache_(bce), initialDepth_(initialDepth) {} 18 19 bool OptionalEmitter::emitJumpShortCircuit() { 20 MOZ_ASSERT(state_ == State::Start || state_ == State::ShortCircuit || 21 state_ == State::ShortCircuitForCall); 22 MOZ_ASSERT(initialDepth_ + 1 == bce_->bytecodeSection().stackDepth()); 23 24 if (!bce_->emit1(JSOp::IsNullOrUndefined)) { 25 // [stack] OBJ NULL-OR-UNDEF 26 return false; 27 } 28 if (!bce_->emitJump(JSOp::JumpIfTrue, &jumpShortCircuit_)) { 29 // [stack] OBJ 30 return false; 31 } 32 33 #ifdef DEBUG 34 state_ = State::ShortCircuit; 35 #endif 36 return true; 37 } 38 39 bool OptionalEmitter::emitJumpShortCircuitForCall() { 40 MOZ_ASSERT(state_ == State::Start || state_ == State::ShortCircuit || 41 state_ == State::ShortCircuitForCall); 42 int32_t depth = bce_->bytecodeSection().stackDepth(); 43 MOZ_ASSERT(initialDepth_ + 2 == depth); 44 if (!bce_->emit1(JSOp::Swap)) { 45 // [stack] THIS CALLEE 46 return false; 47 } 48 49 InternalIfEmitter ifEmitter(bce_); 50 if (!bce_->emit1(JSOp::IsNullOrUndefined)) { 51 // [stack] THIS CALLEE NULL-OR-UNDEF 52 return false; 53 } 54 55 if (!ifEmitter.emitThen()) { 56 // [stack] THIS CALLEE 57 return false; 58 } 59 60 if (!bce_->emit1(JSOp::Pop)) { 61 // [stack] THIS 62 return false; 63 } 64 65 if (!bce_->emitJump(JSOp::Goto, &jumpShortCircuit_)) { 66 // [stack] THIS 67 return false; 68 } 69 70 if (!ifEmitter.emitEnd()) { 71 return false; 72 } 73 74 bce_->bytecodeSection().setStackDepth(depth); 75 76 if (!bce_->emit1(JSOp::Swap)) { 77 // [stack] THIS CALLEE 78 return false; 79 } 80 #ifdef DEBUG 81 state_ = State::ShortCircuitForCall; 82 #endif 83 return true; 84 } 85 86 bool OptionalEmitter::emitOptionalJumpTarget(JSOp op, 87 Kind kind /* = Kind::Other */) { 88 #ifdef DEBUG 89 int32_t depth = bce_->bytecodeSection().stackDepth(); 90 #endif 91 MOZ_ASSERT(state_ == State::ShortCircuit || 92 state_ == State::ShortCircuitForCall); 93 94 // if we get to this point, it means that the optional chain did not short 95 // circuit, so we should skip the short circuiting bytecode. 96 if (!bce_->emitJump(JSOp::Goto, &jumpFinish_)) { 97 // [stack] RESULT 98 return false; 99 } 100 101 if (!bce_->emitJumpTargetAndPatch(jumpShortCircuit_)) { 102 // [stack] # if call 103 // [stack] THIS 104 // [stack] # otherwise 105 // [stack] OBJ 106 return false; 107 } 108 109 // reset stack depth to the depth when we jumped 110 bce_->bytecodeSection().setStackDepth(initialDepth_ + 1); 111 112 if (!bce_->emit1(JSOp::Pop)) { 113 // [stack] 114 return false; 115 } 116 117 if (!bce_->emit1(op)) { 118 // [stack] JSOP 119 return false; 120 } 121 122 if (kind == Kind::Reference) { 123 if (!bce_->emit1(op)) { 124 // [stack] JSOP JSOP 125 return false; 126 } 127 } 128 129 MOZ_ASSERT(depth == bce_->bytecodeSection().stackDepth()); 130 131 if (!bce_->emitJumpTargetAndPatch(jumpFinish_)) { 132 // [stack] # if call 133 // [stack] CALLEE THIS 134 // [stack] # otherwise 135 // [stack] VAL 136 return false; 137 } 138 #ifdef DEBUG 139 state_ = State::JumpEnd; 140 #endif 141 return true; 142 }