tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }