tor-browser

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

PropOpEmitter.cpp (6339B)


      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/PropOpEmitter.h"
      8 
      9 #include "frontend/BytecodeEmitter.h"
     10 #include "frontend/ParserAtom.h"  // ParserAtom
     11 #include "frontend/SharedContext.h"
     12 #include "vm/Opcodes.h"
     13 #include "vm/ThrowMsgKind.h"  // ThrowMsgKind
     14 
     15 using namespace js;
     16 using namespace js::frontend;
     17 
     18 PropOpEmitter::PropOpEmitter(BytecodeEmitter* bce, Kind kind, ObjKind objKind)
     19    : bce_(bce), kind_(kind), objKind_(objKind) {}
     20 
     21 bool PropOpEmitter::prepareAtomIndex(TaggedParserAtomIndex prop) {
     22  return bce_->makeAtomIndex(prop, ParserAtom::Atomize::Yes, &propAtomIndex_);
     23 }
     24 
     25 bool PropOpEmitter::prepareForObj() {
     26  MOZ_ASSERT(state_ == State::Start);
     27 
     28 #ifdef DEBUG
     29  state_ = State::Obj;
     30 #endif
     31  return true;
     32 }
     33 
     34 bool PropOpEmitter::emitGet(TaggedParserAtomIndex prop) {
     35  MOZ_ASSERT(state_ == State::Obj);
     36 
     37  if (!prepareAtomIndex(prop)) {
     38    return false;
     39  }
     40  if (isCall()) {
     41    if (!bce_->emit1(JSOp::Dup)) {
     42      //            [stack] # if Super
     43      //            [stack] THIS THIS
     44      //            [stack] # otherwise
     45      //            [stack] OBJ OBJ
     46      return false;
     47    }
     48  }
     49  if (isSuper()) {
     50    if (!bce_->emitSuperBase()) {
     51      //            [stack] THIS? THIS SUPERBASE
     52      return false;
     53    }
     54  }
     55  if (isIncDec() || isCompoundAssignment()) {
     56    if (isSuper()) {
     57      if (!bce_->emit1(JSOp::Dup2)) {
     58        //          [stack] THIS SUPERBASE THIS SUPERBASE
     59        return false;
     60      }
     61    } else {
     62      if (!bce_->emit1(JSOp::Dup)) {
     63        //          [stack] OBJ OBJ
     64        return false;
     65      }
     66    }
     67  }
     68 
     69  JSOp op = isSuper() ? JSOp::GetPropSuper : JSOp::GetProp;
     70  if (!bce_->emitAtomOp(op, propAtomIndex_)) {
     71    //              [stack] # if Get
     72    //              [stack] PROP
     73    //              [stack] # if Call
     74    //              [stack] THIS PROP
     75    //              [stack] # if Inc/Dec/Compound, Super]
     76    //              [stack] THIS SUPERBASE PROP
     77    //              [stack] # if Inc/Dec/Compound, other
     78    //              [stack] OBJ PROP
     79    return false;
     80  }
     81  if (isCall()) {
     82    if (!bce_->emit1(JSOp::Swap)) {
     83      //            [stack] PROP THIS
     84      return false;
     85    }
     86  }
     87 
     88 #ifdef DEBUG
     89  state_ = State::Get;
     90 #endif
     91  return true;
     92 }
     93 
     94 bool PropOpEmitter::prepareForRhs() {
     95  MOZ_ASSERT(isSimpleAssignment() || isPropInit() || isCompoundAssignment());
     96  MOZ_ASSERT_IF(isSimpleAssignment() || isPropInit(), state_ == State::Obj);
     97  MOZ_ASSERT_IF(isCompoundAssignment(), state_ == State::Get);
     98 
     99  if (isSimpleAssignment() || isPropInit()) {
    100    // For CompoundAssignment, SuperBase is already emitted by emitGet.
    101    if (isSuper()) {
    102      if (!bce_->emitSuperBase()) {
    103        //          [stack] THIS SUPERBASE
    104        return false;
    105      }
    106    }
    107  }
    108 
    109 #ifdef DEBUG
    110  state_ = State::Rhs;
    111 #endif
    112  return true;
    113 }
    114 
    115 bool PropOpEmitter::emitDelete(TaggedParserAtomIndex prop) {
    116  MOZ_ASSERT(state_ == State::Obj);
    117  MOZ_ASSERT(isDelete());
    118 
    119  if (!prepareAtomIndex(prop)) {
    120    return false;
    121  }
    122  if (isSuper()) {
    123    if (!bce_->emitSuperBase()) {
    124      //            [stack] THIS SUPERBASE
    125      return false;
    126    }
    127 
    128    // Unconditionally throw when attempting to delete a super-reference.
    129    if (!bce_->emit2(JSOp::ThrowMsg, uint8_t(ThrowMsgKind::CantDeleteSuper))) {
    130      //            [stack] THIS SUPERBASE
    131      return false;
    132    }
    133 
    134    // Another wrinkle: Balance the stack from the emitter's point of view.
    135    // Execution will not reach here, as the last bytecode threw.
    136    if (!bce_->emit1(JSOp::Pop)) {
    137      //            [stack] THIS
    138      return false;
    139    }
    140  } else {
    141    JSOp op = bce_->sc->strict() ? JSOp::StrictDelProp : JSOp::DelProp;
    142    if (!bce_->emitAtomOp(op, propAtomIndex_)) {
    143      //            [stack] SUCCEEDED
    144      return false;
    145    }
    146  }
    147 
    148 #ifdef DEBUG
    149  state_ = State::Delete;
    150 #endif
    151  return true;
    152 }
    153 
    154 bool PropOpEmitter::emitAssignment(TaggedParserAtomIndex prop) {
    155  MOZ_ASSERT(isSimpleAssignment() || isPropInit() || isCompoundAssignment());
    156  MOZ_ASSERT(state_ == State::Rhs);
    157 
    158  if (isSimpleAssignment() || isPropInit()) {
    159    if (!prepareAtomIndex(prop)) {
    160      return false;
    161    }
    162  }
    163 
    164  MOZ_ASSERT_IF(isPropInit(), !isSuper());
    165  JSOp setOp = isPropInit() ? JSOp::InitProp
    166               : isSuper()  ? bce_->sc->strict() ? JSOp::StrictSetPropSuper
    167                                                 : JSOp::SetPropSuper
    168               : bce_->sc->strict() ? JSOp::StrictSetProp
    169                                    : JSOp::SetProp;
    170  if (!bce_->emitAtomOp(setOp, propAtomIndex_)) {
    171    //              [stack] VAL
    172    return false;
    173  }
    174 
    175 #ifdef DEBUG
    176  state_ = State::Assignment;
    177 #endif
    178  return true;
    179 }
    180 
    181 bool PropOpEmitter::emitIncDec(TaggedParserAtomIndex prop,
    182                               ValueUsage valueUsage) {
    183  MOZ_ASSERT(state_ == State::Obj);
    184  MOZ_ASSERT(isIncDec());
    185 
    186  if (!emitGet(prop)) {
    187    return false;
    188  }
    189 
    190  MOZ_ASSERT(state_ == State::Get);
    191 
    192  JSOp incOp = isInc() ? JSOp::Inc : JSOp::Dec;
    193 
    194  if (!bce_->emit1(JSOp::ToNumeric)) {
    195    //              [stack] ... N
    196    return false;
    197  }
    198  if (isPostIncDec() && valueUsage == ValueUsage::WantValue) {
    199    //              [stack] OBJ SUPERBASE? N
    200    if (!bce_->emit1(JSOp::Dup)) {
    201      //            [stack] .. N N
    202      return false;
    203    }
    204    if (!bce_->emit2(JSOp::Unpick, 2 + isSuper())) {
    205      //            [stack] N OBJ SUPERBASE? N
    206      return false;
    207    }
    208  }
    209  if (!bce_->emit1(incOp)) {
    210    //              [stack] ... N+1
    211    return false;
    212  }
    213 
    214  JSOp setOp = isSuper() ? bce_->sc->strict() ? JSOp::StrictSetPropSuper
    215                                              : JSOp::SetPropSuper
    216               : bce_->sc->strict() ? JSOp::StrictSetProp
    217                                    : JSOp::SetProp;
    218  if (!bce_->emitAtomOp(setOp, propAtomIndex_)) {
    219    //              [stack] N? N+1
    220    return false;
    221  }
    222  if (isPostIncDec() && valueUsage == ValueUsage::WantValue) {
    223    if (!bce_->emit1(JSOp::Pop)) {
    224      //            [stack] N
    225      return false;
    226    }
    227  }
    228 
    229 #ifdef DEBUG
    230  state_ = State::IncDec;
    231 #endif
    232  return true;
    233 }