// 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::New(size)) { #ifdef DEBUG ZapCode(reinterpret_cast
(buffer_.start()), size); #endif } byte* start() const override { return buffer_.start(); } int size() const override { return static_cast(buffer_.size()); } std::unique_ptr Grow(int new_size) override { DCHECK_LT(size(), new_size); return base::make_unique(new_size); } private: OwnedVector 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 Grow(int new_size) override { FATAL("Cannot grow external assembler buffer"); } private: byte* const start_; const int size_; }; } // namespace std::unique_ptr ExternalAssemblerBuffer(void* start, int size) { return base::make_unique( reinterpret_cast(start), size); } std::unique_ptr NewAssemblerBuffer(int size) { return base::make_unique(size); } // ----------------------------------------------------------------------------- // Implementation of AssemblerBase AssemblerBase::AssemblerBase(const AssemblerOptions& options, std::unique_ptr 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(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 target) { DCHECK(!options().v8_agnostic_code); int current = static_cast(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 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) { 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