| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // NOLINT | 5 #include "vm/globals.h" // NOLINT |
| 6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
| 7 | 7 |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 #include "vm/cpu.h" | 9 #include "vm/cpu.h" |
| 10 #include "vm/heap.h" | 10 #include "vm/heap.h" |
| (...skipping 2471 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2482 | 2482 |
| 2483 | 2483 |
| 2484 void Assembler::hlt() { | 2484 void Assembler::hlt() { |
| 2485 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 2485 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 2486 EmitUint8(0xF4); | 2486 EmitUint8(0xF4); |
| 2487 } | 2487 } |
| 2488 | 2488 |
| 2489 | 2489 |
| 2490 void Assembler::j(Condition condition, Label* label, bool near) { | 2490 void Assembler::j(Condition condition, Label* label, bool near) { |
| 2491 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 2491 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 2492 if (VerifiedMemory::enabled()) { | |
| 2493 near = Assembler::kFarJump; | |
| 2494 } | |
| 2495 if (label->IsBound()) { | 2492 if (label->IsBound()) { |
| 2496 static const int kShortSize = 2; | 2493 static const int kShortSize = 2; |
| 2497 static const int kLongSize = 6; | 2494 static const int kLongSize = 6; |
| 2498 intptr_t offset = label->Position() - buffer_.Size(); | 2495 intptr_t offset = label->Position() - buffer_.Size(); |
| 2499 ASSERT(offset <= 0); | 2496 ASSERT(offset <= 0); |
| 2500 if (Utils::IsInt(8, offset - kShortSize)) { | 2497 if (Utils::IsInt(8, offset - kShortSize)) { |
| 2501 EmitUint8(0x70 + condition); | 2498 EmitUint8(0x70 + condition); |
| 2502 EmitUint8((offset - kShortSize) & 0xFF); | 2499 EmitUint8((offset - kShortSize) & 0xFF); |
| 2503 } else { | 2500 } else { |
| 2504 EmitUint8(0x0F); | 2501 EmitUint8(0x0F); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2539 void Assembler::jmp(const Address& dst) { | 2536 void Assembler::jmp(const Address& dst) { |
| 2540 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 2537 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 2541 EmitOperandREX(4, dst, REX_NONE); | 2538 EmitOperandREX(4, dst, REX_NONE); |
| 2542 EmitUint8(0xFF); | 2539 EmitUint8(0xFF); |
| 2543 EmitOperand(4, dst); | 2540 EmitOperand(4, dst); |
| 2544 } | 2541 } |
| 2545 | 2542 |
| 2546 | 2543 |
| 2547 void Assembler::jmp(Label* label, bool near) { | 2544 void Assembler::jmp(Label* label, bool near) { |
| 2548 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 2545 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 2549 if (VerifiedMemory::enabled()) { | |
| 2550 near = Assembler::kFarJump; | |
| 2551 } | |
| 2552 if (label->IsBound()) { | 2546 if (label->IsBound()) { |
| 2553 static const int kShortSize = 2; | 2547 static const int kShortSize = 2; |
| 2554 static const int kLongSize = 5; | 2548 static const int kLongSize = 5; |
| 2555 intptr_t offset = label->Position() - buffer_.Size(); | 2549 intptr_t offset = label->Position() - buffer_.Size(); |
| 2556 ASSERT(offset <= 0); | 2550 ASSERT(offset <= 0); |
| 2557 if (Utils::IsInt(8, offset - kShortSize)) { | 2551 if (Utils::IsInt(8, offset - kShortSize)) { |
| 2558 EmitUint8(0xEB); | 2552 EmitUint8(0xEB); |
| 2559 EmitUint8((offset - kShortSize) & 0xFF); | 2553 EmitUint8((offset - kShortSize) & 0xFF); |
| 2560 } else { | 2554 } else { |
| 2561 EmitUint8(0xE9); | 2555 EmitUint8(0xE9); |
| (...skipping 375 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2937 // Mask out higher, uninteresting bits which were polluted by dest. | 2931 // Mask out higher, uninteresting bits which were polluted by dest. |
| 2938 andl(value, Immediate(kObjectAlignment - 1)); | 2932 andl(value, Immediate(kObjectAlignment - 1)); |
| 2939 // Compare with the expected bit pattern. | 2933 // Compare with the expected bit pattern. |
| 2940 cmpl(value, Immediate( | 2934 cmpl(value, Immediate( |
| 2941 (kNewObjectAlignmentOffset >> 1) + kHeapObjectTag + | 2935 (kNewObjectAlignmentOffset >> 1) + kHeapObjectTag + |
| 2942 kOldObjectAlignmentOffset + kHeapObjectTag)); | 2936 kOldObjectAlignmentOffset + kHeapObjectTag)); |
| 2943 j(NOT_ZERO, no_update, Assembler::kNearJump); | 2937 j(NOT_ZERO, no_update, Assembler::kNearJump); |
| 2944 } | 2938 } |
| 2945 | 2939 |
| 2946 | 2940 |
| 2947 void Assembler::VerifyHeapWord(const Address& address, | |
| 2948 FieldContent old_content) { | |
| 2949 #if defined(DEBUG) | |
| 2950 switch (old_content) { | |
| 2951 case kEmptyOrSmiOrNull: | |
| 2952 VerifyUninitialized(address); | |
| 2953 break; | |
| 2954 case kHeapObjectOrSmi: | |
| 2955 VerifyObjectOrSmi(address); | |
| 2956 break; | |
| 2957 case kOnlySmi: | |
| 2958 VerifySmi(address); | |
| 2959 break; | |
| 2960 } | |
| 2961 #endif // DEBUG | |
| 2962 if (VerifiedMemory::enabled()) { | |
| 2963 Register addr_reg = RDX; | |
| 2964 Register value = RBX; | |
| 2965 // Preserve registers. | |
| 2966 pushq(addr_reg); | |
| 2967 pushq(value); | |
| 2968 leaq(addr_reg, address); | |
| 2969 // ASSERT(*address == *(address + offset)) | |
| 2970 movq(value, Address(addr_reg, 0)); | |
| 2971 cmpq(value, Address(addr_reg, VerifiedMemory::offset())); | |
| 2972 Label ok; | |
| 2973 j(EQUAL, &ok); | |
| 2974 static const bool kFixedLengthEncoding = true; | |
| 2975 Stop("Write barrier verification failed", kFixedLengthEncoding); | |
| 2976 Bind(&ok); | |
| 2977 popq(value); | |
| 2978 popq(addr_reg); | |
| 2979 } | |
| 2980 } | |
| 2981 | |
| 2982 | |
| 2983 void Assembler::VerifiedWrite(const Address& dest, | |
| 2984 Register value, | |
| 2985 FieldContent old_content) { | |
| 2986 VerifyHeapWord(dest, old_content); | |
| 2987 movq(dest, value); | |
| 2988 if (VerifiedMemory::enabled()) { | |
| 2989 Register temp = (value == RDX) ? RCX : RDX; | |
| 2990 pushq(temp); | |
| 2991 leaq(temp, dest); | |
| 2992 movq(Address(temp, VerifiedMemory::offset()), value); | |
| 2993 popq(temp); | |
| 2994 } | |
| 2995 } | |
| 2996 | |
| 2997 | |
| 2998 #if defined(DEBUG) | |
| 2999 void Assembler::VerifyObjectOrSmi(const Address& dest) { | |
| 3000 Label ok; | |
| 3001 testb(dest, Immediate(kHeapObjectTag)); | |
| 3002 j(ZERO, &ok, Assembler::kNearJump); | |
| 3003 // Non-smi case: Verify object pointer is word-aligned when untagged. | |
| 3004 COMPILE_ASSERT(kHeapObjectTag == 1); | |
| 3005 testb(dest, Immediate((kWordSize - 1) - kHeapObjectTag)); | |
| 3006 j(ZERO, &ok, Assembler::kNearJump); | |
| 3007 static const bool kFixedLengthEncoding = true; | |
| 3008 Stop("Expected heap object or Smi", kFixedLengthEncoding); | |
| 3009 Bind(&ok); | |
| 3010 } | |
| 3011 | |
| 3012 | |
| 3013 void Assembler::VerifyUninitialized(const Address& dest) { | |
| 3014 Label ok; | |
| 3015 testb(dest, Immediate(kHeapObjectTag)); | |
| 3016 j(ZERO, &ok, Assembler::kNearJump); | |
| 3017 // Non-smi case: Check for the special zap word or null. | |
| 3018 #if defined(DEBUG) | |
| 3019 cmpq(dest, Immediate(Heap::kZap64Bits)); | |
| 3020 j(EQUAL, &ok, Assembler::kNearJump); | |
| 3021 #else | |
| 3022 #error Only supported in DEBUG mode | |
| 3023 #endif | |
| 3024 LoadObject(TMP, Object::null_object()); | |
| 3025 cmpq(dest, TMP); | |
| 3026 j(EQUAL, &ok, Assembler::kNearJump); | |
| 3027 static const bool kFixedLengthEncoding = true; | |
| 3028 Stop("Expected zapped, Smi or null", kFixedLengthEncoding); | |
| 3029 Bind(&ok); | |
| 3030 } | |
| 3031 | |
| 3032 | |
| 3033 void Assembler::VerifySmi(const Address& dest, const char* stop_msg) { | |
| 3034 Label done; | |
| 3035 testb(dest, Immediate(kHeapObjectTag)); | |
| 3036 j(ZERO, &done, Assembler::kNearJump); | |
| 3037 static const bool kFixedLengthEncoding = true; | |
| 3038 Stop(stop_msg, kFixedLengthEncoding); | |
| 3039 Bind(&done); | |
| 3040 } | |
| 3041 #endif // defined(DEBUG) | |
| 3042 | |
| 3043 | |
| 3044 void Assembler::StoreIntoObject(Register object, | 2941 void Assembler::StoreIntoObject(Register object, |
| 3045 const Address& dest, | 2942 const Address& dest, |
| 3046 Register value, | 2943 Register value, |
| 3047 bool can_value_be_smi) { | 2944 bool can_value_be_smi) { |
| 3048 ASSERT(object != value); | 2945 ASSERT(object != value); |
| 3049 VerifiedWrite(dest, value, kHeapObjectOrSmi); | 2946 movq(dest, value); |
| 3050 Label done; | 2947 Label done; |
| 3051 if (can_value_be_smi) { | 2948 if (can_value_be_smi) { |
| 3052 StoreIntoObjectFilter(object, value, &done); | 2949 StoreIntoObjectFilter(object, value, &done); |
| 3053 } else { | 2950 } else { |
| 3054 StoreIntoObjectFilterNoSmi(object, value, &done); | 2951 StoreIntoObjectFilterNoSmi(object, value, &done); |
| 3055 } | 2952 } |
| 3056 // A store buffer update is required. | 2953 // A store buffer update is required. |
| 3057 if (value != RDX) pushq(RDX); | 2954 if (value != RDX) pushq(RDX); |
| 3058 if (object != RDX) { | 2955 if (object != RDX) { |
| 3059 movq(RDX, object); | 2956 movq(RDX, object); |
| 3060 } | 2957 } |
| 3061 pushq(CODE_REG); | 2958 pushq(CODE_REG); |
| 3062 movq(CODE_REG, Address(THR, Thread::update_store_buffer_code_offset())); | 2959 movq(CODE_REG, Address(THR, Thread::update_store_buffer_code_offset())); |
| 3063 movq(TMP, Address(THR, Thread::update_store_buffer_entry_point_offset())); | 2960 movq(TMP, Address(THR, Thread::update_store_buffer_entry_point_offset())); |
| 3064 call(TMP); | 2961 call(TMP); |
| 3065 | 2962 |
| 3066 popq(CODE_REG); | 2963 popq(CODE_REG); |
| 3067 if (value != RDX) popq(RDX); | 2964 if (value != RDX) popq(RDX); |
| 3068 Bind(&done); | 2965 Bind(&done); |
| 3069 } | 2966 } |
| 3070 | 2967 |
| 3071 | 2968 |
| 3072 void Assembler::StoreIntoObjectNoBarrier(Register object, | 2969 void Assembler::StoreIntoObjectNoBarrier(Register object, |
| 3073 const Address& dest, | 2970 const Address& dest, |
| 3074 Register value, | 2971 Register value) { |
| 3075 FieldContent old_content) { | 2972 movq(dest, value); |
| 3076 VerifiedWrite(dest, value, old_content); | |
| 3077 #if defined(DEBUG) | 2973 #if defined(DEBUG) |
| 3078 Label done; | 2974 Label done; |
| 3079 pushq(value); | 2975 pushq(value); |
| 3080 StoreIntoObjectFilter(object, value, &done); | 2976 StoreIntoObjectFilter(object, value, &done); |
| 3081 Stop("Store buffer update is required"); | 2977 Stop("Store buffer update is required"); |
| 3082 Bind(&done); | 2978 Bind(&done); |
| 3083 popq(value); | 2979 popq(value); |
| 3084 #endif // defined(DEBUG) | 2980 #endif // defined(DEBUG) |
| 3085 // No store buffer update. | 2981 // No store buffer update. |
| 3086 } | 2982 } |
| 3087 | 2983 |
| 3088 | 2984 |
| 3089 void Assembler::StoreIntoObjectNoBarrier(Register object, | 2985 void Assembler::StoreIntoObjectNoBarrier(Register object, |
| 3090 const Address& dest, | 2986 const Address& dest, |
| 3091 const Object& value, | 2987 const Object& value) { |
| 3092 FieldContent old_content) { | |
| 3093 ASSERT(!value.IsICData() || ICData::Cast(value).IsOriginal()); | 2988 ASSERT(!value.IsICData() || ICData::Cast(value).IsOriginal()); |
| 3094 ASSERT(!value.IsField() || Field::Cast(value).IsOriginal()); | 2989 ASSERT(!value.IsField() || Field::Cast(value).IsOriginal()); |
| 3095 VerifyHeapWord(dest, old_content); | 2990 StoreObject(dest, value); |
| 3096 if (VerifiedMemory::enabled()) { | |
| 3097 const Register temp = RCX; | |
| 3098 pushq(temp); | |
| 3099 leaq(temp, dest); | |
| 3100 StoreObject(Address(temp, 0), value); | |
| 3101 StoreObject(Address(temp, VerifiedMemory::offset()), value); | |
| 3102 popq(temp); | |
| 3103 } else { | |
| 3104 StoreObject(dest, value); | |
| 3105 } | |
| 3106 // TODO(koda): Use 'object', verify that generational barrier's not needed. | |
| 3107 } | 2991 } |
| 3108 | 2992 |
| 3109 | 2993 |
| 3110 void Assembler::StoreIntoSmiField(const Address& dest, Register value) { | 2994 void Assembler::StoreIntoSmiField(const Address& dest, Register value) { |
| 3111 #if defined(DEBUG) | 2995 #if defined(DEBUG) |
| 3112 Label done; | 2996 Label done; |
| 3113 testq(value, Immediate(kHeapObjectTag)); | 2997 testq(value, Immediate(kHeapObjectTag)); |
| 3114 j(ZERO, &done); | 2998 j(ZERO, &done); |
| 3115 Stop("New value must be Smi."); | 2999 Stop("New value must be Smi."); |
| 3116 Bind(&done); | 3000 Bind(&done); |
| 3117 #endif // defined(DEBUG) | 3001 #endif // defined(DEBUG) |
| 3118 VerifiedWrite(dest, value, kOnlySmi); | 3002 movq(dest, value); |
| 3119 } | 3003 } |
| 3120 | 3004 |
| 3121 | 3005 |
| 3122 void Assembler::ZeroInitSmiField(const Address& dest) { | 3006 void Assembler::ZeroInitSmiField(const Address& dest) { |
| 3123 // TODO(koda): Add VerifySmi once we distinguish initalization. | |
| 3124 VerifyHeapWord(dest, kEmptyOrSmiOrNull); | |
| 3125 Immediate zero(Smi::RawValue(0)); | 3007 Immediate zero(Smi::RawValue(0)); |
| 3126 movq(dest, zero); | 3008 movq(dest, zero); |
| 3127 if (VerifiedMemory::enabled()) { | |
| 3128 Register temp = RCX; | |
| 3129 pushq(temp); | |
| 3130 leaq(temp, dest); | |
| 3131 movq(Address(temp, VerifiedMemory::offset()), zero); | |
| 3132 popq(temp); | |
| 3133 } | |
| 3134 } | 3009 } |
| 3135 | 3010 |
| 3136 | 3011 |
| 3137 void Assembler::IncrementSmiField(const Address& dest, int64_t increment) { | 3012 void Assembler::IncrementSmiField(const Address& dest, int64_t increment) { |
| 3138 // Note: FlowGraphCompiler::EdgeCounterIncrementSizeInBytes depends on | 3013 // Note: FlowGraphCompiler::EdgeCounterIncrementSizeInBytes depends on |
| 3139 // the length of this instruction sequence. | 3014 // the length of this instruction sequence. |
| 3140 // TODO(koda): Add VerifySmi once we distinguish initalization. | |
| 3141 VerifyHeapWord(dest, kOnlySmi); | |
| 3142 Immediate inc_imm(Smi::RawValue(increment)); | 3015 Immediate inc_imm(Smi::RawValue(increment)); |
| 3143 addq(dest, inc_imm); | 3016 addq(dest, inc_imm); |
| 3144 if (VerifiedMemory::enabled()) { | |
| 3145 Register temp = RCX; | |
| 3146 pushq(temp); | |
| 3147 leaq(temp, dest); | |
| 3148 addq(Address(temp, VerifiedMemory::offset()), inc_imm); | |
| 3149 popq(temp); | |
| 3150 } | |
| 3151 } | 3017 } |
| 3152 | 3018 |
| 3153 | 3019 |
| 3154 void Assembler::DoubleNegate(XmmRegister d) { | 3020 void Assembler::DoubleNegate(XmmRegister d) { |
| 3155 // {0x8000000000000000LL, 0x8000000000000000LL} | 3021 // {0x8000000000000000LL, 0x8000000000000000LL} |
| 3156 movq(TMP, Address(THR, Thread::double_negate_address_offset())); | 3022 movq(TMP, Address(THR, Thread::double_negate_address_offset())); |
| 3157 xorpd(d, Address(TMP, 0)); | 3023 xorpd(d, Address(TMP, 0)); |
| 3158 } | 3024 } |
| 3159 | 3025 |
| 3160 | 3026 |
| (...skipping 757 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3918 | 3784 |
| 3919 | 3785 |
| 3920 const char* Assembler::FpuRegisterName(FpuRegister reg) { | 3786 const char* Assembler::FpuRegisterName(FpuRegister reg) { |
| 3921 ASSERT((0 <= reg) && (reg < kNumberOfXmmRegisters)); | 3787 ASSERT((0 <= reg) && (reg < kNumberOfXmmRegisters)); |
| 3922 return xmm_reg_names[reg]; | 3788 return xmm_reg_names[reg]; |
| 3923 } | 3789 } |
| 3924 | 3790 |
| 3925 } // namespace dart | 3791 } // namespace dart |
| 3926 | 3792 |
| 3927 #endif // defined TARGET_ARCH_X64 | 3793 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |