79e60c9382
to IsGeneratingEmbeddedBuiltins() to clarify its meaning. Bug: v8:6666 Change-Id: I8b282f29775a103a03f502c3e9629b40b4a690bd Reviewed-on: https://chromium-review.googlesource.com/c/1480380 Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Commit-Queue: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#59815}
291 lines
10 KiB
C++
291 lines
10 KiB
C++
// 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;
|
|
}
|
|
|
|
void AssemblerBase::ReserveCodeTargetSpace(size_t num_of_code_targets) {
|
|
code_targets_.reserve(num_of_code_targets);
|
|
}
|
|
|
|
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
|