@ 261106.4
current
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/debug/debug-frames.h"

#include "src/builtins/accessors.h"
#include "src/deoptimizer/deoptimizer.h"
#include "src/execution/frames-inl.h"
#include "src/objects/debug-objects-inl.h"
#include "src/sandbox/check.h"

#if V8_ENABLE_WEBASSEMBLY
#include "src/debug/debug-wasm-objects.h"
#endif  // V8_ENABLE_WEBASSEMBLY

namespace v8 {
namespace internal {

FrameInspector::FrameInspector(CommonFrame* frame, int inlined_frame_index,
                               Isolate* isolate)
    : frame_(frame),
      inlined_frame_index_(inlined_frame_index),
      isolate_(isolate) {
  // Extract the relevant information from the frame summary and discard it.
  FrameSummary summary = FrameSummary::Get(frame, inlined_frame_index);
  summary.EnsureSourcePositionsAvailable();

  is_constructor_ = summary.is_constructor();
  source_position_ = summary.SourcePosition();
  script_ = Cast<Script>(summary.script());
  receiver_ = summary.receiver();

  if (summary.IsJavaScript()) {
    function_ = summary.AsJavaScript().function();
  }

#if V8_ENABLE_WEBASSEMBLY
  JavaScriptFrame* js_frame =
      frame->is_javascript() ? javascript_frame() : nullptr;
  DCHECK(js_frame || frame->is_wasm());
#else
  JavaScriptFrame* js_frame = javascript_frame();
#endif  // V8_ENABLE_WEBASSEMBLY
  is_optimized_ = js_frame && js_frame->is_optimized();

  // Calculate the deoptimized frame.
  if (is_optimized_) {
    DCHECK_NOT_NULL(js_frame);
    deoptimized_frame_.reset(Deoptimizer::DebuggerInspectableFrame(
        js_frame, inlined_frame_index, isolate));
  }
}

// Destructor needs to be defined in the .cc file, because it instantiates
// std::unique_ptr destructors but the types are not known in the header.
FrameInspector::~FrameInspector() = default;

JavaScriptFrame* FrameInspector::javascript_frame() {
  return JavaScriptFrame::cast(frame_);
}

Handle<Object> FrameInspector::GetParameter(int index) {
  if (is_optimized_) return deoptimized_frame_->GetParameter(index);
  DCHECK(IsJavaScript());
  return handle(javascript_frame()->GetParameter(index), isolate_);
}

Handle<Object> FrameInspector::GetExpression(int index) {
  return is_optimized_ ? deoptimized_frame_->GetExpression(index)
                       : handle(frame_->GetExpression(index), isolate_);
}

Handle<Object> FrameInspector::GetContext() {
  return deoptimized_frame_ ? deoptimized_frame_->GetContext()
                            : handle(frame_->context(), isolate_);
}

DirectHandle<String> FrameInspector::GetFunctionName() {
#if V8_ENABLE_WEBASSEMBLY
  if (IsWasm()) {
#if V8_ENABLE_DRUMBRAKE
    if (IsWasmInterpreter()) {
      auto wasm_frame = WasmInterpreterEntryFrame::cast(frame_);
      auto instance_data =
          handle(wasm_frame->trusted_instance_data(), isolate_);
      return GetWasmFunctionDebugName(
          isolate_, instance_data,
          wasm_frame->function_index(inlined_frame_index_));
    }
#endif  // V8_ENABLE_DRUMBRAKE
    auto wasm_frame = WasmFrame::cast(frame_);
    auto instance_data = handle(wasm_frame->trusted_instance_data(), isolate_);
    int top_func_index = FrameSummary::Get(wasm_frame, inlined_frame_index_)
                             .AsWasm()
                             .function_index();
    return GetWasmFunctionDebugName(isolate_, instance_data, top_func_index);
  }
#endif  // V8_ENABLE_WEBASSEMBLY
  return JSFunction::GetDebugName(isolate_, function_);
}

#if V8_ENABLE_WEBASSEMBLY
bool FrameInspector::IsWasm() { return frame_->is_wasm(); }
#if V8_ENABLE_DRUMBRAKE
bool FrameInspector::IsWasmInterpreter() {
  return frame_->is_wasm_interpreter_entry();
}
#endif  // V8_ENABLE_DRUMBRAKE
#endif  // V8_ENABLE_WEBASSEMBLY

bool FrameInspector::IsJavaScript() { return frame_->is_javascript(); }

bool FrameInspector::ParameterIsShadowedByContextLocal(
    DirectHandle<ScopeInfo> info, DirectHandle<String> parameter_name) {
  return info->ContextSlotIndex(*parameter_name) != -1;
}

RedirectActiveFunctions::RedirectActiveFunctions(
    Isolate* isolate, Tagged<SharedFunctionInfo> shared, Mode mode)
    : shared_(shared), mode_(mode) {
  DCHECK(shared->HasBytecodeArray());
  DCHECK(shared->HasDebugInfo(isolate));
}

void RedirectActiveFunctions::VisitThread(Isolate* isolate,
                                          ThreadLocalTop* top) {
  Tagged<DebugInfo> debug_info = shared_->GetDebugInfo(isolate);
  Tagged<BytecodeArray> original_bytecode =
      debug_info->OriginalBytecodeArray(isolate);
  Tagged<BytecodeArray> debug_bytecode =
      debug_info->DebugBytecodeArray(isolate);

  for (JavaScriptStackFrameIterator it(isolate, top); !it.done();
       it.Advance()) {
    JavaScriptFrame* frame = it.frame();
    // Skip live-edited frames, they'll be restarted from scratch anyway.
    if (isolate->debug()->ShouldRestartFrame(frame->id())) continue;
    Tagged<JSFunction> function = frame->function();
    if (!frame->is_interpreted()) continue;
    if (function->shared() != shared_) continue;
    InterpretedFrame* interpreted_frame =
        reinterpret_cast<InterpretedFrame*>(frame);

    if (mode_ == Mode::kUseDebugBytecode) {
      SBXCHECK_EQ(interpreted_frame->GetBytecodeArray(), original_bytecode);
      interpreted_frame->PatchBytecodeArray(debug_bytecode);
    } else {
      SBXCHECK_EQ(interpreted_frame->GetBytecodeArray(), debug_bytecode);
      interpreted_frame->PatchBytecodeArray(original_bytecode);
    }
  }
}

}  // namespace internal
}  // namespace v8