blob: f23dccb53ecff98750996ef60e42577f3ebd7005 [file] [log] [blame]
// 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/codegen/assembler.h"
#include "src/codegen/assembler-inl.h"
#include "src/codegen/string-constants.h"
#include "src/deoptimizer/deoptimizer.h"
#include "src/diagnostics/disassembler.h"
#include "src/execution/isolate.h"
#include "src/heap/heap-inl.h" // For MemoryAllocator. TODO(jkummerow): Drop.
#include "src/snapshot/embedded/embedded-data.h"
#include "src/snapshot/snapshot.h"
#include "src/utils/ostreams.h"
#include "src/utils/vector.h"
namespace v8 {
namespace internal {
AssemblerOptions AssemblerOptions::Default(Isolate* isolate) {
AssemblerOptions options;
const bool serializer = isolate->serializer_enabled();
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
// Even though the simulator is enabled, we may still need to generate code
// that may need to run on both the simulator and real hardware. For example,
// if we are cross-compiling and embedding a script into the snapshot, the
// script will need to run on the host causing the embedded builtins to run in
// the simulator. While the final cross-compiled V8 will not have a simulator.
// So here we enable simulator specific code if not generating the snapshot or
// if we are but we are targetting the simulator *only*.
options.enable_simulator_code = !serializer || FLAG_target_is_simulator;
#endif
options.inline_offheap_trampolines &= !generating_embedded_builtin;
#if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64
const base::AddressRegion& code_range = isolate->heap()->code_range();
DCHECK_IMPLIES(code_range.begin() != kNullAddress, !code_range.is_empty());
options.code_range_start = code_range.begin();
#endif
return options;
}
AssemblerOptions AssemblerOptions::DefaultForOffHeapTrampoline(
Isolate* isolate) {
AssemblerOptions options = AssemblerOptions::Default(isolate);
// Off-heap trampolines may not contain any metadata since their metadata
// offsets refer to the off-heap metadata area.
options.emit_code_comments = false;
return options;
}
namespace {
class DefaultAssemblerBuffer : public AssemblerBuffer {
public:
explicit DefaultAssemblerBuffer(int size)
: buffer_(OwnedVector<uint8_t>::NewForOverwrite(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 std::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 std::make_unique<ExternalAssemblerBufferImpl>(
reinterpret_cast<byte*>(start), size);
}
std::unique_ptr<AssemblerBuffer> NewAssemblerBuffer(int size) {
return std::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(kDefaultBufferSize);
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 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) {
request.set_offset(pc_offset());
heap_object_requests_.push_front(request);
}
int AssemblerBase::AddCodeTarget(Handle<Code> target) {
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_LT(static_cast<size_t>(code_target_index), code_targets_.size());
return code_targets_[code_target_index];
}
AssemblerBase::EmbeddedObjectIndex AssemblerBase::AddEmbeddedObject(
Handle<HeapObject> object) {
EmbeddedObjectIndex current = embedded_objects_.size();
// Do not deduplicate invalid handles, they are to heap object requests.
if (!object.is_null()) {
auto entry = embedded_objects_map_.find(object);
if (entry != embedded_objects_map_.end()) {
return entry->second;
}
embedded_objects_map_[object] = current;
}
embedded_objects_.push_back(object);
return current;
}
Handle<HeapObject> AssemblerBase::GetEmbeddedObject(
EmbeddedObjectIndex index) const {
DCHECK_LT(index, embedded_objects_.size());
return embedded_objects_[index];
}
int Assembler::WriteCodeComments() {
CHECK_IMPLIES(code_comments_writer_.entry_count() > 0,
options().emit_code_comments);
if (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