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

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

Issue 10458031: In generated code for x64 don't load object's class directly from class_ field. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Eliminate CoreClass helpers on ia32/x64 and use class ids for array classes. 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') | runtime/vm/intermediate_language_x64.cc » ('j') | 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 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
129 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; 129 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1;
130 char* chars = reinterpret_cast<char*>( 130 char* chars = reinterpret_cast<char*>(
131 Isolate::Current()->current_zone()->Allocate(len)); 131 Isolate::Current()->current_zone()->Allocate(len));
132 OS::SNPrint(chars, len, kFormat, function_name, reason); 132 OS::SNPrint(chars, len, kFormat, function_name, reason);
133 const Error& error = Error::Handle( 133 const Error& error = Error::Handle(
134 LanguageError::New(String::Handle(String::New(chars)))); 134 LanguageError::New(String::Handle(String::New(chars))));
135 Isolate::Current()->long_jump_base()->Jump(1, error); 135 Isolate::Current()->long_jump_base()->Jump(1, error);
136 } 136 }
137 137
138 138
139 static const Class* CoreClass(const char* c_name) {
140 const String& class_name = String::Handle(String::NewSymbol(c_name));
141 const Class& cls = Class::ZoneHandle(Library::Handle(
142 Library::CoreImplLibrary()).LookupClass(class_name));
143 ASSERT(!cls.IsNull());
144 return &cls;
145 }
146
147
148 #define __ assembler_-> 139 #define __ assembler_->
149 140
150 141
151 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if 142 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if
152 // type test is conclusive, otherwise fallthrough if a type test could not 143 // type test is conclusive, otherwise fallthrough if a type test could not
153 // be completed. 144 // be completed.
154 // RAX: instance (must survive), 145 // RAX: instance (must survive),
155 RawSubtypeTestCache* 146 RawSubtypeTestCache*
156 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( 147 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
157 intptr_t cid, 148 intptr_t cid,
158 intptr_t token_index, 149 intptr_t token_index,
159 const AbstractType& type, 150 const AbstractType& type,
160 Label* is_instance_lbl, 151 Label* is_instance_lbl,
161 Label* is_not_instance_lbl) { 152 Label* is_not_instance_lbl) {
162 ASSERT(type.IsInstantiated()); 153 ASSERT(type.IsInstantiated());
163 const Class& type_class = Class::ZoneHandle(type.type_class()); 154 const Class& type_class = Class::ZoneHandle(type.type_class());
164 ASSERT(type_class.HasTypeArguments()); 155 ASSERT(type_class.HasTypeArguments());
165 // A Smi object cannot be the instance of a parameterized class. 156 // A Smi object cannot be the instance of a parameterized class.
166 __ testq(RAX, Immediate(kSmiTagMask)); 157 __ testq(RAX, Immediate(kSmiTagMask));
167 __ j(ZERO, is_not_instance_lbl); 158 __ j(ZERO, is_not_instance_lbl);
168 const AbstractTypeArguments& type_arguments = 159 const AbstractTypeArguments& type_arguments =
169 AbstractTypeArguments::ZoneHandle(type.arguments()); 160 AbstractTypeArguments::ZoneHandle(type.arguments());
170 const bool is_raw_type = type_arguments.IsNull() || 161 const bool is_raw_type = type_arguments.IsNull() ||
171 type_arguments.IsRaw(type_arguments.Length()); 162 type_arguments.IsRaw(type_arguments.Length());
172 if (is_raw_type) { 163 if (is_raw_type) {
173 // Dynamic type argument, check only classes. 164 // Dynamic type argument, check only classes.
174 // List is a very common case. 165 // List is a very common case.
175 __ movq(R10, FieldAddress(RAX, Object::class_offset())); 166 __ LoadClassId(R10, RAX);
176 if (!type_class.is_interface()) { 167 if (!type_class.is_interface()) {
177 __ CompareObject(R10, type_class); 168 __ cmpl(R10, Immediate(type_class.index()));
178 __ j(EQUAL, is_instance_lbl); 169 __ j(EQUAL, is_instance_lbl);
179 } 170 }
180 if (type.IsListInterface()) { 171 if (type.IsListInterface()) {
181 Label unknown; 172 Label unknown;
182 GrowableArray<const Class*> args; 173 GrowableArray<intptr_t> args;
183 args.Add(CoreClass("ObjectArray")); 174 args.Add(kArray);
184 args.Add(CoreClass("GrowableObjectArray")); 175 args.Add(kGrowableObjectArray);
185 args.Add(CoreClass("ImmutableArray")); 176 args.Add(kImmutableArray);
186 CheckClasses(args, is_instance_lbl, &unknown); 177 CheckClassIds(args, is_instance_lbl, &unknown);
187 __ Bind(&unknown); 178 __ Bind(&unknown);
188 } 179 }
189 return GenerateSubtype1TestCacheLookup( 180 return GenerateSubtype1TestCacheLookup(
190 cid, token_index, type_class, is_instance_lbl, is_not_instance_lbl); 181 cid, token_index, type_class, is_instance_lbl, is_not_instance_lbl);
191 } 182 }
192 // If one type argument only, check if type argument is Object or Dynamic. 183 // If one type argument only, check if type argument is Object or Dynamic.
193 if (type_arguments.Length() == 1) { 184 if (type_arguments.Length() == 1) {
194 const AbstractType& tp_argument = AbstractType::ZoneHandle( 185 const AbstractType& tp_argument = AbstractType::ZoneHandle(
195 type_arguments.TypeAt(0)); 186 type_arguments.TypeAt(0));
196 ASSERT(!tp_argument.IsMalformed()); 187 ASSERT(!tp_argument.IsMalformed());
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
228 __ j(EQUAL, &runtime_call, Assembler::kNearJump); 219 __ j(EQUAL, &runtime_call, Assembler::kNearJump);
229 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); 220 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
230 __ CompareObject(RCX, bool_true); 221 __ CompareObject(RCX, bool_true);
231 __ j(EQUAL, is_instance_lbl); 222 __ j(EQUAL, is_instance_lbl);
232 __ jmp(is_not_instance_lbl); 223 __ jmp(is_not_instance_lbl);
233 __ Bind(&runtime_call); 224 __ Bind(&runtime_call);
234 return type_test_cache.raw(); 225 return type_test_cache.raw();
235 } 226 }
236 227
237 228
238 // R10: instance class to check. 229 // R10: instance class id to check.
239 void FlowGraphCompiler::CheckClasses(const GrowableArray<const Class*>& classes, 230 void FlowGraphCompiler::CheckClassIds(const GrowableArray<intptr_t>& class_ids,
240 Label* is_instance_lbl, 231 Label* is_instance_lbl,
241 Label* is_not_instance_lbl) { 232 Label* is_not_instance_lbl) {
242 for (intptr_t i = 0; i < classes.length(); i++) { 233 for (intptr_t i = 0; i < class_ids.length(); i++) {
243 __ CompareObject(R10, *classes[i]); 234 __ cmpl(R10, Immediate(class_ids[i]));
244 __ j(EQUAL, is_instance_lbl); 235 __ j(EQUAL, is_instance_lbl);
245 } 236 }
246 __ jmp(is_not_instance_lbl); 237 __ jmp(is_not_instance_lbl);
247 } 238 }
248 239
249 240
250 241
251 // Testing against an instantiated type with no arguments, without 242 // Testing against an instantiated type with no arguments, without
252 // SubtypeTestCache. 243 // SubtypeTestCache.
253 // RAX: instance to test against (preserved). 244 // RAX: instance to test against (preserved).
(...skipping 16 matching lines...) Expand all
270 Error& malformed_error = Error::Handle(); 261 Error& malformed_error = Error::Handle();
271 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), 262 if (smi_class.IsSubtypeOf(TypeArguments::Handle(),
272 type_class, 263 type_class,
273 TypeArguments::Handle(), 264 TypeArguments::Handle(),
274 &malformed_error)) { 265 &malformed_error)) {
275 __ jmp(is_instance_lbl); 266 __ jmp(is_instance_lbl);
276 } else { 267 } else {
277 __ jmp(is_not_instance_lbl); 268 __ jmp(is_not_instance_lbl);
278 } 269 }
279 270
280 ObjectStore* object_store = Isolate::Current()->object_store();
281 // Compare if the classes are equal. Instance is not Smi. 271 // Compare if the classes are equal. Instance is not Smi.
282 __ Bind(&compare_classes); 272 __ Bind(&compare_classes);
283 __ movq(R10, FieldAddress(RAX, Object::class_offset())); 273 __ LoadClassId(R10, RAX);
284 // If type is an interface, we can skip the class equality check. 274 // If type is an interface, we can skip the class equality check.
285 if (!type_class.is_interface()) { 275 if (!type_class.is_interface()) {
286 __ CompareObject(R10, type_class); 276 __ cmpl(R10, Immediate(type_class.index()));
287 __ j(EQUAL, is_instance_lbl); 277 __ j(EQUAL, is_instance_lbl);
288 } 278 }
289 // Check for interfaces that cannot be implemented by user. 279 // Check for interfaces that cannot be implemented by user.
290 // (see ClassFinalizer::ResolveInterfaces for list of restricted interfaces). 280 // (see ClassFinalizer::ResolveInterfaces for list of restricted interfaces).
291 // Bool interface can be implemented only by core class Bool. 281 // Bool interface can be implemented only by core class Bool.
292 if (type.IsBoolInterface()) { 282 if (type.IsBoolInterface()) {
293 const Class& bool_class = Class::ZoneHandle(object_store->bool_class()); 283 __ cmpl(R10, Immediate(kBool));
294 __ CompareObject(R10, bool_class);
295 __ j(EQUAL, is_instance_lbl); 284 __ j(EQUAL, is_instance_lbl);
296 __ jmp(is_not_instance_lbl); 285 __ jmp(is_not_instance_lbl);
297 return; 286 return;
298 } 287 }
299 if (type.IsFunctionInterface()) { 288 if (type.IsFunctionInterface()) {
300 // Check if instance is a closure. 289 // Check if instance is a closure.
301 const Immediate raw_null = 290 const Immediate raw_null =
302 Immediate(reinterpret_cast<intptr_t>(Object::null())); 291 Immediate(reinterpret_cast<intptr_t>(Object::null()));
303 __ movq(R10, FieldAddress(R10, Class::signature_function_offset())); 292 __ LoadClassById(R13, R10);
304 __ cmpq(R10, raw_null); 293 __ movq(R13, FieldAddress(R13, Class::signature_function_offset()));
294 __ cmpq(R13, raw_null);
305 __ j(NOT_EQUAL, is_instance_lbl); 295 __ j(NOT_EQUAL, is_instance_lbl);
306 __ jmp(is_not_instance_lbl); 296 __ jmp(is_not_instance_lbl);
307 return; 297 return;
308 } 298 }
309 // Custom checking for numbers (Smi, Mint, Bigint and Double). 299 // Custom checking for numbers (Smi, Mint, Bigint and Double).
310 // Note that instance is not Smi(checked above). 300 // Note that instance is not Smi(checked above).
311 if (type.IsSubtypeOf( 301 if (type.IsSubtypeOf(
312 Type::Handle(Type::NumberInterface()), &malformed_error)) { 302 Type::Handle(Type::NumberInterface()), &malformed_error)) {
313 const Class& mint_class = Class::ZoneHandle(object_store->mint_class()); 303 GrowableArray<intptr_t> args;
314 const Class& bigint_class = Class::ZoneHandle(object_store->bigint_class());
315 const Class& double_class = Class::ZoneHandle(object_store->double_class());
316 GrowableArray<const Class*> args;
317 if (type.IsNumberInterface()) { 304 if (type.IsNumberInterface()) {
318 args.Add(&double_class); 305 args.Add(kDouble);
319 args.Add(&mint_class); 306 args.Add(kMint);
320 args.Add(&bigint_class); 307 args.Add(kBigint);
321 } else if (type.IsIntInterface()) { 308 } else if (type.IsIntInterface()) {
322 args.Add(&mint_class); 309 args.Add(kMint);
323 args.Add(&bigint_class); 310 args.Add(kBigint);
324 } else if (type.IsDoubleInterface()) { 311 } else if (type.IsDoubleInterface()) {
325 args.Add(&double_class); 312 args.Add(kDouble);
326 } 313 }
327 CheckClasses(args, is_instance_lbl, is_not_instance_lbl); 314 CheckClassIds(args, is_instance_lbl, is_not_instance_lbl);
328 return; 315 return;
329 } 316 }
330 if (type.IsStringInterface()) { 317 if (type.IsStringInterface()) {
331 const Class& one_byte_string_class = 318 GrowableArray<intptr_t> args;
332 Class::ZoneHandle(object_store->one_byte_string_class()); 319 args.Add(kOneByteString);
333 const Class& two_byte_string_class = 320 args.Add(kTwoByteString);
334 Class::ZoneHandle(object_store->two_byte_string_class()); 321 args.Add(kFourByteString);
335 const Class& four_byte_string_class = 322 args.Add(kExternalOneByteString);
336 Class::ZoneHandle(object_store->four_byte_string_class()); 323 args.Add(kExternalTwoByteString);
337 const Class& external_one_byte_string_class = 324 args.Add(kExternalFourByteString);
338 Class::ZoneHandle(object_store->external_one_byte_string_class()); 325 CheckClassIds(args, is_instance_lbl, is_not_instance_lbl);
339 const Class& external_two_byte_string_class =
340 Class::ZoneHandle(object_store->external_two_byte_string_class());
341 const Class& external_four_byte_string_class =
342 Class::ZoneHandle(object_store->external_four_byte_string_class());
343 GrowableArray<const Class*> args;
344 args.Add(&one_byte_string_class);
345 args.Add(&two_byte_string_class);
346 args.Add(&four_byte_string_class);
347 args.Add(&external_one_byte_string_class);
348 args.Add(&external_two_byte_string_class);
349 args.Add(&external_four_byte_string_class);
350 CheckClasses(args, is_instance_lbl, is_not_instance_lbl);
351 return; 326 return;
352 } 327 }
353 // Otherwise fallthrough. 328 // Otherwise fallthrough.
354 } 329 }
355 330
356 331
357 // Uses SubtypeTestCache to store instance class and result. 332 // Uses SubtypeTestCache to store instance class and result.
358 // RAX: instance to test. 333 // RAX: instance to test.
359 // Immediate class test already done. 334 // Immediate class test already done.
360 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( 335 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
361 intptr_t cid, 336 intptr_t cid,
362 intptr_t token_index, 337 intptr_t token_index,
363 const Class& type_class, 338 const Class& type_class,
364 Label* is_instance_lbl, 339 Label* is_instance_lbl,
365 Label* is_not_instance_lbl) { 340 Label* is_not_instance_lbl) {
366 const SubtypeTestCache& type_test_cache = 341 const SubtypeTestCache& type_test_cache =
367 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); 342 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
368 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); 343 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
369 const Immediate raw_null = 344 const Immediate raw_null =
370 Immediate(reinterpret_cast<intptr_t>(Object::null())); 345 Immediate(reinterpret_cast<intptr_t>(Object::null()));
371 __ movq(R10, FieldAddress(RAX, Object::class_offset())); 346 __ LoadClass(R10, RAX);
372 // Check immediate superclass equality. 347 // Check immediate superclass equality.
373 __ movq(R13, FieldAddress(R10, Class::super_type_offset())); 348 __ movq(R13, FieldAddress(R10, Class::super_type_offset()));
374 __ movq(R13, FieldAddress(R13, Type::type_class_offset())); 349 __ movq(R13, FieldAddress(R13, Type::type_class_offset()));
375 __ CompareObject(R13, type_class); 350 __ CompareObject(R13, type_class);
376 __ j(EQUAL, is_instance_lbl); 351 __ j(EQUAL, is_instance_lbl);
377 352
378 __ LoadObject(R10, type_test_cache); 353 __ LoadObject(R10, type_test_cache);
379 __ pushq(R10); // Cache array. 354 __ pushq(R10); // Cache array.
380 __ pushq(RAX); // Instance. 355 __ pushq(RAX); // Instance.
381 __ pushq(raw_null); // Unused 356 __ pushq(raw_null); // Unused
(...skipping 28 matching lines...) Expand all
410 if (type.IsTypeParameter()) { 385 if (type.IsTypeParameter()) {
411 // Load instantiator (or null) and instantiator type arguments on stack. 386 // Load instantiator (or null) and instantiator type arguments on stack.
412 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. 387 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments.
413 // RDX: instantiator type arguments. 388 // RDX: instantiator type arguments.
414 // Check if type argument is Dynamic. 389 // Check if type argument is Dynamic.
415 __ cmpq(RDX, raw_null); 390 __ cmpq(RDX, raw_null);
416 __ j(EQUAL, is_instance_lbl); 391 __ j(EQUAL, is_instance_lbl);
417 // Can handle only type arguments that are instances of TypeArguments. 392 // Can handle only type arguments that are instances of TypeArguments.
418 // (runtime checks canonicalize type arguments). 393 // (runtime checks canonicalize type arguments).
419 Label fall_through; 394 Label fall_through;
420 __ movq(R10, FieldAddress(RDX, Object::class_offset())); 395 __ CompareClassId(RDX, kTypeArguments);
421 __ CompareObject(R10, Object::ZoneHandle(Object::type_arguments_class()));
422 __ j(NOT_EQUAL, &fall_through); 396 __ j(NOT_EQUAL, &fall_through);
423 __ movq(RDI, 397 __ movq(RDI,
424 FieldAddress(RDX, TypeArguments::type_at_offset(type.Index()))); 398 FieldAddress(RDX, TypeArguments::type_at_offset(type.Index())));
425 // RDI: Concrete type. 399 // RDI: Concrete type.
426 // Check if it is Dynamic, 400 // Check if it is Dynamic,
427 __ CompareObject(RDI, Type::ZoneHandle(Type::DynamicType())); 401 __ CompareObject(RDI, Type::ZoneHandle(Type::DynamicType()));
428 __ j(EQUAL, is_instance_lbl); 402 __ j(EQUAL, is_instance_lbl);
429 __ cmpq(RDI, raw_null); 403 __ cmpq(RDI, raw_null);
430 __ j(EQUAL, is_instance_lbl); 404 __ j(EQUAL, is_instance_lbl);
431 // For Smi check quickly against int and num interface types. 405 // For Smi check quickly against int and num interface types.
(...skipping 577 matching lines...) Expand 10 before | Expand all | Expand 10 after
1009 __ cmpq(RAX, raw_null); 983 __ cmpq(RAX, raw_null);
1010 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); 984 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
1011 } 985 }
1012 // Instantiate non-null type arguments. 986 // Instantiate non-null type arguments.
1013 if (comp->type_arguments().IsUninstantiatedIdentity()) { 987 if (comp->type_arguments().IsUninstantiatedIdentity()) {
1014 // Check if the instantiator type argument vector is a TypeArguments of a 988 // Check if the instantiator type argument vector is a TypeArguments of a
1015 // matching length and, if so, use it as the instantiated type_arguments. 989 // matching length and, if so, use it as the instantiated type_arguments.
1016 // No need to check the instantiator (RAX) for null here, because a null 990 // No need to check the instantiator (RAX) for null here, because a null
1017 // instantiator will have the wrong class (Null instead of TypeArguments). 991 // instantiator will have the wrong class (Null instead of TypeArguments).
1018 Label type_arguments_uninstantiated; 992 Label type_arguments_uninstantiated;
1019 __ LoadObject(RCX, Class::ZoneHandle(Object::type_arguments_class())); 993 __ CompareClassId(RAX, kTypeArguments);
1020 __ cmpq(RCX, FieldAddress(RAX, Object::class_offset()));
1021 __ j(NOT_EQUAL, &type_arguments_uninstantiated, Assembler::kNearJump); 994 __ j(NOT_EQUAL, &type_arguments_uninstantiated, Assembler::kNearJump);
1022 Immediate arguments_length = 995 Immediate arguments_length =
1023 Immediate(Smi::RawValue(comp->type_arguments().Length())); 996 Immediate(Smi::RawValue(comp->type_arguments().Length()));
1024 __ cmpq(FieldAddress(RAX, TypeArguments::length_offset()), 997 __ cmpq(FieldAddress(RAX, TypeArguments::length_offset()),
1025 arguments_length); 998 arguments_length);
1026 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); 999 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
1027 __ Bind(&type_arguments_uninstantiated); 1000 __ Bind(&type_arguments_uninstantiated);
1028 } 1001 }
1029 // In the non-factory case, we rely on the allocation stub to 1002 // In the non-factory case, we rely on the allocation stub to
1030 // instantiate the type arguments. 1003 // instantiate the type arguments.
(...skipping 691 matching lines...) Expand 10 before | Expand all | Expand 10 after
1722 1695
1723 void FlowGraphCompiler::FinalizeComments(const Code& code) { 1696 void FlowGraphCompiler::FinalizeComments(const Code& code) {
1724 code.set_comments(assembler_->GetCodeComments()); 1697 code.set_comments(assembler_->GetCodeComments());
1725 } 1698 }
1726 1699
1727 #undef __ 1700 #undef __
1728 1701
1729 } // namespace dart 1702 } // namespace dart
1730 1703
1731 #endif // defined TARGET_ARCH_X64 1704 #endif // defined TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_compiler_x64.h ('k') | runtime/vm/intermediate_language_x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698