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

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

Powered by Google App Engine
This is Rietveld 408576698