Line data Source code
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 : #ifndef V8_ASSEMBLER_H_
36 : #define V8_ASSEMBLER_H_
37 :
38 : #include <forward_list>
39 :
40 : #include "src/allocation.h"
41 : #include "src/builtins/builtins.h"
42 : #include "src/deoptimize-reason.h"
43 : #include "src/double.h"
44 : #include "src/globals.h"
45 : #include "src/label.h"
46 : #include "src/log.h"
47 : #include "src/register-configuration.h"
48 : #include "src/reglist.h"
49 : #include "src/runtime/runtime.h"
50 :
51 : namespace v8 {
52 :
53 : // Forward declarations.
54 : class ApiFunction;
55 :
56 : namespace internal {
57 :
58 : // Forward declarations.
59 : class Isolate;
60 : class SourcePosition;
61 : class StatsCounter;
62 :
63 : void SetUpJSCallerSavedCodeData();
64 :
65 : // Return the code of the n-th saved register available to JavaScript.
66 : int JSCallerSavedCode(int n);
67 :
68 : // -----------------------------------------------------------------------------
69 : // Optimization for far-jmp like instructions that can be replaced by shorter.
70 :
71 51346 : class JumpOptimizationInfo {
72 : public:
73 : bool is_collecting() const { return stage_ == kCollection; }
74 : bool is_optimizing() const { return stage_ == kOptimization; }
75 23146 : void set_optimizing() { stage_ = kOptimization; }
76 :
77 : bool is_optimizable() const { return optimizable_; }
78 23146 : void set_optimizable() { optimizable_ = true; }
79 :
80 : std::vector<uint32_t>& farjmp_bitmap() { return farjmp_bitmap_; }
81 :
82 : private:
83 : enum { kCollection, kOptimization } stage_ = kCollection;
84 : bool optimizable_ = false;
85 : std::vector<uint32_t> farjmp_bitmap_;
86 : };
87 :
88 : // -----------------------------------------------------------------------------
89 : // Platform independent assembler base class.
90 :
91 : enum class CodeObjectRequired { kNo, kYes };
92 :
93 :
94 : class AssemblerBase: public Malloced {
95 : public:
96 : struct IsolateData {
97 : explicit IsolateData(Isolate* isolate);
98 : IsolateData(const IsolateData&) = default;
99 :
100 : bool serializer_enabled_;
101 : #if V8_TARGET_ARCH_X64
102 : Address code_range_start_;
103 : #endif
104 : };
105 :
106 : AssemblerBase(IsolateData isolate_data, void* buffer, int buffer_size);
107 : virtual ~AssemblerBase();
108 :
109 : IsolateData isolate_data() const { return isolate_data_; }
110 :
111 : bool serializer_enabled() const { return isolate_data_.serializer_enabled_; }
112 265924 : void enable_serializer() { isolate_data_.serializer_enabled_ = true; }
113 :
114 : bool emit_debug_code() const { return emit_debug_code_; }
115 38432 : void set_emit_debug_code(bool value) { emit_debug_code_ = value; }
116 :
117 : bool predictable_code_size() const { return predictable_code_size_; }
118 0 : void set_predictable_code_size(bool value) { predictable_code_size_ = value; }
119 :
120 : uint64_t enabled_cpu_features() const { return enabled_cpu_features_; }
121 : void set_enabled_cpu_features(uint64_t features) {
122 : enabled_cpu_features_ = features;
123 : }
124 : // Features are usually enabled by CpuFeatureScope, which also asserts that
125 : // the features are supported before they are enabled.
126 : bool IsEnabled(CpuFeature f) {
127 : return (enabled_cpu_features_ & (static_cast<uint64_t>(1) << f)) != 0;
128 : }
129 : void EnableCpuFeature(CpuFeature f) {
130 : enabled_cpu_features_ |= (static_cast<uint64_t>(1) << f);
131 : }
132 :
133 : bool is_constant_pool_available() const {
134 : if (FLAG_enable_embedded_constant_pool) {
135 : return constant_pool_available_;
136 : } else {
137 : // Embedded constant pool not supported on this architecture.
138 : UNREACHABLE();
139 : }
140 : }
141 :
142 : JumpOptimizationInfo* jump_optimization_info() {
143 : return jump_optimization_info_;
144 : }
145 : void set_jump_optimization_info(JumpOptimizationInfo* jump_opt) {
146 1301515 : jump_optimization_info_ = jump_opt;
147 : }
148 :
149 : // Overwrite a host NaN with a quiet target NaN. Used by mksnapshot for
150 : // cross-snapshotting.
151 : static void QuietNaN(HeapObject* nan) { }
152 :
153 689481214 : int pc_offset() const { return static_cast<int>(pc_ - buffer_); }
154 :
155 : // This function is called when code generation is aborted, so that
156 : // the assembler could clean up internal data structures.
157 0 : virtual void AbortedCodeGeneration() { }
158 :
159 : // Debugging
160 : void Print(Isolate* isolate);
161 :
162 : static const int kMinimalBufferSize = 4*KB;
163 :
164 : static void FlushICache(Isolate* isolate, void* start, size_t size);
165 :
166 : protected:
167 : // The buffer into which code and relocation info are generated. It could
168 : // either be owned by the assembler or be provided externally.
169 : byte* buffer_;
170 : int buffer_size_;
171 : bool own_buffer_;
172 :
173 : void set_constant_pool_available(bool available) {
174 : if (FLAG_enable_embedded_constant_pool) {
175 : constant_pool_available_ = available;
176 : } else {
177 : // Embedded constant pool not supported on this architecture.
178 : UNREACHABLE();
179 : }
180 : }
181 :
182 : // The program counter, which points into the buffer above and moves forward.
183 : byte* pc_;
184 :
185 : private:
186 : IsolateData isolate_data_;
187 : uint64_t enabled_cpu_features_;
188 : bool emit_debug_code_;
189 : bool predictable_code_size_;
190 :
191 : // Indicates whether the constant pool can be accessed, which is only possible
192 : // if the pp register points to the current code object's constant pool.
193 : bool constant_pool_available_;
194 :
195 : JumpOptimizationInfo* jump_optimization_info_;
196 :
197 : // Constant pool.
198 : friend class FrameAndConstantPoolScope;
199 : friend class ConstantPoolUnavailableScope;
200 : };
201 :
202 : // Avoids emitting debug code during the lifetime of this scope object.
203 : class DontEmitDebugCodeScope BASE_EMBEDDED {
204 : public:
205 : explicit DontEmitDebugCodeScope(AssemblerBase* assembler)
206 : : assembler_(assembler), old_value_(assembler->emit_debug_code()) {
207 : assembler_->set_emit_debug_code(false);
208 : }
209 : ~DontEmitDebugCodeScope() {
210 : assembler_->set_emit_debug_code(old_value_);
211 : }
212 : private:
213 : AssemblerBase* assembler_;
214 : bool old_value_;
215 : };
216 :
217 :
218 : // Avoids using instructions that vary in size in unpredictable ways between the
219 : // snapshot and the running VM.
220 : class PredictableCodeSizeScope {
221 : public:
222 : explicit PredictableCodeSizeScope(AssemblerBase* assembler);
223 : PredictableCodeSizeScope(AssemblerBase* assembler, int expected_size);
224 : ~PredictableCodeSizeScope();
225 : void ExpectSize(int expected_size) { expected_size_ = expected_size; }
226 :
227 : private:
228 : AssemblerBase* assembler_;
229 : int expected_size_;
230 : int start_offset_;
231 : bool old_value_;
232 : };
233 :
234 :
235 : // Enable a specified feature within a scope.
236 : class CpuFeatureScope BASE_EMBEDDED {
237 : public:
238 : enum CheckPolicy {
239 : kCheckSupported,
240 : kDontCheckSupported,
241 : };
242 :
243 : #ifdef DEBUG
244 : CpuFeatureScope(AssemblerBase* assembler, CpuFeature f,
245 : CheckPolicy check = kCheckSupported);
246 : ~CpuFeatureScope();
247 :
248 : private:
249 : AssemblerBase* assembler_;
250 : uint64_t old_enabled_;
251 : #else
252 : CpuFeatureScope(AssemblerBase* assembler, CpuFeature f,
253 : CheckPolicy check = kCheckSupported) {}
254 : #endif
255 : };
256 :
257 :
258 : // CpuFeatures keeps track of which features are supported by the target CPU.
259 : // Supported features must be enabled by a CpuFeatureScope before use.
260 : // Example:
261 : // if (assembler->IsSupported(SSE3)) {
262 : // CpuFeatureScope fscope(assembler, SSE3);
263 : // // Generate code containing SSE3 instructions.
264 : // } else {
265 : // // Generate alternative code.
266 : // }
267 : class CpuFeatures : public AllStatic {
268 : public:
269 : static void Probe(bool cross_compile) {
270 : STATIC_ASSERT(NUMBER_OF_CPU_FEATURES <= kBitsPerInt);
271 1356262 : if (initialized_) return;
272 53977 : initialized_ = true;
273 53977 : ProbeImpl(cross_compile);
274 : }
275 :
276 : static unsigned SupportedFeatures() {
277 : Probe(false);
278 1302278 : return supported_;
279 : }
280 :
281 : static bool IsSupported(CpuFeature f) {
282 7035370 : return (supported_ & (1u << f)) != 0;
283 : }
284 :
285 : static inline bool SupportsCrankshaft();
286 :
287 : static inline bool SupportsWasmSimd128();
288 :
289 : static inline unsigned icache_line_size() {
290 : DCHECK_NE(icache_line_size_, 0);
291 : return icache_line_size_;
292 : }
293 :
294 : static inline unsigned dcache_line_size() {
295 : DCHECK_NE(dcache_line_size_, 0);
296 : return dcache_line_size_;
297 : }
298 :
299 : static void PrintTarget();
300 : static void PrintFeatures();
301 :
302 : private:
303 : friend class ExternalReference;
304 : friend class AssemblerBase;
305 : // Flush instruction cache.
306 : static void FlushICache(void* start, size_t size);
307 :
308 : // Platform-dependent implementation.
309 : static void ProbeImpl(bool cross_compile);
310 :
311 : static unsigned supported_;
312 : static unsigned icache_line_size_;
313 : static unsigned dcache_line_size_;
314 : static bool initialized_;
315 : DISALLOW_COPY_AND_ASSIGN(CpuFeatures);
316 : };
317 :
318 :
319 : enum SaveFPRegsMode { kDontSaveFPRegs, kSaveFPRegs };
320 :
321 : enum ArgvMode { kArgvOnStack, kArgvInRegister };
322 :
323 : // Specifies whether to perform icache flush operations on RelocInfo updates.
324 : // If FLUSH_ICACHE_IF_NEEDED, the icache will always be flushed if an
325 : // instruction was modified. If SKIP_ICACHE_FLUSH the flush will always be
326 : // skipped (only use this if you will flush the icache manually before it is
327 : // executed).
328 : enum ICacheFlushMode { FLUSH_ICACHE_IF_NEEDED, SKIP_ICACHE_FLUSH };
329 :
330 : // -----------------------------------------------------------------------------
331 : // Relocation information
332 :
333 :
334 : // Relocation information consists of the address (pc) of the datum
335 : // to which the relocation information applies, the relocation mode
336 : // (rmode), and an optional data field. The relocation mode may be
337 : // "descriptive" and not indicate a need for relocation, but simply
338 : // describe a property of the datum. Such rmodes are useful for GC
339 : // and nice disassembly output.
340 :
341 : class RelocInfo {
342 : public:
343 : // This string is used to add padding comments to the reloc info in cases
344 : // where we are not sure to have enough space for patching in during
345 : // lazy deoptimization. This is the case if we have indirect calls for which
346 : // we do not normally record relocation info.
347 : static const char* const kFillerCommentString;
348 :
349 : // The minimum size of a comment is equal to two bytes for the extra tagged
350 : // pc and kPointerSize for the actual pointer to the comment.
351 : static const int kMinRelocCommentSize = 2 + kPointerSize;
352 :
353 : // The maximum size for a call instruction including pc-jump.
354 : static const int kMaxCallSize = 6;
355 :
356 : // The maximum pc delta that will use the short encoding.
357 : static const int kMaxSmallPCDelta;
358 :
359 : enum Mode {
360 : // Please note the order is important (see IsCodeTarget, IsGCRelocMode).
361 : CODE_TARGET,
362 : EMBEDDED_OBJECT,
363 : // Wasm entries are to relocate pointers into the wasm memory embedded in
364 : // wasm code. Everything after WASM_CONTEXT_REFERENCE (inclusive) is not
365 : // GC'ed.
366 : WASM_CONTEXT_REFERENCE,
367 : WASM_FUNCTION_TABLE_SIZE_REFERENCE,
368 : WASM_PROTECTED_INSTRUCTION_LANDING,
369 : WASM_GLOBAL_HANDLE,
370 :
371 : RUNTIME_ENTRY,
372 : COMMENT,
373 :
374 : EXTERNAL_REFERENCE, // The address of an external C++ function.
375 : INTERNAL_REFERENCE, // An address inside the same function.
376 :
377 : // Encoded internal reference, used only on MIPS, MIPS64 and PPC.
378 : INTERNAL_REFERENCE_ENCODED,
379 :
380 : // Marks constant and veneer pools. Only used on ARM and ARM64.
381 : // They use a custom noncompact encoding.
382 : CONST_POOL,
383 : VENEER_POOL,
384 :
385 : DEOPT_SCRIPT_OFFSET,
386 : DEOPT_INLINING_ID, // Deoptimization source position.
387 : DEOPT_REASON, // Deoptimization reason index.
388 : DEOPT_ID, // Deoptimization inlining id.
389 :
390 : // This is not an actual reloc mode, but used to encode a long pc jump that
391 : // cannot be encoded as part of another record.
392 : PC_JUMP,
393 :
394 : // Pseudo-types
395 : NUMBER_OF_MODES,
396 : NONE32, // never recorded 32-bit value
397 : NONE64, // never recorded 64-bit value
398 :
399 : FIRST_REAL_RELOC_MODE = CODE_TARGET,
400 : LAST_REAL_RELOC_MODE = VENEER_POOL,
401 : LAST_CODE_ENUM = CODE_TARGET,
402 : LAST_GCED_ENUM = EMBEDDED_OBJECT,
403 : FIRST_SHAREABLE_RELOC_MODE = RUNTIME_ENTRY,
404 : };
405 :
406 : STATIC_ASSERT(NUMBER_OF_MODES <= kBitsPerInt);
407 :
408 : RelocInfo() = default;
409 :
410 : RelocInfo(byte* pc, Mode rmode, intptr_t data, Code* host)
411 16439249 : : pc_(pc), rmode_(rmode), data_(data), host_(host) {}
412 :
413 : static inline bool IsRealRelocMode(Mode mode) {
414 : return mode >= FIRST_REAL_RELOC_MODE && mode <= LAST_REAL_RELOC_MODE;
415 : }
416 505734 : static inline bool IsCodeTarget(Mode mode) {
417 452227477 : return mode <= LAST_CODE_ENUM;
418 : }
419 11748 : static inline bool IsEmbeddedObject(Mode mode) {
420 11748 : return mode == EMBEDDED_OBJECT;
421 : }
422 326844 : static inline bool IsRuntimeEntry(Mode mode) {
423 326844 : return mode == RUNTIME_ENTRY;
424 : }
425 : // Is the relocation mode affected by GC?
426 : static inline bool IsGCRelocMode(Mode mode) {
427 : return mode <= LAST_GCED_ENUM;
428 : }
429 : static inline bool IsComment(Mode mode) {
430 : return mode == COMMENT;
431 : }
432 : static inline bool IsConstPool(Mode mode) {
433 : return mode == CONST_POOL;
434 : }
435 : static inline bool IsVeneerPool(Mode mode) {
436 : return mode == VENEER_POOL;
437 : }
438 : static inline bool IsDeoptPosition(Mode mode) {
439 247804136 : return mode == DEOPT_SCRIPT_OFFSET || mode == DEOPT_INLINING_ID;
440 : }
441 : static inline bool IsDeoptReason(Mode mode) {
442 : return mode == DEOPT_REASON;
443 : }
444 : static inline bool IsDeoptId(Mode mode) {
445 : return mode == DEOPT_ID;
446 : }
447 11472 : static inline bool IsExternalReference(Mode mode) {
448 11472 : return mode == EXTERNAL_REFERENCE;
449 : }
450 332977 : static inline bool IsInternalReference(Mode mode) {
451 332977 : return mode == INTERNAL_REFERENCE;
452 : }
453 : static inline bool IsInternalReferenceEncoded(Mode mode) {
454 : return mode == INTERNAL_REFERENCE_ENCODED;
455 : }
456 : static inline bool IsNone(Mode mode) {
457 34582280 : return mode == NONE32 || mode == NONE64;
458 : }
459 : static inline bool IsWasmContextReference(Mode mode) {
460 : return mode == WASM_CONTEXT_REFERENCE;
461 : }
462 : static inline bool IsWasmFunctionTableSizeReference(Mode mode) {
463 : return mode == WASM_FUNCTION_TABLE_SIZE_REFERENCE;
464 : }
465 : static inline bool IsWasmReference(Mode mode) {
466 2377809 : return IsWasmPtrReference(mode) || IsWasmSizeReference(mode);
467 : }
468 : static inline bool IsWasmSizeReference(Mode mode) {
469 : return IsWasmFunctionTableSizeReference(mode);
470 : }
471 : static inline bool IsWasmPtrReference(Mode mode) {
472 5920247 : return mode == WASM_CONTEXT_REFERENCE || mode == WASM_GLOBAL_HANDLE;
473 : }
474 : static inline bool IsWasmProtectedLanding(Mode mode) {
475 : return mode == WASM_PROTECTED_INSTRUCTION_LANDING;
476 : }
477 :
478 10 : static inline int ModeMask(Mode mode) { return 1 << mode; }
479 :
480 : // Accessors
481 : byte* pc() const { return pc_; }
482 : void set_pc(byte* pc) { pc_ = pc; }
483 : Mode rmode() const { return rmode_; }
484 : intptr_t data() const { return data_; }
485 10163493 : Code* host() const { return host_; }
486 : void set_host(Code* host) { host_ = host; }
487 :
488 : // Apply a relocation by delta bytes. When the code object is moved, PC
489 : // relative addresses have to be updated as well as absolute addresses
490 : // inside the code (internal references).
491 : // Do not forget to flush the icache afterwards!
492 : INLINE(void apply(intptr_t delta));
493 :
494 : // Is the pointer this relocation info refers to coded like a plain pointer
495 : // or is it strange in some way (e.g. relative or patched into a series of
496 : // instructions).
497 : bool IsCodedSpecially();
498 :
499 : // If true, the pointer this relocation info refers to is an entry in the
500 : // constant pool, otherwise the pointer is embedded in the instruction stream.
501 : bool IsInConstantPool();
502 :
503 : Address wasm_context_reference() const;
504 : uint32_t wasm_function_table_size_reference() const;
505 : Address global_handle() const;
506 :
507 : void set_wasm_context_reference(
508 : Isolate* isolate, Address address,
509 : ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
510 : void update_wasm_function_table_size_reference(
511 : Isolate* isolate, uint32_t old_base, uint32_t new_base,
512 : ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
513 : void set_target_address(
514 : Isolate* isolate, Address target,
515 : WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER,
516 : ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
517 :
518 : void set_global_handle(
519 : Isolate* isolate, Address address,
520 : ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
521 :
522 : // this relocation applies to;
523 : // can only be called if IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)
524 : INLINE(Address target_address());
525 : INLINE(HeapObject* target_object());
526 : INLINE(Handle<HeapObject> target_object_handle(Assembler* origin));
527 : INLINE(void set_target_object(
528 : HeapObject* target,
529 : WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER,
530 : ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED));
531 : INLINE(Address target_runtime_entry(Assembler* origin));
532 : INLINE(void set_target_runtime_entry(
533 : Isolate* isolate, Address target,
534 : WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER,
535 : ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED));
536 : INLINE(Cell* target_cell());
537 : INLINE(Handle<Cell> target_cell_handle());
538 : INLINE(void set_target_cell(
539 : Cell* cell, WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER,
540 : ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED));
541 :
542 : // Returns the address of the constant pool entry where the target address
543 : // is held. This should only be called if IsInConstantPool returns true.
544 : INLINE(Address constant_pool_entry_address());
545 :
546 : // Read the address of the word containing the target_address in an
547 : // instruction stream. What this means exactly is architecture-independent.
548 : // The only architecture-independent user of this function is the serializer.
549 : // The serializer uses it to find out how many raw bytes of instruction to
550 : // output before the next target. Architecture-independent code shouldn't
551 : // dereference the pointer it gets back from this.
552 : INLINE(Address target_address_address());
553 :
554 : // This indicates how much space a target takes up when deserializing a code
555 : // stream. For most architectures this is just the size of a pointer. For
556 : // an instruction like movw/movt where the target bits are mixed into the
557 : // instruction bits the size of the target will be zero, indicating that the
558 : // serializer should not step forwards in memory after a target is resolved
559 : // and written. In this case the target_address_address function above
560 : // should return the end of the instructions to be patched, allowing the
561 : // deserializer to deserialize the instructions as raw bytes and put them in
562 : // place, ready to be patched with the target.
563 : INLINE(int target_address_size());
564 :
565 : // Read the reference in the instruction this relocation
566 : // applies to; can only be called if rmode_ is EXTERNAL_REFERENCE.
567 : INLINE(Address target_external_reference());
568 :
569 : // Read the reference in the instruction this relocation
570 : // applies to; can only be called if rmode_ is INTERNAL_REFERENCE.
571 : INLINE(Address target_internal_reference());
572 :
573 : // Return the reference address this relocation applies to;
574 : // can only be called if rmode_ is INTERNAL_REFERENCE.
575 : INLINE(Address target_internal_reference_address());
576 :
577 : // Wipe out a relocation to a fixed value, used for making snapshots
578 : // reproducible.
579 : INLINE(void WipeOut(Isolate* isolate));
580 :
581 : template <typename ObjectVisitor>
582 : inline void Visit(Isolate* isolate, ObjectVisitor* v);
583 :
584 : #ifdef DEBUG
585 : // Check whether the given code contains relocation information that
586 : // either is position-relative or movable by the garbage collector.
587 : static bool RequiresRelocation(Isolate* isolate, const CodeDesc& desc);
588 : #endif
589 :
590 : #ifdef ENABLE_DISASSEMBLER
591 : // Printing
592 : static const char* RelocModeName(Mode rmode);
593 : void Print(Isolate* isolate, std::ostream& os); // NOLINT
594 : #endif // ENABLE_DISASSEMBLER
595 : #ifdef VERIFY_HEAP
596 : void Verify(Isolate* isolate);
597 : #endif
598 :
599 : static const int kCodeTargetMask = (1 << (LAST_CODE_ENUM + 1)) - 1;
600 : static const int kApplyMask; // Modes affected by apply. Depends on arch.
601 :
602 : private:
603 : void set_embedded_address(Isolate* isolate, Address address,
604 : ICacheFlushMode flush_mode);
605 : void set_embedded_size(Isolate* isolate, uint32_t size,
606 : ICacheFlushMode flush_mode);
607 :
608 : uint32_t embedded_size() const;
609 : Address embedded_address() const;
610 :
611 : // On ARM, note that pc_ is the address of the constant pool entry
612 : // to be relocated and not the address of the instruction
613 : // referencing the constant pool entry (except when rmode_ ==
614 : // comment).
615 : byte* pc_;
616 : Mode rmode_;
617 : intptr_t data_;
618 : Code* host_;
619 : friend class RelocIterator;
620 : };
621 :
622 :
623 : // RelocInfoWriter serializes a stream of relocation info. It writes towards
624 : // lower addresses.
625 : class RelocInfoWriter BASE_EMBEDDED {
626 : public:
627 1709024 : RelocInfoWriter() : pos_(nullptr), last_pc_(nullptr) {}
628 : RelocInfoWriter(byte* pos, byte* pc) : pos_(pos), last_pc_(pc) {}
629 :
630 : byte* pos() const { return pos_; }
631 : byte* last_pc() const { return last_pc_; }
632 :
633 : void Write(const RelocInfo* rinfo);
634 :
635 : // Update the state of the stream after reloc info buffer
636 : // and/or code is moved while the stream is active.
637 : void Reposition(byte* pos, byte* pc) {
638 1913058 : pos_ = pos;
639 1913058 : last_pc_ = pc;
640 : }
641 :
642 : // Max size (bytes) of a written RelocInfo. Longest encoding is
643 : // ExtraTag, VariableLengthPCJump, ExtraTag, pc_delta, data_delta.
644 : // On ia32 and arm this is 1 + 4 + 1 + 1 + 4 = 11.
645 : // On x64 this is 1 + 4 + 1 + 1 + 8 == 15;
646 : // Here we use the maximum of the two.
647 : static const int kMaxSize = 15;
648 :
649 : private:
650 : inline uint32_t WriteLongPCJump(uint32_t pc_delta);
651 :
652 : inline void WriteShortTaggedPC(uint32_t pc_delta, int tag);
653 : inline void WriteShortData(intptr_t data_delta);
654 :
655 : inline void WriteMode(RelocInfo::Mode rmode);
656 : inline void WriteModeAndPC(uint32_t pc_delta, RelocInfo::Mode rmode);
657 : inline void WriteIntData(int data_delta);
658 : inline void WriteData(intptr_t data_delta);
659 :
660 : byte* pos_;
661 : byte* last_pc_;
662 : RelocInfo::Mode last_mode_;
663 :
664 : DISALLOW_COPY_AND_ASSIGN(RelocInfoWriter);
665 : };
666 :
667 :
668 : // A RelocIterator iterates over relocation information.
669 : // Typical use:
670 : //
671 : // for (RelocIterator it(code); !it.done(); it.next()) {
672 : // // do something with it.rinfo() here
673 : // }
674 : //
675 : // A mask can be specified to skip unwanted modes.
676 : class RelocIterator: public Malloced {
677 : public:
678 : // Create a new iterator positioned at
679 : // the beginning of the reloc info.
680 : // Relocation information with mode k is included in the
681 : // iteration iff bit k of mode_mask is set.
682 : explicit RelocIterator(Code* code, int mode_mask = -1);
683 : explicit RelocIterator(const CodeDesc& desc, int mode_mask = -1);
684 :
685 : // Iteration
686 100 : bool done() const { return done_; }
687 : void next();
688 :
689 : // Return pointer valid until next next().
690 70 : RelocInfo* rinfo() {
691 : DCHECK(!done());
692 70 : return &rinfo_;
693 : }
694 :
695 : private:
696 : // Advance* moves the position before/after reading.
697 : // *Read* reads from current byte(s) into rinfo_.
698 : // *Get* just reads and returns info on current byte.
699 5179672 : void Advance(int bytes = 1) { pos_ -= bytes; }
700 : int AdvanceGetTag();
701 : RelocInfo::Mode GetMode();
702 :
703 : void AdvanceReadLongPCJump();
704 :
705 : void ReadShortTaggedPC();
706 : void ReadShortData();
707 :
708 : void AdvanceReadPC();
709 : void AdvanceReadInt();
710 : void AdvanceReadData();
711 :
712 : // If the given mode is wanted, set it in rinfo_ and return true.
713 : // Else return false. Used for efficiently skipping unwanted modes.
714 : bool SetMode(RelocInfo::Mode mode) {
715 484247382 : return (mode_mask_ & (1 << mode)) ? (rinfo_.rmode_ = mode, true) : false;
716 : }
717 :
718 : byte* pos_;
719 : byte* end_;
720 : RelocInfo rinfo_;
721 : bool done_;
722 : int mode_mask_;
723 : DISALLOW_COPY_AND_ASSIGN(RelocIterator);
724 : };
725 :
726 :
727 : //------------------------------------------------------------------------------
728 : // External function
729 :
730 : //----------------------------------------------------------------------------
731 : class SCTableReference;
732 : class Debug_Address;
733 :
734 :
735 : // An ExternalReference represents a C++ address used in the generated
736 : // code. All references to C++ functions and variables must be encapsulated in
737 : // an ExternalReference instance. This is done in order to track the origin of
738 : // all external references in the code so that they can be bound to the correct
739 : // addresses when deserializing a heap.
740 : class ExternalReference BASE_EMBEDDED {
741 : public:
742 : // Used in the simulator to support different native api calls.
743 : enum Type {
744 : // Builtin call.
745 : // Object* f(v8::internal::Arguments).
746 : BUILTIN_CALL, // default
747 :
748 : // Builtin call returning object pair.
749 : // ObjectPair f(v8::internal::Arguments).
750 : BUILTIN_CALL_PAIR,
751 :
752 : // Builtin that takes float arguments and returns an int.
753 : // int f(double, double).
754 : BUILTIN_COMPARE_CALL,
755 :
756 : // Builtin call that returns floating point.
757 : // double f(double, double).
758 : BUILTIN_FP_FP_CALL,
759 :
760 : // Builtin call that returns floating point.
761 : // double f(double).
762 : BUILTIN_FP_CALL,
763 :
764 : // Builtin call that returns floating point.
765 : // double f(double, int).
766 : BUILTIN_FP_INT_CALL,
767 :
768 : // Direct call to API function callback.
769 : // void f(v8::FunctionCallbackInfo&)
770 : DIRECT_API_CALL,
771 :
772 : // Call to function callback via InvokeFunctionCallback.
773 : // void f(v8::FunctionCallbackInfo&, v8::FunctionCallback)
774 : PROFILING_API_CALL,
775 :
776 : // Direct call to accessor getter callback.
777 : // void f(Local<Name> property, PropertyCallbackInfo& info)
778 : DIRECT_GETTER_CALL,
779 :
780 : // Call to accessor getter callback via InvokeAccessorGetterCallback.
781 : // void f(Local<Name> property, PropertyCallbackInfo& info,
782 : // AccessorNameGetterCallback callback)
783 : PROFILING_GETTER_CALL
784 : };
785 :
786 : static void SetUp();
787 :
788 : // These functions must use the isolate in a thread-safe way.
789 : typedef void* ExternalReferenceRedirector(Isolate* isolate, void* original,
790 : Type type);
791 :
792 5509970 : ExternalReference() : address_(nullptr) {}
793 :
794 : ExternalReference(Address address, Isolate* isolate);
795 :
796 : ExternalReference(ApiFunction* ptr, Type type, Isolate* isolate);
797 :
798 : ExternalReference(Runtime::FunctionId id, Isolate* isolate);
799 :
800 : ExternalReference(const Runtime::Function* f, Isolate* isolate);
801 :
802 : explicit ExternalReference(StatsCounter* counter);
803 :
804 : ExternalReference(IsolateAddressId id, Isolate* isolate);
805 :
806 : explicit ExternalReference(const SCTableReference& table_ref);
807 :
808 : // Isolate as an external reference.
809 : static ExternalReference isolate_address(Isolate* isolate);
810 :
811 : // The builtins table as an external reference, used by lazy deserialization.
812 : static ExternalReference builtins_address(Isolate* isolate);
813 :
814 : // One-of-a-kind references. These references are not part of a general
815 : // pattern. This means that they have to be added to the
816 : // ExternalReferenceTable in serialize.cc manually.
817 :
818 : static ExternalReference interpreter_dispatch_table_address(Isolate* isolate);
819 : static ExternalReference interpreter_dispatch_counters(Isolate* isolate);
820 : static ExternalReference bytecode_size_table_address(Isolate* isolate);
821 :
822 : static ExternalReference incremental_marking_record_write_function(
823 : Isolate* isolate);
824 : static ExternalReference store_buffer_overflow_function(
825 : Isolate* isolate);
826 : static ExternalReference delete_handle_scope_extensions(Isolate* isolate);
827 :
828 : static ExternalReference get_date_field_function(Isolate* isolate);
829 : static ExternalReference date_cache_stamp(Isolate* isolate);
830 :
831 : // Deoptimization support.
832 : static ExternalReference new_deoptimizer_function(Isolate* isolate);
833 : static ExternalReference compute_output_frames_function(Isolate* isolate);
834 :
835 : static ExternalReference wasm_f32_trunc(Isolate* isolate);
836 : static ExternalReference wasm_f32_floor(Isolate* isolate);
837 : static ExternalReference wasm_f32_ceil(Isolate* isolate);
838 : static ExternalReference wasm_f32_nearest_int(Isolate* isolate);
839 : static ExternalReference wasm_f64_trunc(Isolate* isolate);
840 : static ExternalReference wasm_f64_floor(Isolate* isolate);
841 : static ExternalReference wasm_f64_ceil(Isolate* isolate);
842 : static ExternalReference wasm_f64_nearest_int(Isolate* isolate);
843 : static ExternalReference wasm_int64_to_float32(Isolate* isolate);
844 : static ExternalReference wasm_uint64_to_float32(Isolate* isolate);
845 : static ExternalReference wasm_int64_to_float64(Isolate* isolate);
846 : static ExternalReference wasm_uint64_to_float64(Isolate* isolate);
847 : static ExternalReference wasm_float32_to_int64(Isolate* isolate);
848 : static ExternalReference wasm_float32_to_uint64(Isolate* isolate);
849 : static ExternalReference wasm_float64_to_int64(Isolate* isolate);
850 : static ExternalReference wasm_float64_to_uint64(Isolate* isolate);
851 : static ExternalReference wasm_int64_div(Isolate* isolate);
852 : static ExternalReference wasm_int64_mod(Isolate* isolate);
853 : static ExternalReference wasm_uint64_div(Isolate* isolate);
854 : static ExternalReference wasm_uint64_mod(Isolate* isolate);
855 : static ExternalReference wasm_word32_ctz(Isolate* isolate);
856 : static ExternalReference wasm_word64_ctz(Isolate* isolate);
857 : static ExternalReference wasm_word32_popcnt(Isolate* isolate);
858 : static ExternalReference wasm_word64_popcnt(Isolate* isolate);
859 : static ExternalReference wasm_float64_pow(Isolate* isolate);
860 : static ExternalReference wasm_set_thread_in_wasm_flag(Isolate* isolate);
861 : static ExternalReference wasm_clear_thread_in_wasm_flag(Isolate* isolate);
862 :
863 : static ExternalReference f64_acos_wrapper_function(Isolate* isolate);
864 : static ExternalReference f64_asin_wrapper_function(Isolate* isolate);
865 : static ExternalReference f64_mod_wrapper_function(Isolate* isolate);
866 :
867 : // Trap callback function for cctest/wasm/wasm-run-utils.h
868 : static ExternalReference wasm_call_trap_callback_for_testing(
869 : Isolate* isolate);
870 :
871 : // Log support.
872 : static ExternalReference log_enter_external_function(Isolate* isolate);
873 : static ExternalReference log_leave_external_function(Isolate* isolate);
874 :
875 : // Static variable Heap::roots_array_start()
876 : static ExternalReference roots_array_start(Isolate* isolate);
877 :
878 : // Static variable Heap::allocation_sites_list_address()
879 : static ExternalReference allocation_sites_list_address(Isolate* isolate);
880 :
881 : // Static variable StackGuard::address_of_jslimit()
882 : V8_EXPORT_PRIVATE static ExternalReference address_of_stack_limit(
883 : Isolate* isolate);
884 :
885 : // Static variable StackGuard::address_of_real_jslimit()
886 : static ExternalReference address_of_real_stack_limit(Isolate* isolate);
887 :
888 : // Static variable RegExpStack::limit_address()
889 : static ExternalReference address_of_regexp_stack_limit(Isolate* isolate);
890 :
891 : // Direct access to FLAG_harmony_regexp_dotall.
892 : static ExternalReference address_of_regexp_dotall_flag(Isolate* isolate);
893 :
894 : // Static variables for RegExp.
895 : static ExternalReference address_of_static_offsets_vector(Isolate* isolate);
896 : static ExternalReference address_of_regexp_stack_memory_address(
897 : Isolate* isolate);
898 : static ExternalReference address_of_regexp_stack_memory_size(
899 : Isolate* isolate);
900 :
901 : // Write barrier.
902 : static ExternalReference store_buffer_top(Isolate* isolate);
903 : static ExternalReference heap_is_marking_flag_address(Isolate* isolate);
904 :
905 : // Used for fast allocation in generated code.
906 : static ExternalReference new_space_allocation_top_address(Isolate* isolate);
907 : static ExternalReference new_space_allocation_limit_address(Isolate* isolate);
908 : static ExternalReference old_space_allocation_top_address(Isolate* isolate);
909 : static ExternalReference old_space_allocation_limit_address(Isolate* isolate);
910 :
911 : static ExternalReference mod_two_doubles_operation(Isolate* isolate);
912 : static ExternalReference power_double_double_function(Isolate* isolate);
913 :
914 : static ExternalReference handle_scope_next_address(Isolate* isolate);
915 : static ExternalReference handle_scope_limit_address(Isolate* isolate);
916 : static ExternalReference handle_scope_level_address(Isolate* isolate);
917 :
918 : static ExternalReference scheduled_exception_address(Isolate* isolate);
919 : static ExternalReference address_of_pending_message_obj(Isolate* isolate);
920 :
921 : // Static variables containing common double constants.
922 : static ExternalReference address_of_min_int();
923 : static ExternalReference address_of_one_half();
924 : static ExternalReference address_of_minus_one_half();
925 : static ExternalReference address_of_negative_infinity();
926 : static ExternalReference address_of_the_hole_nan();
927 : static ExternalReference address_of_uint32_bias();
928 :
929 : // Static variables containing simd constants.
930 : static ExternalReference address_of_float_abs_constant();
931 : static ExternalReference address_of_float_neg_constant();
932 : static ExternalReference address_of_double_abs_constant();
933 : static ExternalReference address_of_double_neg_constant();
934 :
935 : // IEEE 754 functions.
936 : static ExternalReference ieee754_acos_function(Isolate* isolate);
937 : static ExternalReference ieee754_acosh_function(Isolate* isolate);
938 : static ExternalReference ieee754_asin_function(Isolate* isolate);
939 : static ExternalReference ieee754_asinh_function(Isolate* isolate);
940 : static ExternalReference ieee754_atan_function(Isolate* isolate);
941 : static ExternalReference ieee754_atanh_function(Isolate* isolate);
942 : static ExternalReference ieee754_atan2_function(Isolate* isolate);
943 : static ExternalReference ieee754_cbrt_function(Isolate* isolate);
944 : static ExternalReference ieee754_cos_function(Isolate* isolate);
945 : static ExternalReference ieee754_cosh_function(Isolate* isolate);
946 : static ExternalReference ieee754_exp_function(Isolate* isolate);
947 : static ExternalReference ieee754_expm1_function(Isolate* isolate);
948 : static ExternalReference ieee754_log_function(Isolate* isolate);
949 : static ExternalReference ieee754_log1p_function(Isolate* isolate);
950 : static ExternalReference ieee754_log10_function(Isolate* isolate);
951 : static ExternalReference ieee754_log2_function(Isolate* isolate);
952 : static ExternalReference ieee754_sin_function(Isolate* isolate);
953 : static ExternalReference ieee754_sinh_function(Isolate* isolate);
954 : static ExternalReference ieee754_tan_function(Isolate* isolate);
955 : static ExternalReference ieee754_tanh_function(Isolate* isolate);
956 :
957 : static ExternalReference libc_memchr_function(Isolate* isolate);
958 : static ExternalReference libc_memcpy_function(Isolate* isolate);
959 : static ExternalReference libc_memmove_function(Isolate* isolate);
960 : static ExternalReference libc_memset_function(Isolate* isolate);
961 :
962 : static ExternalReference printf_function(Isolate* isolate);
963 :
964 : static ExternalReference try_internalize_string_function(Isolate* isolate);
965 :
966 : static ExternalReference check_object_type(Isolate* isolate);
967 :
968 : #ifdef V8_INTL_SUPPORT
969 : static ExternalReference intl_convert_one_byte_to_lower(Isolate* isolate);
970 : static ExternalReference intl_to_latin1_lower_table(Isolate* isolate);
971 : #endif // V8_INTL_SUPPORT
972 :
973 : template <typename SubjectChar, typename PatternChar>
974 : static ExternalReference search_string_raw(Isolate* isolate);
975 :
976 : static ExternalReference orderedhashmap_gethash_raw(Isolate* isolate);
977 :
978 : static ExternalReference get_or_create_hash_raw(Isolate* isolate);
979 :
980 : static ExternalReference page_flags(Page* page);
981 :
982 : static ExternalReference ForDeoptEntry(Address entry);
983 :
984 : static ExternalReference cpu_features();
985 :
986 : static ExternalReference debug_is_active_address(Isolate* isolate);
987 : static ExternalReference debug_hook_on_function_call_address(
988 : Isolate* isolate);
989 :
990 : static ExternalReference is_profiling_address(Isolate* isolate);
991 : static ExternalReference invoke_function_callback(Isolate* isolate);
992 : static ExternalReference invoke_accessor_getter_callback(Isolate* isolate);
993 :
994 : static ExternalReference promise_hook_or_debug_is_active_address(
995 : Isolate* isolate);
996 :
997 : V8_EXPORT_PRIVATE static ExternalReference runtime_function_table_address(
998 : Isolate* isolate);
999 :
1000 57388585 : Address address() const { return reinterpret_cast<Address>(address_); }
1001 :
1002 : // Used to read out the last step action of the debugger.
1003 : static ExternalReference debug_last_step_action_address(Isolate* isolate);
1004 :
1005 : // Used to check for suspended generator, used for stepping across await call.
1006 : static ExternalReference debug_suspended_generator_address(Isolate* isolate);
1007 :
1008 : // Used to store the frame pointer to drop to when restarting a frame.
1009 : static ExternalReference debug_restart_fp_address(Isolate* isolate);
1010 :
1011 : #ifndef V8_INTERPRETED_REGEXP
1012 : // C functions called from RegExp generated code.
1013 :
1014 : // Function NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16()
1015 : static ExternalReference re_case_insensitive_compare_uc16(Isolate* isolate);
1016 :
1017 : // Function RegExpMacroAssembler*::CheckStackGuardState()
1018 : static ExternalReference re_check_stack_guard_state(Isolate* isolate);
1019 :
1020 : // Function NativeRegExpMacroAssembler::GrowStack()
1021 : static ExternalReference re_grow_stack(Isolate* isolate);
1022 :
1023 : // byte NativeRegExpMacroAssembler::word_character_bitmap
1024 : static ExternalReference re_word_character_map();
1025 :
1026 : #endif
1027 :
1028 : // This lets you register a function that rewrites all external references.
1029 : // Used by the ARM simulator to catch calls to external references.
1030 : static void set_redirector(Isolate* isolate,
1031 : ExternalReferenceRedirector* redirector);
1032 :
1033 : static ExternalReference stress_deopt_count(Isolate* isolate);
1034 :
1035 : static ExternalReference fixed_typed_array_base_data_offset();
1036 :
1037 : private:
1038 : explicit ExternalReference(void* address)
1039 : : address_(address) {}
1040 :
1041 49895343 : static void* Redirect(Isolate* isolate,
1042 : Address address_arg,
1043 : Type type = ExternalReference::BUILTIN_CALL) {
1044 : ExternalReferenceRedirector* redirector =
1045 : reinterpret_cast<ExternalReferenceRedirector*>(
1046 : isolate->external_reference_redirector());
1047 : void* address = reinterpret_cast<void*>(address_arg);
1048 : void* answer = (redirector == nullptr)
1049 : ? address
1050 49895343 : : (*redirector)(isolate, address, type);
1051 : return answer;
1052 : }
1053 :
1054 : void* address_;
1055 : };
1056 :
1057 : V8_EXPORT_PRIVATE bool operator==(ExternalReference, ExternalReference);
1058 : bool operator!=(ExternalReference, ExternalReference);
1059 :
1060 : size_t hash_value(ExternalReference);
1061 :
1062 : V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, ExternalReference);
1063 :
1064 : // -----------------------------------------------------------------------------
1065 : // Utility functions
1066 :
1067 : // Computes pow(x, y) with the special cases in the spec for Math.pow.
1068 : double power_helper(Isolate* isolate, double x, double y);
1069 : double power_double_int(double x, int y);
1070 : double power_double_double(double x, double y);
1071 :
1072 :
1073 : // -----------------------------------------------------------------------------
1074 : // Constant pool support
1075 :
1076 : class ConstantPoolEntry {
1077 : public:
1078 : ConstantPoolEntry() {}
1079 : ConstantPoolEntry(int position, intptr_t value, bool sharing_ok)
1080 : : position_(position),
1081 : merged_index_(sharing_ok ? SHARING_ALLOWED : SHARING_PROHIBITED),
1082 342 : value_(value) {}
1083 : ConstantPoolEntry(int position, Double value)
1084 : : position_(position),
1085 : merged_index_(SHARING_ALLOWED),
1086 342 : value64_(value.AsUint64()) {}
1087 :
1088 : int position() const { return position_; }
1089 : bool sharing_ok() const { return merged_index_ != SHARING_PROHIBITED; }
1090 : bool is_merged() const { return merged_index_ >= 0; }
1091 : int merged_index(void) const {
1092 : DCHECK(is_merged());
1093 : return merged_index_;
1094 : }
1095 : void set_merged_index(int index) {
1096 : DCHECK(sharing_ok());
1097 72 : merged_index_ = index;
1098 : DCHECK(is_merged());
1099 : }
1100 : int offset(void) const {
1101 : DCHECK_GE(merged_index_, 0);
1102 : return merged_index_;
1103 : }
1104 : void set_offset(int offset) {
1105 : DCHECK_GE(offset, 0);
1106 0 : merged_index_ = offset;
1107 : }
1108 : intptr_t value() const { return value_; }
1109 : uint64_t value64() const { return value64_; }
1110 :
1111 : enum Type { INTPTR, DOUBLE, NUMBER_OF_TYPES };
1112 :
1113 : static int size(Type type) {
1114 : return (type == INTPTR) ? kPointerSize : kDoubleSize;
1115 : }
1116 :
1117 : enum Access { REGULAR, OVERFLOWED };
1118 :
1119 : private:
1120 : int position_;
1121 : int merged_index_;
1122 : union {
1123 : intptr_t value_;
1124 : uint64_t value64_;
1125 : };
1126 : enum { SHARING_PROHIBITED = -2, SHARING_ALLOWED = -1 };
1127 : };
1128 :
1129 :
1130 : // -----------------------------------------------------------------------------
1131 : // Embedded constant pool support
1132 :
1133 108 : class ConstantPoolBuilder BASE_EMBEDDED {
1134 : public:
1135 : ConstantPoolBuilder(int ptr_reach_bits, int double_reach_bits);
1136 :
1137 : // Add pointer-sized constant to the embedded constant pool
1138 : ConstantPoolEntry::Access AddEntry(int position, intptr_t value,
1139 : bool sharing_ok) {
1140 : ConstantPoolEntry entry(position, value, sharing_ok);
1141 342 : return AddEntry(entry, ConstantPoolEntry::INTPTR);
1142 : }
1143 :
1144 : // Add double constant to the embedded constant pool
1145 : ConstantPoolEntry::Access AddEntry(int position, Double value) {
1146 : ConstantPoolEntry entry(position, value);
1147 342 : return AddEntry(entry, ConstantPoolEntry::DOUBLE);
1148 : }
1149 :
1150 : // Add double constant to the embedded constant pool
1151 : ConstantPoolEntry::Access AddEntry(int position, double value) {
1152 : return AddEntry(position, Double(value));
1153 : }
1154 :
1155 : // Previews the access type required for the next new entry to be added.
1156 : ConstantPoolEntry::Access NextAccess(ConstantPoolEntry::Type type) const;
1157 :
1158 : bool IsEmpty() {
1159 66 : return info_[ConstantPoolEntry::INTPTR].entries.empty() &&
1160 42 : info_[ConstantPoolEntry::INTPTR].shared_entries.empty() &&
1161 114 : info_[ConstantPoolEntry::DOUBLE].entries.empty() &&
1162 : info_[ConstantPoolEntry::DOUBLE].shared_entries.empty();
1163 : }
1164 :
1165 : // Emit the constant pool. Invoke only after all entries have been
1166 : // added and all instructions have been emitted.
1167 : // Returns position of the emitted pool (zero implies no constant pool).
1168 : int Emit(Assembler* assm);
1169 :
1170 : // Returns the label associated with the start of the constant pool.
1171 : // Linking to this label in the function prologue may provide an
1172 : // efficient means of constant pool pointer register initialization
1173 : // on some architectures.
1174 : inline Label* EmittedPosition() { return &emitted_label_; }
1175 :
1176 : private:
1177 : ConstantPoolEntry::Access AddEntry(ConstantPoolEntry& entry,
1178 : ConstantPoolEntry::Type type);
1179 : void EmitSharedEntries(Assembler* assm, ConstantPoolEntry::Type type);
1180 : void EmitGroup(Assembler* assm, ConstantPoolEntry::Access access,
1181 : ConstantPoolEntry::Type type);
1182 :
1183 144 : struct PerTypeEntryInfo {
1184 72 : PerTypeEntryInfo() : regular_count(0), overflow_start(-1) {}
1185 : bool overflow() const {
1186 1794 : return (overflow_start >= 0 &&
1187 480 : overflow_start < static_cast<int>(entries.size()));
1188 : }
1189 : int regular_reach_bits;
1190 : int regular_count;
1191 : int overflow_start;
1192 : std::vector<ConstantPoolEntry> entries;
1193 : std::vector<ConstantPoolEntry> shared_entries;
1194 : };
1195 :
1196 : Label emitted_label_; // Records pc_offset of emitted pool
1197 : PerTypeEntryInfo info_[ConstantPoolEntry::NUMBER_OF_TYPES];
1198 : };
1199 :
1200 : class HeapObjectRequest {
1201 : public:
1202 : explicit HeapObjectRequest(double heap_number, int offset = -1);
1203 : explicit HeapObjectRequest(CodeStub* code_stub, int offset = -1);
1204 :
1205 : enum Kind { kHeapNumber, kCodeStub };
1206 : Kind kind() const { return kind_; }
1207 :
1208 : double heap_number() const {
1209 : DCHECK_EQ(kind(), kHeapNumber);
1210 : return value_.heap_number;
1211 : }
1212 :
1213 : CodeStub* code_stub() const {
1214 : DCHECK_EQ(kind(), kCodeStub);
1215 : return value_.code_stub;
1216 : }
1217 :
1218 : // The code buffer offset at the time of the request.
1219 : int offset() const {
1220 : DCHECK_GE(offset_, 0);
1221 : return offset_;
1222 : }
1223 : void set_offset(int offset) {
1224 : DCHECK_LT(offset_, 0);
1225 88646 : offset_ = offset;
1226 : DCHECK_GE(offset_, 0);
1227 : }
1228 :
1229 : private:
1230 : Kind kind_;
1231 :
1232 : union {
1233 : double heap_number;
1234 : CodeStub* code_stub;
1235 : } value_;
1236 :
1237 : int offset_;
1238 : };
1239 :
1240 : // Base type for CPU Registers.
1241 : //
1242 : // 1) We would prefer to use an enum for registers, but enum values are
1243 : // assignment-compatible with int, which has caused code-generation bugs.
1244 : //
1245 : // 2) By not using an enum, we are possibly preventing the compiler from
1246 : // doing certain constant folds, which may significantly reduce the
1247 : // code generated for some assembly instructions (because they boil down
1248 : // to a few constants). If this is a problem, we could change the code
1249 : // such that we use an enum in optimized mode, and the class in debug
1250 : // mode. This way we get the compile-time error checking in debug mode
1251 : // and best performance in optimized code.
1252 : template <typename SubType, int kAfterLastRegister>
1253 : class RegisterBase {
1254 : public:
1255 : static constexpr int kCode_no_reg = -1;
1256 : static constexpr int kNumRegisters = kAfterLastRegister;
1257 :
1258 : static constexpr SubType no_reg() { return SubType{kCode_no_reg}; }
1259 :
1260 : template <int code>
1261 : static constexpr SubType from_code() {
1262 : static_assert(code >= 0 && code < kNumRegisters, "must be valid reg code");
1263 : return SubType{code};
1264 : }
1265 :
1266 : static SubType from_code(int code) {
1267 : DCHECK_LE(0, code);
1268 : DCHECK_GT(kNumRegisters, code);
1269 : return SubType{code};
1270 : }
1271 :
1272 3596 : bool is_valid() const { return reg_code_ != kCode_no_reg; }
1273 :
1274 : int code() const {
1275 : DCHECK(is_valid());
1276 5302206 : return reg_code_;
1277 : }
1278 :
1279 276027 : int bit() const { return 1 << code(); }
1280 :
1281 : inline bool operator==(SubType other) const {
1282 727559 : return reg_code_ == other.reg_code_;
1283 : }
1284 : inline bool operator!=(SubType other) const { return !(*this == other); }
1285 :
1286 : protected:
1287 : explicit constexpr RegisterBase(int code) : reg_code_(code) {}
1288 : int reg_code_;
1289 : };
1290 :
1291 : } // namespace internal
1292 : } // namespace v8
1293 : #endif // V8_ASSEMBLER_H_
|