tor-browser

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

BaselineFrameInfo.cpp (6453B)


      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 "jit/BaselineFrameInfo.h"
      8 
      9 #include <algorithm>
     10 
     11 #include "jit/BaselineIC.h"
     12 #ifdef DEBUG
     13 #  include "jit/BytecodeAnalysis.h"
     14 #endif
     15 
     16 #include "jit/BaselineFrameInfo-inl.h"
     17 #include "jit/JitFrames.h"
     18 #include "jit/MacroAssembler-inl.h"
     19 
     20 using namespace js;
     21 using namespace js::jit;
     22 
     23 bool CompilerFrameInfo::init(TempAllocator& alloc) {
     24  // An extra slot is needed for global scopes because INITGLEXICAL (stack
     25  // depth 1) is compiled as a SETPROP (stack depth 2) on the global lexical
     26  // scope.
     27  size_t extra = script->isGlobalCode() ? 1 : 0;
     28  size_t nstack =
     29      std::max(script->nslots() - script->nfixed(), size_t(MinJITStackSize)) +
     30      extra;
     31  if (!stack.init(alloc, nstack)) {
     32    return false;
     33  }
     34 
     35  return true;
     36 }
     37 
     38 void CompilerFrameInfo::sync(StackValue* val) {
     39  switch (val->kind()) {
     40    case StackValue::Stack:
     41      break;
     42    case StackValue::LocalSlot:
     43      masm.pushValue(addressOfLocal(val->localSlot()));
     44      break;
     45    case StackValue::ArgSlot:
     46      masm.pushValue(addressOfArg(val->argSlot()));
     47      break;
     48    case StackValue::ThisSlot:
     49      masm.pushValue(addressOfThis());
     50      break;
     51    case StackValue::Register:
     52      masm.pushValue(val->reg());
     53      break;
     54    case StackValue::Constant:
     55      masm.pushValue(val->constant());
     56      break;
     57    default:
     58      MOZ_CRASH("Invalid kind");
     59  }
     60 
     61  val->setStack();
     62 }
     63 
     64 void CompilerFrameInfo::syncStack(uint32_t uses) {
     65  MOZ_ASSERT(uses <= stackDepth());
     66 
     67  uint32_t depth = stackDepth() - uses;
     68 
     69  for (uint32_t i = 0; i < depth; i++) {
     70    StackValue* current = &stack[i];
     71    sync(current);
     72  }
     73 }
     74 
     75 uint32_t CompilerFrameInfo::numUnsyncedSlots() {
     76  // Start at the bottom, find the first value that's not synced.
     77  uint32_t i = 0;
     78  for (; i < stackDepth(); i++) {
     79    if (peek(-int32_t(i + 1))->kind() == StackValue::Stack) {
     80      break;
     81    }
     82  }
     83  return i;
     84 }
     85 
     86 void CompilerFrameInfo::popValue(ValueOperand dest) {
     87  StackValue* val = peek(-1);
     88 
     89  switch (val->kind()) {
     90    case StackValue::Constant:
     91      masm.moveValue(val->constant(), dest);
     92      break;
     93    case StackValue::LocalSlot:
     94      masm.loadValue(addressOfLocal(val->localSlot()), dest);
     95      break;
     96    case StackValue::ArgSlot:
     97      masm.loadValue(addressOfArg(val->argSlot()), dest);
     98      break;
     99    case StackValue::ThisSlot:
    100      masm.loadValue(addressOfThis(), dest);
    101      break;
    102    case StackValue::Stack:
    103      masm.popValue(dest);
    104      break;
    105    case StackValue::Register:
    106      masm.moveValue(val->reg(), dest);
    107      break;
    108    default:
    109      MOZ_CRASH("Invalid kind");
    110  }
    111 
    112  // masm.popValue already adjusted the stack pointer, don't do it twice.
    113  pop(DontAdjustStack);
    114 }
    115 
    116 void CompilerFrameInfo::popRegsAndSync(uint32_t uses) {
    117  // x86 has only 3 Value registers. Only support 2 regs here for now,
    118  // so that there's always a scratch Value register for reg -> reg
    119  // moves.
    120  MOZ_ASSERT(uses > 0);
    121  MOZ_ASSERT(uses <= 2);
    122  MOZ_ASSERT(uses <= stackDepth());
    123 
    124  syncStack(uses);
    125 
    126  switch (uses) {
    127    case 1:
    128      popValue(R0);
    129      break;
    130    case 2: {
    131      // If the second value is in R1, move it to R2 so that it's not
    132      // clobbered by the first popValue.
    133      StackValue* val = peek(-2);
    134      if (val->kind() == StackValue::Register && val->reg() == R1) {
    135        masm.moveValue(R1, ValueOperand(R2));
    136        val->setRegister(R2);
    137      }
    138      popValue(R1);
    139      popValue(R0);
    140      break;
    141    }
    142    default:
    143      MOZ_CRASH("Invalid uses");
    144  }
    145  // On arm64, SP may be < PSP now (that's OK).
    146  // eg testcase: tests/bug1580246.js
    147 }
    148 
    149 void InterpreterFrameInfo::popRegsAndSync(uint32_t uses) {
    150  switch (uses) {
    151    case 1:
    152      popValue(R0);
    153      break;
    154    case 2: {
    155      popValue(R1);
    156      popValue(R0);
    157      break;
    158    }
    159    default:
    160      MOZ_CRASH("Invalid uses");
    161  }
    162  // On arm64, SP may be < PSP now (that's OK).
    163  // eg testcase: tests/backup-point-bug1315634.js
    164 }
    165 
    166 void InterpreterFrameInfo::bumpInterpreterICEntry() {
    167  masm.addPtr(Imm32(sizeof(ICEntry)), addressOfInterpreterICEntry());
    168 }
    169 
    170 void CompilerFrameInfo::storeStackValue(int32_t depth, const Address& dest,
    171                                        const ValueOperand& scratch) {
    172  const StackValue* source = peek(depth);
    173  switch (source->kind()) {
    174    case StackValue::Constant:
    175      masm.storeValue(source->constant(), dest);
    176      break;
    177    case StackValue::Register:
    178      masm.storeValue(source->reg(), dest);
    179      break;
    180    case StackValue::LocalSlot:
    181      masm.loadValue(addressOfLocal(source->localSlot()), scratch);
    182      masm.storeValue(scratch, dest);
    183      break;
    184    case StackValue::ArgSlot:
    185      masm.loadValue(addressOfArg(source->argSlot()), scratch);
    186      masm.storeValue(scratch, dest);
    187      break;
    188    case StackValue::ThisSlot:
    189      masm.loadValue(addressOfThis(), scratch);
    190      masm.storeValue(scratch, dest);
    191      break;
    192    case StackValue::Stack:
    193      masm.loadValue(addressOfStackValue(depth), scratch);
    194      masm.storeValue(scratch, dest);
    195      break;
    196    default:
    197      MOZ_CRASH("Invalid kind");
    198  }
    199 }
    200 
    201 #ifdef DEBUG
    202 void CompilerFrameInfo::assertValidState(const BytecodeInfo& info) {
    203  // Check stack depth.
    204  MOZ_ASSERT(stackDepth() == info.stackDepth);
    205 
    206  // Start at the bottom, find the first value that's not synced.
    207  uint32_t i = 0;
    208  for (; i < stackDepth(); i++) {
    209    if (stack[i].kind() != StackValue::Stack) {
    210      break;
    211    }
    212  }
    213 
    214  // Assert all values on top of it are also not synced.
    215  for (; i < stackDepth(); i++) {
    216    MOZ_ASSERT(stack[i].kind() != StackValue::Stack);
    217  }
    218 
    219  // Assert every Value register is used by at most one StackValue.
    220  // R2 is used as scratch register by the compiler and FrameInfo,
    221  // so it shouldn't be used for StackValues.
    222  bool usedR0 = false, usedR1 = false;
    223 
    224  for (i = 0; i < stackDepth(); i++) {
    225    if (stack[i].kind() == StackValue::Register) {
    226      ValueOperand reg = stack[i].reg();
    227      if (reg == R0) {
    228        MOZ_ASSERT(!usedR0);
    229        usedR0 = true;
    230      } else if (reg == R1) {
    231        MOZ_ASSERT(!usedR1);
    232        usedR1 = true;
    233      } else {
    234        MOZ_CRASH("Invalid register");
    235      }
    236    }
    237  }
    238 }
    239 #endif