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 #include "src/codegen/assembler-inl.h"
38 #include "src/codegen/string-constants.h"
39 #include "src/deoptimizer/deoptimizer.h"
40 #include "src/diagnostics/disassembler.h"
41 #include "src/execution/isolate.h"
42 #include "src/heap/heap-inl.h" // For MemoryAllocator. TODO(jkummerow): Drop.
43 #include "src/snapshot/embedded/embedded-data.h"
44 #include "src/snapshot/serializer-common.h"
45 #include "src/snapshot/snapshot.h"
46 #include "src/utils/ostreams.h"
47 #include "src/utils/vector.h"
48
49 namespace v8 {
50 namespace internal {
51
Default(Isolate * isolate)52 AssemblerOptions AssemblerOptions::Default(Isolate* isolate) {
53 AssemblerOptions options;
54 const bool serializer = isolate->serializer_enabled();
55 const bool generating_embedded_builtin =
56 isolate->IsGeneratingEmbeddedBuiltins();
57 options.record_reloc_info_for_serialization = serializer;
58 options.enable_root_array_delta_access =
59 !serializer && !generating_embedded_builtin;
60 #ifdef USE_SIMULATOR
61 // Even though the simulator is enabled, we may still need to generate code
62 // that may need to run on both the simulator and real hardware. For example,
63 // if we are cross-compiling and embedding a script into the snapshot, the
64 // script will need to run on the host causing the embedded builtins to run in
65 // the simulator. While the final cross-compiled V8 will not have a simulator.
66
67 // So here we enable simulator specific code if not generating the snapshot or
68 // if we are but we are targetting the simulator *only*.
69 options.enable_simulator_code = !serializer || FLAG_target_is_simulator;
70 #endif
71 options.inline_offheap_trampolines &= !generating_embedded_builtin;
72 #if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64
73 const base::AddressRegion& code_range = isolate->heap()->code_range();
74 DCHECK_IMPLIES(code_range.begin() != kNullAddress, !code_range.is_empty());
75 options.code_range_start = code_range.begin();
76 #endif
77 return options;
78 }
79
80 namespace {
81
82 class DefaultAssemblerBuffer : public AssemblerBuffer {
83 public:
DefaultAssemblerBuffer(int size)84 explicit DefaultAssemblerBuffer(int size)
85 : buffer_(OwnedVector<uint8_t>::New(size)) {
86 #ifdef DEBUG
87 ZapCode(reinterpret_cast<Address>(buffer_.start()), size);
88 #endif
89 }
90
start() const91 byte* start() const override { return buffer_.start(); }
92
size() const93 int size() const override { return static_cast<int>(buffer_.size()); }
94
Grow(int new_size)95 std::unique_ptr<AssemblerBuffer> Grow(int new_size) override {
96 DCHECK_LT(size(), new_size);
97 return std::make_unique<DefaultAssemblerBuffer>(new_size);
98 }
99
100 private:
101 OwnedVector<uint8_t> buffer_;
102 };
103
104 class ExternalAssemblerBufferImpl : public AssemblerBuffer {
105 public:
ExternalAssemblerBufferImpl(byte * start,int size)106 ExternalAssemblerBufferImpl(byte* start, int size)
107 : start_(start), size_(size) {}
108
start() const109 byte* start() const override { return start_; }
110
size() const111 int size() const override { return size_; }
112
Grow(int new_size)113 std::unique_ptr<AssemblerBuffer> Grow(int new_size) override {
114 FATAL("Cannot grow external assembler buffer");
115 }
116
117 private:
118 byte* const start_;
119 const int size_;
120 };
121
122 } // namespace
123
ExternalAssemblerBuffer(void * start,int size)124 std::unique_ptr<AssemblerBuffer> ExternalAssemblerBuffer(void* start,
125 int size) {
126 return std::make_unique<ExternalAssemblerBufferImpl>(
127 reinterpret_cast<byte*>(start), size);
128 }
129
NewAssemblerBuffer(int size)130 std::unique_ptr<AssemblerBuffer> NewAssemblerBuffer(int size) {
131 return std::make_unique<DefaultAssemblerBuffer>(size);
132 }
133
134 // -----------------------------------------------------------------------------
135 // Implementation of AssemblerBase
136
AssemblerBase(const AssemblerOptions & options,std::unique_ptr<AssemblerBuffer> buffer)137 AssemblerBase::AssemblerBase(const AssemblerOptions& options,
138 std::unique_ptr<AssemblerBuffer> buffer)
139 : buffer_(std::move(buffer)),
140 options_(options),
141 enabled_cpu_features_(0),
142 emit_debug_code_(FLAG_debug_code),
143 predictable_code_size_(false),
144 constant_pool_available_(false),
145 jump_optimization_info_(nullptr) {
146 if (!buffer_) buffer_ = NewAssemblerBuffer(kDefaultBufferSize);
147 buffer_start_ = buffer_->start();
148 pc_ = buffer_start_;
149 }
150
151 AssemblerBase::~AssemblerBase() = default;
152
Print(Isolate * isolate)153 void AssemblerBase::Print(Isolate* isolate) {
154 StdoutStream os;
155 v8::internal::Disassembler::Decode(isolate, &os, buffer_start_, pc_);
156 }
157
158 // -----------------------------------------------------------------------------
159 // Implementation of CpuFeatureScope
160
161 #ifdef DEBUG
CpuFeatureScope(AssemblerBase * assembler,CpuFeature f,CheckPolicy check)162 CpuFeatureScope::CpuFeatureScope(AssemblerBase* assembler, CpuFeature f,
163 CheckPolicy check)
164 : assembler_(assembler) {
165 DCHECK_IMPLIES(check == kCheckSupported, CpuFeatures::IsSupported(f));
166 old_enabled_ = assembler_->enabled_cpu_features();
167 assembler_->EnableCpuFeature(f);
168 }
169
~CpuFeatureScope()170 CpuFeatureScope::~CpuFeatureScope() {
171 assembler_->set_enabled_cpu_features(old_enabled_);
172 }
173 #endif
174
175 bool CpuFeatures::initialized_ = false;
176 unsigned CpuFeatures::supported_ = 0;
177 unsigned CpuFeatures::icache_line_size_ = 0;
178 unsigned CpuFeatures::dcache_line_size_ = 0;
179
HeapObjectRequest(double heap_number,int offset)180 HeapObjectRequest::HeapObjectRequest(double heap_number, int offset)
181 : kind_(kHeapNumber), offset_(offset) {
182 value_.heap_number = heap_number;
183 DCHECK(!IsSmiDouble(value_.heap_number));
184 }
185
HeapObjectRequest(const StringConstantBase * string,int offset)186 HeapObjectRequest::HeapObjectRequest(const StringConstantBase* string,
187 int offset)
188 : kind_(kStringConstant), offset_(offset) {
189 value_.string = string;
190 DCHECK_NOT_NULL(value_.string);
191 }
192
193 // Platform specific but identical code for all the platforms.
194
RecordDeoptReason(DeoptimizeReason reason,SourcePosition position,int id)195 void Assembler::RecordDeoptReason(DeoptimizeReason reason,
196 SourcePosition position, int id) {
197 EnsureSpace ensure_space(this);
198 RecordRelocInfo(RelocInfo::DEOPT_SCRIPT_OFFSET, position.ScriptOffset());
199 RecordRelocInfo(RelocInfo::DEOPT_INLINING_ID, position.InliningId());
200 RecordRelocInfo(RelocInfo::DEOPT_REASON, static_cast<int>(reason));
201 RecordRelocInfo(RelocInfo::DEOPT_ID, id);
202 }
203
DataAlign(int m)204 void Assembler::DataAlign(int m) {
205 DCHECK(m >= 2 && base::bits::IsPowerOfTwo(m));
206 while ((pc_offset() & (m - 1)) != 0) {
207 // Pad with 0xcc (= int3 on ia32 and x64); the primary motivation is that
208 // the disassembler expects to find valid instructions, but this is also
209 // nice from a security point of view.
210 db(0xcc);
211 }
212 }
213
RequestHeapObject(HeapObjectRequest request)214 void AssemblerBase::RequestHeapObject(HeapObjectRequest request) {
215 request.set_offset(pc_offset());
216 heap_object_requests_.push_front(request);
217 }
218
AddCodeTarget(Handle<Code> target)219 int AssemblerBase::AddCodeTarget(Handle<Code> target) {
220 int current = static_cast<int>(code_targets_.size());
221 if (current > 0 && !target.is_null() &&
222 code_targets_.back().address() == target.address()) {
223 // Optimization if we keep jumping to the same code target.
224 return current - 1;
225 } else {
226 code_targets_.push_back(target);
227 return current;
228 }
229 }
230
GetCodeTarget(intptr_t code_target_index) const231 Handle<Code> AssemblerBase::GetCodeTarget(intptr_t code_target_index) const {
232 DCHECK_LT(static_cast<size_t>(code_target_index), code_targets_.size());
233 return code_targets_[code_target_index];
234 }
235
AddEmbeddedObject(Handle<HeapObject> object)236 AssemblerBase::EmbeddedObjectIndex AssemblerBase::AddEmbeddedObject(
237 Handle<HeapObject> object) {
238 EmbeddedObjectIndex current = embedded_objects_.size();
239 // Do not deduplicate invalid handles, they are to heap object requests.
240 if (!object.is_null()) {
241 auto entry = embedded_objects_map_.find(object);
242 if (entry != embedded_objects_map_.end()) {
243 return entry->second;
244 }
245 embedded_objects_map_[object] = current;
246 }
247 embedded_objects_.push_back(object);
248 return current;
249 }
250
GetEmbeddedObject(EmbeddedObjectIndex index) const251 Handle<HeapObject> AssemblerBase::GetEmbeddedObject(
252 EmbeddedObjectIndex index) const {
253 DCHECK_LT(index, embedded_objects_.size());
254 return embedded_objects_[index];
255 }
256
257
WriteCodeComments()258 int Assembler::WriteCodeComments() {
259 if (!FLAG_code_comments || code_comments_writer_.entry_count() == 0) return 0;
260 int offset = pc_offset();
261 code_comments_writer_.Emit(this);
262 int size = pc_offset() - offset;
263 DCHECK_EQ(size, code_comments_writer_.section_size());
264 return size;
265 }
266
267 } // namespace internal
268 } // namespace v8
269