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