text: // Copyright (c) 1994-2006 Sun Microsystems Inc.
  // All Rights Reserved.
  //
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions are
  // met:
  //
  // - Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // - Redistribution in binary form must reproduce the above copyright
  // notice, this list of conditions and the following disclaimer in the
  // documentation and/or other materials provided with the distribution.
  //
  // - Neither the name of Sun Microsystems or the names of contributors may
  // be used to endorse or promote products derived from this software without
  // specific prior written permission.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
  // The original source code covered by the above license above has been
  // modified significantly by Google Inc.
  // Copyright 2012 the V8 project authors. All rights reserved.
  
  #include "src/assembler.h"
  
  #include "src/assembler-inl.h"
  #include "src/deoptimizer.h"
  #include "src/disassembler.h"
  #include "src/heap/heap-inl.h"  // For MemoryAllocator. TODO(jkummerow): Drop.
  #include "src/isolate.h"
  #include "src/ostreams.h"
  #include "src/snapshot/embedded-data.h"
  #include "src/snapshot/serializer-common.h"
  #include "src/snapshot/snapshot.h"
  #include "src/string-constants.h"
  #include "src/vector.h"
  
  namespace v8 {
  namespace internal {
  
  AssemblerOptions AssemblerOptions::EnableV8AgnosticCode() const {
    AssemblerOptions options = *this;
    options.v8_agnostic_code = true;
    options.record_reloc_info_for_serialization = false;
    options.enable_root_array_delta_access = false;
    // Inherit |enable_simulator_code| value.
    options.isolate_independent_code = false;
    options.inline_offheap_trampolines = false;
    // Inherit |code_range_start| value.
    // Inherit |use_pc_relative_calls_and_jumps| value.
    return options;
  }
  
  AssemblerOptions AssemblerOptions::Default(
      Isolate* isolate, bool explicitly_support_serialization) {
    AssemblerOptions options;
    const bool serializer =
        isolate->serializer_enabled() || explicitly_support_serialization;
    const bool generating_embedded_builtin =
        isolate->IsGeneratingEmbeddedBuiltins();
    options.record_reloc_info_for_serialization = serializer;
    options.enable_root_array_delta_access =
        !serializer && !generating_embedded_builtin;
  #ifdef USE_SIMULATOR
    // Don't generate simulator specific code if we are building a snapshot, which
    // might be run on real hardware.
    options.enable_simulator_code = !serializer;
  #endif
    options.inline_offheap_trampolines =
        FLAG_embedded_builtins && !serializer && !generating_embedded_builtin;
  #if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64
    const base::AddressRegion& code_range =
        isolate->heap()->memory_allocator()->code_range();
    DCHECK_IMPLIES(code_range.begin() != kNullAddress, !code_range.is_empty());
    options.code_range_start = code_range.begin();
  #endif
    return options;
  }
  
  namespace {
  
  class DefaultAssemblerBuffer : public AssemblerBuffer {
   public:
    explicit DefaultAssemblerBuffer(int size)
        : buffer_(OwnedVector<uint8_t>::New(size)) {
  #ifdef DEBUG
      ZapCode(reinterpret_cast<Address>(buffer_.start()), size);
  #endif
    }
  
    byte* start() const override { return buffer_.start(); }
  
    int size() const override { return static_cast<int>(buffer_.size()); }
  
    std::unique_ptr<AssemblerBuffer> Grow(int new_size) override {
      DCHECK_LT(size(), new_size);
      return base::make_unique<DefaultAssemblerBuffer>(new_size);
    }
  
   private:
    OwnedVector<uint8_t> buffer_;
  };
  
  class ExternalAssemblerBufferImpl : public AssemblerBuffer {
   public:
    ExternalAssemblerBufferImpl(byte* start, int size)
        : start_(start), size_(size) {}
  
    byte* start() const override { return start_; }
  
    int size() const override { return size_; }
  
    std::unique_ptr<AssemblerBuffer> Grow(int new_size) override {
      FATAL("Cannot grow external assembler buffer");
    }
  
   private:
    byte* const start_;
    const int size_;
  };
  
  }  // namespace
  
  std::unique_ptr<AssemblerBuffer> ExternalAssemblerBuffer(void* start,
                                                           int size) {
    return base::make_unique<ExternalAssemblerBufferImpl>(
        reinterpret_cast<byte*>(start), size);
  }
  
  std::unique_ptr<AssemblerBuffer> NewAssemblerBuffer(int size) {
    return base::make_unique<DefaultAssemblerBuffer>(size);
  }
  
  // -----------------------------------------------------------------------------
  // Implementation of AssemblerBase
  
  AssemblerBase::AssemblerBase(const AssemblerOptions& options,
                               std::unique_ptr<AssemblerBuffer> buffer)
      : buffer_(std::move(buffer)),
        options_(options),
        enabled_cpu_features_(0),
        emit_debug_code_(FLAG_debug_code),
        predictable_code_size_(false),
        constant_pool_available_(false),
        jump_optimization_info_(nullptr) {
    if (!buffer_) buffer_ = NewAssemblerBuffer(kMinimalBufferSize);
    buffer_start_ = buffer_->start();
    pc_ = buffer_start_;
  }
  
  AssemblerBase::~AssemblerBase() = default;
  
  void AssemblerBase::Print(Isolate* isolate) {
    StdoutStream os;
    v8::internal::Disassembler::Decode(isolate, &os, buffer_start_, pc_);
  }
  
  // -----------------------------------------------------------------------------
  // Implementation of PredictableCodeSizeScope
  
  PredictableCodeSizeScope::PredictableCodeSizeScope(AssemblerBase* assembler,
                                                     int expected_size)
      : assembler_(assembler),
        expected_size_(expected_size),
        start_offset_(assembler->pc_offset()),
        old_value_(assembler->predictable_code_size()) {
    assembler_->set_predictable_code_size(true);
  }
  
  PredictableCodeSizeScope::~PredictableCodeSizeScope() {
    CHECK_EQ(expected_size_, assembler_->pc_offset() - start_offset_);
    assembler_->set_predictable_code_size(old_value_);
  }
  
  // -----------------------------------------------------------------------------
  // Implementation of CpuFeatureScope
  
  #ifdef DEBUG
  CpuFeatureScope::CpuFeatureScope(AssemblerBase* assembler, CpuFeature f,
                                   CheckPolicy check)
      : assembler_(assembler) {
    DCHECK_IMPLIES(check == kCheckSupported, CpuFeatures::IsSupported(f));
    old_enabled_ = assembler_->enabled_cpu_features();
    assembler_->EnableCpuFeature(f);
  }
  
  CpuFeatureScope::~CpuFeatureScope() {
    assembler_->set_enabled_cpu_features(old_enabled_);
  }
  #endif
  
  bool CpuFeatures::initialized_ = false;
  unsigned CpuFeatures::supported_ = 0;
  unsigned CpuFeatures::icache_line_size_ = 0;
  unsigned CpuFeatures::dcache_line_size_ = 0;
  
  HeapObjectRequest::HeapObjectRequest(double heap_number, int offset)
      : kind_(kHeapNumber), offset_(offset) {
    value_.heap_number = heap_number;
    DCHECK(!IsSmiDouble(value_.heap_number));
  }
  
  HeapObjectRequest::HeapObjectRequest(const StringConstantBase* string,
                                       int offset)
      : kind_(kStringConstant), offset_(offset) {
    value_.string = string;
    DCHECK_NOT_NULL(value_.string);
  }
  
  // Platform specific but identical code for all the platforms.
  
  void Assembler::RecordDeoptReason(DeoptimizeReason reason,
                                    SourcePosition position, int id) {
    EnsureSpace ensure_space(this);
    RecordRelocInfo(RelocInfo::DEOPT_SCRIPT_OFFSET, position.ScriptOffset());
    RecordRelocInfo(RelocInfo::DEOPT_INLINING_ID, position.InliningId());
    RecordRelocInfo(RelocInfo::DEOPT_REASON, static_cast<int>(reason));
    RecordRelocInfo(RelocInfo::DEOPT_ID, id);
  }
  
  void Assembler::DataAlign(int m) {
    DCHECK(m >= 2 && base::bits::IsPowerOfTwo(m));
    while ((pc_offset() & (m - 1)) != 0) {
      // Pad with 0xcc (= int3 on ia32 and x64); the primary motivation is that
      // the disassembler expects to find valid instructions, but this is also
      // nice from a security point of view.
      db(0xcc);
    }
  }
  
  void AssemblerBase::RequestHeapObject(HeapObjectRequest request) {
    DCHECK(!options().v8_agnostic_code);
    request.set_offset(pc_offset());
    heap_object_requests_.push_front(request);
  }
  
  int AssemblerBase::AddCodeTarget(Handle<Code> target) {
    DCHECK(!options().v8_agnostic_code);
    int current = static_cast<int>(code_targets_.size());
    if (current > 0 && !target.is_null() &&
        code_targets_.back().address() == target.address()) {
      // Optimization if we keep jumping to the same code target.
      return current - 1;
    } else {
      code_targets_.push_back(target);
      return current;
    }
  }
  
  Handle<Code> AssemblerBase::GetCodeTarget(intptr_t code_target_index) const {
    DCHECK(!options().v8_agnostic_code);
    DCHECK_LE(0, code_target_index);
    DCHECK_LT(code_target_index, code_targets_.size());
    return code_targets_[code_target_index];
  }
  
  void AssemblerBase::UpdateCodeTarget(intptr_t code_target_index,
                                       Handle<Code> code) {
    DCHECK(!options().v8_agnostic_code);
    DCHECK_LE(0, code_target_index);
    DCHECK_LT(code_target_index, code_targets_.size());
    code_targets_[code_target_index] = code;
  }
  
  int Assembler::WriteCodeComments() {
    if (!FLAG_code_comments || code_comments_writer_.entry_count() == 0) return 0;
    int offset = pc_offset();
    code_comments_writer_.Emit(this);
    int size = pc_offset() - offset;
    DCHECK_EQ(size, code_comments_writer_.section_size());
    return size;
  }
  
  }  // namespace internal
  }  // namespace v8
  