// Copyright 2017 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-scope-iterator.h"

#include "src/api.h"
#include "src/debug/debug.h"
#include "src/debug/liveedit.h"
#include "src/frames-inl.h"
#include "src/isolate.h"
#include "src/wasm/wasm-objects-inl.h"

namespace v8 {

std::unique_ptr<debug::ScopeIterator> debug::ScopeIterator::CreateForFunction(
    v8::Isolate* v8_isolate, v8::Local<v8::Function> v8_func) {
  internal::Handle<internal::JSFunction> func =
      internal::Handle<internal::JSFunction>::cast(Utils::OpenHandle(*v8_func));
  // Blink has function objects with callable map, JS_SPECIAL_API_OBJECT_TYPE
  // but without context on heap.
  if (!func->has_context()) return nullptr;
  return std::unique_ptr<debug::ScopeIterator>(new internal::DebugScopeIterator(
      reinterpret_cast<internal::Isolate*>(v8_isolate), func));
}

std::unique_ptr<debug::ScopeIterator>
debug::ScopeIterator::CreateForGeneratorObject(
    v8::Isolate* v8_isolate, v8::Local<v8::Object> v8_generator) {
  internal::Handle<internal::Object> generator =
      Utils::OpenHandle(*v8_generator);
  DCHECK(generator->IsJSGeneratorObject());
  return std::unique_ptr<debug::ScopeIterator>(new internal::DebugScopeIterator(
      reinterpret_cast<internal::Isolate*>(v8_isolate),
      internal::Handle<internal::JSGeneratorObject>::cast(generator)));
}

namespace internal {

DebugScopeIterator::DebugScopeIterator(Isolate* isolate,
                                       FrameInspector* frame_inspector)
    : iterator_(isolate, frame_inspector) {
  if (!Done() && ShouldIgnore()) Advance();
}

DebugScopeIterator::DebugScopeIterator(Isolate* isolate,
                                       Handle<JSFunction> function)
    : iterator_(isolate, function) {
  if (!Done() && ShouldIgnore()) Advance();
}

DebugScopeIterator::DebugScopeIterator(Isolate* isolate,
                                       Handle<JSGeneratorObject> generator)
    : iterator_(isolate, generator) {
  if (!Done() && ShouldIgnore()) Advance();
}

bool DebugScopeIterator::Done() { return iterator_.Done(); }

void DebugScopeIterator::Advance() {
  DCHECK(!Done());
  iterator_.Next();
  while (!Done() && ShouldIgnore()) {
    iterator_.Next();
  }
}

bool DebugScopeIterator::ShouldIgnore() {
  // Almost always Script scope will be empty, so just filter out that noise.
  // Also drop empty Block, Eval and Script scopes, should we get any.
  DCHECK(!Done());
  debug::ScopeIterator::ScopeType type = GetType();
  if (type != debug::ScopeIterator::ScopeTypeBlock &&
      type != debug::ScopeIterator::ScopeTypeScript &&
      type != debug::ScopeIterator::ScopeTypeEval &&
      type != debug::ScopeIterator::ScopeTypeModule) {
    return false;
  }

  // TODO(kozyatinskiy): make this function faster.
  Handle<JSObject> value;
  if (!iterator_.ScopeObject().ToHandle(&value)) return false;
  Handle<FixedArray> keys =
      KeyAccumulator::GetKeys(value, KeyCollectionMode::kOwnOnly,
                              ENUMERABLE_STRINGS,
                              GetKeysConversion::kConvertToString)
          .ToHandleChecked();
  return keys->length() == 0;
}

v8::debug::ScopeIterator::ScopeType DebugScopeIterator::GetType() {
  DCHECK(!Done());
  return static_cast<v8::debug::ScopeIterator::ScopeType>(iterator_.Type());
}

v8::Local<v8::Object> DebugScopeIterator::GetObject() {
  DCHECK(!Done());
  Handle<JSObject> value;
  if (iterator_.ScopeObject().ToHandle(&value)) {
    return Utils::ToLocal(value);
  }
  return v8::Local<v8::Object>();
}

v8::Local<v8::Function> DebugScopeIterator::GetFunction() {
  DCHECK(!Done());
  Handle<JSFunction> closure = iterator_.GetClosure();
  if (closure.is_null()) return v8::Local<v8::Function>();
  return Utils::ToLocal(closure);
}

debug::Location DebugScopeIterator::GetStartLocation() {
  DCHECK(!Done());
  Handle<JSFunction> closure = iterator_.GetClosure();
  if (closure.is_null()) return debug::Location();
  Object* obj = closure->shared()->script();
  if (!obj->IsScript()) return debug::Location();
  return ToApiHandle<v8::debug::Script>(handle(Script::cast(obj)))
      ->GetSourceLocation(iterator_.start_position());
}

debug::Location DebugScopeIterator::GetEndLocation() {
  DCHECK(!Done());
  Handle<JSFunction> closure = iterator_.GetClosure();
  if (closure.is_null()) return debug::Location();
  Object* obj = closure->shared()->script();
  if (!obj->IsScript()) return debug::Location();
  return ToApiHandle<v8::debug::Script>(handle(Script::cast(obj)))
      ->GetSourceLocation(iterator_.end_position());
}

bool DebugScopeIterator::SetVariableValue(v8::Local<v8::String> name,
                                          v8::Local<v8::Value> value) {
  DCHECK(!Done());
  return iterator_.SetVariableValue(Utils::OpenHandle(*name),
                                    Utils::OpenHandle(*value));
}

DebugWasmScopeIterator::DebugWasmScopeIterator(Isolate* isolate,
                                               StandardFrame* frame,
                                               int inlined_frame_index)
    : isolate_(isolate),
      frame_(frame),
      inlined_frame_index_(inlined_frame_index),
      type_(debug::ScopeIterator::ScopeTypeGlobal) {}

bool DebugWasmScopeIterator::Done() {
  return type_ != debug::ScopeIterator::ScopeTypeGlobal &&
         type_ != debug::ScopeIterator::ScopeTypeLocal;
}

void DebugWasmScopeIterator::Advance() {
  DCHECK(!Done());
  if (type_ == debug::ScopeIterator::ScopeTypeGlobal) {
    type_ = debug::ScopeIterator::ScopeTypeLocal;
  } else {
    // We use ScopeTypeWith type as marker for done.
    type_ = debug::ScopeIterator::ScopeTypeWith;
  }
}

v8::debug::ScopeIterator::ScopeType DebugWasmScopeIterator::GetType() {
  DCHECK(!Done());
  return type_;
}

v8::Local<v8::Object> DebugWasmScopeIterator::GetObject() {
  DCHECK(!Done());
  Handle<WasmDebugInfo> debug_info(
      WasmInterpreterEntryFrame::cast(frame_)->wasm_instance()->debug_info(),
      isolate_);
  switch (type_) {
    case debug::ScopeIterator::ScopeTypeGlobal:
      return Utils::ToLocal(WasmDebugInfo::GetGlobalScopeObject(
          debug_info, frame_->fp(), inlined_frame_index_));
    case debug::ScopeIterator::ScopeTypeLocal:
      return Utils::ToLocal(WasmDebugInfo::GetLocalScopeObject(
          debug_info, frame_->fp(), inlined_frame_index_));
    default:
      return v8::Local<v8::Object>();
  }
  return v8::Local<v8::Object>();
}

v8::Local<v8::Function> DebugWasmScopeIterator::GetFunction() {
  DCHECK(!Done());
  return v8::Local<v8::Function>();
}

debug::Location DebugWasmScopeIterator::GetStartLocation() {
  DCHECK(!Done());
  return debug::Location();
}

debug::Location DebugWasmScopeIterator::GetEndLocation() {
  DCHECK(!Done());
  return debug::Location();
}

bool DebugWasmScopeIterator::SetVariableValue(v8::Local<v8::String> name,
                                              v8::Local<v8::Value> value) {
  DCHECK(!Done());
  return false;
}
}  // namespace internal
}  // namespace v8
