// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "lib/stacktrace.h"
#include "vm/bootstrap_natives.h"
#include "vm/debugger.h"
#include "vm/exceptions.h"
#include "vm/native_entry.h"
#include "vm/object_store.h"
#include "vm/runtime_entry.h"
#include "vm/stack_frame.h"
#include "vm/stack_trace.h"

namespace dart {

DECLARE_FLAG(bool, show_invisible_frames);

static const intptr_t kDefaultStackAllocation = 8;

static StackTracePtr CurrentSyncStackTraceLazy(Thread* thread,
                                               intptr_t skip_frames = 1) {
  Zone* zone = thread->zone();

  const auto& code_array = GrowableObjectArray::ZoneHandle(
      zone, GrowableObjectArray::New(kDefaultStackAllocation));
  const auto& pc_offset_array = GrowableObjectArray::ZoneHandle(
      zone, GrowableObjectArray::New(kDefaultStackAllocation));

  // Collect the frames.
  StackTraceUtils::CollectFramesLazy(thread, code_array, pc_offset_array,
                                     skip_frames);

  const auto& code_array_fixed =
      Array::Handle(zone, Array::MakeFixedLength(code_array));
  const auto& pc_offset_array_fixed =
      Array::Handle(zone, Array::MakeFixedLength(pc_offset_array));

  return StackTrace::New(code_array_fixed, pc_offset_array_fixed);
}

static StackTracePtr CurrentSyncStackTrace(Thread* thread,
                                           intptr_t skip_frames = 1) {
  Zone* zone = thread->zone();
  const Function& null_function = Function::ZoneHandle(zone);

  // Determine how big the stack trace is.
  const intptr_t stack_trace_length =
      StackTraceUtils::CountFrames(thread, skip_frames, null_function, nullptr);

  // Allocate once.
  const Array& code_array =
      Array::ZoneHandle(zone, Array::New(stack_trace_length));
  const Array& pc_offset_array =
      Array::ZoneHandle(zone, Array::New(stack_trace_length));

  // Collect the frames.
  const intptr_t collected_frames_count = StackTraceUtils::CollectFrames(
      thread, code_array, pc_offset_array, 0, stack_trace_length, skip_frames);

  ASSERT(collected_frames_count == stack_trace_length);

  return StackTrace::New(code_array, pc_offset_array);
}

static StackTracePtr CurrentStackTrace(
    Thread* thread,
    bool for_async_function,
    intptr_t skip_frames = 1,
    bool causal_async_stacks = FLAG_causal_async_stacks) {
  if (FLAG_lazy_async_stacks) {
    return CurrentSyncStackTraceLazy(thread, skip_frames);
  }
  if (!causal_async_stacks) {
    // Return the synchronous stack trace.
    return CurrentSyncStackTrace(thread, skip_frames);
  }

  Zone* zone = thread->zone();
  Code& code = Code::ZoneHandle(zone);
  Smi& offset = Smi::ZoneHandle(zone);
  Function& async_function = Function::ZoneHandle(zone);
  StackTrace& async_stack_trace = StackTrace::ZoneHandle(zone);
  Array& async_code_array = Array::ZoneHandle(zone);
  Array& async_pc_offset_array = Array::ZoneHandle(zone);

  StackTraceUtils::ExtractAsyncStackTraceInfo(
      thread, &async_function, &async_stack_trace, &async_code_array,
      &async_pc_offset_array);

  // Determine the size of the stack trace.
  const intptr_t extra_frames = for_async_function ? 1 : 0;
  bool sync_async_end = false;
  const intptr_t synchronous_stack_trace_length = StackTraceUtils::CountFrames(
      thread, skip_frames, async_function, &sync_async_end);

  const intptr_t capacity = synchronous_stack_trace_length +
                            extra_frames;  // For the asynchronous gap.

  // Allocate memory for the stack trace.
  const Array& code_array = Array::ZoneHandle(zone, Array::New(capacity));
  const Array& pc_offset_array = Array::ZoneHandle(zone, Array::New(capacity));

  intptr_t write_cursor = 0;
  if (for_async_function) {
    // Place the asynchronous gap marker at the top of the stack trace.
    code = StubCode::AsynchronousGapMarker().raw();
    ASSERT(!code.IsNull());
    offset = Smi::New(0);
    code_array.SetAt(write_cursor, code);
    pc_offset_array.SetAt(write_cursor, offset);
    write_cursor++;
  }

  // Append the synchronous stack trace.
  const intptr_t collected_frames_count = StackTraceUtils::CollectFrames(
      thread, code_array, pc_offset_array, write_cursor,
      synchronous_stack_trace_length, skip_frames);

  write_cursor += collected_frames_count;

  ASSERT(write_cursor == capacity);

  const StackTrace& result = StackTrace::Handle(
      zone, StackTrace::New(code_array, pc_offset_array, async_stack_trace,
                            sync_async_end));

  return result.raw();
}

StackTracePtr GetStackTraceForException() {
  Thread* thread = Thread::Current();
  return CurrentStackTrace(thread, false, 0);
}

DEFINE_NATIVE_ENTRY(StackTrace_current, 0, 0) {
  return CurrentStackTrace(thread, false);
}

DEFINE_NATIVE_ENTRY(StackTrace_asyncStackTraceHelper, 0, 1) {
  if (!FLAG_causal_async_stacks) {
    // If causal async stacks are not enabled we should recognize this method
    // and never call to the NOP runtime.
    // See kernel_to_il.cc.
    UNREACHABLE();
  }
#if !defined(PRODUCT)
  GET_NATIVE_ARGUMENT(Closure, async_op, arguments->NativeArgAt(0));
  Debugger* debugger = isolate->debugger();
  if (debugger != NULL) {
    debugger->MaybeAsyncStepInto(async_op);
  }
#endif
  return CurrentStackTrace(thread, true);
}

DEFINE_NATIVE_ENTRY(StackTrace_clearAsyncThreadStackTrace, 0, 0) {
  thread->clear_async_stack_trace();
  return Object::null();
}

DEFINE_NATIVE_ENTRY(StackTrace_setAsyncThreadStackTrace, 0, 1) {
  if (!FLAG_causal_async_stacks) {
    return Object::null();
  }

  GET_NON_NULL_NATIVE_ARGUMENT(StackTrace, stack_trace,
                               arguments->NativeArgAt(0));
  thread->set_async_stack_trace(stack_trace);
  return Object::null();
}

static void AppendFrames(const GrowableObjectArray& code_list,
                         const GrowableObjectArray& pc_offset_list,
                         int skip_frames) {
  Thread* thread = Thread::Current();
  Zone* zone = thread->zone();
  StackFrameIterator frames(ValidationPolicy::kDontValidateFrames, thread,
                            StackFrameIterator::kNoCrossThreadIteration);
  StackFrame* frame = frames.NextFrame();
  ASSERT(frame != NULL);  // We expect to find a dart invocation frame.
  Code& code = Code::Handle(zone);
  Smi& offset = Smi::Handle(zone);
  for (; frame != NULL; frame = frames.NextFrame()) {
    if (!frame->IsDartFrame()) {
      continue;
    }
    if (skip_frames > 0) {
      skip_frames--;
      continue;
    }

    code = frame->LookupDartCode();
    offset = Smi::New(frame->pc() - code.PayloadStart());
    code_list.Add(code);
    pc_offset_list.Add(offset);
  }
}

// Creates a StackTrace object from the current stack.
//
// Skips the first skip_frames Dart frames.
const StackTrace& GetCurrentStackTrace(int skip_frames) {
  const GrowableObjectArray& code_list =
      GrowableObjectArray::Handle(GrowableObjectArray::New());
  const GrowableObjectArray& pc_offset_list =
      GrowableObjectArray::Handle(GrowableObjectArray::New());
  AppendFrames(code_list, pc_offset_list, skip_frames);
  const Array& code_array = Array::Handle(Array::MakeFixedLength(code_list));
  const Array& pc_offset_array =
      Array::Handle(Array::MakeFixedLength(pc_offset_list));
  const StackTrace& stacktrace =
      StackTrace::Handle(StackTrace::New(code_array, pc_offset_array));
  return stacktrace;
}

bool HasStack() {
  Thread* thread = Thread::Current();
  StackFrameIterator frames(ValidationPolicy::kDontValidateFrames, thread,
                            StackFrameIterator::kNoCrossThreadIteration);
  StackFrame* frame = frames.NextFrame();
  return frame != nullptr;
}

}  // namespace dart
