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