tor-browser

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

WasmDebugFrame.cpp (5958B)


      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 *
      4 * Copyright 2021 Mozilla Foundation
      5 *
      6 * Licensed under the Apache License, Version 2.0 (the "License");
      7 * you may not use this file except in compliance with the License.
      8 * You may obtain a copy of the License at
      9 *
     10 *     http://www.apache.org/licenses/LICENSE-2.0
     11 *
     12 * Unless required by applicable law or agreed to in writing, software
     13 * distributed under the License is distributed on an "AS IS" BASIS,
     14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15 * See the License for the specific language governing permissions and
     16 * limitations under the License.
     17 */
     18 
     19 #include "wasm/WasmDebugFrame.h"
     20 
     21 #include "vm/EnvironmentObject.h"
     22 #include "wasm/WasmBaselineCompile.h"
     23 #include "wasm/WasmDebug.h"
     24 #include "wasm/WasmInstance.h"
     25 #include "wasm/WasmInstanceData.h"
     26 #include "wasm/WasmStubs.h"
     27 
     28 #include "vm/NativeObject-inl.h"
     29 #include "wasm/WasmInstance-inl.h"
     30 
     31 using namespace js;
     32 using namespace js::jit;
     33 using namespace js::wasm;
     34 
     35 /* static */
     36 DebugFrame* DebugFrame::from(Frame* fp) {
     37  MOZ_ASSERT(GetNearestEffectiveInstance(fp)->code().debugEnabled());
     38  auto* df =
     39      reinterpret_cast<DebugFrame*>((uint8_t*)fp - DebugFrame::offsetOfFrame());
     40  MOZ_ASSERT(GetNearestEffectiveInstance(fp) == df->instance());
     41  return df;
     42 }
     43 
     44 void DebugFrame::alignmentStaticAsserts() {
     45  // VS2017 doesn't consider offsetOfFrame() to be a constexpr, so we have
     46  // to use offsetof directly. These asserts can't be at class-level
     47  // because the type is incomplete.
     48 
     49  static_assert(WasmStackAlignment >= Alignment,
     50                "Aligned by ABI before pushing DebugFrame");
     51 #ifndef JS_CODEGEN_NONE
     52  static_assert((offsetof(DebugFrame, frame_) + sizeof(Frame)) % Alignment == 0,
     53                "Aligned after pushing DebugFrame");
     54 #endif
     55 #ifdef JS_CODEGEN_ARM64
     56  // This constraint may or may not be necessary.  If you hit this because
     57  // you've changed the frame size then feel free to remove it, but be extra
     58  // aware of possible problems.
     59  static_assert(sizeof(DebugFrame) % 16 == 0, "ARM64 SP alignment");
     60 #endif
     61 }
     62 
     63 Instance* DebugFrame::instance() {
     64  return GetNearestEffectiveInstance(&frame_);
     65 }
     66 
     67 const Instance* DebugFrame::instance() const {
     68  return GetNearestEffectiveInstance(&frame_);
     69 }
     70 
     71 GlobalObject* DebugFrame::global() { return &instance()->object()->global(); }
     72 
     73 bool DebugFrame::hasGlobal(const GlobalObject* global) const {
     74  return global == &instance()->objectUnbarriered()->global();
     75 }
     76 
     77 JSObject* DebugFrame::environmentChain() {
     78  return &global()->lexicalEnvironment();
     79 }
     80 
     81 bool DebugFrame::getLocal(uint32_t localIndex, MutableHandleValue vp) {
     82  ValTypeVector locals;
     83  size_t argsLength;
     84  StackResults stackResults;
     85  if (!instance()->debug().debugGetLocalTypes(funcIndex(), &locals, &argsLength,
     86                                              &stackResults)) {
     87    return false;
     88  }
     89 
     90  ValTypeVector args;
     91  MOZ_ASSERT(argsLength <= locals.length());
     92  if (!args.append(locals.begin(), argsLength)) {
     93    return false;
     94  }
     95  ArgTypeVector abiArgs(args, stackResults);
     96 
     97  BaseLocalIter iter(locals, abiArgs, /* debugEnabled = */ true);
     98  while (!iter.done() && iter.index() < localIndex) {
     99    iter++;
    100  }
    101  MOZ_ALWAYS_TRUE(!iter.done());
    102 
    103  uint8_t* frame = static_cast<uint8_t*>((void*)this) + offsetOfFrame();
    104  void* dataPtr = frame - iter.frameOffset();
    105  switch (iter.mirType()) {
    106    case jit::MIRType::Int32:
    107      vp.set(Int32Value(*static_cast<int32_t*>(dataPtr)));
    108      break;
    109    case jit::MIRType::Int64:
    110      // Just display as a Number; it's ok if we lose some precision
    111      vp.set(NumberValue((double)*static_cast<int64_t*>(dataPtr)));
    112      break;
    113    case jit::MIRType::Float32:
    114      vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast<float*>(dataPtr))));
    115      break;
    116    case jit::MIRType::Double:
    117      vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast<double*>(dataPtr))));
    118      break;
    119    case jit::MIRType::WasmAnyRef:
    120      vp.set(((AnyRef*)dataPtr)->toJSValue());
    121      break;
    122 #ifdef ENABLE_WASM_SIMD
    123    case jit::MIRType::Simd128:
    124      vp.set(NumberValue(0));
    125      break;
    126 #endif
    127    default:
    128      MOZ_CRASH("local type");
    129  }
    130  return true;
    131 }
    132 
    133 bool DebugFrame::updateReturnJSValue(JSContext* cx) {
    134  MutableHandleValue rval =
    135      MutableHandleValue::fromMarkedLocation(&cachedReturnJSValue_);
    136  rval.setUndefined();
    137  flags_.hasCachedReturnJSValue = true;
    138  ResultType resultType = ResultType::Vector(
    139      instance()->codeMeta().getFuncType(funcIndex()).results());
    140  mozilla::Maybe<char*> stackResultsLoc;
    141  if (ABIResultIter::HasStackResults(resultType)) {
    142    stackResultsLoc = mozilla::Some(static_cast<char*>(stackResultsPointer_));
    143  }
    144  DebugCodegen(DebugChannel::Function,
    145               "wasm-function[%d] updateReturnJSValue [", funcIndex());
    146  bool ok =
    147      ResultsToJSValue(cx, resultType, registerResults_, stackResultsLoc, rval);
    148  DebugCodegen(DebugChannel::Function, "]\n");
    149  return ok;
    150 }
    151 
    152 void DebugFrame::discardReturnJSValue() {
    153  MutableHandleValue rval =
    154      MutableHandleValue::fromMarkedLocation(&cachedReturnJSValue_);
    155  rval.setMagic(JS_OPTIMIZED_OUT);
    156  flags_.hasCachedReturnJSValue = true;
    157 }
    158 
    159 HandleValue DebugFrame::returnValue() const {
    160  MOZ_ASSERT(flags_.hasCachedReturnJSValue);
    161  return HandleValue::fromMarkedLocation(&cachedReturnJSValue_);
    162 }
    163 
    164 void DebugFrame::clearReturnJSValue() {
    165  flags_.hasCachedReturnJSValue = true;
    166  cachedReturnJSValue_.setUndefined();
    167 }
    168 
    169 void DebugFrame::observe(JSContext* cx) {
    170  if (!flags_.observing) {
    171    instance()->debug().adjustEnterAndLeaveFrameTrapsState(
    172        cx, instance(), /* enabled = */ true);
    173    flags_.observing = true;
    174  }
    175 }
    176 
    177 void DebugFrame::leave(JSContext* cx) {
    178  if (flags_.observing) {
    179    instance()->debug().adjustEnterAndLeaveFrameTrapsState(
    180        cx, instance(), /* enabled = */ false);
    181    flags_.observing = false;
    182  }
    183 }