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