1// Copyright (c) 1994-2006 Sun Microsystems Inc. 2// All Rights Reserved. 3// 4// Redistribution and use in source and binary forms, with or without 5// modification, are permitted provided that the following conditions are 6// met: 7// 8// - Redistributions of source code must retain the above copyright notice, 9// this list of conditions and the following disclaimer. 10// 11// - Redistribution in binary form must reproduce the above copyright 12// notice, this list of conditions and the following disclaimer in the 13// documentation and/or other materials provided with the distribution. 14// 15// - Neither the name of Sun Microsystems or the names of contributors may 16// be used to endorse or promote products derived from this software without 17// specific prior written permission. 18// 19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31// The original source code covered by the above license above has been 32// modified significantly by Google Inc. 33// Copyright 2012 the V8 project authors. All rights reserved. 34 35#include "src/codegen/assembler.h" 36 37#ifdef V8_CODE_COMMENTS 38#include <iomanip> 39#endif 40#include "src/base/vector.h" 41#include "src/codegen/assembler-inl.h" 42#include "src/codegen/string-constants.h" 43#include "src/deoptimizer/deoptimizer.h" 44#include "src/diagnostics/disassembler.h" 45#include "src/execution/isolate.h" 46#include "src/heap/heap-inl.h" // For MemoryAllocator. TODO(jkummerow): Drop. 47#include "src/snapshot/embedded/embedded-data.h" 48#include "src/snapshot/snapshot.h" 49#include "src/utils/ostreams.h" 50 51namespace v8 { 52namespace internal { 53 54AssemblerOptions AssemblerOptions::Default(Isolate* isolate) { 55 AssemblerOptions options; 56 const bool serializer = isolate->serializer_enabled(); 57 const bool generating_embedded_builtin = 58 isolate->IsGeneratingEmbeddedBuiltins(); 59 options.record_reloc_info_for_serialization = serializer; 60 options.enable_root_relative_access = 61 !serializer && !generating_embedded_builtin; 62#ifdef USE_SIMULATOR 63 // Even though the simulator is enabled, we may still need to generate code 64 // that may need to run on both the simulator and real hardware. For example, 65 // if we are cross-compiling and embedding a script into the snapshot, the 66 // script will need to run on the host causing the embedded builtins to run in 67 // the simulator. While the final cross-compiled V8 will not have a simulator. 68 69 // So here we enable simulator specific code if not generating the snapshot or 70 // if we are but we are targetting the simulator *only*. 71 options.enable_simulator_code = !serializer || FLAG_target_is_simulator; 72#endif 73 options.inline_offheap_trampolines &= !generating_embedded_builtin; 74#if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64 75 options.code_range_base = isolate->heap()->code_range_base(); 76#endif 77 options.short_builtin_calls = 78 isolate->is_short_builtin_calls_enabled() && 79 !generating_embedded_builtin && 80 (options.code_range_base != kNullAddress) && 81 // Serialization of RUNTIME_ENTRY reloc infos is not supported yet. 82 !serializer; 83 return options; 84} 85 86AssemblerOptions AssemblerOptions::DefaultForOffHeapTrampoline( 87 Isolate* isolate) { 88 AssemblerOptions options = AssemblerOptions::Default(isolate); 89 // Off-heap trampolines may not contain any metadata since their metadata 90 // offsets refer to the off-heap metadata area. 91 options.emit_code_comments = false; 92 return options; 93} 94 95namespace { 96 97class DefaultAssemblerBuffer : public AssemblerBuffer { 98 public: 99 explicit DefaultAssemblerBuffer(int size) 100 : buffer_(base::OwnedVector<uint8_t>::NewForOverwrite( 101 std::max(AssemblerBase::kMinimalBufferSize, size))) { 102#ifdef DEBUG 103 ZapCode(reinterpret_cast<Address>(buffer_.start()), buffer_.size()); 104#endif 105 } 106 107 byte* start() const override { return buffer_.start(); } 108 109 int size() const override { return static_cast<int>(buffer_.size()); } 110 111 std::unique_ptr<AssemblerBuffer> Grow(int new_size) override { 112 DCHECK_LT(size(), new_size); 113 return std::make_unique<DefaultAssemblerBuffer>(new_size); 114 } 115 116 private: 117 base::OwnedVector<uint8_t> buffer_; 118}; 119 120class ExternalAssemblerBufferImpl : public AssemblerBuffer { 121 public: 122 ExternalAssemblerBufferImpl(byte* start, int size) 123 : start_(start), size_(size) {} 124 125 byte* start() const override { return start_; } 126 127 int size() const override { return size_; } 128 129 std::unique_ptr<AssemblerBuffer> Grow(int new_size) override { 130 FATAL("Cannot grow external assembler buffer"); 131 } 132 133 void* operator new(std::size_t count); 134 void operator delete(void* ptr) noexcept; 135 136 private: 137 byte* const start_; 138 const int size_; 139}; 140 141static thread_local std::aligned_storage_t<sizeof(ExternalAssemblerBufferImpl), 142 alignof(ExternalAssemblerBufferImpl)> 143 tls_singleton_storage; 144 145static thread_local bool tls_singleton_taken{false}; 146 147void* ExternalAssemblerBufferImpl::operator new(std::size_t count) { 148 DCHECK_EQ(count, sizeof(ExternalAssemblerBufferImpl)); 149 if (V8_LIKELY(!tls_singleton_taken)) { 150 tls_singleton_taken = true; 151 return &tls_singleton_storage; 152 } 153 return ::operator new(count); 154} 155 156void ExternalAssemblerBufferImpl::operator delete(void* ptr) noexcept { 157 if (V8_LIKELY(ptr == &tls_singleton_storage)) { 158 DCHECK(tls_singleton_taken); 159 tls_singleton_taken = false; 160 return; 161 } 162 ::operator delete(ptr); 163} 164 165} // namespace 166 167std::unique_ptr<AssemblerBuffer> ExternalAssemblerBuffer(void* start, 168 int size) { 169 return std::make_unique<ExternalAssemblerBufferImpl>( 170 reinterpret_cast<byte*>(start), size); 171} 172 173std::unique_ptr<AssemblerBuffer> NewAssemblerBuffer(int size) { 174 return std::make_unique<DefaultAssemblerBuffer>(size); 175} 176 177// ----------------------------------------------------------------------------- 178// Implementation of AssemblerBase 179 180// static 181constexpr int AssemblerBase::kMinimalBufferSize; 182 183// static 184constexpr int AssemblerBase::kDefaultBufferSize; 185 186AssemblerBase::AssemblerBase(const AssemblerOptions& options, 187 std::unique_ptr<AssemblerBuffer> buffer) 188 : buffer_(std::move(buffer)), 189 options_(options), 190 enabled_cpu_features_(0), 191 predictable_code_size_(false), 192 constant_pool_available_(false), 193 jump_optimization_info_(nullptr) { 194 if (!buffer_) buffer_ = NewAssemblerBuffer(kDefaultBufferSize); 195 buffer_start_ = buffer_->start(); 196 pc_ = buffer_start_; 197} 198 199AssemblerBase::~AssemblerBase() = default; 200 201void AssemblerBase::Print(Isolate* isolate) { 202 StdoutStream os; 203 v8::internal::Disassembler::Decode(isolate, os, buffer_start_, pc_); 204} 205 206// ----------------------------------------------------------------------------- 207// Implementation of CpuFeatureScope 208 209#ifdef DEBUG 210CpuFeatureScope::CpuFeatureScope(AssemblerBase* assembler, CpuFeature f, 211 CheckPolicy check) 212 : assembler_(assembler) { 213 DCHECK_IMPLIES(check == kCheckSupported, CpuFeatures::IsSupported(f)); 214 old_enabled_ = assembler_->enabled_cpu_features(); 215 assembler_->EnableCpuFeature(f); 216} 217 218CpuFeatureScope::~CpuFeatureScope() { 219 assembler_->set_enabled_cpu_features(old_enabled_); 220} 221#endif 222 223bool CpuFeatures::initialized_ = false; 224bool CpuFeatures::supports_wasm_simd_128_ = false; 225bool CpuFeatures::supports_cetss_ = false; 226unsigned CpuFeatures::supported_ = 0; 227unsigned CpuFeatures::icache_line_size_ = 0; 228unsigned CpuFeatures::dcache_line_size_ = 0; 229 230HeapObjectRequest::HeapObjectRequest(double heap_number, int offset) 231 : kind_(kHeapNumber), offset_(offset) { 232 value_.heap_number = heap_number; 233 DCHECK(!IsSmiDouble(value_.heap_number)); 234} 235 236HeapObjectRequest::HeapObjectRequest(const StringConstantBase* string, 237 int offset) 238 : kind_(kStringConstant), offset_(offset) { 239 value_.string = string; 240 DCHECK_NOT_NULL(value_.string); 241} 242 243// Platform specific but identical code for all the platforms. 244 245void Assembler::RecordDeoptReason(DeoptimizeReason reason, uint32_t node_id, 246 SourcePosition position, int id) { 247 EnsureSpace ensure_space(this); 248 RecordRelocInfo(RelocInfo::DEOPT_SCRIPT_OFFSET, position.ScriptOffset()); 249 RecordRelocInfo(RelocInfo::DEOPT_INLINING_ID, position.InliningId()); 250 RecordRelocInfo(RelocInfo::DEOPT_REASON, static_cast<int>(reason)); 251 RecordRelocInfo(RelocInfo::DEOPT_ID, id); 252#ifdef DEBUG 253 RecordRelocInfo(RelocInfo::DEOPT_NODE_ID, node_id); 254#endif // DEBUG 255} 256 257void Assembler::DataAlign(int m) { 258 DCHECK(m >= 2 && base::bits::IsPowerOfTwo(m)); 259 while ((pc_offset() & (m - 1)) != 0) { 260 // Pad with 0xcc (= int3 on ia32 and x64); the primary motivation is that 261 // the disassembler expects to find valid instructions, but this is also 262 // nice from a security point of view. 263 db(0xcc); 264 } 265} 266 267void AssemblerBase::RequestHeapObject(HeapObjectRequest request) { 268 request.set_offset(pc_offset()); 269 heap_object_requests_.push_front(request); 270} 271 272int AssemblerBase::AddCodeTarget(Handle<CodeT> target) { 273 int current = static_cast<int>(code_targets_.size()); 274 if (current > 0 && !target.is_null() && 275 code_targets_.back().address() == target.address()) { 276 // Optimization if we keep jumping to the same code target. 277 return current - 1; 278 } else { 279 code_targets_.push_back(target); 280 return current; 281 } 282} 283 284Handle<CodeT> AssemblerBase::GetCodeTarget(intptr_t code_target_index) const { 285 DCHECK_LT(static_cast<size_t>(code_target_index), code_targets_.size()); 286 return code_targets_[code_target_index]; 287} 288 289AssemblerBase::EmbeddedObjectIndex AssemblerBase::AddEmbeddedObject( 290 Handle<HeapObject> object) { 291 EmbeddedObjectIndex current = embedded_objects_.size(); 292 // Do not deduplicate invalid handles, they are to heap object requests. 293 if (!object.is_null()) { 294 auto entry = embedded_objects_map_.find(object); 295 if (entry != embedded_objects_map_.end()) { 296 return entry->second; 297 } 298 embedded_objects_map_[object] = current; 299 } 300 embedded_objects_.push_back(object); 301 return current; 302} 303 304Handle<HeapObject> AssemblerBase::GetEmbeddedObject( 305 EmbeddedObjectIndex index) const { 306 DCHECK_LT(index, embedded_objects_.size()); 307 return embedded_objects_[index]; 308} 309 310 311int Assembler::WriteCodeComments() { 312 if (!FLAG_code_comments) return 0; 313 CHECK_IMPLIES(code_comments_writer_.entry_count() > 0, 314 options().emit_code_comments); 315 if (code_comments_writer_.entry_count() == 0) return 0; 316 int offset = pc_offset(); 317 code_comments_writer_.Emit(this); 318 int size = pc_offset() - offset; 319 DCHECK_EQ(size, code_comments_writer_.section_size()); 320 return size; 321} 322 323#ifdef V8_CODE_COMMENTS 324int Assembler::CodeComment::depth() const { return assembler_->comment_depth_; } 325void Assembler::CodeComment::Open(const std::string& comment) { 326 std::stringstream sstream; 327 sstream << std::setfill(' ') << std::setw(depth() * kIndentWidth + 2); 328 sstream << "[ " << comment; 329 assembler_->comment_depth_++; 330 assembler_->RecordComment(sstream.str()); 331} 332 333void Assembler::CodeComment::Close() { 334 assembler_->comment_depth_--; 335 std::string comment = "]"; 336 comment.insert(0, depth() * kIndentWidth, ' '); 337 DCHECK_LE(0, depth()); 338 assembler_->RecordComment(comment); 339} 340#endif 341 342} // namespace internal 343} // namespace v8 344