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

Side by Side Diff: vm/flow_graph_compiler_x64.cc

Issue 10632009: Make the parser agnostic to the TokenStream implementation. This is the first step towards compacti… (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/runtime/
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 | « vm/flow_graph_compiler_x64.h ('k') | vm/intermediate_language.h » ('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 22 matching lines...) Expand all
33 __ Bind(entry_label()); 33 __ Bind(entry_label());
34 for (intptr_t i = 0; i < registers_.length(); i++) { 34 for (intptr_t i = 0; i < registers_.length(); i++) {
35 if (registers_[i] != kNoRegister) { 35 if (registers_[i] != kNoRegister) {
36 __ pushq(registers_[i]); 36 __ pushq(registers_[i]);
37 } 37 }
38 } 38 }
39 __ movq(RAX, Immediate(Smi::RawValue(reason_))); 39 __ movq(RAX, Immediate(Smi::RawValue(reason_)));
40 __ call(&StubCode::DeoptimizeLabel()); 40 __ call(&StubCode::DeoptimizeLabel());
41 compiler->AddCurrentDescriptor(PcDescriptors::kOther, 41 compiler->AddCurrentDescriptor(PcDescriptors::kOther,
42 deopt_id_, 42 deopt_id_,
43 deopt_token_index_, 43 deopt_token_pos_,
44 try_index_); 44 try_index_);
45 #undef __ 45 #undef __
46 } 46 }
47 47
48 48
49 #define __ assembler()-> 49 #define __ assembler()->
50 50
51 51
52 52
53 // Fall through if bool_register contains null. 53 // Fall through if bool_register contains null.
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 return type_test_cache.raw(); 102 return type_test_cache.raw();
103 } 103 }
104 104
105 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if 105 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if
106 // type test is conclusive, otherwise fallthrough if a type test could not 106 // type test is conclusive, otherwise fallthrough if a type test could not
107 // be completed. 107 // be completed.
108 // RAX: instance (must survive), 108 // RAX: instance (must survive),
109 RawSubtypeTestCache* 109 RawSubtypeTestCache*
110 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( 110 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
111 intptr_t cid, 111 intptr_t cid,
112 intptr_t token_index, 112 intptr_t token_pos,
113 const AbstractType& type, 113 const AbstractType& type,
114 Label* is_instance_lbl, 114 Label* is_instance_lbl,
115 Label* is_not_instance_lbl) { 115 Label* is_not_instance_lbl) {
116 ASSERT(type.IsInstantiated()); 116 ASSERT(type.IsInstantiated());
117 const Class& type_class = Class::ZoneHandle(type.type_class()); 117 const Class& type_class = Class::ZoneHandle(type.type_class());
118 ASSERT(type_class.HasTypeArguments()); 118 ASSERT(type_class.HasTypeArguments());
119 const Register kInstanceReg = RAX; 119 const Register kInstanceReg = RAX;
120 // A Smi object cannot be the instance of a parameterized class. 120 // A Smi object cannot be the instance of a parameterized class.
121 __ testq(kInstanceReg, Immediate(kSmiTagMask)); 121 __ testq(kInstanceReg, Immediate(kSmiTagMask));
122 __ j(ZERO, is_not_instance_lbl); 122 __ j(ZERO, is_not_instance_lbl);
123 const AbstractTypeArguments& type_arguments = 123 const AbstractTypeArguments& type_arguments =
124 AbstractTypeArguments::ZoneHandle(type.arguments()); 124 AbstractTypeArguments::ZoneHandle(type.arguments());
125 const bool is_raw_type = type_arguments.IsNull() || 125 const bool is_raw_type = type_arguments.IsNull() ||
126 type_arguments.IsRaw(type_arguments.Length()); 126 type_arguments.IsRaw(type_arguments.Length());
127 if (is_raw_type) { 127 if (is_raw_type) {
128 const Register kClassIdReg = R10; 128 const Register kClassIdReg = R10;
129 // Dynamic type argument, check only classes. 129 // Dynamic type argument, check only classes.
130 // List is a very common case. 130 // List is a very common case.
131 __ LoadClassId(kClassIdReg, kInstanceReg); 131 __ LoadClassId(kClassIdReg, kInstanceReg);
132 if (!type_class.is_interface()) { 132 if (!type_class.is_interface()) {
133 __ cmpl(kClassIdReg, Immediate(type_class.id())); 133 __ cmpl(kClassIdReg, Immediate(type_class.id()));
134 __ j(EQUAL, is_instance_lbl); 134 __ j(EQUAL, is_instance_lbl);
135 } 135 }
136 if (type.IsListInterface()) { 136 if (type.IsListInterface()) {
137 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); 137 GenerateListTypeCheck(kClassIdReg, is_instance_lbl);
138 } 138 }
139 return GenerateSubtype1TestCacheLookup( 139 return GenerateSubtype1TestCacheLookup(
140 cid, token_index, type_class, is_instance_lbl, is_not_instance_lbl); 140 cid, token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
141 } 141 }
142 // If one type argument only, check if type argument is Object or Dynamic. 142 // If one type argument only, check if type argument is Object or Dynamic.
143 if (type_arguments.Length() == 1) { 143 if (type_arguments.Length() == 1) {
144 const AbstractType& tp_argument = AbstractType::ZoneHandle( 144 const AbstractType& tp_argument = AbstractType::ZoneHandle(
145 type_arguments.TypeAt(0)); 145 type_arguments.TypeAt(0));
146 ASSERT(!tp_argument.IsMalformed()); 146 ASSERT(!tp_argument.IsMalformed());
147 if (tp_argument.IsType()) { 147 if (tp_argument.IsType()) {
148 ASSERT(tp_argument.HasResolvedTypeClass()); 148 ASSERT(tp_argument.HasResolvedTypeClass());
149 // Check if type argument is dynamic or Object. 149 // Check if type argument is dynamic or Object.
150 const Type& object_type = 150 const Type& object_type =
151 Type::Handle(Isolate::Current()->object_store()->object_type()); 151 Type::Handle(Isolate::Current()->object_store()->object_type());
152 Error& malformed_error = Error::Handle(); 152 Error& malformed_error = Error::Handle();
153 if (object_type.IsSubtypeOf(tp_argument, &malformed_error)) { 153 if (object_type.IsSubtypeOf(tp_argument, &malformed_error)) {
154 // Instance class test only necessary. 154 // Instance class test only necessary.
155 return GenerateSubtype1TestCacheLookup( 155 return GenerateSubtype1TestCacheLookup(
156 cid, token_index, type_class, is_instance_lbl, is_not_instance_lbl); 156 cid, token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
157 } 157 }
158 } 158 }
159 } 159 }
160 160
161 // Regular subtype test cache involving instance's type arguments. 161 // Regular subtype test cache involving instance's type arguments.
162 const Register kTypeArgumentsReg = kNoRegister; 162 const Register kTypeArgumentsReg = kNoRegister;
163 const Register kTempReg = R10; 163 const Register kTempReg = R10;
164 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, 164 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs,
165 kInstanceReg, 165 kInstanceReg,
166 kTypeArgumentsReg, 166 kTypeArgumentsReg,
(...skipping 14 matching lines...) Expand all
181 __ jmp(is_not_equal_lbl); 181 __ jmp(is_not_equal_lbl);
182 } 182 }
183 183
184 184
185 185
186 // Testing against an instantiated type with no arguments, without 186 // Testing against an instantiated type with no arguments, without
187 // SubtypeTestCache. 187 // SubtypeTestCache.
188 // RAX: instance to test against (preserved). 188 // RAX: instance to test against (preserved).
189 void FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( 189 void FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
190 intptr_t cid, 190 intptr_t cid,
191 intptr_t token_index, 191 intptr_t token_pos,
192 const AbstractType& type, 192 const AbstractType& type,
193 Label* is_instance_lbl, 193 Label* is_instance_lbl,
194 Label* is_not_instance_lbl) { 194 Label* is_not_instance_lbl) {
195 ASSERT(type.IsInstantiated()); 195 ASSERT(type.IsInstantiated());
196 const Class& type_class = Class::ZoneHandle(type.type_class()); 196 const Class& type_class = Class::ZoneHandle(type.type_class());
197 ASSERT(!type_class.HasTypeArguments()); 197 ASSERT(!type_class.HasTypeArguments());
198 198
199 Label compare_classes; 199 Label compare_classes;
200 __ testq(RAX, Immediate(kSmiTagMask)); 200 __ testq(RAX, Immediate(kSmiTagMask));
201 __ j(NOT_ZERO, &compare_classes); 201 __ j(NOT_ZERO, &compare_classes);
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 } 255 }
256 // Otherwise fallthrough. 256 // Otherwise fallthrough.
257 } 257 }
258 258
259 259
260 // Uses SubtypeTestCache to store instance class and result. 260 // Uses SubtypeTestCache to store instance class and result.
261 // RAX: instance to test. 261 // RAX: instance to test.
262 // Immediate class test already done. 262 // Immediate class test already done.
263 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( 263 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
264 intptr_t cid, 264 intptr_t cid,
265 intptr_t token_index, 265 intptr_t token_pos,
266 const Class& type_class, 266 const Class& type_class,
267 Label* is_instance_lbl, 267 Label* is_instance_lbl,
268 Label* is_not_instance_lbl) { 268 Label* is_not_instance_lbl) {
269 const Register kInstanceReg = RAX; 269 const Register kInstanceReg = RAX;
270 __ LoadClass(R10, kInstanceReg); 270 __ LoadClass(R10, kInstanceReg);
271 // Check immediate superclass equality. 271 // Check immediate superclass equality.
272 __ movq(R13, FieldAddress(R10, Class::super_type_offset())); 272 __ movq(R13, FieldAddress(R10, Class::super_type_offset()));
273 __ movq(R13, FieldAddress(R13, Type::type_class_offset())); 273 __ movq(R13, FieldAddress(R13, Type::type_class_offset()));
274 __ CompareObject(R13, type_class); 274 __ CompareObject(R13, type_class);
275 __ j(EQUAL, is_instance_lbl); 275 __ j(EQUAL, is_instance_lbl);
276 276
277 const Register kTypeArgumentsReg = kNoRegister; 277 const Register kTypeArgumentsReg = kNoRegister;
278 const Register kTempReg = R10; 278 const Register kTempReg = R10;
279 return GenerateCallSubtypeTestStub(kTestTypeOneArg, 279 return GenerateCallSubtypeTestStub(kTestTypeOneArg,
280 kInstanceReg, 280 kInstanceReg,
281 kTypeArgumentsReg, 281 kTypeArgumentsReg,
282 kTempReg, 282 kTempReg,
283 is_instance_lbl, 283 is_instance_lbl,
284 is_not_instance_lbl); 284 is_not_instance_lbl);
285 } 285 }
286 286
287 287
288 // Generates inlined check if 'type' is a type parameter or type itsef 288 // Generates inlined check if 'type' is a type parameter or type itsef
289 // RAX: instance (preserved). 289 // RAX: instance (preserved).
290 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( 290 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
291 intptr_t cid, 291 intptr_t cid,
292 intptr_t token_index, 292 intptr_t token_pos,
293 const AbstractType& type, 293 const AbstractType& type,
294 Label* is_instance_lbl, 294 Label* is_instance_lbl,
295 Label* is_not_instance_lbl) { 295 Label* is_not_instance_lbl) {
296 ASSERT(!type.IsInstantiated()); 296 ASSERT(!type.IsInstantiated());
297 const Immediate raw_null = 297 const Immediate raw_null =
298 Immediate(reinterpret_cast<intptr_t>(Object::null())); 298 Immediate(reinterpret_cast<intptr_t>(Object::null()));
299 if (type.IsTypeParameter()) { 299 if (type.IsTypeParameter()) {
300 // Load instantiator (or null) and instantiator type arguments on stack. 300 // Load instantiator (or null) and instantiator type arguments on stack.
301 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. 301 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments.
302 // RDX: instantiator type arguments. 302 // RDX: instantiator type arguments.
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
374 // - RAX: instance to test against (preserved). 374 // - RAX: instance to test against (preserved).
375 // - RDX: optional instantiator type arguments (preserved). 375 // - RDX: optional instantiator type arguments (preserved).
376 // Destroys RCX. 376 // Destroys RCX.
377 // Returns: 377 // Returns:
378 // - unchanged object in RAX and optional instantiator type arguments in RDX. 378 // - unchanged object in RAX and optional instantiator type arguments in RDX.
379 // Note that this inlined code must be followed by the runtime_call code, as it 379 // Note that this inlined code must be followed by the runtime_call code, as it
380 // may fall through to it. Otherwise, this inline code will jump to the label 380 // may fall through to it. Otherwise, this inline code will jump to the label
381 // is_instance or to the label is_not_instance. 381 // is_instance or to the label is_not_instance.
382 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( 382 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof(
383 intptr_t cid, 383 intptr_t cid,
384 intptr_t token_index, 384 intptr_t token_pos,
385 const AbstractType& type, 385 const AbstractType& type,
386 Label* is_instance_lbl, 386 Label* is_instance_lbl,
387 Label* is_not_instance_lbl) { 387 Label* is_not_instance_lbl) {
388 if (type.IsInstantiated()) { 388 if (type.IsInstantiated()) {
389 const Class& type_class = Class::ZoneHandle(type.type_class()); 389 const Class& type_class = Class::ZoneHandle(type.type_class());
390 // A Smi object cannot be the instance of a parameterized class. 390 // A Smi object cannot be the instance of a parameterized class.
391 // A class equality check is only applicable with a dst type of a 391 // A class equality check is only applicable with a dst type of a
392 // non-parameterized class or with a raw dst type of a parameterized class. 392 // non-parameterized class or with a raw dst type of a parameterized class.
393 if (type_class.HasTypeArguments()) { 393 if (type_class.HasTypeArguments()) {
394 return GenerateInstantiatedTypeWithArgumentsTest(cid, 394 return GenerateInstantiatedTypeWithArgumentsTest(cid,
395 token_index, 395 token_pos,
396 type, 396 type,
397 is_instance_lbl, 397 is_instance_lbl,
398 is_not_instance_lbl); 398 is_not_instance_lbl);
399 // Fall through to runtime call. 399 // Fall through to runtime call.
400 } else { 400 } else {
401 GenerateInstantiatedTypeNoArgumentsTest(cid, 401 GenerateInstantiatedTypeNoArgumentsTest(cid,
402 token_index, 402 token_pos,
403 type, 403 type,
404 is_instance_lbl, 404 is_instance_lbl,
405 is_not_instance_lbl); 405 is_not_instance_lbl);
406 // If test non-conclusive so far, try the inlined type-test cache. 406 // If test non-conclusive so far, try the inlined type-test cache.
407 // 'type' is known at compile time. 407 // 'type' is known at compile time.
408 return GenerateSubtype1TestCacheLookup( 408 return GenerateSubtype1TestCacheLookup(
409 cid, token_index, type_class, 409 cid, token_pos, type_class,
410 is_instance_lbl, is_not_instance_lbl); 410 is_instance_lbl, is_not_instance_lbl);
411 } 411 }
412 } else { 412 } else {
413 return GenerateUninstantiatedTypeTest(cid, 413 return GenerateUninstantiatedTypeTest(cid,
414 token_index, 414 token_pos,
415 type, 415 type,
416 is_instance_lbl, 416 is_instance_lbl,
417 is_not_instance_lbl); 417 is_not_instance_lbl);
418 } 418 }
419 return SubtypeTestCache::null(); 419 return SubtypeTestCache::null();
420 } 420 }
421 421
422 422
423 // Optimize assignable type check by adding inlined tests for: 423 // Optimize assignable type check by adding inlined tests for:
424 // - NULL -> return NULL. 424 // - NULL -> return NULL.
425 // - Smi -> compile time subtype check (only if dst class is not parameterized). 425 // - Smi -> compile time subtype check (only if dst class is not parameterized).
426 // - Class equality (only if class is not parameterized). 426 // - Class equality (only if class is not parameterized).
427 // Inputs: 427 // Inputs:
428 // - RAX: object. 428 // - RAX: object.
429 // - RDX: instantiator type arguments or raw_null. 429 // - RDX: instantiator type arguments or raw_null.
430 // - RCX: instantiator or raw_null. 430 // - RCX: instantiator or raw_null.
431 // Returns: 431 // Returns:
432 // - object in RAX for successful assignable check (or throws TypeError). 432 // - object in RAX for successful assignable check (or throws TypeError).
433 // Performance notes: positive checks must be quick, negative checks can be slow 433 // Performance notes: positive checks must be quick, negative checks can be slow
434 // as they throw an exception. 434 // as they throw an exception.
435 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t cid, 435 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t cid,
436 intptr_t token_index, 436 intptr_t token_pos,
437 intptr_t try_index, 437 intptr_t try_index,
438 const AbstractType& dst_type, 438 const AbstractType& dst_type,
439 const String& dst_name) { 439 const String& dst_name) {
440 ASSERT(FLAG_enable_type_checks); 440 ASSERT(FLAG_enable_type_checks);
441 ASSERT(token_index >= 0); 441 ASSERT(token_pos >= 0);
442 ASSERT(!dst_type.IsNull()); 442 ASSERT(!dst_type.IsNull());
443 ASSERT(dst_type.IsFinalized()); 443 ASSERT(dst_type.IsFinalized());
444 // Assignable check is skipped in FlowGraphBuilder, not here. 444 // Assignable check is skipped in FlowGraphBuilder, not here.
445 ASSERT(dst_type.IsMalformed() || 445 ASSERT(dst_type.IsMalformed() ||
446 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); 446 (!dst_type.IsDynamicType() && !dst_type.IsObjectType()));
447 ASSERT(!dst_type.IsVoidType()); 447 ASSERT(!dst_type.IsVoidType());
448 __ pushq(RCX); // Store instantiator. 448 __ pushq(RCX); // Store instantiator.
449 __ pushq(RDX); // Store instantiator type arguments. 449 __ pushq(RDX); // Store instantiator type arguments.
450 // A null object is always assignable and is returned as result. 450 // A null object is always assignable and is returned as result.
451 const Immediate raw_null = 451 const Immediate raw_null =
452 Immediate(reinterpret_cast<intptr_t>(Object::null())); 452 Immediate(reinterpret_cast<intptr_t>(Object::null()));
453 Label is_assignable, runtime_call; 453 Label is_assignable, runtime_call;
454 __ cmpq(RAX, raw_null); 454 __ cmpq(RAX, raw_null);
455 __ j(EQUAL, &is_assignable); 455 __ j(EQUAL, &is_assignable);
456 456
457 // Generate throw new TypeError() if the type is malformed. 457 // Generate throw new TypeError() if the type is malformed.
458 if (dst_type.IsMalformed()) { 458 if (dst_type.IsMalformed()) {
459 const Error& error = Error::Handle(dst_type.malformed_error()); 459 const Error& error = Error::Handle(dst_type.malformed_error());
460 const String& error_message = String::ZoneHandle( 460 const String& error_message = String::ZoneHandle(
461 String::NewSymbol(error.ToErrorCString())); 461 String::NewSymbol(error.ToErrorCString()));
462 __ PushObject(Object::ZoneHandle()); // Make room for the result. 462 __ PushObject(Object::ZoneHandle()); // Make room for the result.
463 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location. 463 __ pushq(Immediate(Smi::RawValue(token_pos))); // Source location.
464 __ pushq(RAX); // Push the source object. 464 __ pushq(RAX); // Push the source object.
465 __ PushObject(dst_name); // Push the name of the destination. 465 __ PushObject(dst_name); // Push the name of the destination.
466 __ PushObject(error_message); 466 __ PushObject(error_message);
467 GenerateCallRuntime(cid, 467 GenerateCallRuntime(cid,
468 token_index, 468 token_pos,
469 try_index, 469 try_index,
470 kMalformedTypeErrorRuntimeEntry); 470 kMalformedTypeErrorRuntimeEntry);
471 // We should never return here. 471 // We should never return here.
472 __ int3(); 472 __ int3();
473 473
474 __ Bind(&is_assignable); // For a null object. 474 __ Bind(&is_assignable); // For a null object.
475 return; 475 return;
476 } 476 }
477 477
478 // Generate inline type check, linking to runtime call if not assignable. 478 // Generate inline type check, linking to runtime call if not assignable.
479 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); 479 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
480 test_cache = GenerateInlineInstanceof(cid, token_index, dst_type, 480 test_cache = GenerateInlineInstanceof(cid, token_pos, dst_type,
481 &is_assignable, &runtime_call); 481 &is_assignable, &runtime_call);
482 __ Bind(&runtime_call); 482 __ Bind(&runtime_call);
483 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. 483 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments.
484 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. 484 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator.
485 __ PushObject(Object::ZoneHandle()); // Make room for the result. 485 __ PushObject(Object::ZoneHandle()); // Make room for the result.
486 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location. 486 __ pushq(Immediate(Smi::RawValue(token_pos))); // Source location.
487 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id. 487 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id.
488 __ pushq(RAX); // Push the source object. 488 __ pushq(RAX); // Push the source object.
489 __ PushObject(dst_type); // Push the type of the destination. 489 __ PushObject(dst_type); // Push the type of the destination.
490 __ pushq(RCX); // Instantiator. 490 __ pushq(RCX); // Instantiator.
491 __ pushq(RDX); // Instantiator type arguments. 491 __ pushq(RDX); // Instantiator type arguments.
492 __ PushObject(dst_name); // Push the name of the destination. 492 __ PushObject(dst_name); // Push the name of the destination.
493 __ LoadObject(RAX, test_cache); 493 __ LoadObject(RAX, test_cache);
494 __ pushq(RAX); 494 __ pushq(RAX);
495 GenerateCallRuntime(cid, 495 GenerateCallRuntime(cid,
496 token_index, 496 token_pos,
497 try_index, 497 try_index,
498 kTypeCheckRuntimeEntry); 498 kTypeCheckRuntimeEntry);
499 // Pop the parameters supplied to the runtime entry. The result of the 499 // Pop the parameters supplied to the runtime entry. The result of the
500 // type check runtime call is the checked value. 500 // type check runtime call is the checked value.
501 __ Drop(8); 501 __ Drop(8);
502 __ popq(RAX); 502 __ popq(RAX);
503 503
504 __ Bind(&is_assignable); 504 __ Bind(&is_assignable);
505 __ popq(RDX); // Remove pushed instantiator type arguments.. 505 __ popq(RDX); // Remove pushed instantiator type arguments..
506 __ popq(RCX); // Remove pushed instantiator. 506 __ popq(RCX); // Remove pushed instantiator.
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
553 // - Smi -> compile time subtype check (only if dst class is not parameterized). 553 // - Smi -> compile time subtype check (only if dst class is not parameterized).
554 // - Class equality (only if class is not parameterized). 554 // - Class equality (only if class is not parameterized).
555 // Inputs: 555 // Inputs:
556 // - RAX: object. 556 // - RAX: object.
557 // - RDX: instantiator type arguments or raw_null. 557 // - RDX: instantiator type arguments or raw_null.
558 // - RCX: instantiator or raw_null. 558 // - RCX: instantiator or raw_null.
559 // Destroys RCX and RDX. 559 // Destroys RCX and RDX.
560 // Returns: 560 // Returns:
561 // - true or false in RAX. 561 // - true or false in RAX.
562 void FlowGraphCompiler::GenerateInstanceOf(intptr_t cid, 562 void FlowGraphCompiler::GenerateInstanceOf(intptr_t cid,
563 intptr_t token_index, 563 intptr_t token_pos,
564 intptr_t try_index, 564 intptr_t try_index,
565 const AbstractType& type, 565 const AbstractType& type,
566 bool negate_result) { 566 bool negate_result) {
567 ASSERT(type.IsFinalized() && !type.IsMalformed()); 567 ASSERT(type.IsFinalized() && !type.IsMalformed());
568 568
569 const Immediate raw_null = 569 const Immediate raw_null =
570 Immediate(reinterpret_cast<intptr_t>(Object::null())); 570 Immediate(reinterpret_cast<intptr_t>(Object::null()));
571 Label is_instance, is_not_instance; 571 Label is_instance, is_not_instance;
572 __ pushq(RCX); // Store instantiator on stack. 572 __ pushq(RCX); // Store instantiator on stack.
573 __ pushq(RDX); // Store instantiator type arguments. 573 __ pushq(RDX); // Store instantiator type arguments.
574 // If type is instantiated and non-parameterized, we can inline code 574 // If type is instantiated and non-parameterized, we can inline code
575 // checking whether the tested instance is a Smi. 575 // checking whether the tested instance is a Smi.
576 if (type.IsInstantiated()) { 576 if (type.IsInstantiated()) {
577 // A null object is only an instance of Object and Dynamic, which has 577 // A null object is only an instance of Object and Dynamic, which has
578 // already been checked above (if the type is instantiated). So we can 578 // already been checked above (if the type is instantiated). So we can
579 // return false here if the instance is null (and if the type is 579 // return false here if the instance is null (and if the type is
580 // instantiated). 580 // instantiated).
581 // We can only inline this null check if the type is instantiated at compile 581 // We can only inline this null check if the type is instantiated at compile
582 // time, since an uninstantiated type at compile time could be Object or 582 // time, since an uninstantiated type at compile time could be Object or
583 // Dynamic at run time. 583 // Dynamic at run time.
584 __ cmpq(RAX, raw_null); 584 __ cmpq(RAX, raw_null);
585 __ j(EQUAL, &is_not_instance); 585 __ j(EQUAL, &is_not_instance);
586 } 586 }
587 587
588 // Generate inline instanceof test. 588 // Generate inline instanceof test.
589 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); 589 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
590 test_cache = GenerateInlineInstanceof(cid, token_index, type, 590 test_cache = GenerateInlineInstanceof(cid, token_pos, type,
591 &is_instance, &is_not_instance); 591 &is_instance, &is_not_instance);
592 592
593 // Generate runtime call. 593 // Generate runtime call.
594 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. 594 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments.
595 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. 595 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator.
596 __ PushObject(Object::ZoneHandle()); // Make room for the result. 596 __ PushObject(Object::ZoneHandle()); // Make room for the result.
597 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location. 597 __ pushq(Immediate(Smi::RawValue(token_pos))); // Source location.
598 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id. 598 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id.
599 __ pushq(RAX); // Push the instance. 599 __ pushq(RAX); // Push the instance.
600 __ PushObject(type); // Push the type. 600 __ PushObject(type); // Push the type.
601 __ pushq(RCX); // TODO(srdjan): Pass instantiator instead of null. 601 __ pushq(RCX); // TODO(srdjan): Pass instantiator instead of null.
602 __ pushq(RDX); // Instantiator type arguments. 602 __ pushq(RDX); // Instantiator type arguments.
603 __ LoadObject(RAX, test_cache); 603 __ LoadObject(RAX, test_cache);
604 __ pushq(RAX); 604 __ pushq(RAX);
605 GenerateCallRuntime(cid, token_index, try_index, kInstanceofRuntimeEntry); 605 GenerateCallRuntime(cid, token_pos, try_index, kInstanceofRuntimeEntry);
606 // Pop the two parameters supplied to the runtime entry. The result of the 606 // Pop the two parameters supplied to the runtime entry. The result of the
607 // instanceof runtime call will be left as the result of the operation. 607 // instanceof runtime call will be left as the result of the operation.
608 __ Drop(7); 608 __ Drop(7);
609 Label done; 609 Label done;
610 if (negate_result) { 610 if (negate_result) {
611 __ popq(RDX); 611 __ popq(RDX);
612 __ LoadObject(RAX, bool_true()); 612 __ LoadObject(RAX, bool_true());
613 __ cmpq(RDX, RAX); 613 __ cmpq(RDX, RAX);
614 __ j(NOT_EQUAL, &done, Assembler::kNearJump); 614 __ j(NOT_EQUAL, &done, Assembler::kNearJump);
615 __ LoadObject(RAX, bool_false()); 615 __ LoadObject(RAX, bool_false());
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after
935 #endif 935 #endif
936 if (check_arguments) { 936 if (check_arguments) {
937 // Check that num_fixed <= argc <= num_params. 937 // Check that num_fixed <= argc <= num_params.
938 Label argc_in_range; 938 Label argc_in_range;
939 // Total number of args is the first Smi in args descriptor array (R10). 939 // Total number of args is the first Smi in args descriptor array (R10).
940 __ movq(RAX, FieldAddress(R10, Array::data_offset())); 940 __ movq(RAX, FieldAddress(R10, Array::data_offset()));
941 __ cmpq(RAX, Immediate(Smi::RawValue(parameter_count))); 941 __ cmpq(RAX, Immediate(Smi::RawValue(parameter_count)));
942 __ j(EQUAL, &argc_in_range, Assembler::kNearJump); 942 __ j(EQUAL, &argc_in_range, Assembler::kNearJump);
943 if (function.IsClosureFunction()) { 943 if (function.IsClosureFunction()) {
944 GenerateCallRuntime(AstNode::kNoId, 944 GenerateCallRuntime(AstNode::kNoId,
945 function.token_index(), 945 function.token_pos(),
946 CatchClauseNode::kInvalidTryIndex, 946 CatchClauseNode::kInvalidTryIndex,
947 kClosureArgumentMismatchRuntimeEntry); 947 kClosureArgumentMismatchRuntimeEntry);
948 } else { 948 } else {
949 __ Stop("Wrong number of arguments"); 949 __ Stop("Wrong number of arguments");
950 } 950 }
951 __ Bind(&argc_in_range); 951 __ Bind(&argc_in_range);
952 } 952 }
953 } else { 953 } else {
954 CopyParameters(); 954 CopyParameters();
955 } 955 }
956 956
957 // Initialize locals to null. 957 // Initialize locals to null.
958 if (local_count > 0) { 958 if (local_count > 0) {
959 __ movq(RAX, Immediate(reinterpret_cast<intptr_t>(Object::null()))); 959 __ movq(RAX, Immediate(reinterpret_cast<intptr_t>(Object::null())));
960 const int base = parsed_function().first_stack_local_index(); 960 const int base = parsed_function().first_stack_local_index();
961 for (int i = 0; i < local_count; ++i) { 961 for (int i = 0; i < local_count; ++i) {
962 // Subtract index i (locals lie at lower addresses than RBP). 962 // Subtract index i (locals lie at lower addresses than RBP).
963 __ movq(Address(RBP, (base - i) * kWordSize), RAX); 963 __ movq(Address(RBP, (base - i) * kWordSize), RAX);
964 } 964 }
965 } 965 }
966 966
967 // Generate stack overflow check. 967 // Generate stack overflow check.
968 __ movq(RDI, Immediate(Isolate::Current()->stack_limit_address())); 968 __ movq(RDI, Immediate(Isolate::Current()->stack_limit_address()));
969 __ cmpq(RSP, Address(RDI, 0)); 969 __ cmpq(RSP, Address(RDI, 0));
970 Label no_stack_overflow; 970 Label no_stack_overflow;
971 __ j(ABOVE, &no_stack_overflow, Assembler::kNearJump); 971 __ j(ABOVE, &no_stack_overflow, Assembler::kNearJump);
972 GenerateCallRuntime(AstNode::kNoId, 972 GenerateCallRuntime(AstNode::kNoId,
973 function.token_index(), 973 function.token_pos(),
974 CatchClauseNode::kInvalidTryIndex, 974 CatchClauseNode::kInvalidTryIndex,
975 kStackOverflowRuntimeEntry); 975 kStackOverflowRuntimeEntry);
976 __ Bind(&no_stack_overflow); 976 __ Bind(&no_stack_overflow);
977 977
978 if (FLAG_print_scopes) { 978 if (FLAG_print_scopes) {
979 // Print the function scope (again) after generating the prologue in order 979 // Print the function scope (again) after generating the prologue in order
980 // to see annotations such as allocation indices of locals. 980 // to see annotations such as allocation indices of locals.
981 if (FLAG_print_ast) { 981 if (FLAG_print_ast) {
982 // Second printing. 982 // Second printing.
983 OS::Print("Annotated "); 983 OS::Print("Annotated ");
(...skipping 10 matching lines...) Expand all
994 pc_descriptors_list()->AddDescriptor(PcDescriptors::kPatchCode, 994 pc_descriptors_list()->AddDescriptor(PcDescriptors::kPatchCode,
995 assembler()->CodeSize(), 995 assembler()->CodeSize(),
996 AstNode::kNoId, 996 AstNode::kNoId,
997 0, 997 0,
998 -1); 998 -1);
999 __ jmp(&StubCode::FixCallersTargetLabel()); 999 __ jmp(&StubCode::FixCallersTargetLabel());
1000 } 1000 }
1001 1001
1002 1002
1003 // Infrastructure copied from class CodeGenerator. 1003 // Infrastructure copied from class CodeGenerator.
1004 void FlowGraphCompiler::GenerateCall(intptr_t token_index, 1004 void FlowGraphCompiler::GenerateCall(intptr_t token_pos,
1005 intptr_t try_index, 1005 intptr_t try_index,
1006 const ExternalLabel* label, 1006 const ExternalLabel* label,
1007 PcDescriptors::Kind kind) { 1007 PcDescriptors::Kind kind) {
1008 ASSERT(frame_register_allocator()->IsSpilled()); 1008 ASSERT(frame_register_allocator()->IsSpilled());
1009 __ call(label); 1009 __ call(label);
1010 AddCurrentDescriptor(kind, AstNode::kNoId, token_index, try_index); 1010 AddCurrentDescriptor(kind, AstNode::kNoId, token_pos, try_index);
1011 } 1011 }
1012 1012
1013 1013
1014 void FlowGraphCompiler::GenerateCallRuntime(intptr_t cid, 1014 void FlowGraphCompiler::GenerateCallRuntime(intptr_t cid,
1015 intptr_t token_index, 1015 intptr_t token_pos,
1016 intptr_t try_index, 1016 intptr_t try_index,
1017 const RuntimeEntry& entry) { 1017 const RuntimeEntry& entry) {
1018 ASSERT(frame_register_allocator()->IsSpilled()); 1018 ASSERT(frame_register_allocator()->IsSpilled());
1019 __ CallRuntime(entry); 1019 __ CallRuntime(entry);
1020 AddCurrentDescriptor(PcDescriptors::kOther, cid, token_index, try_index); 1020 AddCurrentDescriptor(PcDescriptors::kOther, cid, token_pos, try_index);
1021 } 1021 }
1022 1022
1023 1023
1024 // Checks class id of instance against all 'class_ids'. Jump to 'deopt' label 1024 // Checks class id of instance against all 'class_ids'. Jump to 'deopt' label
1025 // if no match or instance is Smi. 1025 // if no match or instance is Smi.
1026 void FlowGraphCompiler::EmitClassChecksNoSmi(const ICData& ic_data, 1026 void FlowGraphCompiler::EmitClassChecksNoSmi(const ICData& ic_data,
1027 Register instance_reg, 1027 Register instance_reg,
1028 Register temp_reg, 1028 Register temp_reg,
1029 Label* deopt) { 1029 Label* deopt) {
1030 Label ok; 1030 Label ok;
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1068 __ cvtsi2sd(result, temp); 1068 __ cvtsi2sd(result, temp);
1069 __ Bind(&done); 1069 __ Bind(&done);
1070 } 1070 }
1071 1071
1072 1072
1073 #undef __ 1073 #undef __
1074 1074
1075 } // namespace dart 1075 } // namespace dart
1076 1076
1077 #endif // defined TARGET_ARCH_X64 1077 #endif // defined TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « vm/flow_graph_compiler_x64.h ('k') | vm/intermediate_language.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698