Chromium Code Reviews| 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" | 5 #include "vm/globals.h" |
| 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/heap.h" | 9 #include "vm/heap.h" |
| 10 #include "vm/memory_region.h" | 10 #include "vm/memory_region.h" |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 58 reinterpret_cast<DetectCPUFeatures>(instructions.EntryPoint())(); | 58 reinterpret_cast<DetectCPUFeatures>(instructions.EntryPoint())(); |
| 59 sse4_1_supported_ = (features & kSSE4_1BitMask) != 0; | 59 sse4_1_supported_ = (features & kSSE4_1BitMask) != 0; |
| 60 #ifdef DEBUG | 60 #ifdef DEBUG |
| 61 initialized_ = true; | 61 initialized_ = true; |
| 62 #endif | 62 #endif |
| 63 } | 63 } |
| 64 | 64 |
| 65 #undef __ | 65 #undef __ |
| 66 | 66 |
| 67 | 67 |
| 68 Assembler::Assembler(bool use_far_branches) | |
| 69 : buffer_(), | |
| 70 object_pool_(GrowableObjectArray::Handle()), | |
| 71 prologue_offset_(-1), | |
| 72 comments_() { | |
| 73 // Far branching mode is only needed and implemented for MIPS and ARM. | |
| 74 ASSERT(!use_far_branches); | |
| 75 if (Isolate::Current() != Dart::vm_isolate()) { | |
| 76 object_pool_ = GrowableObjectArray::New(Heap::kOld); | |
| 77 | |
| 78 // These objects and labels need to be accessible through every pool-pointer | |
| 79 // at the same index. | |
| 80 object_pool_.Add(Object::Handle(Object::null()), Heap::kOld); | |
| 81 object_pool_.Add(Bool::True(), Heap::kOld); | |
| 82 object_pool_.Add(Bool::False(), Heap::kOld); | |
| 83 | |
| 84 if (StubCode::UpdateStoreBuffer_entry() != NULL) { | |
| 85 AddExternalLabel(&StubCode::UpdateStoreBufferLabel(), kNotPatchable); | |
| 86 } else { | |
| 87 object_pool_.Add(Object::Handle(Object::null()), Heap::kOld); | |
| 88 } | |
| 89 | |
| 90 if (StubCode::CallToRuntime_entry() != NULL) { | |
| 91 AddExternalLabel(&StubCode::CallToRuntimeLabel(), kNotPatchable); | |
| 92 } else { | |
| 93 object_pool_.Add(Object::Handle(Object::null()), Heap::kOld); | |
| 94 } | |
| 95 } | |
| 96 } | |
| 97 | |
| 98 | |
| 68 void Assembler::InitializeMemoryWithBreakpoints(uword data, int length) { | 99 void Assembler::InitializeMemoryWithBreakpoints(uword data, int length) { |
| 69 memset(reinterpret_cast<void*>(data), Instr::kBreakPointInstruction, length); | 100 memset(reinterpret_cast<void*>(data), Instr::kBreakPointInstruction, length); |
| 70 } | 101 } |
| 71 | 102 |
| 72 | 103 |
| 73 void Assembler::call(Register reg) { | 104 void Assembler::call(Register reg) { |
| 74 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 105 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 75 Operand operand(reg); | 106 Operand operand(reg); |
| 76 EmitOperandREX(2, operand, REX_NONE); | 107 EmitOperandREX(2, operand, REX_NONE); |
| 77 EmitUint8(0xFF); | 108 EmitUint8(0xFF); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 88 | 119 |
| 89 | 120 |
| 90 void Assembler::call(Label* label) { | 121 void Assembler::call(Label* label) { |
| 91 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 122 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 92 static const int kSize = 5; | 123 static const int kSize = 5; |
| 93 EmitUint8(0xE8); | 124 EmitUint8(0xE8); |
| 94 EmitLabel(label, kSize); | 125 EmitLabel(label, kSize); |
| 95 } | 126 } |
| 96 | 127 |
| 97 | 128 |
| 129 void Assembler::LoadExternalLabel(Register dst, | |
| 130 const ExternalLabel* label, | |
| 131 Patchability patchable, | |
| 132 Register pp) { | |
| 133 const int32_t offset = | |
| 134 Array::element_offset(AddExternalLabel(label, patchable)); | |
| 135 LoadWordFromPoolOffset(dst, pp, offset - kHeapObjectTag, patchable); | |
| 136 } | |
| 137 | |
| 138 | |
| 98 void Assembler::call(const ExternalLabel* label) { | 139 void Assembler::call(const ExternalLabel* label) { |
| 99 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 140 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 100 intptr_t call_start = buffer_.GetPosition(); | |
| 101 | 141 |
| 102 // Encode movq(TMP, Immediate(label->address())), but always as imm64. | 142 // Encode movq(TMP, Immediate(label->address())), but always as imm64. |
| 103 EmitRegisterREX(TMP, REX_W); | 143 EmitRegisterREX(TMP, REX_W); |
| 104 EmitUint8(0xB8 | (TMP & 7)); | 144 EmitUint8(0xB8 | (TMP & 7)); |
| 105 EmitInt64(label->address()); | 145 EmitInt64(label->address()); |
| 106 | 146 |
| 107 // Encode call(TMP). | 147 // Encode call(TMP). |
| 108 Operand operand(TMP); | 148 Operand operand(TMP); |
| 109 EmitOperandREX(2, operand, REX_NONE); | 149 EmitOperandREX(2, operand, REX_NONE); |
| 110 EmitUint8(0xFF); | 150 EmitUint8(0xFF); |
| 111 EmitOperand(2, operand); | 151 EmitOperand(2, operand); |
| 152 } | |
| 112 | 153 |
| 154 | |
| 155 void Assembler::CallPatchable(const ExternalLabel* label) { | |
| 156 intptr_t call_start = buffer_.GetPosition(); | |
| 157 LoadExternalLabel(TMP, label, kPatchable, PP); | |
| 158 { | |
| 159 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | |
| 160 // Encode call(TMP). | |
| 161 Operand operand(TMP); | |
| 162 EmitOperandREX(2, operand, REX_NONE); | |
| 163 EmitUint8(0xFF); | |
| 164 EmitOperand(2, operand); | |
| 165 } | |
| 113 ASSERT((buffer_.GetPosition() - call_start) == kCallExternalLabelSize); | 166 ASSERT((buffer_.GetPosition() - call_start) == kCallExternalLabelSize); |
| 114 } | 167 } |
| 115 | 168 |
| 116 | 169 |
| 170 void Assembler::CallFromPool(const ExternalLabel* label) { | |
| 171 if (Isolate::Current() == Dart::vm_isolate()) { | |
| 172 call(label); | |
| 173 } else { | |
| 174 LoadExternalLabel(TMP, label, kNotPatchable, PP); | |
| 175 { | |
|
srdjan
2013/09/04 22:57:23
Extra block/scope unnecessary?
zra
2013/09/05 00:23:11
It's needed for EnsureCapacity.
| |
| 176 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | |
| 177 // Encode call(TMP). | |
| 178 Operand operand(TMP); | |
| 179 EmitOperandREX(2, operand, REX_NONE); | |
| 180 EmitUint8(0xFF); | |
| 181 EmitOperand(2, operand); | |
| 182 } | |
| 183 } | |
| 184 } | |
| 185 | |
| 186 | |
| 117 void Assembler::pushq(Register reg) { | 187 void Assembler::pushq(Register reg) { |
| 118 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 188 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 119 EmitRegisterREX(reg, REX_NONE); | 189 EmitRegisterREX(reg, REX_NONE); |
| 120 EmitUint8(0x50 | (reg & 7)); | 190 EmitUint8(0x50 | (reg & 7)); |
| 121 } | 191 } |
| 122 | 192 |
| 123 | 193 |
| 124 void Assembler::pushq(const Address& address) { | 194 void Assembler::pushq(const Address& address) { |
| 125 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 195 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 126 EmitOperandREX(6, address, REX_NONE); | 196 EmitOperandREX(6, address, REX_NONE); |
| (...skipping 1826 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1953 | 2023 |
| 1954 | 2024 |
| 1955 void Assembler::j(Condition condition, const ExternalLabel* label) { | 2025 void Assembler::j(Condition condition, const ExternalLabel* label) { |
| 1956 Label no_jump; | 2026 Label no_jump; |
| 1957 j(static_cast<Condition>(condition ^ 1), &no_jump); // Negate condition. | 2027 j(static_cast<Condition>(condition ^ 1), &no_jump); // Negate condition. |
| 1958 jmp(label); | 2028 jmp(label); |
| 1959 Bind(&no_jump); | 2029 Bind(&no_jump); |
| 1960 } | 2030 } |
| 1961 | 2031 |
| 1962 | 2032 |
| 2033 void Assembler::ConditionalJumpFromPool(Condition condition, | |
| 2034 const ExternalLabel* label, | |
| 2035 Register pp) { | |
| 2036 Label no_jump; | |
| 2037 j(static_cast<Condition>(condition ^ 1), &no_jump); // Negate condition. | |
| 2038 JumpFromPool(label, pp); | |
| 2039 Bind(&no_jump); | |
| 2040 } | |
| 2041 | |
| 2042 | |
| 1963 void Assembler::jmp(Register reg) { | 2043 void Assembler::jmp(Register reg) { |
| 1964 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 2044 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 1965 Operand operand(reg); | 2045 Operand operand(reg); |
| 1966 EmitOperandREX(4, operand, REX_NONE); | 2046 EmitOperandREX(4, operand, REX_NONE); |
| 1967 EmitUint8(0xFF); | 2047 EmitUint8(0xFF); |
| 1968 EmitOperand(4, operand); | 2048 EmitOperand(4, operand); |
| 1969 } | 2049 } |
| 1970 | 2050 |
| 1971 | 2051 |
| 1972 void Assembler::jmp(Label* label, bool near) { | 2052 void Assembler::jmp(Label* label, bool near) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 1988 EmitNearLabelLink(label); | 2068 EmitNearLabelLink(label); |
| 1989 } else { | 2069 } else { |
| 1990 EmitUint8(0xE9); | 2070 EmitUint8(0xE9); |
| 1991 EmitLabelLink(label); | 2071 EmitLabelLink(label); |
| 1992 } | 2072 } |
| 1993 } | 2073 } |
| 1994 | 2074 |
| 1995 | 2075 |
| 1996 void Assembler::jmp(const ExternalLabel* label) { | 2076 void Assembler::jmp(const ExternalLabel* label) { |
| 1997 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 2077 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 1998 intptr_t call_start = buffer_.GetPosition(); | |
| 1999 | 2078 |
| 2000 // Encode movq(TMP, Immediate(label->address())), but always as imm64. | 2079 // Encode movq(TMP, Immediate(label->address())), but always as imm64. |
| 2001 EmitRegisterREX(TMP, REX_W); | 2080 EmitRegisterREX(TMP, REX_W); |
| 2002 EmitUint8(0xB8 | (TMP & 7)); | 2081 EmitUint8(0xB8 | (TMP & 7)); |
| 2003 EmitInt64(label->address()); | 2082 EmitInt64(label->address()); |
| 2004 | 2083 |
| 2005 // Encode jmp(TMP). | 2084 // Encode jmp(TMP). |
| 2006 Operand operand(TMP); | 2085 Operand operand(TMP); |
| 2007 EmitOperandREX(4, operand, REX_NONE); | 2086 EmitOperandREX(4, operand, REX_NONE); |
| 2008 EmitUint8(0xFF); | 2087 EmitUint8(0xFF); |
| 2009 EmitOperand(4, operand); | 2088 EmitOperand(4, operand); |
| 2089 } | |
| 2010 | 2090 |
| 2091 | |
| 2092 void Assembler::JumpPatchable(const ExternalLabel* label, Register pp) { | |
| 2093 intptr_t call_start = buffer_.GetPosition(); | |
| 2094 LoadExternalLabel(TMP, label, kPatchable, pp); | |
| 2095 { | |
|
srdjan
2013/09/04 22:57:23
ditto and elsewhere?
zra
2013/09/05 00:23:11
I've tried to remove, but EnsureCapacity doesn't l
| |
| 2096 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | |
| 2097 // Encode jmp(TMP). | |
| 2098 Operand operand(TMP); | |
| 2099 EmitOperandREX(4, operand, REX_NONE); | |
| 2100 EmitUint8(0xFF); | |
| 2101 EmitOperand(4, operand); | |
| 2102 } | |
| 2011 ASSERT((buffer_.GetPosition() - call_start) == kCallExternalLabelSize); | 2103 ASSERT((buffer_.GetPosition() - call_start) == kCallExternalLabelSize); |
| 2012 } | 2104 } |
| 2013 | 2105 |
| 2014 | 2106 |
| 2107 void Assembler::JumpFromPool(const ExternalLabel* label, Register pp) { | |
| 2108 LoadExternalLabel(TMP, label, kNotPatchable, pp); | |
| 2109 { | |
| 2110 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | |
| 2111 // Encode jmp(TMP). | |
| 2112 Operand operand(TMP); | |
| 2113 EmitOperandREX(4, operand, REX_NONE); | |
| 2114 EmitUint8(0xFF); | |
| 2115 EmitOperand(4, operand); | |
| 2116 } | |
| 2117 } | |
| 2118 | |
| 2119 | |
| 2015 void Assembler::lock() { | 2120 void Assembler::lock() { |
| 2016 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 2121 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 2017 EmitUint8(0xF0); | 2122 EmitUint8(0xF0); |
| 2018 } | 2123 } |
| 2019 | 2124 |
| 2020 | 2125 |
| 2021 void Assembler::cmpxchgl(const Address& address, Register reg) { | 2126 void Assembler::cmpxchgl(const Address& address, Register reg) { |
| 2022 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 2127 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 2023 EmitOperandREX(reg, address, REX_NONE); | 2128 EmitOperandREX(reg, address, REX_NONE); |
| 2024 EmitUint8(0x0F); | 2129 EmitUint8(0x0F); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2084 if (stack_elements <= 4) { | 2189 if (stack_elements <= 4) { |
| 2085 for (intptr_t i = 0; i < stack_elements; i++) { | 2190 for (intptr_t i = 0; i < stack_elements; i++) { |
| 2086 popq(TMP); | 2191 popq(TMP); |
| 2087 } | 2192 } |
| 2088 return; | 2193 return; |
| 2089 } | 2194 } |
| 2090 addq(RSP, Immediate(stack_elements * kWordSize)); | 2195 addq(RSP, Immediate(stack_elements * kWordSize)); |
| 2091 } | 2196 } |
| 2092 | 2197 |
| 2093 | 2198 |
| 2094 void Assembler::LoadObject(Register dst, const Object& object) { | 2199 int32_t Assembler::AddObject(const Object& obj) { |
|
srdjan
2013/09/04 22:57:23
Why int32_t instead of intptr_t? Length() is intpt
zra
2013/09/05 00:23:11
Done.
| |
| 2095 if (object.IsSmi() || object.InVMHeap()) { | 2200 // The object pool cannot be used in the vm isolate. |
| 2201 ASSERT(Isolate::Current() != Dart::vm_isolate()); | |
| 2202 ASSERT(obj.IsNotTemporaryScopedHandle()); | |
| 2203 ASSERT(obj.IsOld()); | |
| 2204 if (object_pool_.IsNull()) { | |
|
srdjan
2013/09/04 22:57:23
Should this be an assert? Assembler constructor al
zra
2013/09/05 00:23:11
Done.
| |
| 2205 object_pool_ = GrowableObjectArray::New(Heap::kOld); | |
| 2206 } | |
| 2207 for (int i = 0; i < object_pool_.Length(); i++) { | |
| 2208 if (object_pool_.At(i) == obj.raw()) { | |
|
srdjan
2013/09/04 22:57:23
This is slow for large code objects, i.e., compila
zra
2013/09/05 00:23:11
Will add a hashmap from obj.raw() to object pool i
| |
| 2209 return i; | |
| 2210 } | |
| 2211 } | |
| 2212 object_pool_.Add(obj, Heap::kOld); | |
| 2213 return object_pool_.Length() - 1; | |
| 2214 } | |
| 2215 | |
| 2216 | |
| 2217 int32_t Assembler::AddExternalLabel(const ExternalLabel* label, | |
| 2218 Patchability patchable) { | |
|
srdjan
2013/09/04 22:57:23
s/int32_t/intptr_t/ ?
zra
2013/09/05 00:23:11
Done.
| |
| 2219 // The object pool cannot be used in the vm isolate. | |
| 2220 ASSERT(Isolate::Current() != Dart::vm_isolate()); | |
| 2221 if (object_pool_.IsNull()) { | |
| 2222 object_pool_ = GrowableObjectArray::New(Heap::kOld); | |
|
srdjan
2013/09/04 22:57:23
Ditto
zra
2013/09/05 00:23:11
Done.
| |
| 2223 } | |
| 2224 const word address = label->address(); | |
|
srdjan
2013/09/04 22:57:23
const uword
zra
2013/09/05 00:23:11
Done.
| |
| 2225 ASSERT(Utils::IsAligned(address, 4)); | |
| 2226 // The address is stored in the object array as a RawSmi. | |
| 2227 const Smi& smi = Smi::Handle(Smi::New(address >> kSmiTagShift)); | |
|
srdjan
2013/09/04 22:57:23
const Smi& smi = Smi::Handle(reinterpret_cast<RawS
zra
2013/09/05 00:23:11
Done.
| |
| 2228 if (patchable == kNotPatchable) { | |
| 2229 // An external label used in a non-patchable call shouldn't also be used in | |
| 2230 // patchable calls. So, we can re-use existing entries for non-patchable | |
| 2231 // calls. | |
| 2232 for (int i = 0; i < object_pool_.Length(); i++) { | |
| 2233 if (object_pool_.At(i) == smi.raw()) { | |
| 2234 return i; | |
| 2235 } | |
| 2236 } | |
| 2237 } | |
| 2238 // If the call is patchable, do not reuse an existing entry since each | |
| 2239 // reference may be patched independently. | |
| 2240 object_pool_.Add(smi, Heap::kOld); | |
| 2241 return object_pool_.Length() - 1; | |
| 2242 } | |
| 2243 | |
| 2244 | |
| 2245 bool Assembler::CanLoadFromObjectPool(const Object& object) { | |
| 2246 return !object.IsSmi() && // Not a Smi | |
| 2247 // Not in the VMHeap, OR is one of the VMHeap objects we put in every | |
| 2248 // object pool. | |
| 2249 (!object.InVMHeap() || (object.raw() == Object::null()) || | |
| 2250 (object.raw() == Bool::True().raw()) || | |
| 2251 (object.raw() == Bool::False().raw())) && | |
| 2252 object.IsNotTemporaryScopedHandle() && | |
| 2253 object.IsOld(); | |
| 2254 } | |
| 2255 | |
| 2256 | |
| 2257 void Assembler::LoadWordFromPoolOffset(Register dst, Register pp, | |
| 2258 int32_t offset, Patchability patchable) { | |
| 2259 movq(dst, Address(pp, offset)); | |
| 2260 // This sequence must be of fixed size. If offset fits in a signed byte we | |
| 2261 // have to pad with nops. | |
|
srdjan
2013/09/04 22:57:23
Why not generate a movq that always emits long for
zra
2013/09/05 00:23:11
Done.
| |
| 2262 if (Utils::IsInt(8, offset) && (patchable == kPatchable)) { | |
| 2263 nop(3); | |
| 2264 } | |
| 2265 } | |
| 2266 | |
| 2267 | |
| 2268 void Assembler::LoadObjectFromPool(Register dst, const Object& object, | |
| 2269 Patchability patchable, Register pp) { | |
| 2270 if (CanLoadFromObjectPool(object)) { | |
| 2271 const int32_t offset = Array::element_offset(AddObject(object)); | |
| 2272 LoadWordFromPoolOffset(dst, pp, offset - kHeapObjectTag, patchable); | |
| 2273 } else { | |
| 2096 movq(dst, Immediate(reinterpret_cast<int64_t>(object.raw()))); | 2274 movq(dst, Immediate(reinterpret_cast<int64_t>(object.raw()))); |
| 2097 } else { | |
| 2098 ASSERT(object.IsNotTemporaryScopedHandle()); | |
| 2099 ASSERT(object.IsOld()); | |
| 2100 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | |
| 2101 EmitRegisterREX(dst, REX_W); | |
| 2102 EmitUint8(0xB8 | (dst & 7)); | |
| 2103 buffer_.EmitObject(object); | |
| 2104 } | 2275 } |
| 2105 } | 2276 } |
| 2106 | 2277 |
| 2107 | 2278 |
| 2108 void Assembler::StoreObject(const Address& dst, const Object& object) { | 2279 void Assembler::StoreObject(const Address& dst, const Object& object) { |
| 2109 if (object.IsSmi() || object.InVMHeap()) { | 2280 if (CanLoadFromObjectPool(object)) { |
| 2281 LoadObjectFromPool(TMP, object, kNotPatchable, PP); | |
| 2282 movq(dst, TMP); | |
| 2283 } else { | |
| 2110 movq(dst, Immediate(reinterpret_cast<int64_t>(object.raw()))); | 2284 movq(dst, Immediate(reinterpret_cast<int64_t>(object.raw()))); |
| 2111 } else { | |
| 2112 ASSERT(object.IsNotTemporaryScopedHandle()); | |
| 2113 ASSERT(object.IsOld()); | |
| 2114 LoadObject(TMP, object); | |
| 2115 movq(dst, TMP); | |
| 2116 } | 2285 } |
| 2117 } | 2286 } |
| 2118 | 2287 |
| 2119 | 2288 |
| 2120 void Assembler::PushObject(const Object& object) { | 2289 void Assembler::PushObject(const Object& object) { |
| 2121 if (object.IsSmi() || object.InVMHeap()) { | 2290 if (CanLoadFromObjectPool(object)) { |
| 2291 LoadObjectFromPool(TMP, object, kNotPatchable, PP); | |
| 2292 pushq(TMP); | |
| 2293 } else { | |
| 2122 pushq(Immediate(reinterpret_cast<int64_t>(object.raw()))); | 2294 pushq(Immediate(reinterpret_cast<int64_t>(object.raw()))); |
| 2123 } else { | |
| 2124 LoadObject(TMP, object); | |
| 2125 pushq(TMP); | |
| 2126 } | 2295 } |
| 2127 } | 2296 } |
| 2128 | 2297 |
| 2129 | 2298 |
| 2130 void Assembler::CompareObject(Register reg, const Object& object) { | 2299 void Assembler::CompareObject(Register reg, const Object& object) { |
| 2131 if (object.IsSmi() || object.InVMHeap()) { | 2300 if (CanLoadFromObjectPool(object)) { |
| 2301 ASSERT(reg != TMP); | |
| 2302 LoadObjectFromPool(TMP, object, kNotPatchable, PP); | |
| 2303 cmpq(reg, TMP); | |
| 2304 } else { | |
| 2132 cmpq(reg, Immediate(reinterpret_cast<int64_t>(object.raw()))); | 2305 cmpq(reg, Immediate(reinterpret_cast<int64_t>(object.raw()))); |
| 2133 } else { | |
| 2134 ASSERT(reg != TMP); | |
| 2135 LoadObject(TMP, object); | |
| 2136 cmpq(reg, TMP); | |
| 2137 } | 2306 } |
| 2138 } | 2307 } |
| 2139 | 2308 |
| 2140 | 2309 |
| 2141 // Destroys the value register. | 2310 // Destroys the value register. |
| 2142 void Assembler::StoreIntoObjectFilterNoSmi(Register object, | 2311 void Assembler::StoreIntoObjectFilterNoSmi(Register object, |
| 2143 Register value, | 2312 Register value, |
| 2144 Label* no_update) { | 2313 Label* no_update) { |
| 2145 COMPILE_ASSERT((kNewObjectAlignmentOffset == kWordSize) && | 2314 COMPILE_ASSERT((kNewObjectAlignmentOffset == kWordSize) && |
| 2146 (kOldObjectAlignmentOffset == 0), young_alignment); | 2315 (kOldObjectAlignmentOffset == 0), young_alignment); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2189 if (can_value_be_smi) { | 2358 if (can_value_be_smi) { |
| 2190 StoreIntoObjectFilter(object, value, &done); | 2359 StoreIntoObjectFilter(object, value, &done); |
| 2191 } else { | 2360 } else { |
| 2192 StoreIntoObjectFilterNoSmi(object, value, &done); | 2361 StoreIntoObjectFilterNoSmi(object, value, &done); |
| 2193 } | 2362 } |
| 2194 // A store buffer update is required. | 2363 // A store buffer update is required. |
| 2195 if (value != RAX) pushq(RAX); | 2364 if (value != RAX) pushq(RAX); |
| 2196 if (object != RAX) { | 2365 if (object != RAX) { |
| 2197 movq(RAX, object); | 2366 movq(RAX, object); |
| 2198 } | 2367 } |
| 2199 call(&StubCode::UpdateStoreBufferLabel()); | 2368 CallFromPool(&StubCode::UpdateStoreBufferLabel()); |
| 2200 if (value != RAX) popq(RAX); | 2369 if (value != RAX) popq(RAX); |
| 2201 Bind(&done); | 2370 Bind(&done); |
| 2202 } | 2371 } |
| 2203 | 2372 |
| 2204 | 2373 |
| 2205 void Assembler::StoreIntoObjectNoBarrier(Register object, | 2374 void Assembler::StoreIntoObjectNoBarrier(Register object, |
| 2206 const Address& dest, | 2375 const Address& dest, |
| 2207 Register value) { | 2376 Register value) { |
| 2208 movq(dest, value); | 2377 movq(dest, value); |
| 2209 #if defined(DEBUG) | 2378 #if defined(DEBUG) |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2291 } | 2460 } |
| 2292 } | 2461 } |
| 2293 | 2462 |
| 2294 | 2463 |
| 2295 void Assembler::LeaveFrame() { | 2464 void Assembler::LeaveFrame() { |
| 2296 movq(RSP, RBP); | 2465 movq(RSP, RBP); |
| 2297 popq(RBP); | 2466 popq(RBP); |
| 2298 } | 2467 } |
| 2299 | 2468 |
| 2300 | 2469 |
| 2470 void Assembler::LeaveFrameWithPP() { | |
| 2471 movq(PP, Address(RBP, -2 * kWordSize)); | |
| 2472 movq(RSP, RBP); | |
| 2473 popq(RBP); | |
| 2474 } | |
| 2475 | |
| 2476 | |
| 2301 void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) { | 2477 void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) { |
| 2302 // Reserve space for arguments and align frame before entering | 2478 // Reserve space for arguments and align frame before entering |
| 2303 // the C++ world. | 2479 // the C++ world. |
| 2304 AddImmediate(RSP, Immediate(-frame_space)); | 2480 AddImmediate(RSP, Immediate(-frame_space)); |
| 2305 if (OS::ActivationFrameAlignment() > 1) { | 2481 if (OS::ActivationFrameAlignment() > 1) { |
| 2306 andq(RSP, Immediate(~(OS::ActivationFrameAlignment() - 1))); | 2482 andq(RSP, Immediate(~(OS::ActivationFrameAlignment() - 1))); |
| 2307 } | 2483 } |
| 2308 } | 2484 } |
| 2309 | 2485 |
| 2310 | 2486 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2371 leave(); | 2547 leave(); |
| 2372 } | 2548 } |
| 2373 | 2549 |
| 2374 | 2550 |
| 2375 void Assembler::CallRuntime(const RuntimeEntry& entry, | 2551 void Assembler::CallRuntime(const RuntimeEntry& entry, |
| 2376 intptr_t argument_count) { | 2552 intptr_t argument_count) { |
| 2377 entry.Call(this, argument_count); | 2553 entry.Call(this, argument_count); |
| 2378 } | 2554 } |
| 2379 | 2555 |
| 2380 | 2556 |
| 2381 void Assembler::EnterDartFrame(intptr_t frame_size) { | 2557 void Assembler::LoadPoolPointer(Register pp) { |
| 2558 Label next; | |
| 2559 call(&next); | |
| 2560 Bind(&next); | |
| 2561 | |
| 2562 // Load new pool pointer. | |
| 2563 const intptr_t object_pool_pc_dist = | |
| 2564 Instructions::HeaderSize() - Instructions::object_pool_offset() + | |
| 2565 CodeSize(); | |
| 2566 popq(pp); | |
| 2567 movq(pp, Address(pp, -object_pool_pc_dist)); | |
| 2568 } | |
| 2569 | |
| 2570 | |
| 2571 void Assembler::EnterDartFrame(intptr_t frame_size, | |
| 2572 Register new_pp, Register new_pc) { | |
| 2382 EnterFrame(0); | 2573 EnterFrame(0); |
| 2383 Label dart_entry; | 2574 if (new_pc == kNoRegister) { |
| 2384 call(&dart_entry); | 2575 Label dart_entry; |
| 2385 Bind(&dart_entry); | 2576 call(&dart_entry); |
| 2386 // The runtime system assumes that the code marker address is | 2577 Bind(&dart_entry); |
| 2387 // kEntryPointToPcMarkerOffset bytes from the entry. If there is any code | 2578 // The runtime system assumes that the code marker address is |
| 2388 // generated before entering the frame, the address needs to be adjusted. | 2579 // kEntryPointToPcMarkerOffset bytes from the entry. If there is any code |
| 2389 const intptr_t offset = kEntryPointToPcMarkerOffset - CodeSize(); | 2580 // generated before entering the frame, the address needs to be adjusted. |
| 2390 if (offset != 0) { | 2581 const intptr_t object_pool_pc_dist = |
| 2391 addq(Address(RSP, 0), Immediate(offset)); | 2582 Instructions::HeaderSize() - Instructions::object_pool_offset() + |
| 2583 CodeSize(); | |
| 2584 const intptr_t offset = kEntryPointToPcMarkerOffset - CodeSize(); | |
| 2585 if (offset != 0) { | |
| 2586 addq(Address(RSP, 0), Immediate(offset)); | |
| 2587 } | |
| 2588 // Save caller's pool pointer | |
| 2589 pushq(PP); | |
| 2590 | |
| 2591 // Load callee's pool pointer. | |
| 2592 movq(PP, Address(RSP, 1 * kWordSize)); | |
| 2593 movq(PP, Address(PP, -object_pool_pc_dist - offset)); | |
| 2594 } else { | |
| 2595 pushq(new_pc); | |
| 2596 pushq(PP); | |
| 2597 movq(PP, new_pp); | |
| 2392 } | 2598 } |
| 2393 if (frame_size != 0) { | 2599 if (frame_size != 0) { |
| 2394 subq(RSP, Immediate(frame_size)); | 2600 subq(RSP, Immediate(frame_size)); |
| 2395 } | 2601 } |
| 2396 } | 2602 } |
| 2397 | 2603 |
| 2398 | 2604 |
| 2399 // On entry to a function compiled for OSR, the caller's frame pointer, the | 2605 // On entry to a function compiled for OSR, the caller's frame pointer, the |
| 2400 // stack locals, and any copied parameters are already in place. The frame | 2606 // stack locals, and any copied parameters are already in place. The frame |
| 2401 // pointer is already set up. The PC marker is not correct for the | 2607 // pointer is already set up. The PC marker is not correct for the |
| 2402 // optimized function and there may be extra space for spill slots to | 2608 // optimized function and there may be extra space for spill slots to |
| 2403 // allocate. | 2609 // allocate. |
| 2404 void Assembler::EnterOsrFrame(intptr_t extra_size) { | 2610 void Assembler::EnterOsrFrame(intptr_t extra_size, |
| 2405 Label dart_entry; | 2611 Register new_pp, Register new_pc) { |
| 2406 call(&dart_entry); | 2612 if (new_pc == kNoRegister) { |
| 2407 Bind(&dart_entry); | 2613 Label dart_entry; |
| 2408 // The runtime system assumes that the code marker address is | 2614 call(&dart_entry); |
| 2409 // kEntryPointToPcMarkerOffset bytes from the entry. Since there is no | 2615 Bind(&dart_entry); |
| 2410 // code to set up the frame pointer, the address needs to be adjusted. | 2616 // The runtime system assumes that the code marker address is |
| 2411 const intptr_t offset = kEntryPointToPcMarkerOffset - CodeSize(); | 2617 // kEntryPointToPcMarkerOffset bytes from the entry. Since there is no |
| 2412 if (offset != 0) { | 2618 // code to set up the frame pointer, the address needs to be adjusted. |
| 2413 addq(Address(RSP, 0), Immediate(offset)); | 2619 const intptr_t object_pool_pc_dist = |
| 2620 Instructions::HeaderSize() - Instructions::object_pool_offset() + | |
| 2621 CodeSize(); | |
| 2622 const intptr_t offset = kEntryPointToPcMarkerOffset - CodeSize(); | |
| 2623 if (offset != 0) { | |
| 2624 addq(Address(RSP, 0), Immediate(offset)); | |
| 2625 } | |
| 2626 | |
| 2627 // Load callee's pool pointer. | |
| 2628 movq(PP, Address(RSP, 0)); | |
| 2629 movq(PP, Address(PP, -object_pool_pc_dist - offset)); | |
| 2630 | |
| 2631 popq(Address(RBP, kPcMarkerSlotFromFp * kWordSize)); | |
| 2632 } else { | |
| 2633 movq(Address(RBP, kPcMarkerSlotFromFp * kWordSize), new_pc); | |
| 2634 movq(PP, new_pp); | |
| 2414 } | 2635 } |
| 2415 popq(Address(RBP, kPcMarkerSlotFromFp * kWordSize)); | |
| 2416 if (extra_size != 0) { | 2636 if (extra_size != 0) { |
| 2417 subq(RSP, Immediate(extra_size)); | 2637 subq(RSP, Immediate(extra_size)); |
| 2418 } | 2638 } |
| 2419 } | 2639 } |
| 2420 | 2640 |
| 2421 | 2641 |
| 2422 void Assembler::EnterStubFrame() { | 2642 void Assembler::EnterStubFrame() { |
| 2423 EnterFrame(0); | 2643 EnterFrame(0); |
| 2424 pushq(Immediate(0)); // Push 0 in the saved PC area for stub frames. | 2644 pushq(Immediate(0)); // Push 0 in the saved PC area for stub frames. |
| 2425 } | 2645 } |
| 2426 | 2646 |
| 2427 | 2647 |
| 2648 void Assembler::EnterStubFrameWithPP() { | |
| 2649 EnterFrame(0); | |
| 2650 pushq(Immediate(0)); // Push 0 in the saved PC area for stub frames. | |
| 2651 pushq(PP); // Save caller's pool pointer | |
| 2652 LoadPoolPointer(PP); | |
| 2653 } | |
| 2654 | |
| 2655 | |
| 2428 void Assembler::TryAllocate(const Class& cls, | 2656 void Assembler::TryAllocate(const Class& cls, |
| 2429 Label* failure, | 2657 Label* failure, |
| 2430 bool near_jump, | 2658 bool near_jump, |
| 2431 Register instance_reg) { | 2659 Register instance_reg) { |
| 2432 ASSERT(failure != NULL); | 2660 ASSERT(failure != NULL); |
| 2433 if (FLAG_inline_alloc) { | 2661 if (FLAG_inline_alloc) { |
| 2434 Heap* heap = Isolate::Current()->heap(); | 2662 Heap* heap = Isolate::Current()->heap(); |
| 2435 const intptr_t instance_size = cls.instance_size(); | 2663 const intptr_t instance_size = cls.instance_size(); |
| 2436 movq(TMP, Immediate(heap->TopAddress())); | 2664 movq(TMP, Immediate(heap->TopAddress())); |
| 2437 movq(instance_reg, Address(TMP, 0)); | 2665 movq(instance_reg, Address(TMP, 0)); |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2644 | 2872 |
| 2645 const char* Assembler::FpuRegisterName(FpuRegister reg) { | 2873 const char* Assembler::FpuRegisterName(FpuRegister reg) { |
| 2646 ASSERT((0 <= reg) && (reg < kNumberOfXmmRegisters)); | 2874 ASSERT((0 <= reg) && (reg < kNumberOfXmmRegisters)); |
| 2647 return xmm_reg_names[reg]; | 2875 return xmm_reg_names[reg]; |
| 2648 } | 2876 } |
| 2649 | 2877 |
| 2650 | 2878 |
| 2651 } // namespace dart | 2879 } // namespace dart |
| 2652 | 2880 |
| 2653 #endif // defined TARGET_ARCH_X64 | 2881 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |