OLD | NEW |
1 // Copyright (c) 1994-2006 Sun Microsystems Inc. | 1 // Copyright (c) 1994-2006 Sun Microsystems Inc. |
2 // All Rights Reserved. | 2 // All Rights Reserved. |
3 // | 3 // |
4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
5 // modification, are permitted provided that the following conditions | 5 // modification, are permitted provided that the following conditions |
6 // are met: | 6 // are met: |
7 // | 7 // |
8 // - Redistributions of source code must retain the above copyright notice, | 8 // - Redistributions of source code must retain the above copyright notice, |
9 // this list of conditions and the following disclaimer. | 9 // this list of conditions and the following disclaimer. |
10 // | 10 // |
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 // ----------------------------------------------------------------------------- | 227 // ----------------------------------------------------------------------------- |
228 // Implementation of RelocInfo | 228 // Implementation of RelocInfo |
229 | 229 |
230 // static | 230 // static |
231 const int RelocInfo::kApplyMask = 0; | 231 const int RelocInfo::kApplyMask = 0; |
232 | 232 |
233 | 233 |
234 bool RelocInfo::IsCodedSpecially() { | 234 bool RelocInfo::IsCodedSpecially() { |
235 // The deserializer needs to know whether a pointer is specially coded. Being | 235 // The deserializer needs to know whether a pointer is specially coded. Being |
236 // specially coded on ARM means that it is a movw/movt instruction, or is an | 236 // specially coded on ARM means that it is a movw/movt instruction, or is an |
237 // embedded constant pool entry. These only occur if | 237 // out of line constant pool entry. These only occur if |
238 // FLAG_enable_embedded_constant_pool is true. | 238 // FLAG_enable_ool_constant_pool is true. |
239 return FLAG_enable_embedded_constant_pool; | 239 return FLAG_enable_ool_constant_pool; |
240 } | 240 } |
241 | 241 |
242 | 242 |
243 bool RelocInfo::IsInConstantPool() { | 243 bool RelocInfo::IsInConstantPool() { |
244 return Assembler::is_constant_pool_load(pc_); | 244 return Assembler::is_constant_pool_load(pc_); |
245 } | 245 } |
246 | 246 |
247 | 247 |
248 // ----------------------------------------------------------------------------- | 248 // ----------------------------------------------------------------------------- |
249 // Implementation of Operand and MemOperand | 249 // Implementation of Operand and MemOperand |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
442 const Instr kLdrRegFpNegOffsetPattern = | 442 const Instr kLdrRegFpNegOffsetPattern = |
443 al | B26 | L | NegOffset | kRegister_fp_Code * B16; | 443 al | B26 | L | NegOffset | kRegister_fp_Code * B16; |
444 const Instr kStrRegFpNegOffsetPattern = | 444 const Instr kStrRegFpNegOffsetPattern = |
445 al | B26 | NegOffset | kRegister_fp_Code * B16; | 445 al | B26 | NegOffset | kRegister_fp_Code * B16; |
446 const Instr kLdrStrInstrTypeMask = 0xffff0000; | 446 const Instr kLdrStrInstrTypeMask = 0xffff0000; |
447 | 447 |
448 | 448 |
449 Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size) | 449 Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size) |
450 : AssemblerBase(isolate, buffer, buffer_size), | 450 : AssemblerBase(isolate, buffer, buffer_size), |
451 recorded_ast_id_(TypeFeedbackId::None()), | 451 recorded_ast_id_(TypeFeedbackId::None()), |
452 constant_pool_builder_(kLdrMaxReachBits, kVldrMaxReachBits), | 452 constant_pool_builder_(), |
453 positions_recorder_(this) { | 453 positions_recorder_(this) { |
454 reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_); | 454 reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_); |
455 num_pending_32_bit_constants_ = 0; | 455 num_pending_32_bit_reloc_info_ = 0; |
456 num_pending_64_bit_constants_ = 0; | 456 num_pending_64_bit_reloc_info_ = 0; |
457 next_buffer_check_ = 0; | 457 next_buffer_check_ = 0; |
458 const_pool_blocked_nesting_ = 0; | 458 const_pool_blocked_nesting_ = 0; |
459 no_const_pool_before_ = 0; | 459 no_const_pool_before_ = 0; |
460 first_const_pool_32_use_ = -1; | 460 first_const_pool_32_use_ = -1; |
461 first_const_pool_64_use_ = -1; | 461 first_const_pool_64_use_ = -1; |
462 last_bound_pos_ = 0; | 462 last_bound_pos_ = 0; |
463 ClearRecordedAstId(); | 463 ClearRecordedAstId(); |
464 } | 464 } |
465 | 465 |
466 | 466 |
467 Assembler::~Assembler() { | 467 Assembler::~Assembler() { |
468 DCHECK(const_pool_blocked_nesting_ == 0); | 468 DCHECK(const_pool_blocked_nesting_ == 0); |
469 } | 469 } |
470 | 470 |
471 | 471 |
472 void Assembler::GetCode(CodeDesc* desc) { | 472 void Assembler::GetCode(CodeDesc* desc) { |
473 reloc_info_writer.Finish(); | 473 reloc_info_writer.Finish(); |
474 | 474 if (!FLAG_enable_ool_constant_pool) { |
475 // Emit constant pool if necessary. | 475 // Emit constant pool if necessary. |
476 int constant_pool_offset = 0; | |
477 if (FLAG_enable_embedded_constant_pool) { | |
478 constant_pool_offset = EmitEmbeddedConstantPool(); | |
479 } else { | |
480 CheckConstPool(true, false); | 476 CheckConstPool(true, false); |
481 DCHECK(num_pending_32_bit_constants_ == 0); | 477 DCHECK(num_pending_32_bit_reloc_info_ == 0); |
482 DCHECK(num_pending_64_bit_constants_ == 0); | 478 DCHECK(num_pending_64_bit_reloc_info_ == 0); |
483 } | 479 } |
484 // Set up code descriptor. | 480 // Set up code descriptor. |
485 desc->buffer = buffer_; | 481 desc->buffer = buffer_; |
486 desc->buffer_size = buffer_size_; | 482 desc->buffer_size = buffer_size_; |
487 desc->instr_size = pc_offset(); | 483 desc->instr_size = pc_offset(); |
488 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); | 484 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); |
489 desc->constant_pool_size = | |
490 (constant_pool_offset ? desc->instr_size - constant_pool_offset : 0); | |
491 desc->origin = this; | 485 desc->origin = this; |
492 } | 486 } |
493 | 487 |
494 | 488 |
495 void Assembler::Align(int m) { | 489 void Assembler::Align(int m) { |
496 DCHECK(m >= 4 && base::bits::IsPowerOfTwo32(m)); | 490 DCHECK(m >= 4 && base::bits::IsPowerOfTwo32(m)); |
497 while ((pc_offset() & (m - 1)) != 0) { | 491 while ((pc_offset() & (m - 1)) != 0) { |
498 nop(); | 492 nop(); |
499 } | 493 } |
500 } | 494 } |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
622 | 616 |
623 | 617 |
624 Register Assembler::GetRm(Instr instr) { | 618 Register Assembler::GetRm(Instr instr) { |
625 Register reg; | 619 Register reg; |
626 reg.code_ = Instruction::RmValue(instr); | 620 reg.code_ = Instruction::RmValue(instr); |
627 return reg; | 621 return reg; |
628 } | 622 } |
629 | 623 |
630 | 624 |
631 Instr Assembler::GetConsantPoolLoadPattern() { | 625 Instr Assembler::GetConsantPoolLoadPattern() { |
632 if (FLAG_enable_embedded_constant_pool) { | 626 if (FLAG_enable_ool_constant_pool) { |
633 return kLdrPpImmedPattern; | 627 return kLdrPpImmedPattern; |
634 } else { | 628 } else { |
635 return kLdrPCImmedPattern; | 629 return kLdrPCImmedPattern; |
636 } | 630 } |
637 } | 631 } |
638 | 632 |
639 | 633 |
640 Instr Assembler::GetConsantPoolLoadMask() { | 634 Instr Assembler::GetConsantPoolLoadMask() { |
641 if (FLAG_enable_embedded_constant_pool) { | 635 if (FLAG_enable_ool_constant_pool) { |
642 return kLdrPpImmedMask; | 636 return kLdrPpImmedMask; |
643 } else { | 637 } else { |
644 return kLdrPCImmedMask; | 638 return kLdrPCImmedMask; |
645 } | 639 } |
646 } | 640 } |
647 | 641 |
648 | 642 |
649 bool Assembler::IsPush(Instr instr) { | 643 bool Assembler::IsPush(Instr instr) { |
650 return ((instr & ~kRdMask) == kPushRegPattern); | 644 return ((instr & ~kRdMask) == kPushRegPattern); |
651 } | 645 } |
(...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1043 return assembler->serializer_enabled(); | 1037 return assembler->serializer_enabled(); |
1044 } else if (RelocInfo::IsNone(rmode_)) { | 1038 } else if (RelocInfo::IsNone(rmode_)) { |
1045 return false; | 1039 return false; |
1046 } | 1040 } |
1047 return true; | 1041 return true; |
1048 } | 1042 } |
1049 | 1043 |
1050 | 1044 |
1051 static bool use_mov_immediate_load(const Operand& x, | 1045 static bool use_mov_immediate_load(const Operand& x, |
1052 const Assembler* assembler) { | 1046 const Assembler* assembler) { |
1053 if (FLAG_enable_embedded_constant_pool && assembler != NULL && | 1047 if (FLAG_enable_ool_constant_pool && assembler != NULL && |
1054 !assembler->is_constant_pool_available()) { | 1048 !assembler->is_ool_constant_pool_available()) { |
1055 return true; | 1049 return true; |
1056 } else if (CpuFeatures::IsSupported(MOVW_MOVT_IMMEDIATE_LOADS) && | 1050 } else if (CpuFeatures::IsSupported(MOVW_MOVT_IMMEDIATE_LOADS) && |
1057 (assembler == NULL || !assembler->predictable_code_size())) { | 1051 (assembler == NULL || !assembler->predictable_code_size())) { |
1058 // Prefer movw / movt to constant pool if it is more efficient on the CPU. | 1052 // Prefer movw / movt to constant pool if it is more efficient on the CPU. |
1059 return true; | 1053 return true; |
1060 } else if (x.must_output_reloc_info(assembler)) { | 1054 } else if (x.must_output_reloc_info(assembler)) { |
1061 // Prefer constant pool if data is likely to be patched. | 1055 // Prefer constant pool if data is likely to be patched. |
1062 return false; | 1056 return false; |
1063 } else { | 1057 } else { |
1064 // Otherwise, use immediate load if movw / movt is available. | 1058 // Otherwise, use immediate load if movw / movt is available. |
1065 return CpuFeatures::IsSupported(ARMv7); | 1059 return CpuFeatures::IsSupported(ARMv7); |
1066 } | 1060 } |
1067 } | 1061 } |
1068 | 1062 |
1069 | 1063 |
1070 int Operand::instructions_required(const Assembler* assembler, | 1064 int Operand::instructions_required(const Assembler* assembler, |
1071 Instr instr) const { | 1065 Instr instr) const { |
1072 if (rm_.is_valid()) return 1; | 1066 if (rm_.is_valid()) return 1; |
1073 uint32_t dummy1, dummy2; | 1067 uint32_t dummy1, dummy2; |
1074 if (must_output_reloc_info(assembler) || | 1068 if (must_output_reloc_info(assembler) || |
1075 !fits_shifter(imm32_, &dummy1, &dummy2, &instr)) { | 1069 !fits_shifter(imm32_, &dummy1, &dummy2, &instr)) { |
1076 // The immediate operand cannot be encoded as a shifter operand, or use of | 1070 // The immediate operand cannot be encoded as a shifter operand, or use of |
1077 // constant pool is required. First account for the instructions required | 1071 // constant pool is required. First account for the instructions required |
1078 // for the constant pool or immediate load | 1072 // for the constant pool or immediate load |
1079 int instructions; | 1073 int instructions; |
1080 if (use_mov_immediate_load(*this, assembler)) { | 1074 if (use_mov_immediate_load(*this, assembler)) { |
1081 // A movw / movt or mov / orr immediate load. | 1075 // A movw / movt or mov / orr immediate load. |
1082 instructions = CpuFeatures::IsSupported(ARMv7) ? 2 : 4; | 1076 instructions = CpuFeatures::IsSupported(ARMv7) ? 2 : 4; |
1083 } else if (assembler != NULL && | 1077 } else if (assembler != NULL && assembler->use_extended_constant_pool()) { |
1084 assembler->ConstantPoolAccessIsInOverflow()) { | 1078 // An extended constant pool load. |
1085 // An overflowed constant pool load. | |
1086 instructions = CpuFeatures::IsSupported(ARMv7) ? 3 : 5; | 1079 instructions = CpuFeatures::IsSupported(ARMv7) ? 3 : 5; |
1087 } else { | 1080 } else { |
1088 // A small constant pool load. | 1081 // A small constant pool load. |
1089 instructions = 1; | 1082 instructions = 1; |
1090 } | 1083 } |
1091 | 1084 |
1092 if ((instr & ~kCondMask) != 13 * B21) { // mov, S not set | 1085 if ((instr & ~kCondMask) != 13 * B21) { // mov, S not set |
1093 // For a mov or mvn instruction which doesn't set the condition | 1086 // For a mov or mvn instruction which doesn't set the condition |
1094 // code, the constant pool or immediate load is enough, otherwise we need | 1087 // code, the constant pool or immediate load is enough, otherwise we need |
1095 // to account for the actual instruction being requested. | 1088 // to account for the actual instruction being requested. |
1096 instructions += 1; | 1089 instructions += 1; |
1097 } | 1090 } |
1098 return instructions; | 1091 return instructions; |
1099 } else { | 1092 } else { |
1100 // No use of constant pool and the immediate operand can be encoded as a | 1093 // No use of constant pool and the immediate operand can be encoded as a |
1101 // shifter operand. | 1094 // shifter operand. |
1102 return 1; | 1095 return 1; |
1103 } | 1096 } |
1104 } | 1097 } |
1105 | 1098 |
1106 | 1099 |
1107 void Assembler::move_32_bit_immediate(Register rd, | 1100 void Assembler::move_32_bit_immediate(Register rd, |
1108 const Operand& x, | 1101 const Operand& x, |
1109 Condition cond) { | 1102 Condition cond) { |
| 1103 RelocInfo rinfo(pc_, x.rmode_, x.imm32_, NULL); |
1110 uint32_t imm32 = static_cast<uint32_t>(x.imm32_); | 1104 uint32_t imm32 = static_cast<uint32_t>(x.imm32_); |
1111 if (x.must_output_reloc_info(this)) { | 1105 if (x.must_output_reloc_info(this)) { |
1112 RecordRelocInfo(x.rmode_); | 1106 RecordRelocInfo(rinfo); |
1113 } | 1107 } |
1114 | 1108 |
1115 if (use_mov_immediate_load(x, this)) { | 1109 if (use_mov_immediate_load(x, this)) { |
1116 Register target = rd.code() == pc.code() ? ip : rd; | 1110 Register target = rd.code() == pc.code() ? ip : rd; |
1117 if (CpuFeatures::IsSupported(ARMv7)) { | 1111 if (CpuFeatures::IsSupported(ARMv7)) { |
1118 if (!FLAG_enable_embedded_constant_pool && | 1112 if (!FLAG_enable_ool_constant_pool && x.must_output_reloc_info(this)) { |
1119 x.must_output_reloc_info(this)) { | |
1120 // Make sure the movw/movt doesn't get separated. | 1113 // Make sure the movw/movt doesn't get separated. |
1121 BlockConstPoolFor(2); | 1114 BlockConstPoolFor(2); |
1122 } | 1115 } |
1123 movw(target, imm32 & 0xffff, cond); | 1116 movw(target, imm32 & 0xffff, cond); |
1124 movt(target, imm32 >> 16, cond); | 1117 movt(target, imm32 >> 16, cond); |
1125 } else { | 1118 } else { |
1126 DCHECK(FLAG_enable_embedded_constant_pool); | 1119 DCHECK(FLAG_enable_ool_constant_pool); |
1127 mov(target, Operand(imm32 & kImm8Mask), LeaveCC, cond); | 1120 mov(target, Operand(imm32 & kImm8Mask), LeaveCC, cond); |
1128 orr(target, target, Operand(imm32 & (kImm8Mask << 8)), LeaveCC, cond); | 1121 orr(target, target, Operand(imm32 & (kImm8Mask << 8)), LeaveCC, cond); |
1129 orr(target, target, Operand(imm32 & (kImm8Mask << 16)), LeaveCC, cond); | 1122 orr(target, target, Operand(imm32 & (kImm8Mask << 16)), LeaveCC, cond); |
1130 orr(target, target, Operand(imm32 & (kImm8Mask << 24)), LeaveCC, cond); | 1123 orr(target, target, Operand(imm32 & (kImm8Mask << 24)), LeaveCC, cond); |
1131 } | 1124 } |
1132 if (target.code() != rd.code()) { | 1125 if (target.code() != rd.code()) { |
1133 mov(rd, target, LeaveCC, cond); | 1126 mov(rd, target, LeaveCC, cond); |
1134 } | 1127 } |
1135 } else { | 1128 } else { |
1136 DCHECK(!FLAG_enable_embedded_constant_pool || is_constant_pool_available()); | 1129 DCHECK(!FLAG_enable_ool_constant_pool || is_ool_constant_pool_available()); |
1137 ConstantPoolEntry::Access access = | 1130 ConstantPoolArray::LayoutSection section = ConstantPoolAddEntry(rinfo); |
1138 ConstantPoolAddEntry(pc_offset(), x.rmode_, x.imm32_); | 1131 if (section == ConstantPoolArray::EXTENDED_SECTION) { |
1139 if (access == ConstantPoolEntry::OVERFLOWED) { | 1132 DCHECK(FLAG_enable_ool_constant_pool); |
1140 DCHECK(FLAG_enable_embedded_constant_pool); | |
1141 Register target = rd.code() == pc.code() ? ip : rd; | 1133 Register target = rd.code() == pc.code() ? ip : rd; |
1142 // Emit instructions to load constant pool offset. | 1134 // Emit instructions to load constant pool offset. |
1143 if (CpuFeatures::IsSupported(ARMv7)) { | 1135 if (CpuFeatures::IsSupported(ARMv7)) { |
1144 movw(target, 0, cond); | 1136 movw(target, 0, cond); |
1145 movt(target, 0, cond); | 1137 movt(target, 0, cond); |
1146 } else { | 1138 } else { |
1147 mov(target, Operand(0), LeaveCC, cond); | 1139 mov(target, Operand(0), LeaveCC, cond); |
1148 orr(target, target, Operand(0), LeaveCC, cond); | 1140 orr(target, target, Operand(0), LeaveCC, cond); |
1149 orr(target, target, Operand(0), LeaveCC, cond); | 1141 orr(target, target, Operand(0), LeaveCC, cond); |
1150 orr(target, target, Operand(0), LeaveCC, cond); | 1142 orr(target, target, Operand(0), LeaveCC, cond); |
1151 } | 1143 } |
1152 // Load from constant pool at offset. | 1144 // Load from constant pool at offset. |
1153 ldr(rd, MemOperand(pp, target), cond); | 1145 ldr(rd, MemOperand(pp, target), cond); |
1154 } else { | 1146 } else { |
1155 DCHECK(access == ConstantPoolEntry::REGULAR); | 1147 DCHECK(section == ConstantPoolArray::SMALL_SECTION); |
1156 ldr(rd, MemOperand(FLAG_enable_embedded_constant_pool ? pp : pc, 0), | 1148 ldr(rd, MemOperand(FLAG_enable_ool_constant_pool ? pp : pc, 0), cond); |
1157 cond); | |
1158 } | 1149 } |
1159 } | 1150 } |
1160 } | 1151 } |
1161 | 1152 |
1162 | 1153 |
1163 void Assembler::addrmod1(Instr instr, | 1154 void Assembler::addrmod1(Instr instr, |
1164 Register rn, | 1155 Register rn, |
1165 Register rd, | 1156 Register rd, |
1166 const Operand& x) { | 1157 const Operand& x) { |
1167 CheckBuffer(); | 1158 CheckBuffer(); |
(...skipping 1388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2556 if (CpuFeatures::IsSupported(VFP3) && FitsVMOVDoubleImmediate(imm, &enc)) { | 2547 if (CpuFeatures::IsSupported(VFP3) && FitsVMOVDoubleImmediate(imm, &enc)) { |
2557 // The double can be encoded in the instruction. | 2548 // The double can be encoded in the instruction. |
2558 // | 2549 // |
2559 // Dd = immediate | 2550 // Dd = immediate |
2560 // Instruction details available in ARM DDI 0406C.b, A8-936. | 2551 // Instruction details available in ARM DDI 0406C.b, A8-936. |
2561 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | imm4H(19-16) | | 2552 // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | imm4H(19-16) | |
2562 // Vd(15-12) | 101(11-9) | sz=1(8) | imm4L(3-0) | 2553 // Vd(15-12) | 101(11-9) | sz=1(8) | imm4L(3-0) |
2563 int vd, d; | 2554 int vd, d; |
2564 dst.split_code(&vd, &d); | 2555 dst.split_code(&vd, &d); |
2565 emit(al | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | enc); | 2556 emit(al | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | enc); |
2566 } else if (FLAG_enable_vldr_imm && is_constant_pool_available()) { | 2557 } else if (FLAG_enable_vldr_imm && is_ool_constant_pool_available()) { |
2567 // TODO(jfb) Temporarily turned off until we have constant blinding or | 2558 // TODO(jfb) Temporarily turned off until we have constant blinding or |
2568 // some equivalent mitigation: an attacker can otherwise control | 2559 // some equivalent mitigation: an attacker can otherwise control |
2569 // generated data which also happens to be executable, a Very Bad | 2560 // generated data which also happens to be executable, a Very Bad |
2570 // Thing indeed. | 2561 // Thing indeed. |
2571 // Blinding gets tricky because we don't have xor, we probably | 2562 // Blinding gets tricky because we don't have xor, we probably |
2572 // need to add/subtract without losing precision, which requires a | 2563 // need to add/subtract without losing precision, which requires a |
2573 // cookie value that Lithium is probably better positioned to | 2564 // cookie value that Lithium is probably better positioned to |
2574 // choose. | 2565 // choose. |
2575 // We could also add a few peepholes here like detecting 0.0 and | 2566 // We could also add a few peepholes here like detecting 0.0 and |
2576 // -0.0 and doing a vmov from the sequestered d14, forcing denorms | 2567 // -0.0 and doing a vmov from the sequestered d14, forcing denorms |
2577 // to zero (we set flush-to-zero), and normalizing NaN values. | 2568 // to zero (we set flush-to-zero), and normalizing NaN values. |
2578 // We could also detect redundant values. | 2569 // We could also detect redundant values. |
2579 // The code could also randomize the order of values, though | 2570 // The code could also randomize the order of values, though |
2580 // that's tricky because vldr has a limited reach. Furthermore | 2571 // that's tricky because vldr has a limited reach. Furthermore |
2581 // it breaks load locality. | 2572 // it breaks load locality. |
2582 ConstantPoolEntry::Access access = ConstantPoolAddEntry(pc_offset(), imm); | 2573 RelocInfo rinfo(pc_, imm); |
2583 if (access == ConstantPoolEntry::OVERFLOWED) { | 2574 ConstantPoolArray::LayoutSection section = ConstantPoolAddEntry(rinfo); |
2584 DCHECK(FLAG_enable_embedded_constant_pool); | 2575 if (section == ConstantPoolArray::EXTENDED_SECTION) { |
| 2576 DCHECK(FLAG_enable_ool_constant_pool); |
2585 // Emit instructions to load constant pool offset. | 2577 // Emit instructions to load constant pool offset. |
2586 movw(ip, 0); | 2578 movw(ip, 0); |
2587 movt(ip, 0); | 2579 movt(ip, 0); |
2588 // Load from constant pool at offset. | 2580 // Load from constant pool at offset. |
2589 vldr(dst, MemOperand(pp, ip)); | 2581 vldr(dst, MemOperand(pp, ip)); |
2590 } else { | 2582 } else { |
2591 DCHECK(access == ConstantPoolEntry::REGULAR); | 2583 DCHECK(section == ConstantPoolArray::SMALL_SECTION); |
2592 vldr(dst, MemOperand(FLAG_enable_embedded_constant_pool ? pp : pc, 0)); | 2584 vldr(dst, MemOperand(FLAG_enable_ool_constant_pool ? pp : pc, 0)); |
2593 } | 2585 } |
2594 } else { | 2586 } else { |
2595 // Synthesise the double from ARM immediates. | 2587 // Synthesise the double from ARM immediates. |
2596 uint32_t lo, hi; | 2588 uint32_t lo, hi; |
2597 DoubleAsTwoUInt32(imm, &lo, &hi); | 2589 DoubleAsTwoUInt32(imm, &lo, &hi); |
2598 | 2590 |
2599 if (lo == hi) { | 2591 if (lo == hi) { |
2600 // Move the low and high parts of the double to a D register in one | 2592 // Move the low and high parts of the double to a D register in one |
2601 // instruction. | 2593 // instruction. |
2602 mov(ip, Operand(lo)); | 2594 mov(ip, Operand(lo)); |
(...skipping 954 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3557 DeleteArray(buffer_); | 3549 DeleteArray(buffer_); |
3558 buffer_ = desc.buffer; | 3550 buffer_ = desc.buffer; |
3559 buffer_size_ = desc.buffer_size; | 3551 buffer_size_ = desc.buffer_size; |
3560 pc_ += pc_delta; | 3552 pc_ += pc_delta; |
3561 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta, | 3553 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta, |
3562 reloc_info_writer.last_pc() + pc_delta); | 3554 reloc_info_writer.last_pc() + pc_delta); |
3563 | 3555 |
3564 // None of our relocation types are pc relative pointing outside the code | 3556 // None of our relocation types are pc relative pointing outside the code |
3565 // buffer nor pc absolute pointing inside the code buffer, so there is no need | 3557 // buffer nor pc absolute pointing inside the code buffer, so there is no need |
3566 // to relocate any emitted relocation entries. | 3558 // to relocate any emitted relocation entries. |
| 3559 |
| 3560 // Relocate pending relocation entries. |
| 3561 for (int i = 0; i < num_pending_32_bit_reloc_info_; i++) { |
| 3562 RelocInfo& rinfo = pending_32_bit_reloc_info_[i]; |
| 3563 DCHECK(rinfo.rmode() != RelocInfo::COMMENT && |
| 3564 rinfo.rmode() != RelocInfo::POSITION); |
| 3565 if (rinfo.rmode() != RelocInfo::JS_RETURN) { |
| 3566 rinfo.set_pc(rinfo.pc() + pc_delta); |
| 3567 } |
| 3568 } |
| 3569 for (int i = 0; i < num_pending_64_bit_reloc_info_; i++) { |
| 3570 RelocInfo& rinfo = pending_64_bit_reloc_info_[i]; |
| 3571 DCHECK(rinfo.rmode() == RelocInfo::NONE64); |
| 3572 rinfo.set_pc(rinfo.pc() + pc_delta); |
| 3573 } |
| 3574 constant_pool_builder_.Relocate(pc_delta); |
3567 } | 3575 } |
3568 | 3576 |
3569 | 3577 |
3570 void Assembler::db(uint8_t data) { | 3578 void Assembler::db(uint8_t data) { |
3571 // No relocation info should be pending while using db. db is used | 3579 // No relocation info should be pending while using db. db is used |
3572 // to write pure data with no pointers and the constant pool should | 3580 // to write pure data with no pointers and the constant pool should |
3573 // be emitted before using db. | 3581 // be emitted before using db. |
3574 DCHECK(num_pending_32_bit_constants_ == 0); | 3582 DCHECK(num_pending_32_bit_reloc_info_ == 0); |
3575 DCHECK(num_pending_64_bit_constants_ == 0); | 3583 DCHECK(num_pending_64_bit_reloc_info_ == 0); |
3576 CheckBuffer(); | 3584 CheckBuffer(); |
3577 *reinterpret_cast<uint8_t*>(pc_) = data; | 3585 *reinterpret_cast<uint8_t*>(pc_) = data; |
3578 pc_ += sizeof(uint8_t); | 3586 pc_ += sizeof(uint8_t); |
3579 } | 3587 } |
3580 | 3588 |
3581 | 3589 |
3582 void Assembler::dd(uint32_t data) { | 3590 void Assembler::dd(uint32_t data) { |
3583 // No relocation info should be pending while using dd. dd is used | 3591 // No relocation info should be pending while using dd. dd is used |
3584 // to write pure data with no pointers and the constant pool should | 3592 // to write pure data with no pointers and the constant pool should |
3585 // be emitted before using dd. | 3593 // be emitted before using dd. |
3586 DCHECK(num_pending_32_bit_constants_ == 0); | 3594 DCHECK(num_pending_32_bit_reloc_info_ == 0); |
3587 DCHECK(num_pending_64_bit_constants_ == 0); | 3595 DCHECK(num_pending_64_bit_reloc_info_ == 0); |
3588 CheckBuffer(); | 3596 CheckBuffer(); |
3589 *reinterpret_cast<uint32_t*>(pc_) = data; | 3597 *reinterpret_cast<uint32_t*>(pc_) = data; |
3590 pc_ += sizeof(uint32_t); | 3598 pc_ += sizeof(uint32_t); |
3591 } | 3599 } |
3592 | 3600 |
3593 | 3601 |
3594 void Assembler::dq(uint64_t value) { | |
3595 // No relocation info should be pending while using dq. dq is used | |
3596 // to write pure data with no pointers and the constant pool should | |
3597 // be emitted before using dd. | |
3598 DCHECK(num_pending_32_bit_constants_ == 0); | |
3599 DCHECK(num_pending_64_bit_constants_ == 0); | |
3600 CheckBuffer(); | |
3601 *reinterpret_cast<uint64_t*>(pc_) = value; | |
3602 pc_ += sizeof(uint64_t); | |
3603 } | |
3604 | |
3605 | |
3606 void Assembler::emit_code_stub_address(Code* stub) { | 3602 void Assembler::emit_code_stub_address(Code* stub) { |
3607 CheckBuffer(); | 3603 CheckBuffer(); |
3608 *reinterpret_cast<uint32_t*>(pc_) = | 3604 *reinterpret_cast<uint32_t*>(pc_) = |
3609 reinterpret_cast<uint32_t>(stub->instruction_start()); | 3605 reinterpret_cast<uint32_t>(stub->instruction_start()); |
3610 pc_ += sizeof(uint32_t); | 3606 pc_ += sizeof(uint32_t); |
3611 } | 3607 } |
3612 | 3608 |
3613 | 3609 |
3614 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { | 3610 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { |
3615 if (RelocInfo::IsNone(rmode) || | |
3616 // Don't record external references unless the heap will be serialized. | |
3617 (rmode == RelocInfo::EXTERNAL_REFERENCE && !serializer_enabled() && | |
3618 !emit_debug_code())) { | |
3619 return; | |
3620 } | |
3621 DCHECK(buffer_space() >= kMaxRelocSize); // too late to grow buffer here | |
3622 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) { | |
3623 data = RecordedAstId().ToInt(); | |
3624 ClearRecordedAstId(); | |
3625 } | |
3626 RelocInfo rinfo(pc_, rmode, data, NULL); | 3611 RelocInfo rinfo(pc_, rmode, data, NULL); |
3627 reloc_info_writer.Write(&rinfo); | 3612 RecordRelocInfo(rinfo); |
3628 } | 3613 } |
3629 | 3614 |
3630 | 3615 |
3631 ConstantPoolEntry::Access Assembler::ConstantPoolAddEntry(int position, | 3616 void Assembler::RecordRelocInfo(const RelocInfo& rinfo) { |
3632 RelocInfo::Mode rmode, | 3617 if (!RelocInfo::IsNone(rinfo.rmode())) { |
3633 intptr_t value) { | 3618 // Don't record external references unless the heap will be serialized. |
3634 DCHECK(rmode != RelocInfo::COMMENT && rmode != RelocInfo::POSITION && | 3619 if (rinfo.rmode() == RelocInfo::EXTERNAL_REFERENCE && |
3635 rmode != RelocInfo::STATEMENT_POSITION && | 3620 !serializer_enabled() && !emit_debug_code()) { |
3636 rmode != RelocInfo::CONST_POOL && rmode != RelocInfo::NONE64); | 3621 return; |
3637 bool sharing_ok = RelocInfo::IsNone(rmode) || | |
3638 !(serializer_enabled() || rmode < RelocInfo::CELL); | |
3639 if (FLAG_enable_embedded_constant_pool) { | |
3640 return constant_pool_builder_.AddEntry(position, value, sharing_ok); | |
3641 } else { | |
3642 DCHECK(num_pending_32_bit_constants_ < kMaxNumPending32Constants); | |
3643 if (num_pending_32_bit_constants_ == 0) { | |
3644 first_const_pool_32_use_ = position; | |
3645 } | 3622 } |
3646 ConstantPoolEntry entry(position, value, sharing_ok); | 3623 DCHECK(buffer_space() >= kMaxRelocSize); // too late to grow buffer here |
3647 pending_32_bit_constants_[num_pending_32_bit_constants_++] = entry; | 3624 if (rinfo.rmode() == RelocInfo::CODE_TARGET_WITH_ID) { |
3648 | 3625 RelocInfo reloc_info_with_ast_id(rinfo.pc(), |
3649 // Make sure the constant pool is not emitted in place of the next | 3626 rinfo.rmode(), |
3650 // instruction for which we just recorded relocation info. | 3627 RecordedAstId().ToInt(), |
3651 BlockConstPoolFor(1); | 3628 NULL); |
3652 return ConstantPoolEntry::REGULAR; | 3629 ClearRecordedAstId(); |
| 3630 reloc_info_writer.Write(&reloc_info_with_ast_id); |
| 3631 } else { |
| 3632 reloc_info_writer.Write(&rinfo); |
| 3633 } |
3653 } | 3634 } |
3654 } | 3635 } |
3655 | 3636 |
3656 | 3637 |
3657 ConstantPoolEntry::Access Assembler::ConstantPoolAddEntry(int position, | 3638 ConstantPoolArray::LayoutSection Assembler::ConstantPoolAddEntry( |
3658 double value) { | 3639 const RelocInfo& rinfo) { |
3659 if (FLAG_enable_embedded_constant_pool) { | 3640 if (FLAG_enable_ool_constant_pool) { |
3660 return constant_pool_builder_.AddEntry(position, value); | 3641 return constant_pool_builder_.AddEntry(this, rinfo); |
3661 } else { | 3642 } else { |
3662 DCHECK(num_pending_64_bit_constants_ < kMaxNumPending64Constants); | 3643 if (rinfo.rmode() == RelocInfo::NONE64) { |
3663 if (num_pending_64_bit_constants_ == 0) { | 3644 DCHECK(num_pending_64_bit_reloc_info_ < kMaxNumPending64RelocInfo); |
3664 first_const_pool_64_use_ = position; | 3645 if (num_pending_64_bit_reloc_info_ == 0) { |
| 3646 first_const_pool_64_use_ = pc_offset(); |
| 3647 } |
| 3648 pending_64_bit_reloc_info_[num_pending_64_bit_reloc_info_++] = rinfo; |
| 3649 } else { |
| 3650 DCHECK(num_pending_32_bit_reloc_info_ < kMaxNumPending32RelocInfo); |
| 3651 if (num_pending_32_bit_reloc_info_ == 0) { |
| 3652 first_const_pool_32_use_ = pc_offset(); |
| 3653 } |
| 3654 pending_32_bit_reloc_info_[num_pending_32_bit_reloc_info_++] = rinfo; |
3665 } | 3655 } |
3666 ConstantPoolEntry entry(position, value); | |
3667 pending_64_bit_constants_[num_pending_64_bit_constants_++] = entry; | |
3668 | |
3669 // Make sure the constant pool is not emitted in place of the next | 3656 // Make sure the constant pool is not emitted in place of the next |
3670 // instruction for which we just recorded relocation info. | 3657 // instruction for which we just recorded relocation info. |
3671 BlockConstPoolFor(1); | 3658 BlockConstPoolFor(1); |
3672 return ConstantPoolEntry::REGULAR; | 3659 return ConstantPoolArray::SMALL_SECTION; |
3673 } | 3660 } |
3674 } | 3661 } |
3675 | 3662 |
3676 | 3663 |
3677 void Assembler::BlockConstPoolFor(int instructions) { | 3664 void Assembler::BlockConstPoolFor(int instructions) { |
3678 if (FLAG_enable_embedded_constant_pool) { | 3665 if (FLAG_enable_ool_constant_pool) { |
3679 // Should be a no-op if using an embedded constant pool. | 3666 // Should be a no-op if using an out-of-line constant pool. |
3680 DCHECK(num_pending_32_bit_constants_ == 0); | 3667 DCHECK(num_pending_32_bit_reloc_info_ == 0); |
3681 DCHECK(num_pending_64_bit_constants_ == 0); | 3668 DCHECK(num_pending_64_bit_reloc_info_ == 0); |
3682 return; | 3669 return; |
3683 } | 3670 } |
3684 | 3671 |
3685 int pc_limit = pc_offset() + instructions * kInstrSize; | 3672 int pc_limit = pc_offset() + instructions * kInstrSize; |
3686 if (no_const_pool_before_ < pc_limit) { | 3673 if (no_const_pool_before_ < pc_limit) { |
3687 // Max pool start (if we need a jump and an alignment). | 3674 // Max pool start (if we need a jump and an alignment). |
3688 #ifdef DEBUG | 3675 #ifdef DEBUG |
3689 int start = pc_limit + kInstrSize + 2 * kPointerSize; | 3676 int start = pc_limit + kInstrSize + 2 * kPointerSize; |
3690 DCHECK((num_pending_32_bit_constants_ == 0) || | 3677 DCHECK((num_pending_32_bit_reloc_info_ == 0) || |
3691 (start - first_const_pool_32_use_ + | 3678 (start - first_const_pool_32_use_ + |
3692 num_pending_64_bit_constants_ * kDoubleSize < | 3679 num_pending_64_bit_reloc_info_ * kDoubleSize < kMaxDistToIntPool)); |
3693 kMaxDistToIntPool)); | 3680 DCHECK((num_pending_64_bit_reloc_info_ == 0) || |
3694 DCHECK((num_pending_64_bit_constants_ == 0) || | |
3695 (start - first_const_pool_64_use_ < kMaxDistToFPPool)); | 3681 (start - first_const_pool_64_use_ < kMaxDistToFPPool)); |
3696 #endif | 3682 #endif |
3697 no_const_pool_before_ = pc_limit; | 3683 no_const_pool_before_ = pc_limit; |
3698 } | 3684 } |
3699 | 3685 |
3700 if (next_buffer_check_ < no_const_pool_before_) { | 3686 if (next_buffer_check_ < no_const_pool_before_) { |
3701 next_buffer_check_ = no_const_pool_before_; | 3687 next_buffer_check_ = no_const_pool_before_; |
3702 } | 3688 } |
3703 } | 3689 } |
3704 | 3690 |
3705 | 3691 |
3706 void Assembler::CheckConstPool(bool force_emit, bool require_jump) { | 3692 void Assembler::CheckConstPool(bool force_emit, bool require_jump) { |
3707 if (FLAG_enable_embedded_constant_pool) { | 3693 if (FLAG_enable_ool_constant_pool) { |
3708 // Should be a no-op if using an embedded constant pool. | 3694 // Should be a no-op if using an out-of-line constant pool. |
3709 DCHECK(num_pending_32_bit_constants_ == 0); | 3695 DCHECK(num_pending_32_bit_reloc_info_ == 0); |
3710 DCHECK(num_pending_64_bit_constants_ == 0); | 3696 DCHECK(num_pending_64_bit_reloc_info_ == 0); |
3711 return; | 3697 return; |
3712 } | 3698 } |
3713 | 3699 |
3714 // Some short sequence of instruction mustn't be broken up by constant pool | 3700 // Some short sequence of instruction mustn't be broken up by constant pool |
3715 // emission, such sequences are protected by calls to BlockConstPoolFor and | 3701 // emission, such sequences are protected by calls to BlockConstPoolFor and |
3716 // BlockConstPoolScope. | 3702 // BlockConstPoolScope. |
3717 if (is_const_pool_blocked()) { | 3703 if (is_const_pool_blocked()) { |
3718 // Something is wrong if emission is forced and blocked at the same time. | 3704 // Something is wrong if emission is forced and blocked at the same time. |
3719 DCHECK(!force_emit); | 3705 DCHECK(!force_emit); |
3720 return; | 3706 return; |
3721 } | 3707 } |
3722 | 3708 |
3723 // There is nothing to do if there are no pending constant pool entries. | 3709 // There is nothing to do if there are no pending constant pool entries. |
3724 if ((num_pending_32_bit_constants_ == 0) && | 3710 if ((num_pending_32_bit_reloc_info_ == 0) && |
3725 (num_pending_64_bit_constants_ == 0)) { | 3711 (num_pending_64_bit_reloc_info_ == 0)) { |
3726 // Calculate the offset of the next check. | 3712 // Calculate the offset of the next check. |
3727 next_buffer_check_ = pc_offset() + kCheckPoolInterval; | 3713 next_buffer_check_ = pc_offset() + kCheckPoolInterval; |
3728 return; | 3714 return; |
3729 } | 3715 } |
3730 | 3716 |
3731 // Check that the code buffer is large enough before emitting the constant | 3717 // Check that the code buffer is large enough before emitting the constant |
3732 // pool (include the jump over the pool and the constant pool marker and | 3718 // pool (include the jump over the pool and the constant pool marker and |
3733 // the gap to the relocation information). | 3719 // the gap to the relocation information). |
3734 int jump_instr = require_jump ? kInstrSize : 0; | 3720 int jump_instr = require_jump ? kInstrSize : 0; |
3735 int size_up_to_marker = jump_instr + kInstrSize; | 3721 int size_up_to_marker = jump_instr + kInstrSize; |
3736 int size_after_marker = num_pending_32_bit_constants_ * kPointerSize; | 3722 int size_after_marker = num_pending_32_bit_reloc_info_ * kPointerSize; |
3737 bool has_fp_values = (num_pending_64_bit_constants_ > 0); | 3723 bool has_fp_values = (num_pending_64_bit_reloc_info_ > 0); |
3738 bool require_64_bit_align = false; | 3724 bool require_64_bit_align = false; |
3739 if (has_fp_values) { | 3725 if (has_fp_values) { |
3740 require_64_bit_align = (((uintptr_t)pc_ + size_up_to_marker) & 0x7); | 3726 require_64_bit_align = (((uintptr_t)pc_ + size_up_to_marker) & 0x7); |
3741 if (require_64_bit_align) { | 3727 if (require_64_bit_align) { |
3742 size_after_marker += kInstrSize; | 3728 size_after_marker += kInstrSize; |
3743 } | 3729 } |
3744 size_after_marker += num_pending_64_bit_constants_ * kDoubleSize; | 3730 size_after_marker += num_pending_64_bit_reloc_info_ * kDoubleSize; |
3745 } | 3731 } |
3746 | 3732 |
3747 int size = size_up_to_marker + size_after_marker; | 3733 int size = size_up_to_marker + size_after_marker; |
3748 | 3734 |
3749 // We emit a constant pool when: | 3735 // We emit a constant pool when: |
3750 // * requested to do so by parameter force_emit (e.g. after each function). | 3736 // * requested to do so by parameter force_emit (e.g. after each function). |
3751 // * the distance from the first instruction accessing the constant pool to | 3737 // * the distance from the first instruction accessing the constant pool to |
3752 // any of the constant pool entries will exceed its limit the next | 3738 // any of the constant pool entries will exceed its limit the next |
3753 // time the pool is checked. This is overly restrictive, but we don't emit | 3739 // time the pool is checked. This is overly restrictive, but we don't emit |
3754 // constant pool entries in-order so it's conservatively correct. | 3740 // constant pool entries in-order so it's conservatively correct. |
3755 // * the instruction doesn't require a jump after itself to jump over the | 3741 // * the instruction doesn't require a jump after itself to jump over the |
3756 // constant pool, and we're getting close to running out of range. | 3742 // constant pool, and we're getting close to running out of range. |
3757 if (!force_emit) { | 3743 if (!force_emit) { |
3758 DCHECK((first_const_pool_32_use_ >= 0) || (first_const_pool_64_use_ >= 0)); | 3744 DCHECK((first_const_pool_32_use_ >= 0) || (first_const_pool_64_use_ >= 0)); |
3759 bool need_emit = false; | 3745 bool need_emit = false; |
3760 if (has_fp_values) { | 3746 if (has_fp_values) { |
3761 int dist64 = pc_offset() + size - | 3747 int dist64 = pc_offset() + |
3762 num_pending_32_bit_constants_ * kPointerSize - | 3748 size - |
| 3749 num_pending_32_bit_reloc_info_ * kPointerSize - |
3763 first_const_pool_64_use_; | 3750 first_const_pool_64_use_; |
3764 if ((dist64 >= kMaxDistToFPPool - kCheckPoolInterval) || | 3751 if ((dist64 >= kMaxDistToFPPool - kCheckPoolInterval) || |
3765 (!require_jump && (dist64 >= kMaxDistToFPPool / 2))) { | 3752 (!require_jump && (dist64 >= kMaxDistToFPPool / 2))) { |
3766 need_emit = true; | 3753 need_emit = true; |
3767 } | 3754 } |
3768 } | 3755 } |
3769 int dist32 = | 3756 int dist32 = |
3770 pc_offset() + size - first_const_pool_32_use_; | 3757 pc_offset() + size - first_const_pool_32_use_; |
3771 if ((dist32 >= kMaxDistToIntPool - kCheckPoolInterval) || | 3758 if ((dist32 >= kMaxDistToIntPool - kCheckPoolInterval) || |
3772 (!require_jump && (dist32 >= kMaxDistToIntPool / 2))) { | 3759 (!require_jump && (dist32 >= kMaxDistToIntPool / 2))) { |
(...skipping 21 matching lines...) Expand all Loading... |
3794 // The data size helps disassembly know what to print. | 3781 // The data size helps disassembly know what to print. |
3795 emit(kConstantPoolMarker | | 3782 emit(kConstantPoolMarker | |
3796 EncodeConstantPoolLength(size_after_marker / kPointerSize)); | 3783 EncodeConstantPoolLength(size_after_marker / kPointerSize)); |
3797 | 3784 |
3798 if (require_64_bit_align) { | 3785 if (require_64_bit_align) { |
3799 emit(kConstantPoolMarker); | 3786 emit(kConstantPoolMarker); |
3800 } | 3787 } |
3801 | 3788 |
3802 // Emit 64-bit constant pool entries first: their range is smaller than | 3789 // Emit 64-bit constant pool entries first: their range is smaller than |
3803 // 32-bit entries. | 3790 // 32-bit entries. |
3804 for (int i = 0; i < num_pending_64_bit_constants_; i++) { | 3791 for (int i = 0; i < num_pending_64_bit_reloc_info_; i++) { |
3805 ConstantPoolEntry& entry = pending_64_bit_constants_[i]; | 3792 RelocInfo& rinfo = pending_64_bit_reloc_info_[i]; |
3806 | 3793 |
3807 DCHECK(!((uintptr_t)pc_ & 0x7)); // Check 64-bit alignment. | 3794 DCHECK(!((uintptr_t)pc_ & 0x7)); // Check 64-bit alignment. |
3808 | 3795 |
3809 Instr instr = instr_at(entry.position()); | 3796 Instr instr = instr_at(rinfo.pc()); |
3810 // Instruction to patch must be 'vldr rd, [pc, #offset]' with offset == 0. | 3797 // Instruction to patch must be 'vldr rd, [pc, #offset]' with offset == 0. |
3811 DCHECK((IsVldrDPcImmediateOffset(instr) && | 3798 DCHECK((IsVldrDPcImmediateOffset(instr) && |
3812 GetVldrDRegisterImmediateOffset(instr) == 0)); | 3799 GetVldrDRegisterImmediateOffset(instr) == 0)); |
3813 | 3800 |
3814 int delta = pc_offset() - entry.position() - kPcLoadDelta; | 3801 int delta = pc_ - rinfo.pc() - kPcLoadDelta; |
3815 DCHECK(is_uint10(delta)); | 3802 DCHECK(is_uint10(delta)); |
3816 | 3803 |
3817 bool found = false; | 3804 bool found = false; |
3818 uint64_t value = entry.value64(); | 3805 uint64_t value = rinfo.raw_data64(); |
3819 for (int j = 0; j < i; j++) { | 3806 for (int j = 0; j < i; j++) { |
3820 ConstantPoolEntry& entry2 = pending_64_bit_constants_[j]; | 3807 RelocInfo& rinfo2 = pending_64_bit_reloc_info_[j]; |
3821 if (value == entry2.value64()) { | 3808 if (value == rinfo2.raw_data64()) { |
3822 found = true; | 3809 found = true; |
3823 Instr instr2 = instr_at(entry2.position()); | 3810 DCHECK(rinfo2.rmode() == RelocInfo::NONE64); |
| 3811 Instr instr2 = instr_at(rinfo2.pc()); |
3824 DCHECK(IsVldrDPcImmediateOffset(instr2)); | 3812 DCHECK(IsVldrDPcImmediateOffset(instr2)); |
3825 delta = GetVldrDRegisterImmediateOffset(instr2); | 3813 delta = GetVldrDRegisterImmediateOffset(instr2); |
3826 delta += entry2.position() - entry.position(); | 3814 delta += rinfo2.pc() - rinfo.pc(); |
3827 break; | 3815 break; |
3828 } | 3816 } |
3829 } | 3817 } |
3830 | 3818 |
3831 instr_at_put(entry.position(), | 3819 instr_at_put(rinfo.pc(), SetVldrDRegisterImmediateOffset(instr, delta)); |
3832 SetVldrDRegisterImmediateOffset(instr, delta)); | |
3833 | 3820 |
3834 if (!found) { | 3821 if (!found) { |
3835 dq(entry.value64()); | 3822 uint64_t uint_data = rinfo.raw_data64(); |
| 3823 emit(uint_data & 0xFFFFFFFF); |
| 3824 emit(uint_data >> 32); |
3836 } | 3825 } |
3837 } | 3826 } |
3838 | 3827 |
3839 // Emit 32-bit constant pool entries. | 3828 // Emit 32-bit constant pool entries. |
3840 for (int i = 0; i < num_pending_32_bit_constants_; i++) { | 3829 for (int i = 0; i < num_pending_32_bit_reloc_info_; i++) { |
3841 ConstantPoolEntry& entry = pending_32_bit_constants_[i]; | 3830 RelocInfo& rinfo = pending_32_bit_reloc_info_[i]; |
3842 Instr instr = instr_at(entry.position()); | 3831 DCHECK(rinfo.rmode() != RelocInfo::COMMENT && |
| 3832 rinfo.rmode() != RelocInfo::POSITION && |
| 3833 rinfo.rmode() != RelocInfo::STATEMENT_POSITION && |
| 3834 rinfo.rmode() != RelocInfo::CONST_POOL && |
| 3835 rinfo.rmode() != RelocInfo::NONE64); |
| 3836 |
| 3837 Instr instr = instr_at(rinfo.pc()); |
3843 | 3838 |
3844 // 64-bit loads shouldn't get here. | 3839 // 64-bit loads shouldn't get here. |
3845 DCHECK(!IsVldrDPcImmediateOffset(instr)); | 3840 DCHECK(!IsVldrDPcImmediateOffset(instr)); |
3846 | 3841 |
3847 if (IsLdrPcImmediateOffset(instr) && | 3842 if (IsLdrPcImmediateOffset(instr) && |
3848 GetLdrRegisterImmediateOffset(instr) == 0) { | 3843 GetLdrRegisterImmediateOffset(instr) == 0) { |
3849 int delta = pc_offset() - entry.position() - kPcLoadDelta; | 3844 int delta = pc_ - rinfo.pc() - kPcLoadDelta; |
3850 DCHECK(is_uint12(delta)); | 3845 DCHECK(is_uint12(delta)); |
3851 // 0 is the smallest delta: | 3846 // 0 is the smallest delta: |
3852 // ldr rd, [pc, #0] | 3847 // ldr rd, [pc, #0] |
3853 // constant pool marker | 3848 // constant pool marker |
3854 // data | 3849 // data |
3855 | 3850 |
3856 bool found = false; | 3851 bool found = false; |
3857 if (entry.sharing_ok()) { | 3852 if (!serializer_enabled() && rinfo.rmode() >= RelocInfo::CELL) { |
3858 for (int j = 0; j < i; j++) { | 3853 for (int j = 0; j < i; j++) { |
3859 ConstantPoolEntry& entry2 = pending_32_bit_constants_[j]; | 3854 RelocInfo& rinfo2 = pending_32_bit_reloc_info_[j]; |
3860 | 3855 |
3861 if (entry2.value() == entry.value()) { | 3856 if ((rinfo2.data() == rinfo.data()) && |
3862 Instr instr2 = instr_at(entry2.position()); | 3857 (rinfo2.rmode() == rinfo.rmode())) { |
| 3858 Instr instr2 = instr_at(rinfo2.pc()); |
3863 if (IsLdrPcImmediateOffset(instr2)) { | 3859 if (IsLdrPcImmediateOffset(instr2)) { |
3864 delta = GetLdrRegisterImmediateOffset(instr2); | 3860 delta = GetLdrRegisterImmediateOffset(instr2); |
3865 delta += entry2.position() - entry.position(); | 3861 delta += rinfo2.pc() - rinfo.pc(); |
3866 found = true; | 3862 found = true; |
3867 break; | 3863 break; |
3868 } | 3864 } |
3869 } | 3865 } |
3870 } | 3866 } |
3871 } | 3867 } |
3872 | 3868 |
3873 instr_at_put(entry.position(), | 3869 instr_at_put(rinfo.pc(), SetLdrRegisterImmediateOffset(instr, delta)); |
3874 SetLdrRegisterImmediateOffset(instr, delta)); | |
3875 | 3870 |
3876 if (!found) { | 3871 if (!found) { |
3877 emit(entry.value()); | 3872 emit(rinfo.data()); |
3878 } | 3873 } |
3879 } else { | 3874 } else { |
3880 DCHECK(IsMovW(instr)); | 3875 DCHECK(IsMovW(instr)); |
3881 } | 3876 } |
3882 } | 3877 } |
3883 | 3878 |
3884 num_pending_32_bit_constants_ = 0; | 3879 num_pending_32_bit_reloc_info_ = 0; |
3885 num_pending_64_bit_constants_ = 0; | 3880 num_pending_64_bit_reloc_info_ = 0; |
3886 first_const_pool_32_use_ = -1; | 3881 first_const_pool_32_use_ = -1; |
3887 first_const_pool_64_use_ = -1; | 3882 first_const_pool_64_use_ = -1; |
3888 | 3883 |
3889 RecordComment("]"); | 3884 RecordComment("]"); |
3890 | 3885 |
3891 if (after_pool.is_linked()) { | 3886 if (after_pool.is_linked()) { |
3892 bind(&after_pool); | 3887 bind(&after_pool); |
3893 } | 3888 } |
3894 } | 3889 } |
3895 | 3890 |
3896 // Since a constant pool was just emitted, move the check offset forward by | 3891 // Since a constant pool was just emitted, move the check offset forward by |
3897 // the standard interval. | 3892 // the standard interval. |
3898 next_buffer_check_ = pc_offset() + kCheckPoolInterval; | 3893 next_buffer_check_ = pc_offset() + kCheckPoolInterval; |
3899 } | 3894 } |
3900 | 3895 |
3901 | 3896 |
3902 void Assembler::PatchConstantPoolAccessInstruction( | 3897 Handle<ConstantPoolArray> Assembler::NewConstantPool(Isolate* isolate) { |
3903 int pc_offset, int offset, ConstantPoolEntry::Access access, | 3898 if (!FLAG_enable_ool_constant_pool) { |
3904 ConstantPoolEntry::Type type) { | 3899 return isolate->factory()->empty_constant_pool_array(); |
3905 DCHECK(FLAG_enable_embedded_constant_pool); | 3900 } |
3906 Address pc = buffer_ + pc_offset; | 3901 return constant_pool_builder_.New(isolate); |
3907 | 3902 } |
3908 // Patch vldr/ldr instruction with correct offset. | 3903 |
3909 Instr instr = instr_at(pc); | 3904 |
3910 if (access == ConstantPoolEntry::OVERFLOWED) { | 3905 void Assembler::PopulateConstantPool(ConstantPoolArray* constant_pool) { |
3911 if (CpuFeatures::IsSupported(ARMv7)) { | 3906 constant_pool_builder_.Populate(this, constant_pool); |
3912 // Instructions to patch must be 'movw rd, [#0]' and 'movt rd, [#0]. | 3907 } |
3913 Instr next_instr = instr_at(pc + kInstrSize); | 3908 |
3914 DCHECK((IsMovW(instr) && Instruction::ImmedMovwMovtValue(instr) == 0)); | 3909 |
3915 DCHECK((IsMovT(next_instr) && | 3910 ConstantPoolBuilder::ConstantPoolBuilder() |
3916 Instruction::ImmedMovwMovtValue(next_instr) == 0)); | 3911 : entries_(), current_section_(ConstantPoolArray::SMALL_SECTION) {} |
3917 instr_at_put(pc, PatchMovwImmediate(instr, offset & 0xffff)); | 3912 |
3918 instr_at_put(pc + kInstrSize, | 3913 |
3919 PatchMovwImmediate(next_instr, offset >> 16)); | 3914 bool ConstantPoolBuilder::IsEmpty() { |
| 3915 return entries_.size() == 0; |
| 3916 } |
| 3917 |
| 3918 |
| 3919 ConstantPoolArray::Type ConstantPoolBuilder::GetConstantPoolType( |
| 3920 RelocInfo::Mode rmode) { |
| 3921 if (rmode == RelocInfo::NONE64) { |
| 3922 return ConstantPoolArray::INT64; |
| 3923 } else if (!RelocInfo::IsGCRelocMode(rmode)) { |
| 3924 return ConstantPoolArray::INT32; |
| 3925 } else if (RelocInfo::IsCodeTarget(rmode)) { |
| 3926 return ConstantPoolArray::CODE_PTR; |
| 3927 } else { |
| 3928 DCHECK(RelocInfo::IsGCRelocMode(rmode) && !RelocInfo::IsCodeTarget(rmode)); |
| 3929 return ConstantPoolArray::HEAP_PTR; |
| 3930 } |
| 3931 } |
| 3932 |
| 3933 |
| 3934 ConstantPoolArray::LayoutSection ConstantPoolBuilder::AddEntry( |
| 3935 Assembler* assm, const RelocInfo& rinfo) { |
| 3936 RelocInfo::Mode rmode = rinfo.rmode(); |
| 3937 DCHECK(rmode != RelocInfo::COMMENT && |
| 3938 rmode != RelocInfo::POSITION && |
| 3939 rmode != RelocInfo::STATEMENT_POSITION && |
| 3940 rmode != RelocInfo::CONST_POOL); |
| 3941 |
| 3942 // Try to merge entries which won't be patched. |
| 3943 int merged_index = -1; |
| 3944 ConstantPoolArray::LayoutSection entry_section = current_section_; |
| 3945 if (RelocInfo::IsNone(rmode) || |
| 3946 (!assm->serializer_enabled() && (rmode >= RelocInfo::CELL))) { |
| 3947 size_t i; |
| 3948 std::vector<ConstantPoolEntry>::const_iterator it; |
| 3949 for (it = entries_.begin(), i = 0; it != entries_.end(); it++, i++) { |
| 3950 if (RelocInfo::IsEqual(rinfo, it->rinfo_)) { |
| 3951 // Merge with found entry. |
| 3952 merged_index = i; |
| 3953 entry_section = entries_[i].section_; |
| 3954 break; |
| 3955 } |
| 3956 } |
| 3957 } |
| 3958 DCHECK(entry_section <= current_section_); |
| 3959 entries_.push_back(ConstantPoolEntry(rinfo, entry_section, merged_index)); |
| 3960 |
| 3961 if (merged_index == -1) { |
| 3962 // Not merged, so update the appropriate count. |
| 3963 number_of_entries_[entry_section].increment(GetConstantPoolType(rmode)); |
| 3964 } |
| 3965 |
| 3966 // Check if we still have room for another entry in the small section |
| 3967 // given Arm's ldr and vldr immediate offset range. |
| 3968 if (current_section_ == ConstantPoolArray::SMALL_SECTION && |
| 3969 !(is_uint12(ConstantPoolArray::SizeFor(*small_entries())) && |
| 3970 is_uint10(ConstantPoolArray::MaxInt64Offset( |
| 3971 small_entries()->count_of(ConstantPoolArray::INT64))))) { |
| 3972 current_section_ = ConstantPoolArray::EXTENDED_SECTION; |
| 3973 } |
| 3974 return entry_section; |
| 3975 } |
| 3976 |
| 3977 |
| 3978 void ConstantPoolBuilder::Relocate(int pc_delta) { |
| 3979 for (std::vector<ConstantPoolEntry>::iterator entry = entries_.begin(); |
| 3980 entry != entries_.end(); entry++) { |
| 3981 DCHECK(entry->rinfo_.rmode() != RelocInfo::JS_RETURN); |
| 3982 entry->rinfo_.set_pc(entry->rinfo_.pc() + pc_delta); |
| 3983 } |
| 3984 } |
| 3985 |
| 3986 |
| 3987 Handle<ConstantPoolArray> ConstantPoolBuilder::New(Isolate* isolate) { |
| 3988 if (IsEmpty()) { |
| 3989 return isolate->factory()->empty_constant_pool_array(); |
| 3990 } else if (extended_entries()->is_empty()) { |
| 3991 return isolate->factory()->NewConstantPoolArray(*small_entries()); |
| 3992 } else { |
| 3993 DCHECK(current_section_ == ConstantPoolArray::EXTENDED_SECTION); |
| 3994 return isolate->factory()->NewExtendedConstantPoolArray( |
| 3995 *small_entries(), *extended_entries()); |
| 3996 } |
| 3997 } |
| 3998 |
| 3999 |
| 4000 void ConstantPoolBuilder::Populate(Assembler* assm, |
| 4001 ConstantPoolArray* constant_pool) { |
| 4002 DCHECK_EQ(extended_entries()->is_empty(), |
| 4003 !constant_pool->is_extended_layout()); |
| 4004 DCHECK(small_entries()->equals(ConstantPoolArray::NumberOfEntries( |
| 4005 constant_pool, ConstantPoolArray::SMALL_SECTION))); |
| 4006 if (constant_pool->is_extended_layout()) { |
| 4007 DCHECK(extended_entries()->equals(ConstantPoolArray::NumberOfEntries( |
| 4008 constant_pool, ConstantPoolArray::EXTENDED_SECTION))); |
| 4009 } |
| 4010 |
| 4011 // Set up initial offsets. |
| 4012 int offsets[ConstantPoolArray::NUMBER_OF_LAYOUT_SECTIONS] |
| 4013 [ConstantPoolArray::NUMBER_OF_TYPES]; |
| 4014 for (int section = 0; section <= constant_pool->final_section(); section++) { |
| 4015 int section_start = (section == ConstantPoolArray::EXTENDED_SECTION) |
| 4016 ? small_entries()->total_count() |
| 4017 : 0; |
| 4018 for (int i = 0; i < ConstantPoolArray::NUMBER_OF_TYPES; i++) { |
| 4019 ConstantPoolArray::Type type = static_cast<ConstantPoolArray::Type>(i); |
| 4020 if (number_of_entries_[section].count_of(type) != 0) { |
| 4021 offsets[section][type] = constant_pool->OffsetOfElementAt( |
| 4022 number_of_entries_[section].base_of(type) + section_start); |
| 4023 } |
| 4024 } |
| 4025 } |
| 4026 |
| 4027 for (std::vector<ConstantPoolEntry>::iterator entry = entries_.begin(); |
| 4028 entry != entries_.end(); entry++) { |
| 4029 RelocInfo rinfo = entry->rinfo_; |
| 4030 RelocInfo::Mode rmode = entry->rinfo_.rmode(); |
| 4031 ConstantPoolArray::Type type = GetConstantPoolType(rmode); |
| 4032 |
| 4033 // Update constant pool if necessary and get the entry's offset. |
| 4034 int offset; |
| 4035 if (entry->merged_index_ == -1) { |
| 4036 offset = offsets[entry->section_][type]; |
| 4037 offsets[entry->section_][type] += ConstantPoolArray::entry_size(type); |
| 4038 if (type == ConstantPoolArray::INT64) { |
| 4039 constant_pool->set_at_offset(offset, rinfo.data64()); |
| 4040 } else if (type == ConstantPoolArray::INT32) { |
| 4041 constant_pool->set_at_offset(offset, |
| 4042 static_cast<int32_t>(rinfo.data())); |
| 4043 } else if (type == ConstantPoolArray::CODE_PTR) { |
| 4044 constant_pool->set_at_offset(offset, |
| 4045 reinterpret_cast<Address>(rinfo.data())); |
| 4046 } else { |
| 4047 DCHECK(type == ConstantPoolArray::HEAP_PTR); |
| 4048 constant_pool->set_at_offset(offset, |
| 4049 reinterpret_cast<Object*>(rinfo.data())); |
| 4050 } |
| 4051 offset -= kHeapObjectTag; |
| 4052 entry->merged_index_ = offset; // Stash offset for merged entries. |
3920 } else { | 4053 } else { |
3921 // Instructions to patch must be 'mov rd, [#0]' and 'orr rd, rd, [#0]. | 4054 DCHECK(entry->merged_index_ < (entry - entries_.begin())); |
3922 Instr instr_2 = instr_at(pc + kInstrSize); | 4055 offset = entries_[entry->merged_index_].merged_index_; |
3923 Instr instr_3 = instr_at(pc + 2 * kInstrSize); | 4056 } |
3924 Instr instr_4 = instr_at(pc + 3 * kInstrSize); | 4057 |
3925 DCHECK((IsMovImmed(instr) && Instruction::Immed8Value(instr) == 0)); | 4058 // Patch vldr/ldr instruction with correct offset. |
3926 DCHECK((IsOrrImmed(instr_2) && Instruction::Immed8Value(instr_2) == 0) && | 4059 Instr instr = assm->instr_at(rinfo.pc()); |
3927 GetRn(instr_2).is(GetRd(instr_2))); | 4060 if (entry->section_ == ConstantPoolArray::EXTENDED_SECTION) { |
3928 DCHECK((IsOrrImmed(instr_3) && Instruction::Immed8Value(instr_3) == 0) && | 4061 if (CpuFeatures::IsSupported(ARMv7)) { |
3929 GetRn(instr_3).is(GetRd(instr_3))); | 4062 // Instructions to patch must be 'movw rd, [#0]' and 'movt rd, [#0]. |
3930 DCHECK((IsOrrImmed(instr_4) && Instruction::Immed8Value(instr_4) == 0) && | 4063 Instr next_instr = assm->instr_at(rinfo.pc() + Assembler::kInstrSize); |
3931 GetRn(instr_4).is(GetRd(instr_4))); | 4064 DCHECK((Assembler::IsMovW(instr) && |
3932 instr_at_put(pc, PatchShiftImm(instr, (offset & kImm8Mask))); | 4065 Instruction::ImmedMovwMovtValue(instr) == 0)); |
3933 instr_at_put(pc + kInstrSize, | 4066 DCHECK((Assembler::IsMovT(next_instr) && |
3934 PatchShiftImm(instr_2, (offset & (kImm8Mask << 8)))); | 4067 Instruction::ImmedMovwMovtValue(next_instr) == 0)); |
3935 instr_at_put(pc + 2 * kInstrSize, | 4068 assm->instr_at_put( |
3936 PatchShiftImm(instr_3, (offset & (kImm8Mask << 16)))); | 4069 rinfo.pc(), Assembler::PatchMovwImmediate(instr, offset & 0xffff)); |
3937 instr_at_put(pc + 3 * kInstrSize, | 4070 assm->instr_at_put( |
3938 PatchShiftImm(instr_4, (offset & (kImm8Mask << 24)))); | 4071 rinfo.pc() + Assembler::kInstrSize, |
3939 } | 4072 Assembler::PatchMovwImmediate(next_instr, offset >> 16)); |
3940 } else if (type == ConstantPoolEntry::DOUBLE) { | 4073 } else { |
3941 // Instruction to patch must be 'vldr rd, [pp, #0]'. | 4074 // Instructions to patch must be 'mov rd, [#0]' and 'orr rd, rd, [#0]. |
3942 DCHECK((IsVldrDPpImmediateOffset(instr) && | 4075 Instr instr_2 = assm->instr_at(rinfo.pc() + Assembler::kInstrSize); |
3943 GetVldrDRegisterImmediateOffset(instr) == 0)); | 4076 Instr instr_3 = assm->instr_at(rinfo.pc() + 2 * Assembler::kInstrSize); |
3944 DCHECK(is_uint10(offset)); | 4077 Instr instr_4 = assm->instr_at(rinfo.pc() + 3 * Assembler::kInstrSize); |
3945 instr_at_put(pc, SetVldrDRegisterImmediateOffset(instr, offset)); | 4078 DCHECK((Assembler::IsMovImmed(instr) && |
3946 } else { | 4079 Instruction::Immed8Value(instr) == 0)); |
3947 // Instruction to patch must be 'ldr rd, [pp, #0]'. | 4080 DCHECK((Assembler::IsOrrImmed(instr_2) && |
3948 DCHECK((IsLdrPpImmediateOffset(instr) && | 4081 Instruction::Immed8Value(instr_2) == 0) && |
3949 GetLdrRegisterImmediateOffset(instr) == 0)); | 4082 Assembler::GetRn(instr_2).is(Assembler::GetRd(instr_2))); |
3950 DCHECK(is_uint12(offset)); | 4083 DCHECK((Assembler::IsOrrImmed(instr_3) && |
3951 instr_at_put(pc, SetLdrRegisterImmediateOffset(instr, offset)); | 4084 Instruction::Immed8Value(instr_3) == 0) && |
3952 } | 4085 Assembler::GetRn(instr_3).is(Assembler::GetRd(instr_3))); |
3953 } | 4086 DCHECK((Assembler::IsOrrImmed(instr_4) && |
3954 | 4087 Instruction::Immed8Value(instr_4) == 0) && |
| 4088 Assembler::GetRn(instr_4).is(Assembler::GetRd(instr_4))); |
| 4089 assm->instr_at_put( |
| 4090 rinfo.pc(), Assembler::PatchShiftImm(instr, (offset & kImm8Mask))); |
| 4091 assm->instr_at_put( |
| 4092 rinfo.pc() + Assembler::kInstrSize, |
| 4093 Assembler::PatchShiftImm(instr_2, (offset & (kImm8Mask << 8)))); |
| 4094 assm->instr_at_put( |
| 4095 rinfo.pc() + 2 * Assembler::kInstrSize, |
| 4096 Assembler::PatchShiftImm(instr_3, (offset & (kImm8Mask << 16)))); |
| 4097 assm->instr_at_put( |
| 4098 rinfo.pc() + 3 * Assembler::kInstrSize, |
| 4099 Assembler::PatchShiftImm(instr_4, (offset & (kImm8Mask << 24)))); |
| 4100 } |
| 4101 } else if (type == ConstantPoolArray::INT64) { |
| 4102 // Instruction to patch must be 'vldr rd, [pp, #0]'. |
| 4103 DCHECK((Assembler::IsVldrDPpImmediateOffset(instr) && |
| 4104 Assembler::GetVldrDRegisterImmediateOffset(instr) == 0)); |
| 4105 DCHECK(is_uint10(offset)); |
| 4106 assm->instr_at_put(rinfo.pc(), Assembler::SetVldrDRegisterImmediateOffset( |
| 4107 instr, offset)); |
| 4108 } else { |
| 4109 // Instruction to patch must be 'ldr rd, [pp, #0]'. |
| 4110 DCHECK((Assembler::IsLdrPpImmediateOffset(instr) && |
| 4111 Assembler::GetLdrRegisterImmediateOffset(instr) == 0)); |
| 4112 DCHECK(is_uint12(offset)); |
| 4113 assm->instr_at_put( |
| 4114 rinfo.pc(), Assembler::SetLdrRegisterImmediateOffset(instr, offset)); |
| 4115 } |
| 4116 } |
| 4117 } |
| 4118 |
3955 | 4119 |
3956 } // namespace internal | 4120 } // namespace internal |
3957 } // namespace v8 | 4121 } // namespace v8 |
3958 | 4122 |
3959 #endif // V8_TARGET_ARCH_ARM | 4123 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |