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

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

Issue 10407018: Start porting fast typechecks to x64. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 7 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/il_printer.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 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 101
102 // Inputs: 102 // Inputs:
103 // - RAX: object (preserved). 103 // - RAX: object (preserved).
104 // - RDX: optional instantiator type arguments (preserved). 104 // - RDX: optional instantiator type arguments (preserved).
105 // Destroys RCX. 105 // Destroys RCX.
106 // Returns: 106 // Returns:
107 // - unchanged object in RAX and optional instantiator type arguments in RDX. 107 // - unchanged object in RAX and optional instantiator type arguments in RDX.
108 // Note that this inlined code must be followed by the runtime_call code, as it 108 // Note that this inlined code must be followed by the runtime_call code, as it
109 // may fall through to it. Otherwise, this inline code will jump to the label 109 // may fall through to it. Otherwise, this inline code will jump to the label
110 // is_instance or to the label is_not_instance. 110 // is_instance or to the label is_not_instance.
111 void FlowGraphCompiler::GenerateInlineInstanceof(const AbstractType& type, 111 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof(
112 Label* is_instance, 112 intptr_t cid,
113 Label* is_not_instance) { 113 intptr_t token_index,
114 const AbstractType& type,
115 Label* is_instance,
116 Label* is_not_instance) {
114 Label runtime_call; 117 Label runtime_call;
115 if (type.IsInstantiated()) { 118 if (type.IsInstantiated()) {
116 const Class& type_class = Class::ZoneHandle(type.type_class()); 119 const Class& type_class = Class::ZoneHandle(type.type_class());
117 const bool requires_type_arguments = type_class.HasTypeArguments(); 120 const bool requires_type_arguments = type_class.HasTypeArguments();
118 // A Smi object cannot be the instance of a parameterized class. 121 // A Smi object cannot be the instance of a parameterized class.
119 // A class equality check is only applicable with a dst type of a 122 // A class equality check is only applicable with a dst type of a
120 // non-parameterized class or with a raw dst type of a parameterized class. 123 // non-parameterized class or with a raw dst type of a parameterized class.
121 if (requires_type_arguments) { 124 if (requires_type_arguments) {
122 const AbstractTypeArguments& type_arguments = 125 const AbstractTypeArguments& type_arguments =
123 AbstractTypeArguments::Handle(type.arguments()); 126 AbstractTypeArguments::Handle(type.arguments());
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
264 __ movq(RCX, FieldAddress(RCX, Type::type_class_offset())); 267 __ movq(RCX, FieldAddress(RCX, Type::type_class_offset()));
265 __ movq(R10, FieldAddress(RCX, Class::type_parameters_offset())); 268 __ movq(R10, FieldAddress(RCX, Class::type_parameters_offset()));
266 // Check that class of type has no type parameters. 269 // Check that class of type has no type parameters.
267 __ cmpq(R10, raw_null); 270 __ cmpq(R10, raw_null);
268 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump); 271 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump);
269 // TODO(srdjan): Implement subtype test cache. 272 // TODO(srdjan): Implement subtype test cache.
270 // Fall through to runtime call. 273 // Fall through to runtime call.
271 } 274 }
272 } 275 }
273 __ Bind(&runtime_call); 276 __ Bind(&runtime_call);
277 return SubtypeTestCache::null();
274 } 278 }
275 279
276 280
277 // Optimize assignable type check by adding inlined tests for: 281 // Optimize assignable type check by adding inlined tests for:
278 // - NULL -> return NULL. 282 // - NULL -> return NULL.
279 // - Smi -> compile time subtype check (only if dst class is not parameterized). 283 // - Smi -> compile time subtype check (only if dst class is not parameterized).
280 // - Class equality (only if class is not parameterized). 284 // - Class equality (only if class is not parameterized).
281 // Inputs: 285 // Inputs:
282 // - RAX: object. 286 // - RAX: object.
283 // - RDX: optional instantiator type arguments. 287 // - RDX: instantiator type arguments or raw_null.
288 // - RCX: instantiator or raw_null.
284 // Destroys RCX and RDX. 289 // Destroys RCX and RDX.
285 // Returns: 290 // Returns:
286 // - object in RAX for successful assignable check (or throws TypeError). 291 // - object in RAX for successful assignable check (or throws TypeError).
287 // Performance notes: positive checks must be quick, negative checks can be slow 292 // Performance notes: positive checks must be quick, negative checks can be slow
288 // as they throw an exception. 293 // as they throw an exception.
289 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t cid, 294 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t cid,
290 intptr_t token_index, 295 intptr_t token_index,
291 intptr_t try_index, 296 intptr_t try_index,
292 const AbstractType& dst_type, 297 const AbstractType& dst_type,
293 const String& dst_name) { 298 const String& dst_name) {
294 ASSERT(FLAG_enable_type_checks); 299 ASSERT(FLAG_enable_type_checks);
295 ASSERT(token_index >= 0); 300 ASSERT(token_index >= 0);
296 ASSERT(!dst_type.IsNull()); 301 ASSERT(!dst_type.IsNull());
297 ASSERT(dst_type.IsFinalized()); 302 ASSERT(dst_type.IsFinalized());
303 // Assignable check is skipped in FlowGraphBuilder, not here.
298 ASSERT(dst_type.IsMalformed() || 304 ASSERT(dst_type.IsMalformed() ||
299 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); 305 (!dst_type.IsDynamicType() && !dst_type.IsObjectType()));
300 ASSERT(!dst_type.IsVoidType()); 306 ASSERT(!dst_type.IsVoidType());
301 307 __ pushq(RCX); // Temporary store instantiator on stack.
302 // A null object is always assignable and is returned as result. 308 // A null object is always assignable and is returned as result.
303 const Immediate raw_null = 309 const Immediate raw_null =
304 Immediate(reinterpret_cast<intptr_t>(Object::null())); 310 Immediate(reinterpret_cast<intptr_t>(Object::null()));
305 Label is_assignable, runtime_call; 311 Label is_assignable, runtime_call;
306 __ cmpq(RAX, raw_null); 312 __ cmpq(RAX, raw_null);
307 __ j(EQUAL, &is_assignable); 313 __ j(EQUAL, &is_assignable);
308 314
309 // Generate throw new TypeError() if the type is malformed. 315 // Generate throw new TypeError() if the type is malformed.
310 if (dst_type.IsMalformed()) { 316 if (dst_type.IsMalformed()) {
311 const Error& error = Error::Handle(dst_type.malformed_error()); 317 const Error& error = Error::Handle(dst_type.malformed_error());
312 const String& error_message = String::ZoneHandle( 318 const String& error_message = String::ZoneHandle(
313 String::NewSymbol(error.ToErrorCString())); 319 String::NewSymbol(error.ToErrorCString()));
314 __ PushObject(Object::ZoneHandle()); // Make room for the result. 320 __ PushObject(Object::ZoneHandle()); // Make room for the result.
315 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location. 321 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location.
316 __ pushq(RAX); // Push the source object. 322 __ pushq(RAX); // Push the source object.
317 __ PushObject(dst_name); // Push the name of the destination. 323 __ PushObject(dst_name); // Push the name of the destination.
318 __ PushObject(error_message); 324 __ PushObject(error_message);
319 GenerateCallRuntime(cid, 325 GenerateCallRuntime(cid,
320 token_index, 326 token_index,
321 try_index, 327 try_index,
322 kMalformedTypeErrorRuntimeEntry); 328 kMalformedTypeErrorRuntimeEntry);
323 // We should never return here. 329 // We should never return here.
324 __ int3(); 330 __ int3();
325 331
326 __ Bind(&is_assignable); // For a null object. 332 __ Bind(&is_assignable); // For a null object.
327 return; 333 return;
328 } 334 }
329 335
330 // Generate inline type check, linking to runtime call if not assignable. 336 // Generate inline type check, linking to runtime call if not assignable.
331 GenerateInlineInstanceof(dst_type, &is_assignable, &runtime_call); 337 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
332 338 test_cache = GenerateInlineInstanceof(cid, token_index, dst_type,
339 &is_assignable, &runtime_call);
333 __ Bind(&runtime_call); 340 __ Bind(&runtime_call);
341 __ movq(RCX, Address(RSP, 0)); // Get instantiator.
334 __ PushObject(Object::ZoneHandle()); // Make room for the result. 342 __ PushObject(Object::ZoneHandle()); // Make room for the result.
335 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location. 343 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location.
336 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id. 344 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id.
337 __ pushq(RAX); // Push the source object. 345 __ pushq(RAX); // Push the source object.
338 __ PushObject(dst_type); // Push the type of the destination. 346 __ PushObject(dst_type); // Push the type of the destination.
339 __ pushq(raw_null); // TODO(srdjan): Instantiator. 347 __ pushq(RCX); // Instantiator.
340 if (dst_type.IsInstantiated()) { 348 __ pushq(RDX); // Instantiator type arguments.
341 __ pushq(raw_null); // Null instantiator type arguments.
342 } else {
343 __ pushq(RDX); // Instantiator type arguments.
344 }
345 __ PushObject(dst_name); // Push the name of the destination. 349 __ PushObject(dst_name); // Push the name of the destination.
346 __ pushq(raw_null); // SubtypeTestCache not yet supported. 350 __ LoadObject(RAX, test_cache);
351 __ pushq(RAX);
347 GenerateCallRuntime(cid, 352 GenerateCallRuntime(cid,
348 token_index, 353 token_index,
349 try_index, 354 try_index,
350 kTypeCheckRuntimeEntry); 355 kTypeCheckRuntimeEntry);
351 // Pop the parameters supplied to the runtime entry. The result of the 356 // Pop the parameters supplied to the runtime entry. The result of the
352 // type check runtime call is the checked value. 357 // type check runtime call is the checked value.
353 __ Drop(8); 358 __ Drop(8);
354 __ popq(RAX); 359 __ popq(RAX);
355 360
356 __ Bind(&is_assignable); 361 __ Bind(&is_assignable);
362 __ popq(RCX); // Remove pushed instantiator.
357 } 363 }
358 364
359 365
360 void FlowGraphCompiler::LoadValue(Register dst, Value* value) { 366 void FlowGraphCompiler::LoadValue(Register dst, Value* value) {
361 if (value->IsConstant()) { 367 if (value->IsConstant()) {
362 ConstantVal* constant = value->AsConstant(); 368 ConstantVal* constant = value->AsConstant();
363 if (constant->value().IsSmi()) { 369 if (constant->value().IsSmi()) {
364 int64_t imm = reinterpret_cast<int64_t>(constant->value().raw()); 370 int64_t imm = reinterpret_cast<int64_t>(constant->value().raw());
365 __ movq(dst, Immediate(imm)); 371 __ movq(dst, Immediate(imm));
366 } else { 372 } else {
(...skipping 10 matching lines...) Expand all
377 LoadValue(RAX, val); 383 LoadValue(RAX, val);
378 } 384 }
379 385
380 386
381 void FlowGraphCompiler::VisitConstant(ConstantVal* val) { 387 void FlowGraphCompiler::VisitConstant(ConstantVal* val) {
382 LoadValue(RAX, val); 388 LoadValue(RAX, val);
383 } 389 }
384 390
385 391
386 void FlowGraphCompiler::VisitAssertAssignable(AssertAssignableComp* comp) { 392 void FlowGraphCompiler::VisitAssertAssignable(AssertAssignableComp* comp) {
387 if (comp->instantiator_type_arguments() != NULL) { 393 const Immediate raw_null =
388 __ popq(RDX); 394 Immediate(reinterpret_cast<intptr_t>(Object::null()));
395 if (comp->instantiator_type_arguments() == NULL) {
396 __ movq(RDX, raw_null);
397 } else {
398 LoadValue(RDX, comp->instantiator_type_arguments());
399 }
400 if (comp->instantiator() == NULL) {
401 __ movq(RCX, raw_null);
402 } else {
403 LoadValue(RCX, comp->instantiator());
389 } 404 }
390 LoadValue(RAX, comp->value()); 405 LoadValue(RAX, comp->value());
391 GenerateAssertAssignable(comp->cid(), 406 GenerateAssertAssignable(comp->cid(),
392 comp->token_index(), 407 comp->token_index(),
393 comp->try_index(), 408 comp->try_index(),
394 comp->dst_type(), 409 comp->dst_type(),
395 comp->dst_name()); 410 comp->dst_name());
396 } 411 }
397 412
398 413
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after
749 __ Bind(&done); 764 __ Bind(&done);
750 } 765 }
751 766
752 767
753 // Optimize instanceof type test by adding inlined tests for: 768 // Optimize instanceof type test by adding inlined tests for:
754 // - NULL -> return false. 769 // - NULL -> return false.
755 // - Smi -> compile time subtype check (only if dst class is not parameterized). 770 // - Smi -> compile time subtype check (only if dst class is not parameterized).
756 // - Class equality (only if class is not parameterized). 771 // - Class equality (only if class is not parameterized).
757 // Inputs: 772 // Inputs:
758 // - RAX: object. 773 // - RAX: object.
759 // - RDX: optional instantiator type arguments. 774 // - RDX: oinstantiator type arguments or raw_null.
775 // - RCX: instantiator or raw_null.
760 // Destroys RCX and RDX. 776 // Destroys RCX and RDX.
761 // Returns: 777 // Returns:
762 // - true or false in RAX. 778 // - true or false in RAX.
763 void FlowGraphCompiler::GenerateInstanceOf(intptr_t cid, 779 void FlowGraphCompiler::GenerateInstanceOf(intptr_t cid,
764 intptr_t token_index, 780 intptr_t token_index,
765 intptr_t try_index, 781 intptr_t try_index,
766 const AbstractType& type, 782 const AbstractType& type,
767 bool negate_result) { 783 bool negate_result) {
768 ASSERT(type.IsFinalized() && !type.IsMalformed()); 784 ASSERT(type.IsFinalized() && !type.IsMalformed());
769 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); 785 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
770 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); 786 const Bool& bool_false = Bool::ZoneHandle(Bool::False());
771 787
772 const Immediate raw_null = 788 const Immediate raw_null =
773 Immediate(reinterpret_cast<intptr_t>(Object::null())); 789 Immediate(reinterpret_cast<intptr_t>(Object::null()));
774 Label is_instance, is_not_instance; 790 Label is_instance, is_not_instance;
791 __ pushq(RCX); // Temporary store instantiator on stack.
775 // If type is instantiated and non-parameterized, we can inline code 792 // If type is instantiated and non-parameterized, we can inline code
776 // checking whether the tested instance is a Smi. 793 // checking whether the tested instance is a Smi.
777 if (type.IsInstantiated()) { 794 if (type.IsInstantiated()) {
778 // A null object is only an instance of Object and Dynamic, which has 795 // A null object is only an instance of Object and Dynamic, which has
779 // already been checked above (if the type is instantiated). So we can 796 // already been checked above (if the type is instantiated). So we can
780 // return false here if the instance is null (and if the type is 797 // return false here if the instance is null (and if the type is
781 // instantiated). 798 // instantiated).
782 // We can only inline this null check if the type is instantiated at compile 799 // We can only inline this null check if the type is instantiated at compile
783 // time, since an uninstantiated type at compile time could be Object or 800 // time, since an uninstantiated type at compile time could be Object or
784 // Dynamic at run time. 801 // Dynamic at run time.
785 __ cmpq(RAX, raw_null); 802 __ cmpq(RAX, raw_null);
786 __ j(EQUAL, &is_not_instance); 803 __ j(EQUAL, &is_not_instance);
787 } 804 }
788 805
789 // Generate inline instanceof test. 806 // Generate inline instanceof test.
790 GenerateInlineInstanceof(type, &is_instance, &is_not_instance); 807 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
808 test_cache = GenerateInlineInstanceof(cid, token_index, type,
809 &is_instance, &is_not_instance);
791 810
792 // Generate runtime call. 811 // Generate runtime call.
793 __ PushObject(Object::ZoneHandle()); // Make room for the result. 812 __ PushObject(Object::ZoneHandle()); // Make room for the result.
794 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location. 813 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location.
795 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id. 814 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id.
796 __ pushq(RAX); // Push the instance. 815 __ pushq(RAX); // Push the instance.
797 __ PushObject(type); // Push the type. 816 __ PushObject(type); // Push the type.
798 __ pushq(raw_null); // TODO(srdjan): Pass instantiator instead of null. 817 __ pushq(raw_null); // TODO(srdjan): Pass instantiator instead of null.
799 if (type.IsInstantiated()) { 818 if (type.IsInstantiated()) {
800 __ pushq(raw_null); // Null instantiator type arguments. 819 __ pushq(raw_null); // Null instantiator type arguments.
(...skipping 17 matching lines...) Expand all
818 } 837 }
819 __ jmp(&done, Assembler::kNearJump); 838 __ jmp(&done, Assembler::kNearJump);
820 839
821 __ Bind(&is_not_instance); 840 __ Bind(&is_not_instance);
822 __ LoadObject(RAX, negate_result ? bool_true : bool_false); 841 __ LoadObject(RAX, negate_result ? bool_true : bool_false);
823 __ jmp(&done, Assembler::kNearJump); 842 __ jmp(&done, Assembler::kNearJump);
824 843
825 __ Bind(&is_instance); 844 __ Bind(&is_instance);
826 __ LoadObject(RAX, negate_result ? bool_false : bool_true); 845 __ LoadObject(RAX, negate_result ? bool_false : bool_true);
827 __ Bind(&done); 846 __ Bind(&done);
847 __ popq(RCX); // Remove pushed instantiator.
828 } 848 }
829 849
830 850
831 void FlowGraphCompiler::VisitInstanceOf(InstanceOfComp* comp) { 851 void FlowGraphCompiler::VisitInstanceOf(InstanceOfComp* comp) {
832 if (comp->type_arguments() != NULL) { 852 const Immediate raw_null =
833 __ popq(RDX); 853 Immediate(reinterpret_cast<intptr_t>(Object::null()));
854 if (comp->type_arguments() == NULL) {
855 __ movq(RDX, raw_null);
856 } else {
857 LoadValue(RDX, comp->type_arguments());
858 }
859 if (comp->instantiator() == NULL) {
860 __ movq(RCX, raw_null);
861 } else {
862 LoadValue(RCX, comp->instantiator());
834 } 863 }
835 LoadValue(RAX, comp->value()); 864 LoadValue(RAX, comp->value());
836 GenerateInstanceOf(comp->cid(), 865 GenerateInstanceOf(comp->cid(),
837 comp->token_index(), 866 comp->token_index(),
838 comp->try_index(), 867 comp->try_index(),
839 comp->type(), 868 comp->type(),
840 comp->negate_result()); 869 comp->negate_result());
841 } 870 }
842 871
843 872
(...skipping 870 matching lines...) Expand 10 before | Expand all | Expand 10 after
1714 1743
1715 1744
1716 void FlowGraphCompiler::FinalizeComments(const Code& code) { 1745 void FlowGraphCompiler::FinalizeComments(const Code& code) {
1717 code.set_comments(assembler_->GetCodeComments()); 1746 code.set_comments(assembler_->GetCodeComments());
1718 } 1747 }
1719 1748
1720 1749
1721 } // namespace dart 1750 } // namespace dart
1722 1751
1723 #endif // defined TARGET_ARCH_X64 1752 #endif // defined TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_compiler_x64.h ('k') | runtime/vm/il_printer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698