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
51 namespace v8 {
52 namespace internal {
53
Default(Isolate * isolate)54 AssemblerOptions 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
DefaultForOffHeapTrampoline(Isolate * isolate)86 AssemblerOptions 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
95 namespace {
96
97 class DefaultAssemblerBuffer : public AssemblerBuffer {
98 public:
DefaultAssemblerBuffer(int size)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
start() const107 byte* start() const override { return buffer_.start(); }
108
size() const109 int size() const override { return static_cast<int>(buffer_.size()); }
110
Grow(int new_size)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
120 class ExternalAssemblerBufferImpl : public AssemblerBuffer {
121 public:
ExternalAssemblerBufferImpl(byte * start,int size)122 ExternalAssemblerBufferImpl(byte* start, int size)
123 : start_(start), size_(size) {}
124
start() const125 byte* start() const override { return start_; }
126
size() const127 int size() const override { return size_; }
128
Grow(int new_size)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
141 static thread_local std::aligned_storage_t<sizeof(ExternalAssemblerBufferImpl),
142 alignof(ExternalAssemblerBufferImpl)>
143 tls_singleton_storage;
144
145 static thread_local bool tls_singleton_taken{false};
146
operator new(std::size_t count)147 void* 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
operator delete(void * ptr)156 void 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
ExternalAssemblerBuffer(void * start,int size)167 std::unique_ptr<AssemblerBuffer> ExternalAssemblerBuffer(void* start,
168 int size) {
169 return std::make_unique<ExternalAssemblerBufferImpl>(
170 reinterpret_cast<byte*>(start), size);
171 }
172
NewAssemblerBuffer(int size)173 std::unique_ptr<AssemblerBuffer> NewAssemblerBuffer(int size) {
174 return std::make_unique<DefaultAssemblerBuffer>(size);
175 }
176
177 // -----------------------------------------------------------------------------
178 // Implementation of AssemblerBase
179
180 // static
181 constexpr int AssemblerBase::kMinimalBufferSize;
182
183 // static
184 constexpr int AssemblerBase::kDefaultBufferSize;
185
AssemblerBase(const AssemblerOptions & options,std::unique_ptr<AssemblerBuffer> buffer)186 AssemblerBase::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
199 AssemblerBase::~AssemblerBase() = default;
200
Print(Isolate * isolate)201 void 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
CpuFeatureScope(AssemblerBase * assembler,CpuFeature f,CheckPolicy check)210 CpuFeatureScope::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
~CpuFeatureScope()218 CpuFeatureScope::~CpuFeatureScope() {
219 assembler_->set_enabled_cpu_features(old_enabled_);
220 }
221 #endif
222
223 bool CpuFeatures::initialized_ = false;
224 bool CpuFeatures::supports_wasm_simd_128_ = false;
225 bool CpuFeatures::supports_cetss_ = false;
226 unsigned CpuFeatures::supported_ = 0;
227 unsigned CpuFeatures::icache_line_size_ = 0;
228 unsigned CpuFeatures::dcache_line_size_ = 0;
229
HeapObjectRequest(double heap_number,int offset)230 HeapObjectRequest::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
HeapObjectRequest(const StringConstantBase * string,int offset)236 HeapObjectRequest::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
RecordDeoptReason(DeoptimizeReason reason,uint32_t node_id,SourcePosition position,int id)245 void 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
DataAlign(int m)257 void 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
RequestHeapObject(HeapObjectRequest request)267 void AssemblerBase::RequestHeapObject(HeapObjectRequest request) {
268 request.set_offset(pc_offset());
269 heap_object_requests_.push_front(request);
270 }
271
AddCodeTarget(Handle<CodeT> target)272 int 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
GetCodeTarget(intptr_t code_target_index) const284 Handle<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
AddEmbeddedObject(Handle<HeapObject> object)289 AssemblerBase::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
GetEmbeddedObject(EmbeddedObjectIndex index) const304 Handle<HeapObject> AssemblerBase::GetEmbeddedObject(
305 EmbeddedObjectIndex index) const {
306 DCHECK_LT(index, embedded_objects_.size());
307 return embedded_objects_[index];
308 }
309
310
WriteCodeComments()311 int 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
depth() const324 int Assembler::CodeComment::depth() const { return assembler_->comment_depth_; }
Open(const std::string & comment)325 void 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
Close()333 void 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