Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(310)

Side by Side Diff: runtime/vm/flow_graph_compiler_x64.cc

Issue 10477020: Move inlined type checking code to new compiler ia32. Sharing more and more code between ia32/x64 (… (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/flow_graph_compiler_x64.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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" // Needed here to get TARGET_ARCH_X64. 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64.
6 #if defined(TARGET_ARCH_X64) 6 #if defined(TARGET_ARCH_X64)
7 7
8 #include "vm/flow_graph_compiler.h" 8 #include "vm/flow_graph_compiler.h"
9 9
10 #include "lib/error.h" 10 #include "lib/error.h"
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 const GrowableArray<BlockEntryInstr*>& block_order, 53 const GrowableArray<BlockEntryInstr*>& block_order,
54 bool is_optimizing) 54 bool is_optimizing)
55 : FlowGraphCompilerShared(assembler, 55 : FlowGraphCompilerShared(assembler,
56 parsed_function, 56 parsed_function,
57 block_order, 57 block_order,
58 is_optimizing) {} 58 is_optimizing) {}
59 59
60 #define __ assembler()-> 60 #define __ assembler()->
61 61
62 62
63
64 // Fall through if bool_register contains null.
65 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register,
66 Label* is_true,
67 Label* is_false) {
68 const Immediate raw_null =
69 Immediate(reinterpret_cast<intptr_t>(Object::null()));
70 Label fall_through;
71 __ cmpq(bool_register, raw_null);
72 __ j(EQUAL, &fall_through, Assembler::kNearJump);
73 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
74 __ CompareObject(bool_register, bool_true);
75 __ j(EQUAL, is_true);
76 __ jmp(is_false);
77 __ Bind(&fall_through);
78 }
79
80
81 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub(
82 TypeTestStubKind test_kind,
83 Register instance_reg,
84 Register type_arguments_reg,
85 Register temp_reg,
86 Label* is_instance_lbl,
87 Label* is_not_instance_lbl) {
88 const SubtypeTestCache& type_test_cache =
89 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
90 const Immediate raw_null =
91 Immediate(reinterpret_cast<intptr_t>(Object::null()));
92 __ LoadObject(temp_reg, type_test_cache);
93 __ pushq(temp_reg); // Subtype test cache.
94 __ pushq(instance_reg); // Instance.
95 if (test_kind == kTestTypeOneArg) {
96 ASSERT(type_arguments_reg == kNoRegister);
97 __ pushq(raw_null);
98 __ call(&StubCode::Subtype1TestCacheLabel());
99 } else if (test_kind == kTestTypeTwoArgs) {
100 ASSERT(type_arguments_reg == kNoRegister);
101 __ pushq(raw_null);
102 __ call(&StubCode::Subtype2TestCacheLabel());
103 } else if (test_kind == kTestTypeThreeArgs) {
104 __ pushq(type_arguments_reg);
105 __ call(&StubCode::Subtype3TestCacheLabel());
106 } else {
107 UNREACHABLE();
108 }
109 // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False.
110 __ popq(instance_reg); // Discard.
111 __ popq(instance_reg); // Restore receiver.
112 __ popq(temp_reg); // Discard.
113 GenerateBoolToJump(RCX, is_instance_lbl, is_not_instance_lbl);
114 return type_test_cache.raw();
115 }
116
63 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if 117 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if
64 // type test is conclusive, otherwise fallthrough if a type test could not 118 // type test is conclusive, otherwise fallthrough if a type test could not
65 // be completed. 119 // be completed.
66 // RAX: instance (must survive), 120 // RAX: instance (must survive),
67 RawSubtypeTestCache* 121 RawSubtypeTestCache*
68 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( 122 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
69 intptr_t cid, 123 intptr_t cid,
70 intptr_t token_index, 124 intptr_t token_index,
71 const AbstractType& type, 125 const AbstractType& type,
72 Label* is_instance_lbl, 126 Label* is_instance_lbl,
73 Label* is_not_instance_lbl) { 127 Label* is_not_instance_lbl) {
74 ASSERT(type.IsInstantiated()); 128 ASSERT(type.IsInstantiated());
75 const Class& type_class = Class::ZoneHandle(type.type_class()); 129 const Class& type_class = Class::ZoneHandle(type.type_class());
76 ASSERT(type_class.HasTypeArguments()); 130 ASSERT(type_class.HasTypeArguments());
131 const Register kInstanceReg = RAX;
77 // A Smi object cannot be the instance of a parameterized class. 132 // A Smi object cannot be the instance of a parameterized class.
78 __ testq(RAX, Immediate(kSmiTagMask)); 133 __ testq(kInstanceReg, Immediate(kSmiTagMask));
79 __ j(ZERO, is_not_instance_lbl); 134 __ j(ZERO, is_not_instance_lbl);
80 const AbstractTypeArguments& type_arguments = 135 const AbstractTypeArguments& type_arguments =
81 AbstractTypeArguments::ZoneHandle(type.arguments()); 136 AbstractTypeArguments::ZoneHandle(type.arguments());
82 const bool is_raw_type = type_arguments.IsNull() || 137 const bool is_raw_type = type_arguments.IsNull() ||
83 type_arguments.IsRaw(type_arguments.Length()); 138 type_arguments.IsRaw(type_arguments.Length());
84 if (is_raw_type) { 139 if (is_raw_type) {
140 const Register kClassIdReg = R10;
85 // Dynamic type argument, check only classes. 141 // Dynamic type argument, check only classes.
86 // List is a very common case. 142 // List is a very common case.
87 __ LoadClassId(R10, RAX); 143 __ LoadClassId(kClassIdReg, kInstanceReg);
88 if (!type_class.is_interface()) { 144 if (!type_class.is_interface()) {
89 __ cmpl(R10, Immediate(type_class.id())); 145 __ cmpl(kClassIdReg, Immediate(type_class.id()));
90 __ j(EQUAL, is_instance_lbl); 146 __ j(EQUAL, is_instance_lbl);
91 } 147 }
92 if (type.IsListInterface()) { 148 if (type.IsListInterface()) {
93 Label unknown; 149 GenerateListTypeCheck(kClassIdReg, is_instance_lbl);
94 GrowableArray<intptr_t> args;
95 args.Add(kArray);
96 args.Add(kGrowableObjectArray);
97 args.Add(kImmutableArray);
98 CheckClassIds(args, is_instance_lbl, &unknown);
99 __ Bind(&unknown);
100 } 150 }
101 return GenerateSubtype1TestCacheLookup( 151 return GenerateSubtype1TestCacheLookup(
102 cid, token_index, type_class, is_instance_lbl, is_not_instance_lbl); 152 cid, token_index, type_class, is_instance_lbl, is_not_instance_lbl);
103 } 153 }
104 // If one type argument only, check if type argument is Object or Dynamic. 154 // If one type argument only, check if type argument is Object or Dynamic.
105 if (type_arguments.Length() == 1) { 155 if (type_arguments.Length() == 1) {
106 const AbstractType& tp_argument = AbstractType::ZoneHandle( 156 const AbstractType& tp_argument = AbstractType::ZoneHandle(
107 type_arguments.TypeAt(0)); 157 type_arguments.TypeAt(0));
108 ASSERT(!tp_argument.IsMalformed()); 158 ASSERT(!tp_argument.IsMalformed());
109 if (tp_argument.IsType()) { 159 if (tp_argument.IsType()) {
110 ASSERT(tp_argument.HasResolvedTypeClass()); 160 ASSERT(tp_argument.HasResolvedTypeClass());
111 // Check if type argument is dynamic or Object. 161 // Check if type argument is dynamic or Object.
112 const Type& object_type = 162 const Type& object_type =
113 Type::Handle(Isolate::Current()->object_store()->object_type()); 163 Type::Handle(Isolate::Current()->object_store()->object_type());
114 Error& malformed_error = Error::Handle(); 164 Error& malformed_error = Error::Handle();
115 if (object_type.IsSubtypeOf(tp_argument, &malformed_error)) { 165 if (object_type.IsSubtypeOf(tp_argument, &malformed_error)) {
116 // Instance class test only necessary. 166 // Instance class test only necessary.
117 return GenerateSubtype1TestCacheLookup( 167 return GenerateSubtype1TestCacheLookup(
118 cid, token_index, type_class, is_instance_lbl, is_not_instance_lbl); 168 cid, token_index, type_class, is_instance_lbl, is_not_instance_lbl);
119 } 169 }
120 } 170 }
121 } 171 }
122 172
123 // Regular subtype test cache involving instance's type arguments. 173 // Regular subtype test cache involving instance's type arguments.
124 const SubtypeTestCache& type_test_cache = 174 const Register kTypeArgumentsReg = kNoRegister;
125 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); 175 const Register kTempReg = R10;
126 Label runtime_call; 176 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs,
127 const Immediate raw_null = 177 kInstanceReg,
128 Immediate(reinterpret_cast<intptr_t>(Object::null())); 178 kTypeArgumentsReg,
129 __ LoadObject(R10, type_test_cache); 179 kTempReg,
130 __ pushq(R10); // Subtype test cache. 180 is_instance_lbl,
131 __ pushq(RAX); // Instance. 181 is_not_instance_lbl);
132 __ pushq(raw_null); // Unused.
133 __ call(&StubCode::Subtype2TestCacheLabel());
134 __ popq(RAX); // Discard.
135 __ popq(RAX); // Restore receiver.
136 __ popq(RDX); // Discard.
137 // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False.
138
139 __ cmpq(RCX, raw_null);
140 __ j(EQUAL, &runtime_call, Assembler::kNearJump);
141 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
142 __ CompareObject(RCX, bool_true);
143 __ j(EQUAL, is_instance_lbl);
144 __ jmp(is_not_instance_lbl);
145 __ Bind(&runtime_call);
146 return type_test_cache.raw();
147 } 182 }
148 183
149 184
150 // R10: instance class id to check. 185 void FlowGraphCompiler::CheckClassIds(Register class_id_reg,
151 void FlowGraphCompiler::CheckClassIds(const GrowableArray<intptr_t>& class_ids, 186 const GrowableArray<intptr_t>& class_ids,
152 Label* is_instance_lbl, 187 Label* is_equal_lbl,
153 Label* is_not_instance_lbl) { 188 Label* is_not_equal_lbl) {
154 for (intptr_t i = 0; i < class_ids.length(); i++) { 189 for (intptr_t i = 0; i < class_ids.length(); i++) {
155 __ cmpl(R10, Immediate(class_ids[i])); 190 __ cmpl(class_id_reg, Immediate(class_ids[i]));
156 __ j(EQUAL, is_instance_lbl); 191 __ j(EQUAL, is_equal_lbl);
157 } 192 }
158 __ jmp(is_not_instance_lbl); 193 __ jmp(is_not_equal_lbl);
159 } 194 }
160 195
161 196
162 197
163 // Testing against an instantiated type with no arguments, without 198 // Testing against an instantiated type with no arguments, without
164 // SubtypeTestCache. 199 // SubtypeTestCache.
165 // RAX: instance to test against (preserved). 200 // RAX: instance to test against (preserved).
166 void FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( 201 void FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
167 intptr_t cid, 202 intptr_t cid,
168 intptr_t token_index, 203 intptr_t token_index,
(...skipping 15 matching lines...) Expand all
184 type_class, 219 type_class,
185 TypeArguments::Handle(), 220 TypeArguments::Handle(),
186 &malformed_error)) { 221 &malformed_error)) {
187 __ jmp(is_instance_lbl); 222 __ jmp(is_instance_lbl);
188 } else { 223 } else {
189 __ jmp(is_not_instance_lbl); 224 __ jmp(is_not_instance_lbl);
190 } 225 }
191 226
192 // Compare if the classes are equal. Instance is not Smi. 227 // Compare if the classes are equal. Instance is not Smi.
193 __ Bind(&compare_classes); 228 __ Bind(&compare_classes);
194 __ LoadClassId(R10, RAX); 229 const Register kClassIdReg = R10;
230 __ LoadClassId(kClassIdReg, RAX);
195 // If type is an interface, we can skip the class equality check. 231 // If type is an interface, we can skip the class equality check.
196 if (!type_class.is_interface()) { 232 if (!type_class.is_interface()) {
197 __ cmpl(R10, Immediate(type_class.id())); 233 __ cmpl(kClassIdReg, Immediate(type_class.id()));
198 __ j(EQUAL, is_instance_lbl); 234 __ j(EQUAL, is_instance_lbl);
199 } 235 }
200 // Check for interfaces that cannot be implemented by user. 236 // Check for interfaces that cannot be implemented by user.
201 // (see ClassFinalizer::ResolveInterfaces for list of restricted interfaces). 237 // (see ClassFinalizer::ResolveInterfaces for list of restricted interfaces).
202 // Bool interface can be implemented only by core class Bool. 238 // Bool interface can be implemented only by core class Bool.
203 if (type.IsBoolInterface()) { 239 if (type.IsBoolInterface()) {
204 __ cmpl(R10, Immediate(kBool)); 240 __ cmpl(kClassIdReg, Immediate(kBool));
205 __ j(EQUAL, is_instance_lbl); 241 __ j(EQUAL, is_instance_lbl);
206 __ jmp(is_not_instance_lbl); 242 __ jmp(is_not_instance_lbl);
207 return; 243 return;
208 } 244 }
209 if (type.IsFunctionInterface()) { 245 if (type.IsFunctionInterface()) {
210 // Check if instance is a closure. 246 // Check if instance is a closure.
211 const Immediate raw_null = 247 const Immediate raw_null =
212 Immediate(reinterpret_cast<intptr_t>(Object::null())); 248 Immediate(reinterpret_cast<intptr_t>(Object::null()));
213 __ LoadClassById(R13, R10); 249 __ LoadClassById(R13, kClassIdReg);
214 __ movq(R13, FieldAddress(R13, Class::signature_function_offset())); 250 __ movq(R13, FieldAddress(R13, Class::signature_function_offset()));
215 __ cmpq(R13, raw_null); 251 __ cmpq(R13, raw_null);
216 __ j(NOT_EQUAL, is_instance_lbl); 252 __ j(NOT_EQUAL, is_instance_lbl);
217 __ jmp(is_not_instance_lbl); 253 __ jmp(is_not_instance_lbl);
218 return; 254 return;
219 } 255 }
220 // Custom checking for numbers (Smi, Mint, Bigint and Double). 256 // Custom checking for numbers (Smi, Mint, Bigint and Double).
221 // Note that instance is not Smi(checked above). 257 // Note that instance is not Smi(checked above).
222 if (type.IsSubtypeOf( 258 if (type.IsSubtypeOf(
223 Type::Handle(Type::NumberInterface()), &malformed_error)) { 259 Type::Handle(Type::NumberInterface()), &malformed_error)) {
224 GrowableArray<intptr_t> args; 260 GenerateNumberTypeCheck(
225 if (type.IsNumberInterface()) { 261 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl);
226 args.Add(kDouble);
227 args.Add(kMint);
228 args.Add(kBigint);
229 } else if (type.IsIntInterface()) {
230 args.Add(kMint);
231 args.Add(kBigint);
232 } else if (type.IsDoubleInterface()) {
233 args.Add(kDouble);
234 }
235 CheckClassIds(args, is_instance_lbl, is_not_instance_lbl);
236 return; 262 return;
237 } 263 }
238 if (type.IsStringInterface()) { 264 if (type.IsStringInterface()) {
239 GrowableArray<intptr_t> args; 265 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl);
240 args.Add(kOneByteString);
241 args.Add(kTwoByteString);
242 args.Add(kFourByteString);
243 args.Add(kExternalOneByteString);
244 args.Add(kExternalTwoByteString);
245 args.Add(kExternalFourByteString);
246 CheckClassIds(args, is_instance_lbl, is_not_instance_lbl);
247 return; 266 return;
248 } 267 }
249 // Otherwise fallthrough. 268 // Otherwise fallthrough.
250 } 269 }
251 270
252 271
253 // Uses SubtypeTestCache to store instance class and result. 272 // Uses SubtypeTestCache to store instance class and result.
254 // RAX: instance to test. 273 // RAX: instance to test.
255 // Immediate class test already done. 274 // Immediate class test already done.
256 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( 275 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
257 intptr_t cid, 276 intptr_t cid,
258 intptr_t token_index, 277 intptr_t token_index,
259 const Class& type_class, 278 const Class& type_class,
260 Label* is_instance_lbl, 279 Label* is_instance_lbl,
261 Label* is_not_instance_lbl) { 280 Label* is_not_instance_lbl) {
262 const SubtypeTestCache& type_test_cache = 281 const Register kInstanceReg = RAX;
263 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); 282 __ LoadClass(R10, kInstanceReg);
264 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
265 const Immediate raw_null =
266 Immediate(reinterpret_cast<intptr_t>(Object::null()));
267 __ LoadClass(R10, RAX);
268 // Check immediate superclass equality. 283 // Check immediate superclass equality.
269 __ movq(R13, FieldAddress(R10, Class::super_type_offset())); 284 __ movq(R13, FieldAddress(R10, Class::super_type_offset()));
270 __ movq(R13, FieldAddress(R13, Type::type_class_offset())); 285 __ movq(R13, FieldAddress(R13, Type::type_class_offset()));
271 __ CompareObject(R13, type_class); 286 __ CompareObject(R13, type_class);
272 __ j(EQUAL, is_instance_lbl); 287 __ j(EQUAL, is_instance_lbl);
273 288
274 __ LoadObject(R10, type_test_cache); 289 const Register kTypeArgumentsReg = kNoRegister;
275 __ pushq(R10); // Cache array. 290 const Register kTempReg = R10;
276 __ pushq(RAX); // Instance. 291 return GenerateCallSubtypeTestStub(kTestTypeOneArg,
277 __ pushq(raw_null); // Unused 292 kInstanceReg,
278 __ call(&StubCode::Subtype1TestCacheLabel()); 293 kTypeArgumentsReg,
279 __ popq(RAX); // Discard. 294 kTempReg,
280 __ popq(RAX); // Restore receiver. 295 is_instance_lbl,
281 __ popq(RDX); // Discard. 296 is_not_instance_lbl);
282 // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False.
283
284 Label runtime_call;
285 __ cmpq(RCX, raw_null);
286 __ j(EQUAL, &runtime_call, Assembler::kNearJump);
287 __ CompareObject(RCX, bool_true);
288 __ j(EQUAL, is_instance_lbl);
289 __ jmp(is_not_instance_lbl);
290 __ Bind(&runtime_call);
291 return type_test_cache.raw();
292 } 297 }
293 298
294 299
295 // Generates inlined check if 'type' is a type parameter or type itsef 300 // Generates inlined check if 'type' is a type parameter or type itsef
296 // RAX: instance (preserved). 301 // RAX: instance (preserved).
297 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( 302 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
298 const AbstractType& type,
299 intptr_t cid, 303 intptr_t cid,
300 intptr_t token_index, 304 intptr_t token_index,
305 const AbstractType& type,
301 Label* is_instance_lbl, 306 Label* is_instance_lbl,
302 Label* is_not_instance_lbl) { 307 Label* is_not_instance_lbl) {
303 ASSERT(!type.IsInstantiated()); 308 ASSERT(!type.IsInstantiated());
304 const Immediate raw_null = 309 const Immediate raw_null =
305 Immediate(reinterpret_cast<intptr_t>(Object::null())); 310 Immediate(reinterpret_cast<intptr_t>(Object::null()));
306 if (type.IsTypeParameter()) { 311 if (type.IsTypeParameter()) {
307 // Load instantiator (or null) and instantiator type arguments on stack. 312 // Load instantiator (or null) and instantiator type arguments on stack.
308 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. 313 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments.
309 // RDX: instantiator type arguments. 314 // RDX: instantiator type arguments.
310 // Check if type argument is Dynamic. 315 // Check if type argument is Dynamic.
311 __ cmpq(RDX, raw_null); 316 __ cmpq(RDX, raw_null);
312 __ j(EQUAL, is_instance_lbl); 317 __ j(EQUAL, is_instance_lbl);
313 // Can handle only type arguments that are instances of TypeArguments. 318 // Can handle only type arguments that are instances of TypeArguments.
314 // (runtime checks canonicalize type arguments). 319 // (runtime checks canonicalize type arguments).
315 Label fall_through; 320 Label fall_through;
316 __ CompareClassId(RDX, kTypeArguments); 321 __ CompareClassId(RDX, kTypeArguments);
317 __ j(NOT_EQUAL, &fall_through); 322 __ j(NOT_EQUAL, &fall_through);
318 __ movq(RDI, 323 __ movq(RDI,
319 FieldAddress(RDX, TypeArguments::type_at_offset(type.Index()))); 324 FieldAddress(RDX, TypeArguments::type_at_offset(type.Index())));
320 // RDI: Concrete type. 325 // RDI: Concrete type.
321 // Check if it is Dynamic, 326 // Check if it is Dynamic,
322 __ CompareObject(RDI, Type::ZoneHandle(Type::DynamicType())); 327 __ CompareObject(RDI, Type::ZoneHandle(Type::DynamicType()));
323 __ j(EQUAL, is_instance_lbl); 328 __ j(EQUAL, is_instance_lbl);
324 __ cmpq(RDI, raw_null); 329 __ cmpq(RDI, raw_null);
325 __ j(EQUAL, is_instance_lbl); 330 __ j(EQUAL, is_instance_lbl);
331 const Type& object_type =
332 Type::ZoneHandle(Isolate::Current()->object_store()->object_type());
333 __ CompareObject(RDI, object_type);
334 __ j(EQUAL, is_instance_lbl);
335
326 // For Smi check quickly against int and num interface types. 336 // For Smi check quickly against int and num interface types.
327 Label not_smi; 337 Label not_smi;
328 __ testq(RAX, Immediate(kSmiTagMask)); // Value is Smi? 338 __ testq(RAX, Immediate(kSmiTagMask)); // Value is Smi?
329 __ j(NOT_ZERO, &not_smi, Assembler::kNearJump); 339 __ j(NOT_ZERO, &not_smi, Assembler::kNearJump);
330 __ CompareObject(RDI, Type::ZoneHandle(Type::IntInterface())); 340 __ CompareObject(RDI, Type::ZoneHandle(Type::IntInterface()));
331 __ j(EQUAL, is_instance_lbl); 341 __ j(EQUAL, is_instance_lbl);
332 __ CompareObject(RDI, Type::ZoneHandle(Type::NumberInterface())); 342 __ CompareObject(RDI, Type::ZoneHandle(Type::NumberInterface()));
333 __ j(EQUAL, is_instance_lbl); 343 __ j(EQUAL, is_instance_lbl);
344 // Smi must be handled in runtime.
334 __ jmp(&fall_through); 345 __ jmp(&fall_through);
346
335 __ Bind(&not_smi); 347 __ Bind(&not_smi);
336 // RDX: instantiator type arguments. 348 // RDX: instantiator type arguments.
337 // RAX: instance. 349 // RAX: instance.
350 const Register kInstanceReg = RAX;
351 const Register kTypeArgumentsReg = RDX;
352 const Register kTempReg = R10;
338 const SubtypeTestCache& type_test_cache = 353 const SubtypeTestCache& type_test_cache =
339 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); 354 SubtypeTestCache::ZoneHandle(
340 __ LoadObject(R10, type_test_cache); 355 GenerateCallSubtypeTestStub(kTestTypeThreeArgs,
341 __ pushq(R10); // Subtype test cache. 356 kInstanceReg,
342 __ pushq(RAX); // Instance 357 kTypeArgumentsReg,
343 __ pushq(RDX); // Instantiator type arguments. 358 kTempReg,
344 __ call(&StubCode::Subtype3TestCacheLabel()); 359 is_instance_lbl,
345 __ popq(RDX); // Discard type arguments. 360 is_not_instance_lbl));
346 __ popq(RAX); // Restore receiver. 361
347 __ popq(RDX); // Discard subtype test cache.
348 // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False.
349 __ cmpq(RCX, raw_null);
350 __ j(EQUAL, &fall_through, Assembler::kNearJump);
351 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
352 __ CompareObject(RCX, bool_true);
353 __ j(EQUAL, is_instance_lbl);
354 __ jmp(is_not_instance_lbl);
355 __ Bind(&fall_through); 362 __ Bind(&fall_through);
356 return type_test_cache.raw(); 363 return type_test_cache.raw();
357 } 364 }
358 if (type.IsType()) { 365 if (type.IsType()) {
359 Label fall_through; 366 const Register kInstanceReg = RAX;
360 __ testq(RAX, Immediate(kSmiTagMask)); // Is instance Smi? 367 const Register kTypeArgumentsReg = RDX;
368 __ testq(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi?
361 __ j(ZERO, is_not_instance_lbl); 369 __ j(ZERO, is_not_instance_lbl);
362 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. 370 __ movq(kTypeArgumentsReg, Address(RSP, 0)); // Instantiator type args.
363 // Uninstantiated type class is known at compile time, but the type 371 // Uninstantiated type class is known at compile time, but the type
364 // arguments are determined at runtime by the instantiator. 372 // arguments are determined at runtime by the instantiator.
365 const SubtypeTestCache& type_test_cache = 373 const Register kTempReg = R10;
366 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); 374 return GenerateCallSubtypeTestStub(kTestTypeThreeArgs,
367 __ LoadObject(R10, type_test_cache); 375 kInstanceReg,
368 __ pushq(R10); // Subtype test cache. 376 kTypeArgumentsReg,
369 __ pushq(RAX); // Instance. 377 kTempReg,
370 __ pushq(RDX); // Instantiator type arguments. 378 is_instance_lbl,
371 __ call(&StubCode::Subtype3TestCacheLabel()); 379 is_not_instance_lbl);
372 __ popq(RDX); // Discard type arguments.
373 __ popq(RAX); // Restore receiver.
374 __ popq(RDX); // Discard subtype test cache.
375 // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False.
376 __ cmpq(RCX, raw_null);
377 __ j(EQUAL, &fall_through, Assembler::kNearJump);
378 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
379 __ CompareObject(RCX, bool_true);
380 __ j(EQUAL, is_instance_lbl);
381 __ jmp(is_not_instance_lbl);
382 __ Bind(&fall_through);
383 return type_test_cache.raw();
384 } 380 }
385 return SubtypeTestCache::null(); 381 return SubtypeTestCache::null();
386 } 382 }
387 383
388 384
389 // Inputs: 385 // Inputs:
390 // - RAX: instance to test against (preserved). 386 // - RAX: instance to test against (preserved).
391 // - RDX: optional instantiator type arguments (preserved). 387 // - RDX: optional instantiator type arguments (preserved).
392 // Destroys RCX. 388 // Destroys RCX.
393 // Returns: 389 // Returns:
(...skipping 25 matching lines...) Expand all
419 type, 415 type,
420 is_instance_lbl, 416 is_instance_lbl,
421 is_not_instance_lbl); 417 is_not_instance_lbl);
422 // If test non-conclusive so far, try the inlined type-test cache. 418 // If test non-conclusive so far, try the inlined type-test cache.
423 // 'type' is known at compile time. 419 // 'type' is known at compile time.
424 return GenerateSubtype1TestCacheLookup( 420 return GenerateSubtype1TestCacheLookup(
425 cid, token_index, type_class, 421 cid, token_index, type_class,
426 is_instance_lbl, is_not_instance_lbl); 422 is_instance_lbl, is_not_instance_lbl);
427 } 423 }
428 } else { 424 } else {
429 return GenerateUninstantiatedTypeTest(type, 425 return GenerateUninstantiatedTypeTest(cid,
430 cid,
431 token_index, 426 token_index,
427 type,
432 is_instance_lbl, 428 is_instance_lbl,
433 is_not_instance_lbl); 429 is_not_instance_lbl);
434 } 430 }
435 return SubtypeTestCache::null(); 431 return SubtypeTestCache::null();
436 } 432 }
437 433
438 434
439 // Optimize assignable type check by adding inlined tests for: 435 // Optimize assignable type check by adding inlined tests for:
440 // - NULL -> return NULL. 436 // - NULL -> return NULL.
441 // - Smi -> compile time subtype check (only if dst class is not parameterized). 437 // - Smi -> compile time subtype check (only if dst class is not parameterized).
(...skipping 591 matching lines...) Expand 10 before | Expand all | Expand 10 after
1033 __ CallRuntime(entry); 1029 __ CallRuntime(entry);
1034 AddCurrentDescriptor(PcDescriptors::kOther, cid, token_index, try_index); 1030 AddCurrentDescriptor(PcDescriptors::kOther, cid, token_index, try_index);
1035 } 1031 }
1036 1032
1037 1033
1038 #undef __ 1034 #undef __
1039 1035
1040 } // namespace dart 1036 } // namespace dart
1041 1037
1042 #endif // defined TARGET_ARCH_X64 1038 #endif // defined TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_compiler_x64.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698