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 |