// Copyright (c) 2016, 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.

#if !defined(DART_PRECOMPILED_RUNTIME)

#include "vm/kernel.h"

#include "vm/bit_vector.h"
#include "vm/compiler/frontend/constant_reader.h"
#include "vm/compiler/frontend/kernel_translation_helper.h"
#include "vm/compiler/jit/compiler.h"
#include "vm/longjump.h"
#include "vm/object_store.h"
#include "vm/parser.h"  // For Parser::kParameter* constants.
#include "vm/stack_frame.h"

namespace dart {
namespace kernel {

class KernelTokenPositionCollector : public KernelReaderHelper {
 public:
  KernelTokenPositionCollector(
      Zone* zone,
      TranslationHelper* translation_helper,
      const Script& script,
      const TypedDataView& data,
      intptr_t data_program_offset,
      intptr_t initial_script_index,
      intptr_t record_for_script_id,
      GrowableArray<intptr_t>* record_token_positions_into)
      : KernelReaderHelper(zone, translation_helper, data, data_program_offset),
        current_script_id_(initial_script_index),
        record_for_script_id_(record_for_script_id),
        record_token_positions_into_(record_token_positions_into) {}

  void CollectTokenPositions(intptr_t kernel_offset);

  void RecordTokenPosition(TokenPosition position) override;

  void set_current_script_id(intptr_t id) override { current_script_id_ = id; }

 private:
  intptr_t current_script_id_;
  intptr_t record_for_script_id_;
  GrowableArray<intptr_t>* record_token_positions_into_;

  DISALLOW_COPY_AND_ASSIGN(KernelTokenPositionCollector);
};

void KernelTokenPositionCollector::CollectTokenPositions(
    intptr_t kernel_offset) {
  SetOffset(kernel_offset);

  const Tag tag = PeekTag();
  if (tag == kProcedure) {
    ProcedureHelper procedure_helper(this);
    procedure_helper.ReadUntilExcluding(ProcedureHelper::kEnd);
  } else if (tag == kConstructor) {
    ConstructorHelper constructor_helper(this);
    constructor_helper.ReadUntilExcluding(ConstructorHelper::kEnd);
  } else if (tag == kFunctionNode) {
    FunctionNodeHelper function_node_helper(this);
    function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kEnd);
  } else if (tag == kField) {
    FieldHelper field_helper(this);
    field_helper.ReadUntilExcluding(FieldHelper::kEnd);
  } else if (tag == kClass) {
    ClassHelper class_helper(this);
    class_helper.ReadUntilExcluding(ClassHelper::kEnd);
  } else {
    ReportUnexpectedTag("a class or a member", tag);
    UNREACHABLE();
  }
}

void KernelTokenPositionCollector::RecordTokenPosition(TokenPosition position) {
  if (record_for_script_id_ == current_script_id_ &&
      record_token_positions_into_ != nullptr && position.IsReal()) {
    record_token_positions_into_->Add(position.Serialize());
  }
}

static int LowestFirst(const intptr_t* a, const intptr_t* b) {
  return *a - *b;
}

/**
 * If index exists as sublist in list, sort the sublist from lowest to highest,
 * then copy it, as Smis and without duplicates,
 * to a new Array in Heap::kOld which is returned.
 * Note that the source list is both sorted and de-duplicated as well, but will
 * possibly contain duplicate and unsorted data at the end.
 * Otherwise (when sublist doesn't exist in list) return new empty array.
 */
static ArrayPtr AsSortedDuplicateFreeArray(GrowableArray<intptr_t>* source) {
  intptr_t size = source->length();
  if (size == 0) {
    return Object::empty_array().ptr();
  }

  source->Sort(LowestFirst);

  intptr_t last = 0;
  for (intptr_t current = 1; current < size; ++current) {
    if (source->At(last) != source->At(current)) {
      (*source)[++last] = source->At(current);
    }
  }
  Array& array_object = Array::Handle();
  array_object = Array::New(last + 1, Heap::kOld);
  Smi& smi_value = Smi::Handle();
  for (intptr_t i = 0; i <= last; ++i) {
    smi_value = Smi::New(source->At(i));
    array_object.SetAt(i, smi_value);
  }
  return array_object.ptr();
}

static void CollectKernelLibraryTokenPositions(
    const TypedDataView& kernel_data,
    const Script& script,
    intptr_t kernel_offset,
    intptr_t data_kernel_offset,
    Zone* zone,
    TranslationHelper* helper,
    GrowableArray<intptr_t>* token_positions) {
  if (kernel_data.IsNull()) {
    return;
  }

  KernelTokenPositionCollector token_position_collector(
      zone, helper, script, kernel_data, data_kernel_offset,
      script.kernel_script_index(), script.kernel_script_index(),
      token_positions);

  token_position_collector.CollectTokenPositions(kernel_offset);
}

}  // namespace kernel

void Script::CollectTokenPositionsFor() const {
  Thread* thread = Thread::Current();
  Zone* zone = thread->zone();

  const auto& kernel_info =
      KernelProgramInfo::Handle(zone, kernel_program_info());

  kernel::TranslationHelper helper(thread);
  helper.InitFromKernelProgramInfo(kernel_info);

  GrowableArray<intptr_t> token_positions(10);

  auto isolate_group = thread->isolate_group();
  const GrowableObjectArray& libs = GrowableObjectArray::Handle(
      zone, isolate_group->object_store()->libraries());
  Library& lib = Library::Handle(zone);
  Object& entry = Object::Handle(zone);
  Script& entry_script = Script::Handle(zone);
  auto& data = TypedDataView::Handle(zone);

  auto& interesting_script = *this;

  auto& temp_array = Array::Handle(zone);
  auto& temp_field = Field::Handle(zone);
  auto& temp_function = Function::Handle(zone);
  for (intptr_t i = 0; i < libs.Length(); i++) {
    lib ^= libs.At(i);
    lib.EnsureTopLevelClassIsFinalized();
    DictionaryIterator it(lib);
    while (it.HasNext()) {
      entry = it.GetNext();
      data = TypedDataView::null();
      if (entry.IsClass()) {
        const Class& klass = Class::Cast(entry);
        if (klass.script() == interesting_script.ptr()) {
          token_positions.Add(klass.token_pos().Serialize());
          token_positions.Add(klass.end_token_pos().Serialize());
        }
        if (klass.is_finalized()) {
          temp_array = klass.fields();
          for (intptr_t i = 0; i < temp_array.Length(); ++i) {
            temp_field ^= temp_array.At(i);
            if (temp_field.kernel_offset() <= 0) {
              // Skip artificially injected fields.
              continue;
            }
            entry_script = temp_field.Script();
            if (entry_script.ptr() != interesting_script.ptr()) {
              continue;
            }
            data = temp_field.KernelLibrary();
            CollectKernelLibraryTokenPositions(data, interesting_script,
                                               temp_field.kernel_offset(),
                                               temp_field.KernelLibraryOffset(),
                                               zone, &helper, &token_positions);
          }
          temp_array = klass.current_functions();
          for (intptr_t i = 0; i < temp_array.Length(); ++i) {
            temp_function ^= temp_array.At(i);
            entry_script = temp_function.script();
            if (entry_script.ptr() != interesting_script.ptr()) {
              continue;
            }
            data = temp_function.KernelLibrary();
            CollectKernelLibraryTokenPositions(
                data, interesting_script, temp_function.kernel_offset(),
                temp_function.KernelLibraryOffset(), zone, &helper,
                &token_positions);
          }
        } else {
          // Class isn't finalized yet: read the data attached to it.
          ASSERT(klass.kernel_offset() > 0);
          data = lib.KernelLibrary();
          ASSERT(!data.IsNull());
          const intptr_t library_kernel_offset = lib.KernelLibraryOffset();
          ASSERT(library_kernel_offset > 0);
          const intptr_t class_offset = klass.kernel_offset();

          entry_script = klass.script();
          if (entry_script.ptr() != interesting_script.ptr()) {
            continue;
          }
          CollectKernelLibraryTokenPositions(
              data, interesting_script, class_offset, library_kernel_offset,
              zone, &helper, &token_positions);
        }
      } else if (entry.IsFunction()) {
        temp_function ^= entry.ptr();
        entry_script = temp_function.script();
        if (entry_script.ptr() != interesting_script.ptr()) {
          continue;
        }
        data = temp_function.KernelLibrary();
        CollectKernelLibraryTokenPositions(data, interesting_script,
                                           temp_function.kernel_offset(),
                                           temp_function.KernelLibraryOffset(),
                                           zone, &helper, &token_positions);
      } else if (entry.IsField()) {
        const Field& field = Field::Cast(entry);
        if (field.kernel_offset() <= 0) {
          // Skip artificially injected fields.
          continue;
        }
        entry_script = field.Script();
        if (entry_script.ptr() != interesting_script.ptr()) {
          continue;
        }
        data = field.KernelLibrary();
        CollectKernelLibraryTokenPositions(
            data, interesting_script, field.kernel_offset(),
            field.KernelLibraryOffset(), zone, &helper, &token_positions);
      }
    }
  }

  Script& script = Script::Handle(zone, interesting_script.ptr());
  Array& array_object = Array::Handle(zone);
  array_object = kernel::AsSortedDuplicateFreeArray(&token_positions);
  script.set_debug_positions(array_object);
}

#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
ArrayPtr Script::CollectConstConstructorCoverageFrom() const {
  Thread* thread = Thread::Current();
  Zone* zone = thread->zone();
  kernel::TranslationHelper helper(thread);

  const auto& interesting_script = *this;

  const auto& kernel_info =
      KernelProgramInfo::Handle(zone, kernel_program_info());
  helper.InitFromKernelProgramInfo(kernel_info);

  const auto& data =
      TypedDataView::Handle(zone, interesting_script.constant_coverage());

  kernel::KernelReaderHelper kernel_reader(zone, &helper, data, 0);

  // Read "constant coverage constructors".
  const intptr_t constant_coverage_constructors =
      kernel_reader.ReadListLength();
  const Array& constructors =
      Array::Handle(Array::New(constant_coverage_constructors));
  for (intptr_t i = 0; i < constant_coverage_constructors; ++i) {
    kernel::NameIndex kernel_name = kernel_reader.ReadCanonicalNameReference();
    Class& klass = Class::ZoneHandle(
        zone,
        helper.LookupClassByKernelClass(helper.EnclosingName(kernel_name)));
    const Function& target = Function::ZoneHandle(
        zone, helper.LookupConstructorByKernelConstructor(klass, kernel_name));
    constructors.SetAt(i, target);
  }
  return constructors.ptr();
}
#endif  // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)

namespace kernel {

ObjectPtr EvaluateStaticConstFieldInitializer(const Field& field) {
  ASSERT(field.is_static() && field.is_const());

  Thread* thread = Thread::Current();
  LongJumpScope jump(thread);
  if (DART_SETJMP(*jump.Set()) == 0) {
    Zone* zone = thread->zone();
    TranslationHelper helper(thread);
    auto& kernel_program_info =
        KernelProgramInfo::Handle(zone, field.KernelProgramInfo());
    helper.InitFromKernelProgramInfo(kernel_program_info);

    const Class& owner_class = Class::Handle(zone, field.Owner());
    ActiveClass active_class;
    ActiveClassScope active_class_scope(&active_class, &owner_class);

    KernelReaderHelper kernel_reader(
        zone, &helper, TypedDataView::Handle(zone, field.KernelLibrary()),
        field.KernelLibraryOffset());
    kernel_reader.SetOffset(field.kernel_offset());
    ConstantReader constant_reader(&kernel_reader, &active_class);

    FieldHelper field_helper(&kernel_reader);
    field_helper.ReadUntilExcluding(FieldHelper::kInitializer);
    ASSERT(field_helper.IsConst());

    return constant_reader.ReadConstantInitializer();
  } else {
    return thread->StealStickyError();
  }
}

class MetadataEvaluator : public KernelReaderHelper {
 public:
  MetadataEvaluator(Zone* zone,
                    TranslationHelper* translation_helper,
                    const TypedDataView& data,
                    intptr_t data_program_offset,
                    ActiveClass* active_class)
      : KernelReaderHelper(zone, translation_helper, data, data_program_offset),
        constant_reader_(this, active_class) {}

  ObjectPtr EvaluateMetadata(intptr_t kernel_offset,
                             bool is_annotations_offset) {
    SetOffset(kernel_offset);

    // Library and LibraryDependency objects do not have a tag in kernel binary.
    // Synthetic metadata fields corresponding to these objects keep kernel
    // offset of annotations list instead of annotated object.
    if (!is_annotations_offset) {
      const Tag tag = PeekTag();

      if (tag == kClass) {
        ClassHelper class_helper(this);
        class_helper.ReadUntilExcluding(ClassHelper::kAnnotations);
      } else if (tag == kProcedure) {
        ProcedureHelper procedure_helper(this);
        procedure_helper.ReadUntilExcluding(ProcedureHelper::kAnnotations);
      } else if (tag == kField) {
        FieldHelper field_helper(this);
        field_helper.ReadUntilExcluding(FieldHelper::kAnnotations);
      } else if (tag == kConstructor) {
        ConstructorHelper constructor_helper(this);
        constructor_helper.ReadUntilExcluding(ConstructorHelper::kAnnotations);
      } else if (tag == kFunctionDeclaration) {
        ReadTag();
        ReadPosition();  // fileOffset
        VariableDeclarationHelper variable_declaration_helper(this);
        variable_declaration_helper.ReadUntilExcluding(
            VariableDeclarationHelper::kAnnotations);
      } else {
        FATAL("No support for metadata on this type of kernel node: %" Pd32
              "\n",
              tag);
      }
    }

    return constant_reader_.ReadAnnotations();
  }

 private:
  ConstantReader constant_reader_;

  DISALLOW_COPY_AND_ASSIGN(MetadataEvaluator);
};

ObjectPtr EvaluateMetadata(const Library& library,
                           intptr_t kernel_offset,
                           bool is_annotations_offset) {
  Thread* thread = Thread::Current();
  LongJumpScope jump(thread);
  if (DART_SETJMP(*jump.Set()) == 0) {
    Zone* zone = thread->zone();
    TranslationHelper helper(thread);
    const auto& kernel_info =
        KernelProgramInfo::Handle(zone, library.kernel_program_info());
    helper.InitFromKernelProgramInfo(kernel_info);

    const Class& owner_class = Class::Handle(zone, library.toplevel_class());
    ActiveClass active_class;
    ActiveClassScope active_class_scope(&active_class, &owner_class);

    MetadataEvaluator metadata_evaluator(
        zone, &helper, TypedDataView::Handle(zone, library.KernelLibrary()),
        library.KernelLibraryOffset(), &active_class);

    return metadata_evaluator.EvaluateMetadata(kernel_offset,
                                               is_annotations_offset);

  } else {
    return thread->StealStickyError();
  }
}

class ParameterDescriptorBuilder : public KernelReaderHelper {
 public:
  ParameterDescriptorBuilder(TranslationHelper* translation_helper,
                             Zone* zone,
                             const TypedDataView& data,
                             intptr_t data_program_offset,
                             ActiveClass* active_class)
      : KernelReaderHelper(zone, translation_helper, data, data_program_offset),
        constant_reader_(this, active_class) {}

  ObjectPtr BuildParameterDescriptor(const Function& function);

 private:
  ConstantReader constant_reader_;

  DISALLOW_COPY_AND_ASSIGN(ParameterDescriptorBuilder);
};

ObjectPtr ParameterDescriptorBuilder::BuildParameterDescriptor(
    const Function& function) {
  SetOffset(function.kernel_offset());
  ReadUntilFunctionNode();
  FunctionNodeHelper function_node_helper(this);
  function_node_helper.ReadUntilExcluding(
      FunctionNodeHelper::kPositionalParameters);
  intptr_t param_count = function_node_helper.total_parameter_count_;
  intptr_t positional_count = ReadListLength();  // read list length.
  intptr_t named_parameter_count = param_count - positional_count;

  const Array& param_descriptor = Array::Handle(
      Array::New(param_count * Parser::kParameterEntrySize, Heap::kOld));
  for (intptr_t i = 0; i < param_count; ++i) {
    const intptr_t entry_start = i * Parser::kParameterEntrySize;

    if (i == positional_count) {
      intptr_t named_parameter_count_check =
          ReadListLength();  // read list length.
      ASSERT(named_parameter_count_check == named_parameter_count);
    }

    // Read ith variable declaration.
    intptr_t param_kernel_offset = reader_.offset();
    VariableDeclarationHelper helper(this);
    helper.ReadUntilExcluding(VariableDeclarationHelper::kInitializer);
    param_descriptor.SetAt(entry_start + Parser::kParameterIsFinalOffset,
                           helper.IsFinal() ? Bool::True() : Bool::False());

    Tag tag = ReadTag();  // read (first part of) initializer.
    if ((tag == kSomething) && !function.is_abstract()) {
      // This will read the initializer.
      Instance& constant = Instance::ZoneHandle(
          zone_, constant_reader_.ReadConstantExpression());
      param_descriptor.SetAt(entry_start + Parser::kParameterDefaultValueOffset,
                             constant);
    } else {
      if (tag == kSomething) {
        SkipExpression();  // Skip initializer.
      }
      param_descriptor.SetAt(entry_start + Parser::kParameterDefaultValueOffset,
                             Object::null_instance());
    }

    if (FLAG_enable_mirrors && (helper.annotation_count_ > 0)) {
      AlternativeReadingScope alt(&reader_, param_kernel_offset);
      VariableDeclarationHelper helper(this);
      helper.ReadUntilExcluding(VariableDeclarationHelper::kAnnotations);
      Object& metadata =
          Object::ZoneHandle(zone_, constant_reader_.ReadAnnotations());
      param_descriptor.SetAt(entry_start + Parser::kParameterMetadataOffset,
                             metadata);
    } else {
      param_descriptor.SetAt(entry_start + Parser::kParameterMetadataOffset,
                             Object::null_instance());
    }
  }
  return param_descriptor.ptr();
}

ObjectPtr BuildParameterDescriptor(const Function& function) {
  Thread* thread = Thread::Current();
  LongJumpScope jump(thread);
  if (DART_SETJMP(*jump.Set()) == 0) {
    Zone* zone = thread->zone();

    const auto& kernel_info =
        KernelProgramInfo::Handle(zone, function.KernelProgramInfo());

    TranslationHelper helper(thread);
    helper.InitFromKernelProgramInfo(kernel_info);

    const Class& owner_class = Class::Handle(zone, function.Owner());
    ActiveClass active_class;
    ActiveClassScope active_class_scope(&active_class, &owner_class);

    ParameterDescriptorBuilder builder(
        &helper, zone, TypedDataView::Handle(zone, function.KernelLibrary()),
        function.KernelLibraryOffset(), &active_class);

    return builder.BuildParameterDescriptor(function);
  } else {
    return thread->StealStickyError();
  }
}

void ReadParameterCovariance(const Function& function,
                             BitVector* is_covariant,
                             BitVector* is_generic_covariant_impl) {
  Thread* thread = Thread::Current();
  Zone* zone = thread->zone();

  const intptr_t num_params = function.NumParameters();
  ASSERT(is_covariant->length() == num_params);
  ASSERT(is_generic_covariant_impl->length() == num_params);

  const auto& kernel_info =
      KernelProgramInfo::Handle(zone, function.KernelProgramInfo());

  TranslationHelper translation_helper(thread);
  translation_helper.InitFromKernelProgramInfo(kernel_info);

  KernelReaderHelper reader_helper(
      zone, &translation_helper,
      TypedDataView::Handle(zone, function.KernelLibrary()),
      function.KernelLibraryOffset());

  reader_helper.SetOffset(function.kernel_offset());
  reader_helper.ReadUntilFunctionNode();

  FunctionNodeHelper function_node_helper(&reader_helper);
  function_node_helper.ReadUntilExcluding(
      FunctionNodeHelper::kPositionalParameters);

  // Positional.
  const intptr_t num_positional_params = reader_helper.ReadListLength();
  intptr_t param_index = function.NumImplicitParameters();
  for (intptr_t i = 0; i < num_positional_params; ++i, ++param_index) {
    VariableDeclarationHelper helper(&reader_helper);
    helper.ReadUntilExcluding(VariableDeclarationHelper::kEnd);

    if (helper.IsCovariant()) {
      is_covariant->Add(param_index);
    }
    if (helper.IsGenericCovariantImpl()) {
      is_generic_covariant_impl->Add(param_index);
    }
  }

  // Named.
  const intptr_t num_named_params = reader_helper.ReadListLength();
  for (intptr_t i = 0; i < num_named_params; ++i, ++param_index) {
    VariableDeclarationHelper helper(&reader_helper);
    helper.ReadUntilExcluding(VariableDeclarationHelper::kEnd);

    if (helper.IsCovariant()) {
      is_covariant->Add(param_index);
    }
    if (helper.IsGenericCovariantImpl()) {
      is_generic_covariant_impl->Add(param_index);
    }
  }
}

static ProcedureAttributesMetadata ProcedureAttributesOf(
    Zone* zone,
    const KernelProgramInfo& kernel_program_info,
    const TypedDataView& kernel_data,
    intptr_t kernel_data_program_offset,
    intptr_t kernel_offset) {
  TranslationHelper translation_helper(Thread::Current());
  translation_helper.InitFromKernelProgramInfo(kernel_program_info);
  KernelReaderHelper reader_helper(zone, &translation_helper, kernel_data,
                                   kernel_data_program_offset);
  ProcedureAttributesMetadataHelper procedure_attributes_metadata_helper(
      &reader_helper);
  ProcedureAttributesMetadata attrs =
      procedure_attributes_metadata_helper.GetProcedureAttributes(
          kernel_offset);
  return attrs;
}

ProcedureAttributesMetadata ProcedureAttributesOf(const Function& function,
                                                  Zone* zone) {
  const auto& kernel_program_info =
      KernelProgramInfo::Handle(zone, function.KernelProgramInfo());
  return ProcedureAttributesOf(
      zone, kernel_program_info,
      TypedDataView::Handle(zone, function.KernelLibrary()),
      function.KernelLibraryOffset(), function.kernel_offset());
}

ProcedureAttributesMetadata ProcedureAttributesOf(const Field& field,
                                                  Zone* zone) {
  const auto& kernel_program_info =
      KernelProgramInfo::Handle(zone, field.KernelProgramInfo());
  return ProcedureAttributesOf(
      zone, kernel_program_info,
      TypedDataView::Handle(zone, field.KernelLibrary()),
      field.KernelLibraryOffset(), field.kernel_offset());
}

static UnboxingInfoMetadata* UnboxingInfoMetadataOf(
    Zone* zone,
    const KernelProgramInfo& kernel_program_info,
    const TypedDataView& kernel_data,
    intptr_t kernel_data_program_offset,
    intptr_t kernel_offset) {
  TranslationHelper translation_helper(Thread::Current());
  translation_helper.InitFromKernelProgramInfo(kernel_program_info);
  KernelReaderHelper reader_helper(zone, &translation_helper, kernel_data,
                                   kernel_data_program_offset);
  UnboxingInfoMetadataHelper unboxing_info_metadata_helper(&reader_helper);
  return unboxing_info_metadata_helper.GetUnboxingInfoMetadata(kernel_offset);
}

UnboxingInfoMetadata* UnboxingInfoMetadataOf(const Function& function,
                                             Zone* zone) {
  const auto& kernel_program_info =
      KernelProgramInfo::Handle(zone, function.KernelProgramInfo());
  return UnboxingInfoMetadataOf(
      zone, kernel_program_info,
      TypedDataView::Handle(zone, function.KernelLibrary()),
      function.KernelLibraryOffset(), function.kernel_offset());
}

TableSelectorMetadata* TableSelectorMetadataForProgram(
    const KernelProgramInfo& info,
    Zone* zone) {
  TranslationHelper translation_helper(Thread::Current());
  translation_helper.InitFromKernelProgramInfo(info);
  const auto& data = TypedDataView::Handle(zone, info.metadata_payloads());
  KernelReaderHelper reader_helper(zone, &translation_helper, data, 0);
  TableSelectorMetadataHelper table_selector_metadata_helper(&reader_helper);
  return table_selector_metadata_helper.GetTableSelectorMetadata(zone);
}

}  // namespace kernel
}  // namespace dart

#endif  // !defined(DART_PRECOMPILED_RUNTIME)
