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

Side by Side Diff: vm/code_generator_ia32.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/class_finalizer.cc ('k') | vm/compiler.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_IA32. 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32.
6 #if defined(TARGET_ARCH_IA32) 6 #if defined(TARGET_ARCH_IA32)
7 7
8 #include "vm/code_generator.h" 8 #include "vm/code_generator.h"
9 9
10 #include "lib/error.h" 10 #include "lib/error.h"
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after
316 __ pushl(FieldAddress(base, Context::variable_offset(variable.index()))); 316 __ pushl(FieldAddress(base, Context::variable_offset(variable.index())));
317 } else { 317 } else {
318 // The variable lives in the current stack frame. 318 // The variable lives in the current stack frame.
319 __ pushl(Address(EBP, variable.index() * kWordSize)); 319 __ pushl(Address(EBP, variable.index() * kWordSize));
320 } 320 }
321 } 321 }
322 322
323 323
324 void CodeGenerator::GenerateInstanceCall( 324 void CodeGenerator::GenerateInstanceCall(
325 intptr_t node_id, 325 intptr_t node_id,
326 intptr_t token_index, 326 intptr_t token_pos,
327 const String& function_name, 327 const String& function_name,
328 int num_arguments, 328 int num_arguments,
329 const Array& optional_arguments_names, 329 const Array& optional_arguments_names,
330 intptr_t num_args_checked) { 330 intptr_t num_args_checked) {
331 if (FLAG_print_ic_in_optimized && IsOptimizing()) { 331 if (FLAG_print_ic_in_optimized && IsOptimizing()) {
332 OS::Print("Generate IC in optimized code: id %d name: '%s'\n", 332 OS::Print("Generate IC in optimized code: id %d name: '%s'\n",
333 node_id, function_name.ToCString()); 333 node_id, function_name.ToCString());
334 } 334 }
335 ASSERT(num_args_checked > 0); // At least receiver check is necessary. 335 ASSERT(num_args_checked > 0); // At least receiver check is necessary.
336 // Set up the function name and number of arguments (including the receiver) 336 // Set up the function name and number of arguments (including the receiver)
(...skipping 16 matching lines...) Expand all
353 label_address = StubCode::TwoArgsCheckInlineCacheEntryPoint(); 353 label_address = StubCode::TwoArgsCheckInlineCacheEntryPoint();
354 break; 354 break;
355 default: 355 default:
356 UNIMPLEMENTED(); 356 UNIMPLEMENTED();
357 } 357 }
358 ExternalLabel target_label("InlineCache", label_address); 358 ExternalLabel target_label("InlineCache", label_address);
359 359
360 __ call(&target_label); 360 __ call(&target_label);
361 AddCurrentDescriptor(PcDescriptors::kIcCall, 361 AddCurrentDescriptor(PcDescriptors::kIcCall,
362 node_id, 362 node_id,
363 token_index); 363 token_pos);
364 __ addl(ESP, Immediate(num_arguments * kWordSize)); 364 __ addl(ESP, Immediate(num_arguments * kWordSize));
365 } 365 }
366 366
367 367
368 // Input parameters: 368 // Input parameters:
369 // ESP : points to return address. 369 // ESP : points to return address.
370 // ESP + 4 : address of last argument (arg n-1). 370 // ESP + 4 : address of last argument (arg n-1).
371 // ESP + 4*n : address of first argument (arg 0). 371 // ESP + 4*n : address of first argument (arg 0).
372 // EDX : arguments descriptor array. 372 // EDX : arguments descriptor array.
373 void CodeGenerator::GenerateEntryCode() { 373 void CodeGenerator::GenerateEntryCode() {
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after
700 __ popl(EAX); // Remove argument. 700 __ popl(EAX); // Remove argument.
701 __ popl(EAX); // Restore result. 701 __ popl(EAX); // Restore result.
702 } 702 }
703 __ LeaveFrame(); 703 __ LeaveFrame();
704 __ ret(); 704 __ ret();
705 // Add a NOP to make return code pattern 5 bytes long for patching 705 // Add a NOP to make return code pattern 5 bytes long for patching
706 // in breakpoints during debugging. 706 // in breakpoints during debugging.
707 __ nop(1); 707 __ nop(1);
708 AddCurrentDescriptor(PcDescriptors::kReturn, 708 AddCurrentDescriptor(PcDescriptors::kReturn,
709 node->id(), 709 node->id(),
710 node->token_index()); 710 node->token_pos());
711 711
712 #ifdef DEBUG 712 #ifdef DEBUG
713 __ Bind(&wrong_stack); 713 __ Bind(&wrong_stack);
714 __ Stop("Exit stack size does not match the entry stack size."); 714 __ Stop("Exit stack size does not match the entry stack size.");
715 #endif // DEBUG. 715 #endif // DEBUG.
716 } 716 }
717 717
718 718
719 void CodeGenerator::VisitReturnNode(ReturnNode* node) { 719 void CodeGenerator::VisitReturnNode(ReturnNode* node) {
720 ASSERT(!IsResultNeeded(node)); 720 ASSERT(!IsResultNeeded(node));
(...skipping 28 matching lines...) Expand all
749 const RawFunction::Kind kind = parsed_function().function().kind(); 749 const RawFunction::Kind kind = parsed_function().function().kind();
750 const bool is_implicit_getter = 750 const bool is_implicit_getter =
751 (kind == RawFunction::kImplicitGetter) || 751 (kind == RawFunction::kImplicitGetter) ||
752 (kind == RawFunction::kConstImplicitGetter); 752 (kind == RawFunction::kConstImplicitGetter);
753 const bool is_static = parsed_function().function().is_static(); 753 const bool is_static = parsed_function().function().is_static();
754 // Implicit getters do not need a type check at return, unless they compute 754 // Implicit getters do not need a type check at return, unless they compute
755 // the initial value of a static field. 755 // the initial value of a static field.
756 if (is_static || !is_implicit_getter) { 756 if (is_static || !is_implicit_getter) {
757 GenerateAssertAssignable( 757 GenerateAssertAssignable(
758 node->id(), 758 node->id(),
759 node->value()->token_index(), 759 node->value()->token_pos(),
760 node->value(), 760 node->value(),
761 AbstractType::ZoneHandle(parsed_function().function().result_type()), 761 AbstractType::ZoneHandle(parsed_function().function().result_type()),
762 String::ZoneHandle(String::NewSymbol("function result"))); 762 String::ZoneHandle(String::NewSymbol("function result")));
763 } 763 }
764 } 764 }
765 GenerateReturnEpilog(node); 765 GenerateReturnEpilog(node);
766 } 766 }
767 767
768 768
769 void CodeGenerator::VisitLiteralNode(LiteralNode* node) { 769 void CodeGenerator::VisitLiteralNode(LiteralNode* node) {
770 if (!IsResultNeeded(node)) return; 770 if (!IsResultNeeded(node)) return;
771 __ PushObject(node->literal()); 771 __ PushObject(node->literal());
772 } 772 }
773 773
774 774
775 void CodeGenerator::VisitTypeNode(TypeNode* node) { 775 void CodeGenerator::VisitTypeNode(TypeNode* node) {
776 // Type nodes are handled specially by the code generator. 776 // Type nodes are handled specially by the code generator.
777 UNREACHABLE(); 777 UNREACHABLE();
778 } 778 }
779 779
780 780
781 void CodeGenerator::VisitAssignableNode(AssignableNode* node) { 781 void CodeGenerator::VisitAssignableNode(AssignableNode* node) {
782 ASSERT(FLAG_enable_type_checks); 782 ASSERT(FLAG_enable_type_checks);
783 node->expr()->Visit(this); 783 node->expr()->Visit(this);
784 __ popl(EAX); 784 __ popl(EAX);
785 GenerateAssertAssignable(node->id(), 785 GenerateAssertAssignable(node->id(),
786 node->token_index(), 786 node->token_pos(),
787 node->expr(), 787 node->expr(),
788 node->type(), 788 node->type(),
789 node->dst_name()); 789 node->dst_name());
790 if (IsResultNeeded(node)) { 790 if (IsResultNeeded(node)) {
791 __ pushl(EAX); 791 __ pushl(EAX);
792 } 792 }
793 } 793 }
794 794
795 795
796 void CodeGenerator::VisitClosureNode(ClosureNode* node) { 796 void CodeGenerator::VisitClosureNode(ClosureNode* node) {
(...skipping 19 matching lines...) Expand all
816 ASSERT(function.context_scope() != ContextScope::null()); 816 ASSERT(function.context_scope() != ContextScope::null());
817 817
818 // The function type of a closure may have type arguments. In that case, pass 818 // The function type of a closure may have type arguments. In that case, pass
819 // the type arguments of the instantiator. 819 // the type arguments of the instantiator.
820 const Class& cls = Class::Handle(function.signature_class()); 820 const Class& cls = Class::Handle(function.signature_class());
821 ASSERT(!cls.IsNull()); 821 ASSERT(!cls.IsNull());
822 const bool requires_type_arguments = cls.HasTypeArguments(); 822 const bool requires_type_arguments = cls.HasTypeArguments();
823 if (requires_type_arguments) { 823 if (requires_type_arguments) {
824 ASSERT(!function.IsImplicitStaticClosureFunction()); 824 ASSERT(!function.IsImplicitStaticClosureFunction());
825 const bool kPushInstantiator = false; 825 const bool kPushInstantiator = false;
826 GenerateInstantiatorTypeArguments(node->token_index(), kPushInstantiator); 826 GenerateInstantiatorTypeArguments(node->token_pos(), kPushInstantiator);
827 } else { 827 } else {
828 __ pushl(raw_null); // No type arguments. 828 __ pushl(raw_null); // No type arguments.
829 } 829 }
830 const Code& stub = Code::Handle( 830 const Code& stub = Code::Handle(
831 StubCode::GetAllocationStubForClosure(function)); 831 StubCode::GetAllocationStubForClosure(function));
832 const ExternalLabel label(function.ToCString(), stub.EntryPoint()); 832 const ExternalLabel label(function.ToCString(), stub.EntryPoint());
833 GenerateCall(node->token_index(), &label, PcDescriptors::kOther); 833 GenerateCall(node->token_pos(), &label, PcDescriptors::kOther);
834 __ popl(ECX); // Pop type arguments. 834 __ popl(ECX); // Pop type arguments.
835 __ popl(ECX); // Pop receiver. 835 __ popl(ECX); // Pop receiver.
836 if (IsResultNeeded(node)) { 836 if (IsResultNeeded(node)) {
837 __ pushl(EAX); 837 __ pushl(EAX);
838 } 838 }
839 } 839 }
840 840
841 841
842 void CodeGenerator::VisitPrimaryNode(PrimaryNode* node) { 842 void CodeGenerator::VisitPrimaryNode(PrimaryNode* node) {
843 // PrimaryNodes are temporary during parsing. 843 // PrimaryNodes are temporary during parsing.
844 UNREACHABLE(); 844 UNREACHABLE();
845 } 845 }
846 846
847 847
848 void CodeGenerator::VisitCloneContextNode(CloneContextNode *node) { 848 void CodeGenerator::VisitCloneContextNode(CloneContextNode *node) {
849 __ PushObject(Object::ZoneHandle()); // Make room for the result. 849 __ PushObject(Object::ZoneHandle()); // Make room for the result.
850 __ pushl(CTX); 850 __ pushl(CTX);
851 GenerateCallRuntime(node->id(), 851 GenerateCallRuntime(node->id(),
852 node->token_index(), kCloneContextRuntimeEntry); 852 node->token_pos(), kCloneContextRuntimeEntry);
853 __ popl(EAX); 853 __ popl(EAX);
854 __ popl(CTX); // result: cloned context. Set as current context. 854 __ popl(CTX); // result: cloned context. Set as current context.
855 } 855 }
856 856
857 857
858 void CodeGenerator::VisitSequenceNode(SequenceNode* node_sequence) { 858 void CodeGenerator::VisitSequenceNode(SequenceNode* node_sequence) {
859 CodeGeneratorState codegen_state(this); 859 CodeGeneratorState codegen_state(this);
860 LocalScope* scope = node_sequence->scope(); 860 LocalScope* scope = node_sequence->scope();
861 const intptr_t num_context_variables = 861 const intptr_t num_context_variables =
862 (scope != NULL) ? scope->num_context_variables() : 0; 862 (scope != NULL) ? scope->num_context_variables() : 0;
863 intptr_t previous_context_level = context_level(); 863 intptr_t previous_context_level = context_level();
864 if (num_context_variables > 0) { 864 if (num_context_variables > 0) {
865 // The loop local scope declares variables that are captured. 865 // The loop local scope declares variables that are captured.
866 // Allocate and chain a new context. 866 // Allocate and chain a new context.
867 __ movl(EDX, Immediate(num_context_variables)); 867 __ movl(EDX, Immediate(num_context_variables));
868 const ExternalLabel label("alloc_context", 868 const ExternalLabel label("alloc_context",
869 StubCode::AllocateContextEntryPoint()); 869 StubCode::AllocateContextEntryPoint());
870 GenerateCall(node_sequence->token_index(), &label, PcDescriptors::kOther); 870 GenerateCall(node_sequence->token_pos(), &label, PcDescriptors::kOther);
871 871
872 // If this node_sequence is the body of the function being compiled, and if 872 // If this node_sequence is the body of the function being compiled, and if
873 // this function is not a closure, do not link the current context as the 873 // this function is not a closure, do not link the current context as the
874 // parent of the newly allocated context, as it is not accessible. Instead, 874 // parent of the newly allocated context, as it is not accessible. Instead,
875 // save it in a pre-allocated variable and restore it on exit. 875 // save it in a pre-allocated variable and restore it on exit.
876 if ((node_sequence == parsed_function_.node_sequence()) && 876 if ((node_sequence == parsed_function_.node_sequence()) &&
877 (parsed_function_.saved_context_var() != NULL)) { 877 (parsed_function_.saved_context_var() != NULL)) {
878 GenerateStoreVariable( 878 GenerateStoreVariable(
879 *parsed_function_.saved_context_var(), CTX, kNoRegister); 879 *parsed_function_.saved_context_var(), CTX, kNoRegister);
880 __ StoreIntoObjectNoBarrier(EAX, 880 __ StoreIntoObjectNoBarrier(EAX,
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
958 void CodeGenerator::VisitArrayNode(ArrayNode* node) { 958 void CodeGenerator::VisitArrayNode(ArrayNode* node) {
959 // Evaluate the array elements. 959 // Evaluate the array elements.
960 for (int i = 0; i < node->length(); i++) { 960 for (int i = 0; i < node->length(); i++) {
961 AstNode* element = node->ElementAt(i); 961 AstNode* element = node->ElementAt(i);
962 element->Visit(this); 962 element->Visit(this);
963 } 963 }
964 964
965 const AbstractTypeArguments& element_type = node->type_arguments(); 965 const AbstractTypeArguments& element_type = node->type_arguments();
966 const bool instantiate_type_arguments = true; 966 const bool instantiate_type_arguments = true;
967 GenerateTypeArguments(node->id(), 967 GenerateTypeArguments(node->id(),
968 node->token_index(), 968 node->token_pos(),
969 element_type, 969 element_type,
970 instantiate_type_arguments); 970 instantiate_type_arguments);
971 __ popl(ECX); 971 __ popl(ECX);
972 __ movl(EDX, Immediate(Smi::RawValue(node->length()))); 972 __ movl(EDX, Immediate(Smi::RawValue(node->length())));
973 973
974 // Allocate the array. 974 // Allocate the array.
975 // EDX : Array length as Smi. 975 // EDX : Array length as Smi.
976 // ECX : element type for the array. 976 // ECX : element type for the array.
977 GenerateCall(node->token_index(), 977 GenerateCall(node->token_pos(),
978 &StubCode::AllocateArrayLabel(), 978 &StubCode::AllocateArrayLabel(),
979 PcDescriptors::kOther); 979 PcDescriptors::kOther);
980 980
981 // Pop the element values from the stack into the array. 981 // Pop the element values from the stack into the array.
982 __ leal(ECX, FieldAddress(EAX, Array::data_offset())); 982 __ leal(ECX, FieldAddress(EAX, Array::data_offset()));
983 for (int i = node->length() - 1; i >= 0; i--) { 983 for (int i = node->length() - 1; i >= 0; i--) {
984 __ popl(Address(ECX, i * kWordSize)); 984 __ popl(Address(ECX, i * kWordSize));
985 } 985 }
986 986
987 if (IsResultNeeded(node)) { 987 if (IsResultNeeded(node)) {
(...skipping 12 matching lines...) Expand all
1000 GeneratePushVariable(node->local(), EAX); 1000 GeneratePushVariable(node->local(), EAX);
1001 } 1001 }
1002 } 1002 }
1003 1003
1004 1004
1005 void CodeGenerator::VisitStoreLocalNode(StoreLocalNode* node) { 1005 void CodeGenerator::VisitStoreLocalNode(StoreLocalNode* node) {
1006 node->value()->Visit(this); 1006 node->value()->Visit(this);
1007 __ popl(EAX); 1007 __ popl(EAX);
1008 if (FLAG_enable_type_checks) { 1008 if (FLAG_enable_type_checks) {
1009 GenerateAssertAssignable(node->id(), 1009 GenerateAssertAssignable(node->id(),
1010 node->value()->token_index(), 1010 node->value()->token_pos(),
1011 node->value(), 1011 node->value(),
1012 node->local().type(), 1012 node->local().type(),
1013 node->local().name()); 1013 node->local().name());
1014 } 1014 }
1015 GenerateStoreVariable(node->local(), EAX, EDX); 1015 GenerateStoreVariable(node->local(), EAX, EDX);
1016 if (IsResultNeeded(node)) { 1016 if (IsResultNeeded(node)) {
1017 __ pushl(EAX); 1017 __ pushl(EAX);
1018 } 1018 }
1019 } 1019 }
1020 1020
1021 1021
1022 void CodeGenerator::VisitLoadInstanceFieldNode(LoadInstanceFieldNode* node) { 1022 void CodeGenerator::VisitLoadInstanceFieldNode(LoadInstanceFieldNode* node) {
1023 node->instance()->Visit(this); 1023 node->instance()->Visit(this);
1024 MarkDeoptPoint(node->id(), node->token_index()); 1024 MarkDeoptPoint(node->id(), node->token_pos());
1025 __ popl(EAX); // Instance. 1025 __ popl(EAX); // Instance.
1026 __ movl(EAX, FieldAddress(EAX, node->field().Offset())); 1026 __ movl(EAX, FieldAddress(EAX, node->field().Offset()));
1027 if (IsResultNeeded(node)) { 1027 if (IsResultNeeded(node)) {
1028 __ pushl(EAX); 1028 __ pushl(EAX);
1029 } 1029 }
1030 } 1030 }
1031 1031
1032 1032
1033 void CodeGenerator::VisitStoreInstanceFieldNode(StoreInstanceFieldNode* node) { 1033 void CodeGenerator::VisitStoreInstanceFieldNode(StoreInstanceFieldNode* node) {
1034 node->instance()->Visit(this); 1034 node->instance()->Visit(this);
1035 node->value()->Visit(this); 1035 node->value()->Visit(this);
1036 MarkDeoptPoint(node->id(), node->token_index()); 1036 MarkDeoptPoint(node->id(), node->token_pos());
1037 __ popl(EAX); // Value. 1037 __ popl(EAX); // Value.
1038 if (FLAG_enable_type_checks) { 1038 if (FLAG_enable_type_checks) {
1039 GenerateAssertAssignable(node->id(), 1039 GenerateAssertAssignable(node->id(),
1040 node->value()->token_index(), 1040 node->value()->token_pos(),
1041 node->value(), 1041 node->value(),
1042 AbstractType::ZoneHandle(node->field().type()), 1042 AbstractType::ZoneHandle(node->field().type()),
1043 String::ZoneHandle(node->field().name())); 1043 String::ZoneHandle(node->field().name()));
1044 } 1044 }
1045 __ popl(EDX); // Instance. 1045 __ popl(EDX); // Instance.
1046 __ StoreIntoObject(EDX, FieldAddress(EDX, node->field().Offset()), EAX); 1046 __ StoreIntoObject(EDX, FieldAddress(EDX, node->field().Offset()), EAX);
1047 ASSERT(!IsResultNeeded(node)); 1047 ASSERT(!IsResultNeeded(node));
1048 } 1048 }
1049 1049
1050 1050
1051 // Expects array and index on stack and returns result in EAX. 1051 // Expects array and index on stack and returns result in EAX.
1052 void CodeGenerator::GenerateLoadIndexed(intptr_t node_id, 1052 void CodeGenerator::GenerateLoadIndexed(intptr_t node_id,
1053 intptr_t token_index) { 1053 intptr_t token_pos) {
1054 // Invoke the [] operator on the receiver object with the index as argument. 1054 // Invoke the [] operator on the receiver object with the index as argument.
1055 const String& operator_name = 1055 const String& operator_name =
1056 String::ZoneHandle(String::NewSymbol(Token::Str(Token::kINDEX))); 1056 String::ZoneHandle(String::NewSymbol(Token::Str(Token::kINDEX)));
1057 const int kNumArguments = 2; // Receiver and index. 1057 const int kNumArguments = 2; // Receiver and index.
1058 const Array& kNoArgumentNames = Array::Handle(); 1058 const Array& kNoArgumentNames = Array::Handle();
1059 const int kNumArgumentsChecked = 1; 1059 const int kNumArgumentsChecked = 1;
1060 GenerateInstanceCall(node_id, 1060 GenerateInstanceCall(node_id,
1061 token_index, 1061 token_pos,
1062 operator_name, 1062 operator_name,
1063 kNumArguments, 1063 kNumArguments,
1064 kNoArgumentNames, 1064 kNoArgumentNames,
1065 kNumArgumentsChecked); 1065 kNumArgumentsChecked);
1066 } 1066 }
1067 1067
1068 1068
1069 void CodeGenerator::VisitLoadIndexedNode(LoadIndexedNode* node) { 1069 void CodeGenerator::VisitLoadIndexedNode(LoadIndexedNode* node) {
1070 node->array()->Visit(this); 1070 node->array()->Visit(this);
1071 // Now compute the index. 1071 // Now compute the index.
1072 node->index_expr()->Visit(this); 1072 node->index_expr()->Visit(this);
1073 MarkDeoptPoint(node->id(), node->token_index()); 1073 MarkDeoptPoint(node->id(), node->token_pos());
1074 GenerateLoadIndexed(node->id(), node->token_index()); 1074 GenerateLoadIndexed(node->id(), node->token_pos());
1075 // Result is in EAX. 1075 // Result is in EAX.
1076 if (IsResultNeeded(node)) { 1076 if (IsResultNeeded(node)) {
1077 __ pushl(EAX); 1077 __ pushl(EAX);
1078 } 1078 }
1079 } 1079 }
1080 1080
1081 1081
1082 // Expected arguments. 1082 // Expected arguments.
1083 // TOS(0): value. 1083 // TOS(0): value.
1084 // TOS(1): index. 1084 // TOS(1): index.
1085 // TOS(2): array. 1085 // TOS(2): array.
1086 void CodeGenerator::GenerateStoreIndexed(intptr_t node_id, 1086 void CodeGenerator::GenerateStoreIndexed(intptr_t node_id,
1087 intptr_t token_index, 1087 intptr_t token_pos,
1088 bool preserve_value) { 1088 bool preserve_value) {
1089 // It is not necessary to generate a type test of the assigned value here, 1089 // It is not necessary to generate a type test of the assigned value here,
1090 // because the []= operator will check the type of its incoming arguments. 1090 // because the []= operator will check the type of its incoming arguments.
1091 if (preserve_value) { 1091 if (preserve_value) {
1092 __ popl(EAX); 1092 __ popl(EAX);
1093 __ popl(EDX); 1093 __ popl(EDX);
1094 __ popl(ECX); 1094 __ popl(ECX);
1095 __ pushl(EAX); // Preserve stored value. 1095 __ pushl(EAX); // Preserve stored value.
1096 __ pushl(ECX); // Restore arguments. 1096 __ pushl(ECX); // Restore arguments.
1097 __ pushl(EDX); 1097 __ pushl(EDX);
1098 __ pushl(EAX); 1098 __ pushl(EAX);
1099 } 1099 }
1100 // Invoke the []= operator on the receiver object with index and 1100 // Invoke the []= operator on the receiver object with index and
1101 // value as arguments. 1101 // value as arguments.
1102 const String& operator_name = 1102 const String& operator_name =
1103 String::ZoneHandle(String::NewSymbol(Token::Str(Token::kASSIGN_INDEX))); 1103 String::ZoneHandle(String::NewSymbol(Token::Str(Token::kASSIGN_INDEX)));
1104 const int kNumArguments = 3; // Receiver, index and value. 1104 const int kNumArguments = 3; // Receiver, index and value.
1105 const Array& kNoArgumentNames = Array::Handle(); 1105 const Array& kNoArgumentNames = Array::Handle();
1106 const int kNumArgumentsChecked = 1; 1106 const int kNumArgumentsChecked = 1;
1107 GenerateInstanceCall(node_id, 1107 GenerateInstanceCall(node_id,
1108 token_index, 1108 token_pos,
1109 operator_name, 1109 operator_name,
1110 kNumArguments, 1110 kNumArguments,
1111 kNoArgumentNames, 1111 kNoArgumentNames,
1112 kNumArgumentsChecked); 1112 kNumArgumentsChecked);
1113 } 1113 }
1114 1114
1115 1115
1116 void CodeGenerator::VisitStoreIndexedNode(StoreIndexedNode* node) { 1116 void CodeGenerator::VisitStoreIndexedNode(StoreIndexedNode* node) {
1117 // Compute the receiver object and pass as first argument to call. 1117 // Compute the receiver object and pass as first argument to call.
1118 node->array()->Visit(this); 1118 node->array()->Visit(this);
1119 // Now compute the index. 1119 // Now compute the index.
1120 node->index_expr()->Visit(this); 1120 node->index_expr()->Visit(this);
1121 // Finally compute the value to assign. 1121 // Finally compute the value to assign.
1122 node->value()->Visit(this); 1122 node->value()->Visit(this);
1123 MarkDeoptPoint(node->id(), node->token_index()); 1123 MarkDeoptPoint(node->id(), node->token_pos());
1124 GenerateStoreIndexed(node->id(), node->token_index(), IsResultNeeded(node)); 1124 GenerateStoreIndexed(node->id(), node->token_pos(), IsResultNeeded(node));
1125 } 1125 }
1126 1126
1127 1127
1128 void CodeGenerator::VisitLoadStaticFieldNode(LoadStaticFieldNode* node) { 1128 void CodeGenerator::VisitLoadStaticFieldNode(LoadStaticFieldNode* node) {
1129 MarkDeoptPoint(node->id(), node->token_index()); 1129 MarkDeoptPoint(node->id(), node->token_pos());
1130 __ LoadObject(EDX, node->field()); 1130 __ LoadObject(EDX, node->field());
1131 __ movl(EAX, FieldAddress(EDX, Field::value_offset())); 1131 __ movl(EAX, FieldAddress(EDX, Field::value_offset()));
1132 if (IsResultNeeded(node)) { 1132 if (IsResultNeeded(node)) {
1133 __ pushl(EAX); 1133 __ pushl(EAX);
1134 } 1134 }
1135 } 1135 }
1136 1136
1137 1137
1138 void CodeGenerator::VisitStoreStaticFieldNode(StoreStaticFieldNode* node) { 1138 void CodeGenerator::VisitStoreStaticFieldNode(StoreStaticFieldNode* node) {
1139 node->value()->Visit(this); 1139 node->value()->Visit(this);
1140 MarkDeoptPoint(node->id(), node->token_index()); 1140 MarkDeoptPoint(node->id(), node->token_pos());
1141 __ popl(EAX); // Value. 1141 __ popl(EAX); // Value.
1142 if (FLAG_enable_type_checks) { 1142 if (FLAG_enable_type_checks) {
1143 GenerateAssertAssignable(node->id(), 1143 GenerateAssertAssignable(node->id(),
1144 node->value()->token_index(), 1144 node->value()->token_pos(),
1145 node->value(), 1145 node->value(),
1146 AbstractType::ZoneHandle(node->field().type()), 1146 AbstractType::ZoneHandle(node->field().type()),
1147 String::ZoneHandle(node->field().name())); 1147 String::ZoneHandle(node->field().name()));
1148 } 1148 }
1149 __ LoadObject(EDX, node->field()); 1149 __ LoadObject(EDX, node->field());
1150 __ StoreIntoObject(EDX, FieldAddress(EDX, Field::value_offset()), EAX); 1150 __ StoreIntoObject(EDX, FieldAddress(EDX, Field::value_offset()), EAX);
1151 if (IsResultNeeded(node)) { 1151 if (IsResultNeeded(node)) {
1152 // The result is the input value. 1152 // The result is the input value.
1153 __ pushl(EAX); 1153 __ pushl(EAX);
1154 } 1154 }
1155 } 1155 }
1156 1156
1157 1157
1158 void CodeGenerator::GenerateLogicalNotOp(UnaryOpNode* node) { 1158 void CodeGenerator::GenerateLogicalNotOp(UnaryOpNode* node) {
1159 // Generate false if operand is true, otherwise generate true. 1159 // Generate false if operand is true, otherwise generate true.
1160 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); 1160 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
1161 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); 1161 const Bool& bool_false = Bool::ZoneHandle(Bool::False());
1162 node->operand()->Visit(this); 1162 node->operand()->Visit(this);
1163 MarkDeoptPoint(node->id(), node->token_index()); 1163 MarkDeoptPoint(node->id(), node->token_pos());
1164 Label done; 1164 Label done;
1165 GenerateConditionTypeCheck(node->id(), node->operand()->token_index()); 1165 GenerateConditionTypeCheck(node->id(), node->operand()->token_pos());
1166 __ popl(EDX); 1166 __ popl(EDX);
1167 __ LoadObject(EAX, bool_true); 1167 __ LoadObject(EAX, bool_true);
1168 __ cmpl(EAX, EDX); 1168 __ cmpl(EAX, EDX);
1169 __ j(NOT_EQUAL, &done, Assembler::kNearJump); 1169 __ j(NOT_EQUAL, &done, Assembler::kNearJump);
1170 __ LoadObject(EAX, bool_false); 1170 __ LoadObject(EAX, bool_false);
1171 __ Bind(&done); 1171 __ Bind(&done);
1172 if (IsResultNeeded(node)) { 1172 if (IsResultNeeded(node)) {
1173 __ pushl(EAX); 1173 __ pushl(EAX);
1174 } 1174 }
1175 } 1175 }
1176 1176
1177 1177
1178 void CodeGenerator::VisitUnaryOpNode(UnaryOpNode* node) { 1178 void CodeGenerator::VisitUnaryOpNode(UnaryOpNode* node) {
1179 if (node->kind() == Token::kNOT) { 1179 if (node->kind() == Token::kNOT) {
1180 // "!" cannot be overloaded, therefore inline it. 1180 // "!" cannot be overloaded, therefore inline it.
1181 GenerateLogicalNotOp(node); 1181 GenerateLogicalNotOp(node);
1182 return; 1182 return;
1183 } 1183 }
1184 node->operand()->Visit(this); 1184 node->operand()->Visit(this);
1185 if (node->kind() == Token::kADD) { 1185 if (node->kind() == Token::kADD) {
1186 // TODO(srdjan): Remove this as it is not part of Dart language any longer. 1186 // TODO(srdjan): Remove this as it is not part of Dart language any longer.
1187 // Unary operator '+' does not exist, it's a NOP, skip it. 1187 // Unary operator '+' does not exist, it's a NOP, skip it.
1188 if (!IsResultNeeded(node)) { 1188 if (!IsResultNeeded(node)) {
1189 __ popl(EAX); 1189 __ popl(EAX);
1190 } 1190 }
1191 return; 1191 return;
1192 } 1192 }
1193 MarkDeoptPoint(node->id(), node->token_index()); 1193 MarkDeoptPoint(node->id(), node->token_pos());
1194 String& operator_name = String::ZoneHandle(); 1194 String& operator_name = String::ZoneHandle();
1195 if (node->kind() == Token::kSUB) { 1195 if (node->kind() == Token::kSUB) {
1196 operator_name = String::NewSymbol(Token::Str(Token::kNEGATE)); 1196 operator_name = String::NewSymbol(Token::Str(Token::kNEGATE));
1197 } else { 1197 } else {
1198 operator_name = String::NewSymbol(node->Name()); 1198 operator_name = String::NewSymbol(node->Name());
1199 } 1199 }
1200 const int kNumberOfArguments = 1; 1200 const int kNumberOfArguments = 1;
1201 const Array& kNoArgumentNames = Array::Handle(); 1201 const Array& kNoArgumentNames = Array::Handle();
1202 const int kNumArgumentsChecked = 1; 1202 const int kNumArgumentsChecked = 1;
1203 GenerateInstanceCall(node->id(), 1203 GenerateInstanceCall(node->id(),
1204 node->token_index(), 1204 node->token_pos(),
1205 operator_name, 1205 operator_name,
1206 kNumberOfArguments, 1206 kNumberOfArguments,
1207 kNoArgumentNames, 1207 kNoArgumentNames,
1208 kNumArgumentsChecked); 1208 kNumArgumentsChecked);
1209 if (IsResultNeeded(node)) { 1209 if (IsResultNeeded(node)) {
1210 __ pushl(EAX); 1210 __ pushl(EAX);
1211 } 1211 }
1212 } 1212 }
1213 1213
1214 1214
1215 // Instance to test is in EAX. Test if its class is in subtype test cache array 1215 // Instance to test is in EAX. Test if its class is in subtype test cache array
1216 // and use the result in the array to jump to one of the labels. Fall through 1216 // and use the result in the array to jump to one of the labels. Fall through
1217 // if the instance is not in the cache array. 1217 // if the instance is not in the cache array.
1218 // TODO(srdjan): Implement a quicker subtype check, as type test 1218 // TODO(srdjan): Implement a quicker subtype check, as type test
1219 // arrays can grow too high, but they may be useful when optimizing 1219 // arrays can grow too high, but they may be useful when optimizing
1220 // code (type-feedback). 1220 // code (type-feedback).
1221 RawSubtypeTestCache* CodeGenerator::GenerateSubtype1TestCacheLookup( 1221 RawSubtypeTestCache* CodeGenerator::GenerateSubtype1TestCacheLookup(
1222 intptr_t node_id, 1222 intptr_t node_id,
1223 intptr_t token_index, 1223 intptr_t token_pos,
1224 const Class& type_class, 1224 const Class& type_class,
1225 Label* is_instance_lbl, 1225 Label* is_instance_lbl,
1226 Label* is_not_instance_lbl) { 1226 Label* is_not_instance_lbl) {
1227 const SubtypeTestCache& type_test_cache = 1227 const SubtypeTestCache& type_test_cache =
1228 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); 1228 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
1229 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); 1229 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
1230 const Immediate raw_null = 1230 const Immediate raw_null =
1231 Immediate(reinterpret_cast<intptr_t>(Object::null())); 1231 Immediate(reinterpret_cast<intptr_t>(Object::null()));
1232 // Check immediate equality. 1232 // Check immediate equality.
1233 __ LoadClass(ECX, EAX, EDI); 1233 __ LoadClass(ECX, EAX, EDI);
(...skipping 27 matching lines...) Expand all
1261 return type_test_cache.raw(); 1261 return type_test_cache.raw();
1262 } 1262 }
1263 1263
1264 1264
1265 // Inline tests according to the 'type' being tested. Jump to labels 1265 // Inline tests according to the 'type' being tested. Jump to labels
1266 // if we can compute the type-test, otherwise fallthrough. 1266 // if we can compute the type-test, otherwise fallthrough.
1267 // EAX: instance to be tested, must be preserved. 1267 // EAX: instance to be tested, must be preserved.
1268 // Clobbers many registers. 1268 // Clobbers many registers.
1269 RawSubtypeTestCache* CodeGenerator::GenerateInlineInstanceof( 1269 RawSubtypeTestCache* CodeGenerator::GenerateInlineInstanceof(
1270 intptr_t node_id, 1270 intptr_t node_id,
1271 intptr_t token_index, 1271 intptr_t token_pos,
1272 const AbstractType& type, 1272 const AbstractType& type,
1273 Label* is_instance_lbl, 1273 Label* is_instance_lbl,
1274 Label* is_not_instance_lbl) { 1274 Label* is_not_instance_lbl) {
1275 if (type.IsInstantiated()) { 1275 if (type.IsInstantiated()) {
1276 const Class& type_class = Class::ZoneHandle(type.type_class()); 1276 const Class& type_class = Class::ZoneHandle(type.type_class());
1277 // A Smi object cannot be the instance of a parameterized class. 1277 // A Smi object cannot be the instance of a parameterized class.
1278 // A class equality check is only applicable with a dst type of a 1278 // A class equality check is only applicable with a dst type of a
1279 // non-parameterized class or with a raw dst type of a parameterized class. 1279 // non-parameterized class or with a raw dst type of a parameterized class.
1280 if (type_class.HasTypeArguments()) { 1280 if (type_class.HasTypeArguments()) {
1281 return GenerateInstantiatedTypeWithArgumentsTest(node_id, 1281 return GenerateInstantiatedTypeWithArgumentsTest(node_id,
1282 token_index, 1282 token_pos,
1283 type, 1283 type,
1284 is_instance_lbl, 1284 is_instance_lbl,
1285 is_not_instance_lbl); 1285 is_not_instance_lbl);
1286 // Fall through to runtime call. 1286 // Fall through to runtime call.
1287 } else { 1287 } else {
1288 GenerateInstantiatedTypeNoArgumentsTest(node_id, 1288 GenerateInstantiatedTypeNoArgumentsTest(node_id,
1289 token_index, 1289 token_pos,
1290 type, 1290 type,
1291 is_instance_lbl, 1291 is_instance_lbl,
1292 is_not_instance_lbl); 1292 is_not_instance_lbl);
1293 // If test non-conclusive so far, try the inlined type-test cache. 1293 // If test non-conclusive so far, try the inlined type-test cache.
1294 // 'type' is known at compile time. 1294 // 'type' is known at compile time.
1295 return GenerateSubtype1TestCacheLookup( 1295 return GenerateSubtype1TestCacheLookup(
1296 node_id, token_index, type_class, 1296 node_id, token_pos, type_class,
1297 is_instance_lbl, is_not_instance_lbl); 1297 is_instance_lbl, is_not_instance_lbl);
1298 } 1298 }
1299 } else { 1299 } else {
1300 return GenerateUninstantiatedTypeTest(type, 1300 return GenerateUninstantiatedTypeTest(type,
1301 node_id, 1301 node_id,
1302 token_index, 1302 token_pos,
1303 is_instance_lbl, 1303 is_instance_lbl,
1304 is_not_instance_lbl); 1304 is_not_instance_lbl);
1305 } 1305 }
1306 return SubtypeTestCache::null(); 1306 return SubtypeTestCache::null();
1307 } 1307 }
1308 1308
1309 1309
1310 // If instanceof type test cannot be performed successfully at compile time and 1310 // If instanceof type test cannot be performed successfully at compile time and
1311 // therefore eliminated, optimize it by adding inlined tests for: 1311 // therefore eliminated, optimize it by adding inlined tests for:
1312 // - NULL -> return false. 1312 // - NULL -> return false.
1313 // - Smi -> compile time subtype check (only if dst class is not parameterized). 1313 // - Smi -> compile time subtype check (only if dst class is not parameterized).
1314 // - Class equality (only if class is not parameterized). 1314 // - Class equality (only if class is not parameterized).
1315 // Inputs: 1315 // Inputs:
1316 // - EAX: object. 1316 // - EAX: object.
1317 // Destroys ECX. 1317 // Destroys ECX.
1318 // Returns: 1318 // Returns:
1319 // - true or false on stack. 1319 // - true or false on stack.
1320 void CodeGenerator::GenerateInstanceOf(intptr_t node_id, 1320 void CodeGenerator::GenerateInstanceOf(intptr_t node_id,
1321 intptr_t token_index, 1321 intptr_t token_pos,
1322 AstNode* value, 1322 AstNode* value,
1323 const AbstractType& type, 1323 const AbstractType& type,
1324 bool negate_result) { 1324 bool negate_result) {
1325 ASSERT(type.IsFinalized() && !type.IsMalformed()); 1325 ASSERT(type.IsFinalized() && !type.IsMalformed());
1326 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); 1326 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
1327 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); 1327 const Bool& bool_false = Bool::ZoneHandle(Bool::False());
1328 1328
1329 // All objects are instances of type T if Object type is a subtype of type T. 1329 // All objects are instances of type T if Object type is a subtype of type T.
1330 const Type& object_type = 1330 const Type& object_type =
1331 Type::Handle(Isolate::Current()->object_store()->object_type()); 1331 Type::Handle(Isolate::Current()->object_store()->object_type());
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
1378 // time, since an uninstantiated type at compile time could be Object or 1378 // time, since an uninstantiated type at compile time could be Object or
1379 // Dynamic at run time. 1379 // Dynamic at run time.
1380 Label non_null; 1380 Label non_null;
1381 __ cmpl(EAX, raw_null); 1381 __ cmpl(EAX, raw_null);
1382 __ j(NOT_EQUAL, &non_null, Assembler::kNearJump); 1382 __ j(NOT_EQUAL, &non_null, Assembler::kNearJump);
1383 __ PushObject(negate_result ? bool_true : bool_false); 1383 __ PushObject(negate_result ? bool_true : bool_false);
1384 __ jmp(&done); 1384 __ jmp(&done);
1385 __ Bind(&non_null); 1385 __ Bind(&non_null);
1386 } 1386 }
1387 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); 1387 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
1388 test_cache = GenerateInlineInstanceof(node_id, token_index, type, 1388 test_cache = GenerateInlineInstanceof(node_id, token_pos, type,
1389 &is_instance_of, &is_not_instance_of); 1389 &is_instance_of, &is_not_instance_of);
1390 1390
1391 __ PushObject(Object::ZoneHandle()); // Make room for the result. 1391 __ PushObject(Object::ZoneHandle()); // Make room for the result.
1392 const Immediate location = Immediate(Smi::RawValue(token_index)); 1392 const Immediate location = Immediate(Smi::RawValue(token_pos));
1393 const Immediate node_id_as_smi = Immediate(Smi::RawValue(node_id)); 1393 const Immediate node_id_as_smi = Immediate(Smi::RawValue(node_id));
1394 __ pushl(location); // Push the source location. 1394 __ pushl(location); // Push the source location.
1395 __ pushl(node_id_as_smi); // node-id. 1395 __ pushl(node_id_as_smi); // node-id.
1396 __ pushl(EAX); // Push the instance. 1396 __ pushl(EAX); // Push the instance.
1397 __ PushObject(type); // Push the type. 1397 __ PushObject(type); // Push the type.
1398 if (type.IsInstantiated()) { 1398 if (type.IsInstantiated()) {
1399 __ pushl(raw_null); // Null instantiator. 1399 __ pushl(raw_null); // Null instantiator.
1400 __ pushl(raw_null); // Null instantiator. 1400 __ pushl(raw_null); // Null instantiator.
1401 } else { 1401 } else {
1402 const bool kPushInstantiator = true; 1402 const bool kPushInstantiator = true;
1403 GenerateInstantiatorTypeArguments(token_index, kPushInstantiator); 1403 GenerateInstantiatorTypeArguments(token_pos, kPushInstantiator);
1404 } 1404 }
1405 __ LoadObject(EAX, test_cache); 1405 __ LoadObject(EAX, test_cache);
1406 __ pushl(EAX); 1406 __ pushl(EAX);
1407 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry); 1407 GenerateCallRuntime(node_id, token_pos, kInstanceofRuntimeEntry);
1408 // Pop the two parameters supplied to the runtime entry. The result of the 1408 // Pop the two parameters supplied to the runtime entry. The result of the
1409 // instanceof runtime call will be left as the result of the operation. 1409 // instanceof runtime call will be left as the result of the operation.
1410 __ addl(ESP, Immediate(7 * kWordSize)); 1410 __ addl(ESP, Immediate(7 * kWordSize));
1411 if (negate_result) { 1411 if (negate_result) {
1412 __ popl(EDX); 1412 __ popl(EDX);
1413 __ CompareObject(EDX, bool_false); 1413 __ CompareObject(EDX, bool_false);
1414 __ j(EQUAL, &is_not_instance_of, Assembler::kNearJump); 1414 __ j(EQUAL, &is_not_instance_of, Assembler::kNearJump);
1415 // Fall through to is_instance_of. 1415 // Fall through to is_instance_of.
1416 } else { 1416 } else {
1417 __ jmp(&done); 1417 __ jmp(&done);
1418 } 1418 }
1419 1419
1420 __ Bind(&is_instance_of); 1420 __ Bind(&is_instance_of);
1421 __ PushObject(negate_result ? bool_false: bool_true); 1421 __ PushObject(negate_result ? bool_false: bool_true);
1422 __ jmp(&done, Assembler::kNearJump); 1422 __ jmp(&done, Assembler::kNearJump);
1423 __ Bind(&is_not_instance_of); 1423 __ Bind(&is_not_instance_of);
1424 __ PushObject(negate_result ? bool_true: bool_false); 1424 __ PushObject(negate_result ? bool_true: bool_false);
1425 __ Bind(&done); 1425 __ Bind(&done);
1426 } 1426 }
1427 1427
1428 1428
1429 // EAX: instance to test. 1429 // EAX: instance to test.
1430 // Clobbers: ECX. 1430 // Clobbers: ECX.
1431 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if 1431 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if
1432 // type test is conclusive, otherwise fallthrough if a type test could not 1432 // type test is conclusive, otherwise fallthrough if a type test could not
1433 // be completed. 1433 // be completed.
1434 RawSubtypeTestCache* CodeGenerator::GenerateInstantiatedTypeWithArgumentsTest( 1434 RawSubtypeTestCache* CodeGenerator::GenerateInstantiatedTypeWithArgumentsTest(
1435 intptr_t node_id, 1435 intptr_t node_id,
1436 intptr_t token_index, 1436 intptr_t token_pos,
1437 const AbstractType& type, 1437 const AbstractType& type,
1438 Label* is_instance_lbl, 1438 Label* is_instance_lbl,
1439 Label* is_not_instance_lbl) { 1439 Label* is_not_instance_lbl) {
1440 ASSERT(type.IsInstantiated()); 1440 ASSERT(type.IsInstantiated());
1441 const Class& type_class = Class::ZoneHandle(type.type_class()); 1441 const Class& type_class = Class::ZoneHandle(type.type_class());
1442 ASSERT(type_class.HasTypeArguments()); 1442 ASSERT(type_class.HasTypeArguments());
1443 // A Smi object cannot be the instance of a parameterized class. 1443 // A Smi object cannot be the instance of a parameterized class.
1444 // A class equality check is only applicable with a dst type of a 1444 // A class equality check is only applicable with a dst type of a
1445 // non-parameterized class or with a raw dst type of a parameterized class. 1445 // non-parameterized class or with a raw dst type of a parameterized class.
1446 __ testl(EAX, Immediate(kSmiTagMask)); 1446 __ testl(EAX, Immediate(kSmiTagMask));
(...skipping 10 matching lines...) Expand all
1457 __ j(EQUAL, is_instance_lbl); 1457 __ j(EQUAL, is_instance_lbl);
1458 } 1458 }
1459 if (type.IsListInterface()) { 1459 if (type.IsListInterface()) {
1460 // TODO(srdjan) also accept List<Object>. 1460 // TODO(srdjan) also accept List<Object>.
1461 __ cmpl(ECX, Immediate(kArray)); 1461 __ cmpl(ECX, Immediate(kArray));
1462 __ j(EQUAL, is_instance_lbl); 1462 __ j(EQUAL, is_instance_lbl);
1463 __ cmpl(ECX, Immediate(kGrowableObjectArray)); 1463 __ cmpl(ECX, Immediate(kGrowableObjectArray));
1464 __ j(EQUAL, is_instance_lbl); 1464 __ j(EQUAL, is_instance_lbl);
1465 } 1465 }
1466 return 1466 return
1467 GenerateSubtype1TestCacheLookup(node_id, token_index, type_class, 1467 GenerateSubtype1TestCacheLookup(node_id, token_pos, type_class,
1468 is_instance_lbl, is_not_instance_lbl); 1468 is_instance_lbl, is_not_instance_lbl);
1469 } 1469 }
1470 // If one type argument only, quick check. 1470 // If one type argument only, quick check.
1471 if (type_arguments.Length() == 1) { 1471 if (type_arguments.Length() == 1) {
1472 const AbstractType& tp_argument = AbstractType::ZoneHandle( 1472 const AbstractType& tp_argument = AbstractType::ZoneHandle(
1473 type_arguments.TypeAt(0)); 1473 type_arguments.TypeAt(0));
1474 if (tp_argument.IsType()) { 1474 if (tp_argument.IsType()) {
1475 // Malformed type has been caught in the caller chain of this function. 1475 // Malformed type has been caught in the caller chain of this function.
1476 ASSERT(tp_argument.HasResolvedTypeClass()); 1476 ASSERT(tp_argument.HasResolvedTypeClass());
1477 // Check if type argument is dynamic or Object. 1477 // Check if type argument is dynamic or Object.
1478 const Type& object_type = 1478 const Type& object_type =
1479 Type::Handle(Isolate::Current()->object_store()->object_type()); 1479 Type::Handle(Isolate::Current()->object_store()->object_type());
1480 Error& malformed_error = Error::Handle(); 1480 Error& malformed_error = Error::Handle();
1481 if (object_type.IsSubtypeOf(tp_argument, &malformed_error)) { 1481 if (object_type.IsSubtypeOf(tp_argument, &malformed_error)) {
1482 // Instance class test only necessary. 1482 // Instance class test only necessary.
1483 return GenerateSubtype1TestCacheLookup( 1483 return GenerateSubtype1TestCacheLookup(
1484 node_id, 1484 node_id,
1485 token_index, 1485 token_pos,
1486 type_class, 1486 type_class,
1487 is_instance_lbl, 1487 is_instance_lbl,
1488 is_not_instance_lbl); 1488 is_not_instance_lbl);
1489 } 1489 }
1490 } 1490 }
1491 } 1491 }
1492 const SubtypeTestCache& type_test_cache = 1492 const SubtypeTestCache& type_test_cache =
1493 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); 1493 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
1494 Label inlined_check, fall_through; 1494 Label inlined_check, fall_through;
1495 const Immediate raw_null = 1495 const Immediate raw_null =
(...skipping 16 matching lines...) Expand all
1512 __ jmp(is_not_instance_lbl); 1512 __ jmp(is_not_instance_lbl);
1513 __ Bind(&fall_through); 1513 __ Bind(&fall_through);
1514 return type_test_cache.raw(); 1514 return type_test_cache.raw();
1515 } 1515 }
1516 1516
1517 1517
1518 // EAX: instance to test. 1518 // EAX: instance to test.
1519 // Clobbers: EBX, ECX, EDX. 1519 // Clobbers: EBX, ECX, EDX.
1520 void CodeGenerator::GenerateInstantiatedTypeNoArgumentsTest( 1520 void CodeGenerator::GenerateInstantiatedTypeNoArgumentsTest(
1521 intptr_t node_id, 1521 intptr_t node_id,
1522 intptr_t token_index, 1522 intptr_t token_pos,
1523 const AbstractType& type, 1523 const AbstractType& type,
1524 Label* is_instance_lbl, 1524 Label* is_instance_lbl,
1525 Label* is_not_instance_lbl) { 1525 Label* is_not_instance_lbl) {
1526 ASSERT(type.IsInstantiated()); 1526 ASSERT(type.IsInstantiated());
1527 const Class& type_class = Class::Handle(type.type_class()); 1527 const Class& type_class = Class::Handle(type.type_class());
1528 ASSERT(!type_class.HasTypeArguments()); 1528 ASSERT(!type_class.HasTypeArguments());
1529 1529
1530 Label compare_classes; 1530 Label compare_classes;
1531 __ testl(EAX, Immediate(kSmiTagMask)); 1531 __ testl(EAX, Immediate(kSmiTagMask));
1532 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); 1532 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump);
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
1599 } 1599 }
1600 // Otherwise fallthrough. 1600 // Otherwise fallthrough.
1601 } 1601 }
1602 1602
1603 1603
1604 // EAX: instance to test. 1604 // EAX: instance to test.
1605 // Clobbers: EBX, EDX, ECX. 1605 // Clobbers: EBX, EDX, ECX.
1606 RawSubtypeTestCache* CodeGenerator::GenerateUninstantiatedTypeTest( 1606 RawSubtypeTestCache* CodeGenerator::GenerateUninstantiatedTypeTest(
1607 const AbstractType& type, 1607 const AbstractType& type,
1608 intptr_t node_id, 1608 intptr_t node_id,
1609 intptr_t token_index, 1609 intptr_t token_pos,
1610 Label* is_instance_lbl, 1610 Label* is_instance_lbl,
1611 Label* is_not_instance_lbl) { 1611 Label* is_not_instance_lbl) {
1612 ASSERT(!type.IsInstantiated()); 1612 ASSERT(!type.IsInstantiated());
1613 // Skip check if destination is a dynamic type. 1613 // Skip check if destination is a dynamic type.
1614 const Immediate raw_null = 1614 const Immediate raw_null =
1615 Immediate(reinterpret_cast<intptr_t>(Object::null())); 1615 Immediate(reinterpret_cast<intptr_t>(Object::null()));
1616 if (type.IsTypeParameter()) { 1616 if (type.IsTypeParameter()) {
1617 // EAX must be preserved! 1617 // EAX must be preserved!
1618 Label fall_through; 1618 Label fall_through;
1619 const bool kPushInstantiator = false; 1619 const bool kPushInstantiator = false;
1620 GenerateInstantiatorTypeArguments(token_index, kPushInstantiator); 1620 GenerateInstantiatorTypeArguments(token_pos, kPushInstantiator);
1621 // Type arguments are on stack. 1621 // Type arguments are on stack.
1622 __ popl(EBX); 1622 __ popl(EBX);
1623 // Check if type argument is dynamic. 1623 // Check if type argument is dynamic.
1624 __ cmpl(EBX, raw_null); 1624 __ cmpl(EBX, raw_null);
1625 __ j(EQUAL, is_instance_lbl); 1625 __ j(EQUAL, is_instance_lbl);
1626 1626
1627 // EBX: instantiator type arguments. 1627 // EBX: instantiator type arguments.
1628 // For now handle only TypeArguments and bail out if InstantiatedTypeArgs. 1628 // For now handle only TypeArguments and bail out if InstantiatedTypeArgs.
1629 // We expect that frequently checked objects wull have their type arguments 1629 // We expect that frequently checked objects wull have their type arguments
1630 // converted into instance of TypeArguments. 1630 // converted into instance of TypeArguments.
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
1680 __ testl(EAX, Immediate(kSmiTagMask)); // Is instance Smi? 1680 __ testl(EAX, Immediate(kSmiTagMask)); // Is instance Smi?
1681 __ j(ZERO, is_not_instance_lbl); 1681 __ j(ZERO, is_not_instance_lbl);
1682 // Uninstantiated type class is known at compile time, but the type 1682 // Uninstantiated type class is known at compile time, but the type
1683 // arguments are determined at runtime by the instantiator. 1683 // arguments are determined at runtime by the instantiator.
1684 const SubtypeTestCache& type_test_cache = 1684 const SubtypeTestCache& type_test_cache =
1685 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); 1685 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
1686 __ LoadObject(EDX, type_test_cache); 1686 __ LoadObject(EDX, type_test_cache);
1687 __ pushl(EDX); // Subtype test cache. 1687 __ pushl(EDX); // Subtype test cache.
1688 __ pushl(EAX); // Instance. 1688 __ pushl(EAX); // Instance.
1689 const bool kPushInstantiator = false; 1689 const bool kPushInstantiator = false;
1690 GenerateInstantiatorTypeArguments(token_index, kPushInstantiator); 1690 GenerateInstantiatorTypeArguments(token_pos, kPushInstantiator);
1691 __ call(&StubCode::Subtype3TestCacheLabel()); 1691 __ call(&StubCode::Subtype3TestCacheLabel());
1692 __ popl(EDX); // Discard type arguments. 1692 __ popl(EDX); // Discard type arguments.
1693 __ popl(EAX); // Restore receiver. 1693 __ popl(EAX); // Restore receiver.
1694 __ popl(EDX); // Discard subtype test cache. 1694 __ popl(EDX); // Discard subtype test cache.
1695 // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False. 1695 // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False.
1696 __ cmpl(ECX, raw_null); 1696 __ cmpl(ECX, raw_null);
1697 __ j(EQUAL, &fall_through, Assembler::kNearJump); 1697 __ j(EQUAL, &fall_through, Assembler::kNearJump);
1698 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); 1698 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
1699 __ CompareObject(ECX, bool_true); 1699 __ CompareObject(ECX, bool_true);
1700 __ j(EQUAL, is_instance_lbl); 1700 __ j(EQUAL, is_instance_lbl);
(...skipping 11 matching lines...) Expand all
1712 // - Smi -> compile time subtype check (only if dst class is not parameterized). 1712 // - Smi -> compile time subtype check (only if dst class is not parameterized).
1713 // - Class equality (only if class is not parameterized). 1713 // - Class equality (only if class is not parameterized).
1714 // Inputs: 1714 // Inputs:
1715 // - EAX: object. 1715 // - EAX: object.
1716 // Destroys ECX and EDX. 1716 // Destroys ECX and EDX.
1717 // Returns: 1717 // Returns:
1718 // - object in EAX for successful assignable check (or throws TypeError). 1718 // - object in EAX for successful assignable check (or throws TypeError).
1719 // Performance notes: positive checks must be quick, negative checks can be slow 1719 // Performance notes: positive checks must be quick, negative checks can be slow
1720 // as they throw an exception. 1720 // as they throw an exception.
1721 void CodeGenerator::GenerateAssertAssignable(intptr_t node_id, 1721 void CodeGenerator::GenerateAssertAssignable(intptr_t node_id,
1722 intptr_t token_index, 1722 intptr_t token_pos,
1723 AstNode* value, 1723 AstNode* value,
1724 const AbstractType& dst_type, 1724 const AbstractType& dst_type,
1725 const String& dst_name) { 1725 const String& dst_name) {
1726 ASSERT(FLAG_enable_type_checks); 1726 ASSERT(FLAG_enable_type_checks);
1727 ASSERT(token_index >= 0); 1727 ASSERT(token_pos >= 0);
1728 ASSERT(!dst_type.IsNull()); 1728 ASSERT(!dst_type.IsNull());
1729 ASSERT(dst_type.IsFinalized()); 1729 ASSERT(dst_type.IsFinalized());
1730 1730
1731 // Any expression is assignable to the Dynamic type and to the Object type. 1731 // Any expression is assignable to the Dynamic type and to the Object type.
1732 // Skip the test. 1732 // Skip the test.
1733 if (!dst_type.IsMalformed() && 1733 if (!dst_type.IsMalformed() &&
1734 (dst_type.IsDynamicType() || dst_type.IsObjectType())) { 1734 (dst_type.IsDynamicType() || dst_type.IsObjectType())) {
1735 return; 1735 return;
1736 } 1736 }
1737 1737
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1770 Label done, runtime_call; 1770 Label done, runtime_call;
1771 __ cmpl(EAX, raw_null); 1771 __ cmpl(EAX, raw_null);
1772 __ j(EQUAL, &done); 1772 __ j(EQUAL, &done);
1773 1773
1774 // Generate throw new TypeError() if the type is malformed. 1774 // Generate throw new TypeError() if the type is malformed.
1775 if (dst_type.IsMalformed()) { 1775 if (dst_type.IsMalformed()) {
1776 const Error& error = Error::Handle(dst_type.malformed_error()); 1776 const Error& error = Error::Handle(dst_type.malformed_error());
1777 const String& error_message = String::ZoneHandle( 1777 const String& error_message = String::ZoneHandle(
1778 String::NewSymbol(error.ToErrorCString())); 1778 String::NewSymbol(error.ToErrorCString()));
1779 __ PushObject(Object::ZoneHandle()); // Make room for the result. 1779 __ PushObject(Object::ZoneHandle()); // Make room for the result.
1780 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. 1780 __ pushl(Immediate(Smi::RawValue(token_pos))); // Source location.
1781 __ pushl(EAX); // Push the source object. 1781 __ pushl(EAX); // Push the source object.
1782 __ PushObject(dst_name); // Push the name of the destination. 1782 __ PushObject(dst_name); // Push the name of the destination.
1783 __ PushObject(error_message); 1783 __ PushObject(error_message);
1784 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry); 1784 GenerateCallRuntime(node_id, token_pos, kMalformedTypeErrorRuntimeEntry);
1785 // We should never return here. 1785 // We should never return here.
1786 __ int3(); 1786 __ int3();
1787 1787
1788 __ Bind(&done); // For a null object. 1788 __ Bind(&done); // For a null object.
1789 return; 1789 return;
1790 } 1790 }
1791 1791
1792 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); 1792 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
1793 test_cache = GenerateInlineInstanceof(node_id, token_index, dst_type, 1793 test_cache = GenerateInlineInstanceof(node_id, token_pos, dst_type,
1794 &done, &runtime_call); 1794 &done, &runtime_call);
1795 1795
1796 __ Bind(&runtime_call); 1796 __ Bind(&runtime_call);
1797 __ PushObject(Object::ZoneHandle()); // Make room for the result. 1797 __ PushObject(Object::ZoneHandle()); // Make room for the result.
1798 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. 1798 __ pushl(Immediate(Smi::RawValue(token_pos))); // Source location.
1799 __ pushl(Immediate(Smi::RawValue(node_id))); // node-id. 1799 __ pushl(Immediate(Smi::RawValue(node_id))); // node-id.
1800 __ pushl(EAX); // Push the source object. 1800 __ pushl(EAX); // Push the source object.
1801 __ PushObject(dst_type); // Push the type of the destination. 1801 __ PushObject(dst_type); // Push the type of the destination.
1802 if (dst_type.IsInstantiated()) { 1802 if (dst_type.IsInstantiated()) {
1803 __ pushl(raw_null); // Null instantiator. 1803 __ pushl(raw_null); // Null instantiator.
1804 __ pushl(raw_null); // Null instantiator type argument. 1804 __ pushl(raw_null); // Null instantiator type argument.
1805 } else { 1805 } else {
1806 const bool kPushInstantiator = true; 1806 const bool kPushInstantiator = true;
1807 GenerateInstantiatorTypeArguments(token_index, kPushInstantiator); 1807 GenerateInstantiatorTypeArguments(token_pos, kPushInstantiator);
1808 } 1808 }
1809 __ PushObject(dst_name); // Push the name of the destination. 1809 __ PushObject(dst_name); // Push the name of the destination.
1810 __ LoadObject(EAX, test_cache); 1810 __ LoadObject(EAX, test_cache);
1811 __ pushl(EAX); 1811 __ pushl(EAX);
1812 GenerateCallRuntime(node_id, token_index, kTypeCheckRuntimeEntry); 1812 GenerateCallRuntime(node_id, token_pos, kTypeCheckRuntimeEntry);
1813 // Pop the parameters supplied to the runtime entry. The result of the 1813 // Pop the parameters supplied to the runtime entry. The result of the
1814 // type check runtime call is the checked value. 1814 // type check runtime call is the checked value.
1815 __ addl(ESP, Immediate(8 * kWordSize)); 1815 __ addl(ESP, Immediate(8 * kWordSize));
1816 __ popl(EAX); 1816 __ popl(EAX);
1817 1817
1818 // EAX: value. 1818 // EAX: value.
1819 __ Bind(&done); 1819 __ Bind(&done);
1820 } 1820 }
1821 1821
1822 1822
1823 void CodeGenerator::GenerateArgumentTypeChecks() { 1823 void CodeGenerator::GenerateArgumentTypeChecks() {
1824 const Function& function = parsed_function_.function(); 1824 const Function& function = parsed_function_.function();
1825 const SequenceNode& sequence_node = *parsed_function_.node_sequence(); 1825 const SequenceNode& sequence_node = *parsed_function_.node_sequence();
1826 LocalScope* scope = sequence_node.scope(); 1826 LocalScope* scope = sequence_node.scope();
1827 const int num_fixed_params = function.num_fixed_parameters(); 1827 const int num_fixed_params = function.num_fixed_parameters();
1828 const int num_opt_params = function.num_optional_parameters(); 1828 const int num_opt_params = function.num_optional_parameters();
1829 ASSERT(num_fixed_params + num_opt_params <= scope->num_variables()); 1829 ASSERT(num_fixed_params + num_opt_params <= scope->num_variables());
1830 for (intptr_t i = 0; i < num_fixed_params + num_opt_params; i++) { 1830 for (intptr_t i = 0; i < num_fixed_params + num_opt_params; i++) {
1831 LocalVariable* parameter = scope->VariableAt(i); 1831 LocalVariable* parameter = scope->VariableAt(i);
1832 GenerateLoadVariable(EAX, *parameter); 1832 GenerateLoadVariable(EAX, *parameter);
1833 GenerateAssertAssignable(sequence_node.ParameterIdAt(i), 1833 GenerateAssertAssignable(sequence_node.ParameterIdAt(i),
1834 parameter->token_index(), 1834 parameter->token_pos(),
1835 NULL, 1835 NULL,
1836 parameter->type(), 1836 parameter->type(),
1837 parameter->name()); 1837 parameter->name());
1838 } 1838 }
1839 } 1839 }
1840 1840
1841 1841
1842 void CodeGenerator::GenerateConditionTypeCheck(intptr_t node_id, 1842 void CodeGenerator::GenerateConditionTypeCheck(intptr_t node_id,
1843 intptr_t token_index) { 1843 intptr_t token_pos) {
1844 if (!FLAG_enable_type_checks) { 1844 if (!FLAG_enable_type_checks) {
1845 return; 1845 return;
1846 } 1846 }
1847 1847
1848 // Check that the type of the object on the stack is allowed in conditional 1848 // Check that the type of the object on the stack is allowed in conditional
1849 // context. 1849 // context.
1850 // Call the runtime if the object is null or not of type bool. 1850 // Call the runtime if the object is null or not of type bool.
1851 const Immediate raw_null = 1851 const Immediate raw_null =
1852 Immediate(reinterpret_cast<intptr_t>(Object::null())); 1852 Immediate(reinterpret_cast<intptr_t>(Object::null()));
1853 Label runtime_call, done; 1853 Label runtime_call, done;
1854 __ movl(EAX, Address(ESP, 0)); 1854 __ movl(EAX, Address(ESP, 0));
1855 __ cmpl(EAX, raw_null); 1855 __ cmpl(EAX, raw_null);
1856 __ j(EQUAL, &runtime_call, Assembler::kNearJump); 1856 __ j(EQUAL, &runtime_call, Assembler::kNearJump);
1857 __ testl(EAX, Immediate(kSmiTagMask)); 1857 __ testl(EAX, Immediate(kSmiTagMask));
1858 __ j(ZERO, &runtime_call, Assembler::kNearJump); // Call runtime for Smi. 1858 __ j(ZERO, &runtime_call, Assembler::kNearJump); // Call runtime for Smi.
1859 // This check should pass if the receiver's class implements the interface 1859 // This check should pass if the receiver's class implements the interface
1860 // 'bool'. Check only class 'Bool' since it is the only legal implementation 1860 // 'bool'. Check only class 'Bool' since it is the only legal implementation
1861 // of the interface 'bool'. 1861 // of the interface 'bool'.
1862 __ CompareClassId(EAX, kBool, ECX); 1862 __ CompareClassId(EAX, kBool, ECX);
1863 __ j(EQUAL, &done, Assembler::kNearJump); 1863 __ j(EQUAL, &done, Assembler::kNearJump);
1864 1864
1865 __ Bind(&runtime_call); 1865 __ Bind(&runtime_call);
1866 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. 1866 __ pushl(Immediate(Smi::RawValue(token_pos))); // Source location.
1867 __ pushl(EAX); // Push the source object. 1867 __ pushl(EAX); // Push the source object.
1868 GenerateCallRuntime(node_id, token_index, kConditionTypeErrorRuntimeEntry); 1868 GenerateCallRuntime(node_id, token_pos, kConditionTypeErrorRuntimeEntry);
1869 // We should never return here. 1869 // We should never return here.
1870 __ int3(); 1870 __ int3();
1871 1871
1872 __ Bind(&done); 1872 __ Bind(&done);
1873 } 1873 }
1874 1874
1875 1875
1876 void CodeGenerator::VisitComparisonNode(ComparisonNode* node) { 1876 void CodeGenerator::VisitComparisonNode(ComparisonNode* node) {
1877 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); 1877 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
1878 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); 1878 const Bool& bool_false = Bool::ZoneHandle(Bool::False());
1879 node->left()->Visit(this); 1879 node->left()->Visit(this);
1880 1880
1881 // The instanceof operator needs special handling. 1881 // The instanceof operator needs special handling.
1882 if (Token::IsInstanceofOperator(node->kind())) { 1882 if (Token::IsInstanceofOperator(node->kind())) {
1883 __ popl(EAX); // Left operand. 1883 __ popl(EAX); // Left operand.
1884 ASSERT(node->right()->IsTypeNode()); 1884 ASSERT(node->right()->IsTypeNode());
1885 GenerateInstanceOf(node->id(), 1885 GenerateInstanceOf(node->id(),
1886 node->token_index(), 1886 node->token_pos(),
1887 node->left(), 1887 node->left(),
1888 node->right()->AsTypeNode()->type(), 1888 node->right()->AsTypeNode()->type(),
1889 (node->kind() == Token::kISNOT)); 1889 (node->kind() == Token::kISNOT));
1890 if (!IsResultNeeded(node)) { 1890 if (!IsResultNeeded(node)) {
1891 __ popl(EAX); // Pop the result of the instanceof operation. 1891 __ popl(EAX); // Pop the result of the instanceof operation.
1892 } 1892 }
1893 return; 1893 return;
1894 } 1894 }
1895 1895
1896 node->right()->Visit(this); 1896 node->right()->Visit(this);
(...skipping 17 matching lines...) Expand all
1914 __ LoadObject(EAX, bool_false); 1914 __ LoadObject(EAX, bool_false);
1915 __ jmp(&done, Assembler::kNearJump); 1915 __ jmp(&done, Assembler::kNearJump);
1916 __ Bind(&load_true); 1916 __ Bind(&load_true);
1917 __ LoadObject(EAX, bool_true); 1917 __ LoadObject(EAX, bool_true);
1918 __ Bind(&done); 1918 __ Bind(&done);
1919 // Result is in EAX. 1919 // Result is in EAX.
1920 __ pushl(EAX); 1920 __ pushl(EAX);
1921 return; 1921 return;
1922 } 1922 }
1923 1923
1924 MarkDeoptPoint(node->id(), node->token_index()); 1924 MarkDeoptPoint(node->id(), node->token_pos());
1925 1925
1926 // '!=' not overloadable, always implements negation of '=='. 1926 // '!=' not overloadable, always implements negation of '=='.
1927 // Call operator for '=='. 1927 // Call operator for '=='.
1928 if ((node->kind() == Token::kEQ) || (node->kind() == Token::kNE)) { 1928 if ((node->kind() == Token::kEQ) || (node->kind() == Token::kNE)) {
1929 // Null is a special receiver with a special type and frequently used on 1929 // Null is a special receiver with a special type and frequently used on
1930 // operators "==" and "!=". Emit inlined code for null so that it does not 1930 // operators "==" and "!=". Emit inlined code for null so that it does not
1931 // pollute type information at call site. 1931 // pollute type information at call site.
1932 Label null_done; 1932 Label null_done;
1933 { 1933 {
1934 const Immediate raw_null = 1934 const Immediate raw_null =
(...skipping 18 matching lines...) Expand all
1953 __ LoadObject(EAX, bool_true); 1953 __ LoadObject(EAX, bool_true);
1954 __ jmp(&null_done, Assembler::kNearJump); 1954 __ jmp(&null_done, Assembler::kNearJump);
1955 __ Bind(&non_null_compare); 1955 __ Bind(&non_null_compare);
1956 } 1956 }
1957 // Do '==' first then negate if necessary, 1957 // Do '==' first then negate if necessary,
1958 const String& operator_name = String::ZoneHandle(String::NewSymbol("==")); 1958 const String& operator_name = String::ZoneHandle(String::NewSymbol("=="));
1959 const int kNumberOfArguments = 2; 1959 const int kNumberOfArguments = 2;
1960 const Array& kNoArgumentNames = Array::Handle(); 1960 const Array& kNoArgumentNames = Array::Handle();
1961 const int kNumArgumentsChecked = 1; 1961 const int kNumArgumentsChecked = 1;
1962 GenerateInstanceCall(node->id(), 1962 GenerateInstanceCall(node->id(),
1963 node->token_index(), 1963 node->token_pos(),
1964 operator_name, 1964 operator_name,
1965 kNumberOfArguments, 1965 kNumberOfArguments,
1966 kNoArgumentNames, 1966 kNoArgumentNames,
1967 kNumArgumentsChecked); 1967 kNumArgumentsChecked);
1968 1968
1969 // Result is in EAX. No need to negate if result is not needed. 1969 // Result is in EAX. No need to negate if result is not needed.
1970 if ((node->kind() == Token::kNE) && IsResultNeeded(node)) { 1970 if ((node->kind() == Token::kNE) && IsResultNeeded(node)) {
1971 // Negate result. 1971 // Negate result.
1972 Label load_true, done; 1972 Label load_true, done;
1973 __ LoadObject(EDX, bool_false); 1973 __ LoadObject(EDX, bool_false);
1974 __ cmpl(EAX, EDX); 1974 __ cmpl(EAX, EDX);
1975 __ j(EQUAL, &load_true, Assembler::kNearJump); 1975 __ j(EQUAL, &load_true, Assembler::kNearJump);
1976 __ movl(EAX, EDX); // false. 1976 __ movl(EAX, EDX); // false.
1977 __ jmp(&done, Assembler::kNearJump); 1977 __ jmp(&done, Assembler::kNearJump);
1978 __ Bind(&load_true); 1978 __ Bind(&load_true);
1979 __ LoadObject(EAX, bool_true); 1979 __ LoadObject(EAX, bool_true);
1980 __ Bind(&done); 1980 __ Bind(&done);
1981 } 1981 }
1982 __ Bind(&null_done); 1982 __ Bind(&null_done);
1983 // Result is in EAX. 1983 // Result is in EAX.
1984 if (IsResultNeeded(node)) { 1984 if (IsResultNeeded(node)) {
1985 __ pushl(EAX); 1985 __ pushl(EAX);
1986 } 1986 }
1987 return; 1987 return;
1988 } 1988 }
1989 1989
1990 // Call operator. 1990 // Call operator.
1991 GenerateBinaryOperatorCall(node->id(), node->token_index(), node->Name()); 1991 GenerateBinaryOperatorCall(node->id(), node->token_pos(), node->Name());
1992 // Result is in EAX. 1992 // Result is in EAX.
1993 if (IsResultNeeded(node)) { 1993 if (IsResultNeeded(node)) {
1994 __ pushl(EAX); 1994 __ pushl(EAX);
1995 } 1995 }
1996 } 1996 }
1997 1997
1998 1998
1999 void CodeGenerator::HandleBackwardBranch( 1999 void CodeGenerator::HandleBackwardBranch(
2000 intptr_t loop_id, intptr_t token_index) { 2000 intptr_t loop_id, intptr_t token_pos) {
2001 // Use stack overflow check to eventually stop execution of loops. 2001 // Use stack overflow check to eventually stop execution of loops.
2002 // This is necessary only if a loop does not have calls. 2002 // This is necessary only if a loop does not have calls.
2003 __ cmpl(ESP, 2003 __ cmpl(ESP,
2004 Address::Absolute(Isolate::Current()->stack_limit_address())); 2004 Address::Absolute(Isolate::Current()->stack_limit_address()));
2005 Label no_stack_overflow; 2005 Label no_stack_overflow;
2006 __ j(ABOVE, &no_stack_overflow); 2006 __ j(ABOVE, &no_stack_overflow);
2007 GenerateCallRuntime(loop_id, 2007 GenerateCallRuntime(loop_id,
2008 token_index, 2008 token_pos,
2009 kStackOverflowRuntimeEntry); 2009 kStackOverflowRuntimeEntry);
2010 __ Bind(&no_stack_overflow); 2010 __ Bind(&no_stack_overflow);
2011 } 2011 }
2012 2012
2013 2013
2014 void CodeGenerator::VisitWhileNode(WhileNode* node) { 2014 void CodeGenerator::VisitWhileNode(WhileNode* node) {
2015 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); 2015 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
2016 SourceLabel* label = node->label(); 2016 SourceLabel* label = node->label();
2017 __ Bind(label->continue_label()); 2017 __ Bind(label->continue_label());
2018 node->condition()->Visit(this); 2018 node->condition()->Visit(this);
2019 GenerateConditionTypeCheck(node->id(), node->condition()->token_index()); 2019 GenerateConditionTypeCheck(node->id(), node->condition()->token_pos());
2020 __ popl(EAX); 2020 __ popl(EAX);
2021 __ LoadObject(EDX, bool_true); 2021 __ LoadObject(EDX, bool_true);
2022 __ cmpl(EAX, EDX); 2022 __ cmpl(EAX, EDX);
2023 __ j(NOT_EQUAL, label->break_label()); 2023 __ j(NOT_EQUAL, label->break_label());
2024 node->body()->Visit(this); 2024 node->body()->Visit(this);
2025 HandleBackwardBranch(node->id(), node->token_index()); 2025 HandleBackwardBranch(node->id(), node->token_pos());
2026 __ jmp(label->continue_label()); 2026 __ jmp(label->continue_label());
2027 __ Bind(label->break_label()); 2027 __ Bind(label->break_label());
2028 } 2028 }
2029 2029
2030 2030
2031 void CodeGenerator::VisitDoWhileNode(DoWhileNode* node) { 2031 void CodeGenerator::VisitDoWhileNode(DoWhileNode* node) {
2032 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); 2032 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
2033 SourceLabel* label = node->label(); 2033 SourceLabel* label = node->label();
2034 Label loop; 2034 Label loop;
2035 __ Bind(&loop); 2035 __ Bind(&loop);
2036 node->body()->Visit(this); 2036 node->body()->Visit(this);
2037 HandleBackwardBranch(node->id(), node->token_index()); 2037 HandleBackwardBranch(node->id(), node->token_pos());
2038 __ Bind(label->continue_label()); 2038 __ Bind(label->continue_label());
2039 node->condition()->Visit(this); 2039 node->condition()->Visit(this);
2040 GenerateConditionTypeCheck(node->id(), node->condition()->token_index()); 2040 GenerateConditionTypeCheck(node->id(), node->condition()->token_pos());
2041 __ popl(EAX); 2041 __ popl(EAX);
2042 __ LoadObject(EDX, bool_true); 2042 __ LoadObject(EDX, bool_true);
2043 __ cmpl(EAX, EDX); 2043 __ cmpl(EAX, EDX);
2044 __ j(EQUAL, &loop); 2044 __ j(EQUAL, &loop);
2045 __ Bind(label->break_label()); 2045 __ Bind(label->break_label());
2046 } 2046 }
2047 2047
2048 2048
2049 void CodeGenerator::VisitForNode(ForNode* node) { 2049 void CodeGenerator::VisitForNode(ForNode* node) {
2050 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); 2050 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
2051 node->initializer()->Visit(this); 2051 node->initializer()->Visit(this);
2052 SourceLabel* label = node->label(); 2052 SourceLabel* label = node->label();
2053 Label loop; 2053 Label loop;
2054 __ Bind(&loop); 2054 __ Bind(&loop);
2055 if (node->condition() != NULL) { 2055 if (node->condition() != NULL) {
2056 node->condition()->Visit(this); 2056 node->condition()->Visit(this);
2057 GenerateConditionTypeCheck(node->id(), node->condition()->token_index()); 2057 GenerateConditionTypeCheck(node->id(), node->condition()->token_pos());
2058 __ popl(EAX); 2058 __ popl(EAX);
2059 __ LoadObject(EDX, bool_true); 2059 __ LoadObject(EDX, bool_true);
2060 __ cmpl(EAX, EDX); 2060 __ cmpl(EAX, EDX);
2061 __ j(NOT_EQUAL, label->break_label()); 2061 __ j(NOT_EQUAL, label->break_label());
2062 } 2062 }
2063 node->body()->Visit(this); 2063 node->body()->Visit(this);
2064 HandleBackwardBranch(node->id(), node->token_index()); 2064 HandleBackwardBranch(node->id(), node->token_pos());
2065 __ Bind(label->continue_label()); 2065 __ Bind(label->continue_label());
2066 node->increment()->Visit(this); 2066 node->increment()->Visit(this);
2067 __ jmp(&loop); 2067 __ jmp(&loop);
2068 __ Bind(label->break_label()); 2068 __ Bind(label->break_label());
2069 } 2069 }
2070 2070
2071 2071
2072 void CodeGenerator::VisitJumpNode(JumpNode* node) { 2072 void CodeGenerator::VisitJumpNode(JumpNode* node) {
2073 SourceLabel* label = node->label(); 2073 SourceLabel* label = node->label();
2074 2074
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
2110 } else { 2110 } else {
2111 __ jmp(label->continue_label()); 2111 __ jmp(label->continue_label());
2112 } 2112 }
2113 } 2113 }
2114 2114
2115 2115
2116 void CodeGenerator::VisitConditionalExprNode(ConditionalExprNode* node) { 2116 void CodeGenerator::VisitConditionalExprNode(ConditionalExprNode* node) {
2117 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); 2117 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
2118 Label false_label, done; 2118 Label false_label, done;
2119 node->condition()->Visit(this); 2119 node->condition()->Visit(this);
2120 GenerateConditionTypeCheck(node->id(), node->condition()->token_index()); 2120 GenerateConditionTypeCheck(node->id(), node->condition()->token_pos());
2121 __ popl(EAX); 2121 __ popl(EAX);
2122 __ LoadObject(EDX, bool_true); 2122 __ LoadObject(EDX, bool_true);
2123 __ cmpl(EAX, EDX); 2123 __ cmpl(EAX, EDX);
2124 __ j(NOT_EQUAL, &false_label); 2124 __ j(NOT_EQUAL, &false_label);
2125 node->true_expr()->Visit(this); 2125 node->true_expr()->Visit(this);
2126 __ jmp(&done); 2126 __ jmp(&done);
2127 __ Bind(&false_label); 2127 __ Bind(&false_label);
2128 node->false_expr()->Visit(this); 2128 node->false_expr()->Visit(this);
2129 __ Bind(&done); 2129 __ Bind(&done);
2130 if (!IsResultNeeded(node)) { 2130 if (!IsResultNeeded(node)) {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
2170 __ Bind(&case_statements); 2170 __ Bind(&case_statements);
2171 node->statements()->Visit(this); 2171 node->statements()->Visit(this);
2172 __ Bind(&end_case); 2172 __ Bind(&end_case);
2173 } 2173 }
2174 2174
2175 2175
2176 void CodeGenerator::VisitIfNode(IfNode* node) { 2176 void CodeGenerator::VisitIfNode(IfNode* node) {
2177 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); 2177 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
2178 Label false_label; 2178 Label false_label;
2179 node->condition()->Visit(this); 2179 node->condition()->Visit(this);
2180 GenerateConditionTypeCheck(node->id(), node->condition()->token_index()); 2180 GenerateConditionTypeCheck(node->id(), node->condition()->token_pos());
2181 __ popl(EAX); 2181 __ popl(EAX);
2182 __ LoadObject(EDX, bool_true); 2182 __ LoadObject(EDX, bool_true);
2183 __ cmpl(EAX, EDX); 2183 __ cmpl(EAX, EDX);
2184 __ j(NOT_EQUAL, &false_label); 2184 __ j(NOT_EQUAL, &false_label);
2185 node->true_branch()->Visit(this); 2185 node->true_branch()->Visit(this);
2186 if (node->false_branch() != NULL) { 2186 if (node->false_branch() != NULL) {
2187 Label done; 2187 Label done;
2188 __ jmp(&done); 2188 __ jmp(&done);
2189 __ Bind(&false_label); 2189 __ Bind(&false_label);
2190 node->false_branch()->Visit(this); 2190 node->false_branch()->Visit(this);
2191 __ Bind(&done); 2191 __ Bind(&done);
2192 } else { 2192 } else {
2193 __ Bind(&false_label); 2193 __ Bind(&false_label);
2194 } 2194 }
2195 } 2195 }
2196 2196
2197 2197
2198 // Operators '&&' and '||' are not overloadabled, inline them. 2198 // Operators '&&' and '||' are not overloadabled, inline them.
2199 void CodeGenerator::GenerateLogicalAndOrOp(BinaryOpNode* node) { 2199 void CodeGenerator::GenerateLogicalAndOrOp(BinaryOpNode* node) {
2200 // Generate true if (left == true) op (right == true), otherwise generate 2200 // Generate true if (left == true) op (right == true), otherwise generate
2201 // false, with op being either || or &&. 2201 // false, with op being either || or &&.
2202 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); 2202 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
2203 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); 2203 const Bool& bool_false = Bool::ZoneHandle(Bool::False());
2204 Label load_false, done; 2204 Label load_false, done;
2205 node->left()->Visit(this); 2205 node->left()->Visit(this);
2206 GenerateConditionTypeCheck(node->id(), node->left()->token_index()); 2206 GenerateConditionTypeCheck(node->id(), node->left()->token_pos());
2207 __ popl(EAX); 2207 __ popl(EAX);
2208 __ LoadObject(EDX, bool_true); 2208 __ LoadObject(EDX, bool_true);
2209 __ cmpl(EAX, EDX); 2209 __ cmpl(EAX, EDX);
2210 if (node->kind() == Token::kAND) { 2210 if (node->kind() == Token::kAND) {
2211 __ j(NOT_EQUAL, &load_false); 2211 __ j(NOT_EQUAL, &load_false);
2212 } else { 2212 } else {
2213 ASSERT(node->kind() == Token::kOR); 2213 ASSERT(node->kind() == Token::kOR);
2214 __ j(EQUAL, &done); 2214 __ j(EQUAL, &done);
2215 } 2215 }
2216 node->right()->Visit(this); 2216 node->right()->Visit(this);
2217 GenerateConditionTypeCheck(node->id(), node->right()->token_index()); 2217 GenerateConditionTypeCheck(node->id(), node->right()->token_pos());
2218 __ popl(EAX); 2218 __ popl(EAX);
2219 __ LoadObject(EDX, bool_true); 2219 __ LoadObject(EDX, bool_true);
2220 __ cmpl(EAX, EDX); 2220 __ cmpl(EAX, EDX);
2221 __ j(EQUAL, &done); 2221 __ j(EQUAL, &done);
2222 __ Bind(&load_false); 2222 __ Bind(&load_false);
2223 __ LoadObject(EAX, bool_false); 2223 __ LoadObject(EAX, bool_false);
2224 __ Bind(&done); 2224 __ Bind(&done);
2225 if (IsResultNeeded(node)) { 2225 if (IsResultNeeded(node)) {
2226 __ pushl(EAX); 2226 __ pushl(EAX);
2227 } 2227 }
2228 } 2228 }
2229 2229
2230 2230
2231 // Expect receiver(left operand) and right operand on stack. 2231 // Expect receiver(left operand) and right operand on stack.
2232 // Return result in EAX. 2232 // Return result in EAX.
2233 void CodeGenerator::GenerateBinaryOperatorCall(intptr_t node_id, 2233 void CodeGenerator::GenerateBinaryOperatorCall(intptr_t node_id,
2234 intptr_t token_index, 2234 intptr_t token_pos,
2235 const char* name) { 2235 const char* name) {
2236 const String& operator_name = String::ZoneHandle(String::NewSymbol(name)); 2236 const String& operator_name = String::ZoneHandle(String::NewSymbol(name));
2237 const int kNumberOfArguments = 2; 2237 const int kNumberOfArguments = 2;
2238 const Array& kNoArgumentNames = Array::Handle(); 2238 const Array& kNoArgumentNames = Array::Handle();
2239 const int kNumArgumentsChecked = 2; 2239 const int kNumArgumentsChecked = 2;
2240 GenerateInstanceCall(node_id, 2240 GenerateInstanceCall(node_id,
2241 token_index, 2241 token_pos,
2242 operator_name, 2242 operator_name,
2243 kNumberOfArguments, 2243 kNumberOfArguments,
2244 kNoArgumentNames, 2244 kNoArgumentNames,
2245 kNumArgumentsChecked); 2245 kNumArgumentsChecked);
2246 } 2246 }
2247 2247
2248 2248
2249 void CodeGenerator::VisitBinaryOpNode(BinaryOpNode* node) { 2249 void CodeGenerator::VisitBinaryOpNode(BinaryOpNode* node) {
2250 if ((node->kind() == Token::kAND) || (node->kind() == Token::kOR)) { 2250 if ((node->kind() == Token::kAND) || (node->kind() == Token::kOR)) {
2251 // Operators "&&" and "||" cannot be overloaded, therefore inline them 2251 // Operators "&&" and "||" cannot be overloaded, therefore inline them
2252 // instead of calling the operator. 2252 // instead of calling the operator.
2253 GenerateLogicalAndOrOp(node); 2253 GenerateLogicalAndOrOp(node);
2254 return; 2254 return;
2255 } 2255 }
2256 node->left()->Visit(this); 2256 node->left()->Visit(this);
2257 node->right()->Visit(this); 2257 node->right()->Visit(this);
2258 MarkDeoptPoint(node->id(), node->token_index()); 2258 MarkDeoptPoint(node->id(), node->token_pos());
2259 GenerateBinaryOperatorCall(node->id(), node->token_index(), node->Name()); 2259 GenerateBinaryOperatorCall(node->id(), node->token_pos(), node->Name());
2260 if (IsResultNeeded(node)) { 2260 if (IsResultNeeded(node)) {
2261 __ pushl(EAX); 2261 __ pushl(EAX);
2262 } 2262 }
2263 } 2263 }
2264 2264
2265 2265
2266 void CodeGenerator::VisitStringConcatNode(StringConcatNode* node) { 2266 void CodeGenerator::VisitStringConcatNode(StringConcatNode* node) {
2267 const String& cls_name = String::Handle(String::NewSymbol("StringBase")); 2267 const String& cls_name = String::Handle(String::NewSymbol("StringBase"));
2268 const Library& core_lib = Library::Handle( 2268 const Library& core_lib = Library::Handle(
2269 Isolate::Current()->object_store()->core_library()); 2269 Isolate::Current()->object_store()->core_library());
(...skipping 29 matching lines...) Expand all
2299 interpolate_arg.Add(&literals); 2299 interpolate_arg.Add(&literals);
2300 const Array& kNoArgumentNames = Array::Handle(); 2300 const Array& kNoArgumentNames = Array::Handle();
2301 // Call the interpolation function. 2301 // Call the interpolation function.
2302 String& concatenated = String::ZoneHandle(); 2302 String& concatenated = String::ZoneHandle();
2303 concatenated ^= DartEntry::InvokeStatic(interpol_func, 2303 concatenated ^= DartEntry::InvokeStatic(interpol_func,
2304 interpolate_arg, 2304 interpolate_arg,
2305 kNoArgumentNames); 2305 kNoArgumentNames);
2306 if (concatenated.IsUnhandledException()) { 2306 if (concatenated.IsUnhandledException()) {
2307 // TODO(hausner): Shouldn't we generate a throw? 2307 // TODO(hausner): Shouldn't we generate a throw?
2308 // Then remove unused CodeGenerator::ErrorMsg(). 2308 // Then remove unused CodeGenerator::ErrorMsg().
2309 ErrorMsg(node->token_index(), 2309 ErrorMsg(node->token_pos(),
2310 "Exception thrown in CodeGenerator::VisitStringConcatNode"); 2310 "Exception thrown in CodeGenerator::VisitStringConcatNode");
2311 } 2311 }
2312 ASSERT(!concatenated.IsNull()); 2312 ASSERT(!concatenated.IsNull());
2313 concatenated = String::NewSymbol(concatenated); 2313 concatenated = String::NewSymbol(concatenated);
2314 2314
2315 __ LoadObject(EAX, concatenated); 2315 __ LoadObject(EAX, concatenated);
2316 __ pushl(EAX); 2316 __ pushl(EAX);
2317 return; 2317 return;
2318 } 2318 }
2319 2319
2320 // Could not concatenate at compile time, generate a call to 2320 // Could not concatenate at compile time, generate a call to
2321 // interpolation function. 2321 // interpolation function.
2322 ArgumentListNode* interpol_arg = new ArgumentListNode(node->token_index()); 2322 ArgumentListNode* interpol_arg = new ArgumentListNode(node->token_pos());
2323 interpol_arg->Add(node->values()); 2323 interpol_arg->Add(node->values());
2324 node->values()->Visit(this); 2324 node->values()->Visit(this);
2325 __ LoadObject(ECX, interpol_func); 2325 __ LoadObject(ECX, interpol_func);
2326 __ LoadObject(EDX, ArgumentsDescriptor(interpol_arg->length(), 2326 __ LoadObject(EDX, ArgumentsDescriptor(interpol_arg->length(),
2327 interpol_arg->names())); 2327 interpol_arg->names()));
2328 GenerateCall(node->token_index(), 2328 GenerateCall(node->token_pos(),
2329 &StubCode::CallStaticFunctionLabel(), 2329 &StubCode::CallStaticFunctionLabel(),
2330 PcDescriptors::kFuncCall); 2330 PcDescriptors::kFuncCall);
2331 __ addl(ESP, Immediate(interpol_arg->length() * kWordSize)); 2331 __ addl(ESP, Immediate(interpol_arg->length() * kWordSize));
2332 // Result is in EAX. 2332 // Result is in EAX.
2333 if (IsResultNeeded(node)) { 2333 if (IsResultNeeded(node)) {
2334 __ pushl(EAX); 2334 __ pushl(EAX);
2335 } 2335 }
2336 } 2336 }
2337 2337
2338 2338
2339 void CodeGenerator::VisitInstanceCallNode(InstanceCallNode* node) { 2339 void CodeGenerator::VisitInstanceCallNode(InstanceCallNode* node) {
2340 const int number_of_arguments = node->arguments()->length() + 1; 2340 const int number_of_arguments = node->arguments()->length() + 1;
2341 // Compute the receiver object and pass it as first argument to call. 2341 // Compute the receiver object and pass it as first argument to call.
2342 node->receiver()->Visit(this); 2342 node->receiver()->Visit(this);
2343 // Now compute rest of the arguments to the call. 2343 // Now compute rest of the arguments to the call.
2344 node->arguments()->Visit(this); 2344 node->arguments()->Visit(this);
2345 // Some method may be inlined using type feedback, therefore this may be a 2345 // Some method may be inlined using type feedback, therefore this may be a
2346 // deoptimization point. 2346 // deoptimization point.
2347 MarkDeoptPoint(node->id(), node->token_index()); 2347 MarkDeoptPoint(node->id(), node->token_pos());
2348 const int kNumArgumentsChecked = 1; 2348 const int kNumArgumentsChecked = 1;
2349 GenerateInstanceCall(node->id(), 2349 GenerateInstanceCall(node->id(),
2350 node->token_index(), 2350 node->token_pos(),
2351 node->function_name(), 2351 node->function_name(),
2352 number_of_arguments, 2352 number_of_arguments,
2353 node->arguments()->names(), 2353 node->arguments()->names(),
2354 kNumArgumentsChecked); 2354 kNumArgumentsChecked);
2355 // Result is in EAX. 2355 // Result is in EAX.
2356 if (IsResultNeeded(node)) { 2356 if (IsResultNeeded(node)) {
2357 __ pushl(EAX); 2357 __ pushl(EAX);
2358 } 2358 }
2359 } 2359 }
2360 2360
2361 2361
2362 void CodeGenerator::VisitStaticCallNode(StaticCallNode* node) { 2362 void CodeGenerator::VisitStaticCallNode(StaticCallNode* node) {
2363 node->arguments()->Visit(this); 2363 node->arguments()->Visit(this);
2364 __ LoadObject(ECX, node->function()); 2364 __ LoadObject(ECX, node->function());
2365 __ LoadObject(EDX, ArgumentsDescriptor(node->arguments()->length(), 2365 __ LoadObject(EDX, ArgumentsDescriptor(node->arguments()->length(),
2366 node->arguments()->names())); 2366 node->arguments()->names()));
2367 GenerateCall(node->token_index(), 2367 GenerateCall(node->token_pos(),
2368 &StubCode::CallStaticFunctionLabel(), 2368 &StubCode::CallStaticFunctionLabel(),
2369 PcDescriptors::kFuncCall); 2369 PcDescriptors::kFuncCall);
2370 __ addl(ESP, Immediate(node->arguments()->length() * kWordSize)); 2370 __ addl(ESP, Immediate(node->arguments()->length() * kWordSize));
2371 // Result is in EAX. 2371 // Result is in EAX.
2372 if (IsResultNeeded(node)) { 2372 if (IsResultNeeded(node)) {
2373 __ pushl(EAX); 2373 __ pushl(EAX);
2374 } 2374 }
2375 } 2375 }
2376 2376
2377 2377
2378 void CodeGenerator::VisitClosureCallNode(ClosureCallNode* node) { 2378 void CodeGenerator::VisitClosureCallNode(ClosureCallNode* node) {
2379 // The spec states that the closure is evaluated before the arguments. 2379 // The spec states that the closure is evaluated before the arguments.
2380 // Preserve the current context, since it will be overridden by the closure 2380 // Preserve the current context, since it will be overridden by the closure
2381 // context during the call. 2381 // context during the call.
2382 __ pushl(CTX); 2382 __ pushl(CTX);
2383 // Compute the closure object and pass it as first argument to the stub. 2383 // Compute the closure object and pass it as first argument to the stub.
2384 node->closure()->Visit(this); 2384 node->closure()->Visit(this);
2385 // Now compute the arguments to the call. 2385 // Now compute the arguments to the call.
2386 node->arguments()->Visit(this); 2386 node->arguments()->Visit(this);
2387 // Set up the number of arguments (excluding the closure) to the ClosureCall 2387 // Set up the number of arguments (excluding the closure) to the ClosureCall
2388 // stub which will setup the closure context and jump to the entrypoint of the 2388 // stub which will setup the closure context and jump to the entrypoint of the
2389 // closure function (the function will be compiled if it has not already been 2389 // closure function (the function will be compiled if it has not already been
2390 // compiled). 2390 // compiled).
2391 // NOTE: The stub accesses the closure before the parameter list. 2391 // NOTE: The stub accesses the closure before the parameter list.
2392 __ LoadObject(EDX, ArgumentsDescriptor(node->arguments()->length(), 2392 __ LoadObject(EDX, ArgumentsDescriptor(node->arguments()->length(),
2393 node->arguments()->names())); 2393 node->arguments()->names()));
2394 GenerateCall(node->token_index(), 2394 GenerateCall(node->token_pos(),
2395 &StubCode::CallClosureFunctionLabel(), 2395 &StubCode::CallClosureFunctionLabel(),
2396 PcDescriptors::kOther); 2396 PcDescriptors::kOther);
2397 __ addl(ESP, Immediate((node->arguments()->length() + 1) * kWordSize)); 2397 __ addl(ESP, Immediate((node->arguments()->length() + 1) * kWordSize));
2398 // Restore the context. 2398 // Restore the context.
2399 __ popl(CTX); 2399 __ popl(CTX);
2400 // Result is in EAX. 2400 // Result is in EAX.
2401 if (IsResultNeeded(node)) { 2401 if (IsResultNeeded(node)) {
2402 __ pushl(EAX); 2402 __ pushl(EAX);
2403 } 2403 }
2404 } 2404 }
2405 2405
2406 2406
2407 // Pushes either the instantiator or null. 2407 // Pushes either the instantiator or null.
2408 // Pushes the type arguments of the instantiator on the stack. 2408 // Pushes the type arguments of the instantiator on the stack.
2409 // Destroys EBX, ECX. 2409 // Destroys EBX, ECX.
2410 void CodeGenerator::GenerateInstantiatorTypeArguments(intptr_t token_index, 2410 void CodeGenerator::GenerateInstantiatorTypeArguments(intptr_t token_pos,
2411 bool push_instantiator) { 2411 bool push_instantiator) {
2412 if (push_instantiator) { 2412 if (push_instantiator) {
2413 const Immediate raw_null = 2413 const Immediate raw_null =
2414 Immediate(reinterpret_cast<intptr_t>(Object::null())); 2414 Immediate(reinterpret_cast<intptr_t>(Object::null()));
2415 __ pushl(raw_null); // Initial instantiator. 2415 __ pushl(raw_null); // Initial instantiator.
2416 } 2416 }
2417 const Class& instantiator_class = Class::Handle( 2417 const Class& instantiator_class = Class::Handle(
2418 parsed_function().function().owner()); 2418 parsed_function().function().owner());
2419 if (instantiator_class.NumTypeParameters() == 0) { 2419 if (instantiator_class.NumTypeParameters() == 0) {
2420 // The type arguments are compile time constants. 2420 // The type arguments are compile time constants.
2421 AbstractTypeArguments& type_arguments = AbstractTypeArguments::ZoneHandle(); 2421 AbstractTypeArguments& type_arguments = AbstractTypeArguments::ZoneHandle();
2422 // TODO(regis): Temporary type should be allocated in new gen heap. 2422 // TODO(regis): Temporary type should be allocated in new gen heap.
2423 Type& type = Type::Handle( 2423 Type& type = Type::Handle(
2424 Type::New(instantiator_class, type_arguments, token_index)); 2424 Type::New(instantiator_class, type_arguments, token_pos));
2425 type ^= ClassFinalizer::FinalizeType( 2425 type ^= ClassFinalizer::FinalizeType(
2426 instantiator_class, type, ClassFinalizer::kFinalizeWellFormed); 2426 instantiator_class, type, ClassFinalizer::kFinalizeWellFormed);
2427 type_arguments = type.arguments(); 2427 type_arguments = type.arguments();
2428 __ PushObject(type_arguments); 2428 __ PushObject(type_arguments);
2429 } else { 2429 } else {
2430 ASSERT(parsed_function().instantiator() != NULL); 2430 ASSERT(parsed_function().instantiator() != NULL);
2431 parsed_function().instantiator()->Visit(this); 2431 parsed_function().instantiator()->Visit(this);
2432 Function& outer_function = 2432 Function& outer_function =
2433 Function::Handle(parsed_function().function().raw()); 2433 Function::Handle(parsed_function().function().raw());
2434 while (outer_function.IsLocalFunction()) { 2434 while (outer_function.IsLocalFunction()) {
(...skipping 24 matching lines...) Expand all
2459 2459
2460 // Pushes the type arguments on the stack in preparation of an allocation call. 2460 // Pushes the type arguments on the stack in preparation of an allocation call.
2461 // If instantiate_type_arguments is true, the instantiated type arguments 2461 // If instantiate_type_arguments is true, the instantiated type arguments
2462 // are pushed on the stack (after an instantiation run time call, if necessary). 2462 // are pushed on the stack (after an instantiation run time call, if necessary).
2463 // If instantiate_type_arguments is false, the (possibly uninstantiated) type 2463 // If instantiate_type_arguments is false, the (possibly uninstantiated) type
2464 // arguments are pushed on the stack, as well as the type arguments of the 2464 // arguments are pushed on the stack, as well as the type arguments of the
2465 // instantiator (or the special kNoInstantiator Smi marker, if the type 2465 // instantiator (or the special kNoInstantiator Smi marker, if the type
2466 // arguments are instantiated). 2466 // arguments are instantiated).
2467 void CodeGenerator::GenerateTypeArguments( 2467 void CodeGenerator::GenerateTypeArguments(
2468 intptr_t node_id, 2468 intptr_t node_id,
2469 intptr_t token_index, 2469 intptr_t token_pos,
2470 const AbstractTypeArguments& type_arguments, 2470 const AbstractTypeArguments& type_arguments,
2471 bool instantiate_type_arguments) { 2471 bool instantiate_type_arguments) {
2472 const Immediate raw_null = 2472 const Immediate raw_null =
2473 Immediate(reinterpret_cast<intptr_t>(Object::null())); 2473 Immediate(reinterpret_cast<intptr_t>(Object::null()));
2474 if (type_arguments.IsNull() || type_arguments.IsInstantiated()) { 2474 if (type_arguments.IsNull() || type_arguments.IsInstantiated()) {
2475 // The type arguments are instantiated. 2475 // The type arguments are instantiated.
2476 __ PushObject(type_arguments); 2476 __ PushObject(type_arguments);
2477 if (!instantiate_type_arguments) { 2477 if (!instantiate_type_arguments) {
2478 // The type arguments of the instantiator are not needed, since the 2478 // The type arguments of the instantiator are not needed, since the
2479 // type arguments are instantiated. 2479 // type arguments are instantiated.
2480 __ pushl(Immediate(Smi::RawValue(StubCode::kNoInstantiator))); 2480 __ pushl(Immediate(Smi::RawValue(StubCode::kNoInstantiator)));
2481 } 2481 }
2482 } else { 2482 } else {
2483 // The type arguments are uninstantiated. 2483 // The type arguments are uninstantiated.
2484 const bool kPushInstantiator = false; 2484 const bool kPushInstantiator = false;
2485 GenerateInstantiatorTypeArguments(token_index, kPushInstantiator); 2485 GenerateInstantiatorTypeArguments(token_pos, kPushInstantiator);
2486 __ popl(EAX); // Pop instantiator. 2486 __ popl(EAX); // Pop instantiator.
2487 // EAX is the instantiator AbstractTypeArguments object (or null). 2487 // EAX is the instantiator AbstractTypeArguments object (or null).
2488 // If the instantiator is null and if the type argument vector 2488 // If the instantiator is null and if the type argument vector
2489 // instantiated from null becomes a vector of Dynamic, then use null as 2489 // instantiated from null becomes a vector of Dynamic, then use null as
2490 // the type arguments. 2490 // the type arguments.
2491 Label type_arguments_instantiated; 2491 Label type_arguments_instantiated;
2492 const intptr_t len = type_arguments.Length(); 2492 const intptr_t len = type_arguments.Length();
2493 if (type_arguments.IsRawInstantiatedRaw(len)) { 2493 if (type_arguments.IsRawInstantiatedRaw(len)) {
2494 __ cmpl(EAX, raw_null); 2494 __ cmpl(EAX, raw_null);
2495 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); 2495 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
(...skipping 11 matching lines...) Expand all
2507 Immediate(Smi::RawValue(len))); 2507 Immediate(Smi::RawValue(len)));
2508 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); 2508 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
2509 __ Bind(&type_arguments_uninstantiated); 2509 __ Bind(&type_arguments_uninstantiated);
2510 } 2510 }
2511 if (instantiate_type_arguments) { 2511 if (instantiate_type_arguments) {
2512 // A runtime call to instantiate the type arguments is required. 2512 // A runtime call to instantiate the type arguments is required.
2513 __ PushObject(Object::ZoneHandle()); // Make room for the result. 2513 __ PushObject(Object::ZoneHandle()); // Make room for the result.
2514 __ PushObject(type_arguments); 2514 __ PushObject(type_arguments);
2515 __ pushl(EAX); // Push instantiator type arguments. 2515 __ pushl(EAX); // Push instantiator type arguments.
2516 GenerateCallRuntime(node_id, 2516 GenerateCallRuntime(node_id,
2517 token_index, 2517 token_pos,
2518 kInstantiateTypeArgumentsRuntimeEntry); 2518 kInstantiateTypeArgumentsRuntimeEntry);
2519 __ popl(EAX); // Pop instantiator type arguments. 2519 __ popl(EAX); // Pop instantiator type arguments.
2520 __ popl(EAX); // Pop uninstantiated type arguments. 2520 __ popl(EAX); // Pop uninstantiated type arguments.
2521 __ popl(EAX); // Pop instantiated type arguments. 2521 __ popl(EAX); // Pop instantiated type arguments.
2522 __ Bind(&type_arguments_instantiated); 2522 __ Bind(&type_arguments_instantiated);
2523 __ pushl(EAX); // Instantiated type arguments. 2523 __ pushl(EAX); // Instantiated type arguments.
2524 } else { 2524 } else {
2525 // The allocation stub will instantiate the type arguments. 2525 // The allocation stub will instantiate the type arguments.
2526 __ PushObject(type_arguments); 2526 __ PushObject(type_arguments);
2527 __ pushl(EAX); // Instantiator type arguments. 2527 __ pushl(EAX); // Instantiator type arguments.
2528 Label type_arguments_pushed; 2528 Label type_arguments_pushed;
2529 __ jmp(&type_arguments_pushed, Assembler::kNearJump); 2529 __ jmp(&type_arguments_pushed, Assembler::kNearJump);
2530 2530
2531 __ Bind(&type_arguments_instantiated); 2531 __ Bind(&type_arguments_instantiated);
2532 __ pushl(EAX); // Instantiated type arguments. 2532 __ pushl(EAX); // Instantiated type arguments.
2533 __ pushl(Immediate(Smi::RawValue(StubCode::kNoInstantiator))); 2533 __ pushl(Immediate(Smi::RawValue(StubCode::kNoInstantiator)));
2534 __ Bind(&type_arguments_pushed); 2534 __ Bind(&type_arguments_pushed);
2535 } 2535 }
2536 } 2536 }
2537 } 2537 }
2538 2538
2539 2539
2540 void CodeGenerator::VisitConstructorCallNode(ConstructorCallNode* node) { 2540 void CodeGenerator::VisitConstructorCallNode(ConstructorCallNode* node) {
2541 if (node->constructor().IsFactory()) { 2541 if (node->constructor().IsFactory()) {
2542 const bool instantiate_type_arguments = true; // First argument to factory. 2542 const bool instantiate_type_arguments = true; // First argument to factory.
2543 GenerateTypeArguments(node->id(), 2543 GenerateTypeArguments(node->id(),
2544 node->token_index(), 2544 node->token_pos(),
2545 node->type_arguments(), 2545 node->type_arguments(),
2546 instantiate_type_arguments); 2546 instantiate_type_arguments);
2547 // The top of stack is an instantiated AbstractTypeArguments object 2547 // The top of stack is an instantiated AbstractTypeArguments object
2548 // (or null). 2548 // (or null).
2549 int num_args = node->arguments()->length() + 1; // +1 to include type args. 2549 int num_args = node->arguments()->length() + 1; // +1 to include type args.
2550 node->arguments()->Visit(this); 2550 node->arguments()->Visit(this);
2551 // Call the factory. 2551 // Call the factory.
2552 __ LoadObject(ECX, node->constructor()); 2552 __ LoadObject(ECX, node->constructor());
2553 __ LoadObject(EDX, ArgumentsDescriptor(num_args, 2553 __ LoadObject(EDX, ArgumentsDescriptor(num_args,
2554 node->arguments()->names())); 2554 node->arguments()->names()));
2555 GenerateCall(node->token_index(), 2555 GenerateCall(node->token_pos(),
2556 &StubCode::CallStaticFunctionLabel(), 2556 &StubCode::CallStaticFunctionLabel(),
2557 PcDescriptors::kFuncCall); 2557 PcDescriptors::kFuncCall);
2558 // Factory constructor returns object in EAX. 2558 // Factory constructor returns object in EAX.
2559 __ addl(ESP, Immediate(num_args * kWordSize)); 2559 __ addl(ESP, Immediate(num_args * kWordSize));
2560 if (IsResultNeeded(node)) { 2560 if (IsResultNeeded(node)) {
2561 __ pushl(EAX); 2561 __ pushl(EAX);
2562 } 2562 }
2563 return; 2563 return;
2564 } 2564 }
2565 2565
2566 const Class& cls = Class::ZoneHandle(node->constructor().owner()); 2566 const Class& cls = Class::ZoneHandle(node->constructor().owner());
2567 const bool requires_type_arguments = cls.HasTypeArguments(); 2567 const bool requires_type_arguments = cls.HasTypeArguments();
2568 const bool instantiate_type_arguments = false; // Done in stub or runtime. 2568 const bool instantiate_type_arguments = false; // Done in stub or runtime.
2569 if (requires_type_arguments) { 2569 if (requires_type_arguments) {
2570 GenerateTypeArguments(node->id(), 2570 GenerateTypeArguments(node->id(),
2571 node->token_index(), 2571 node->token_pos(),
2572 node->type_arguments(), 2572 node->type_arguments(),
2573 instantiate_type_arguments); 2573 instantiate_type_arguments);
2574 } 2574 }
2575 2575
2576 // If cls is parameterized, the type arguments and the instantiator's 2576 // If cls is parameterized, the type arguments and the instantiator's
2577 // type arguments are on the stack. 2577 // type arguments are on the stack.
2578 // In checked mode, if the type arguments are uninstantiated, they may need to 2578 // In checked mode, if the type arguments are uninstantiated, they may need to
2579 // be checked against declared bounds at run time. 2579 // be checked against declared bounds at run time.
2580 Error& malformed_error = Error::Handle(); 2580 Error& malformed_error = Error::Handle();
2581 if (FLAG_enable_type_checks && 2581 if (FLAG_enable_type_checks &&
2582 requires_type_arguments && 2582 requires_type_arguments &&
2583 !node->type_arguments().IsNull() && 2583 !node->type_arguments().IsNull() &&
2584 !node->type_arguments().IsInstantiated() && 2584 !node->type_arguments().IsInstantiated() &&
2585 !node->type_arguments().IsWithinBoundsOf(cls, 2585 !node->type_arguments().IsWithinBoundsOf(cls,
2586 node->type_arguments(), 2586 node->type_arguments(),
2587 &malformed_error)) { 2587 &malformed_error)) {
2588 // The uninstantiated type arguments cannot be verified to be within their 2588 // The uninstantiated type arguments cannot be verified to be within their
2589 // bounds at compile time, so verify them at runtime. 2589 // bounds at compile time, so verify them at runtime.
2590 // Although the type arguments may be uninstantiated at compile time, they 2590 // Although the type arguments may be uninstantiated at compile time, they
2591 // may represent the identity vector and may be replaced by the instantiated 2591 // may represent the identity vector and may be replaced by the instantiated
2592 // type arguments of the instantiator at run time. 2592 // type arguments of the instantiator at run time.
2593 __ popl(ECX); // Pop instantiator type arguments. 2593 __ popl(ECX); // Pop instantiator type arguments.
2594 __ popl(EAX); // Pop type arguments. 2594 __ popl(EAX); // Pop type arguments.
2595 2595
2596 // Push the result place holder initialized to NULL. 2596 // Push the result place holder initialized to NULL.
2597 __ PushObject(Object::ZoneHandle()); 2597 __ PushObject(Object::ZoneHandle());
2598 __ pushl(Immediate(Smi::RawValue(node->token_index()))); 2598 __ pushl(Immediate(Smi::RawValue(node->token_pos())));
2599 __ PushObject(cls); 2599 __ PushObject(cls);
2600 __ pushl(EAX); // Push type arguments. 2600 __ pushl(EAX); // Push type arguments.
2601 __ pushl(ECX); // Push instantiator type arguments. 2601 __ pushl(ECX); // Push instantiator type arguments.
2602 GenerateCallRuntime(node->id(), 2602 GenerateCallRuntime(node->id(),
2603 node->token_index(), 2603 node->token_pos(),
2604 kAllocateObjectWithBoundsCheckRuntimeEntry); 2604 kAllocateObjectWithBoundsCheckRuntimeEntry);
2605 __ popl(ECX); // Pop instantiator type arguments. 2605 __ popl(ECX); // Pop instantiator type arguments.
2606 __ popl(ECX); // Pop type arguments. 2606 __ popl(ECX); // Pop type arguments.
2607 __ popl(ECX); // Pop class. 2607 __ popl(ECX); // Pop class.
2608 __ popl(ECX); // Pop source location. 2608 __ popl(ECX); // Pop source location.
2609 __ popl(EAX); // Pop new instance. 2609 __ popl(EAX); // Pop new instance.
2610 } else { 2610 } else {
2611 const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls)); 2611 const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls));
2612 const ExternalLabel label(cls.ToCString(), stub.EntryPoint()); 2612 const ExternalLabel label(cls.ToCString(), stub.EntryPoint());
2613 GenerateCall(node->token_index(), &label, PcDescriptors::kOther); 2613 GenerateCall(node->token_pos(), &label, PcDescriptors::kOther);
2614 if (requires_type_arguments) { 2614 if (requires_type_arguments) {
2615 __ popl(ECX); // Pop instantiator type arguments. 2615 __ popl(ECX); // Pop instantiator type arguments.
2616 __ popl(ECX); // Pop type arguments. 2616 __ popl(ECX); // Pop type arguments.
2617 } 2617 }
2618 } 2618 }
2619 2619
2620 if (IsResultNeeded(node)) { 2620 if (IsResultNeeded(node)) {
2621 __ pushl(EAX); // Set up return value from allocate. 2621 __ pushl(EAX); // Set up return value from allocate.
2622 } 2622 }
2623 2623
2624 // First argument(this) for constructor call which follows. 2624 // First argument(this) for constructor call which follows.
2625 __ pushl(EAX); 2625 __ pushl(EAX);
2626 // Second argument is the implicit construction phase parameter. 2626 // Second argument is the implicit construction phase parameter.
2627 // Run both the constructor initializer list and the constructor body. 2627 // Run both the constructor initializer list and the constructor body.
2628 __ pushl(Immediate(Smi::RawValue(Function::kCtorPhaseAll))); 2628 __ pushl(Immediate(Smi::RawValue(Function::kCtorPhaseAll)));
2629 2629
2630 // Now setup rest of the arguments for the constructor call. 2630 // Now setup rest of the arguments for the constructor call.
2631 node->arguments()->Visit(this); 2631 node->arguments()->Visit(this);
2632 2632
2633 // Call the constructor. 2633 // Call the constructor.
2634 // +2 to include implicit receiver and phase arguments. 2634 // +2 to include implicit receiver and phase arguments.
2635 int num_args = node->arguments()->length() + 2; 2635 int num_args = node->arguments()->length() + 2;
2636 __ LoadObject(ECX, node->constructor()); 2636 __ LoadObject(ECX, node->constructor());
2637 __ LoadObject(EDX, ArgumentsDescriptor(num_args, node->arguments()->names())); 2637 __ LoadObject(EDX, ArgumentsDescriptor(num_args, node->arguments()->names()));
2638 GenerateCall(node->token_index(), 2638 GenerateCall(node->token_pos(),
2639 &StubCode::CallStaticFunctionLabel(), 2639 &StubCode::CallStaticFunctionLabel(),
2640 PcDescriptors::kFuncCall); 2640 PcDescriptors::kFuncCall);
2641 // Constructors do not return any value. 2641 // Constructors do not return any value.
2642 2642
2643 // Pop out all the other arguments on the stack. 2643 // Pop out all the other arguments on the stack.
2644 __ addl(ESP, Immediate(num_args * kWordSize)); 2644 __ addl(ESP, Immediate(num_args * kWordSize));
2645 } 2645 }
2646 2646
2647 2647
2648 // Expects receiver on stack, returns result in EAX.. 2648 // Expects receiver on stack, returns result in EAX..
2649 void CodeGenerator::GenerateInstanceGetterCall(intptr_t node_id, 2649 void CodeGenerator::GenerateInstanceGetterCall(intptr_t node_id,
2650 intptr_t token_index, 2650 intptr_t token_pos,
2651 const String& field_name) { 2651 const String& field_name) {
2652 const String& getter_name = 2652 const String& getter_name =
2653 String::ZoneHandle(Field::GetterSymbol(field_name)); 2653 String::ZoneHandle(Field::GetterSymbol(field_name));
2654 const int kNumberOfArguments = 1; 2654 const int kNumberOfArguments = 1;
2655 const Array& kNoArgumentNames = Array::Handle(); 2655 const Array& kNoArgumentNames = Array::Handle();
2656 const int kNumArgumentsChecked = 1; 2656 const int kNumArgumentsChecked = 1;
2657 GenerateInstanceCall(node_id, 2657 GenerateInstanceCall(node_id,
2658 token_index, 2658 token_pos,
2659 getter_name, 2659 getter_name,
2660 kNumberOfArguments, 2660 kNumberOfArguments,
2661 kNoArgumentNames, 2661 kNoArgumentNames,
2662 kNumArgumentsChecked); 2662 kNumArgumentsChecked);
2663 } 2663 }
2664 2664
2665 2665
2666 // Call to the instance getter. 2666 // Call to the instance getter.
2667 void CodeGenerator::VisitInstanceGetterNode(InstanceGetterNode* node) { 2667 void CodeGenerator::VisitInstanceGetterNode(InstanceGetterNode* node) {
2668 node->receiver()->Visit(this); 2668 node->receiver()->Visit(this);
2669 MarkDeoptPoint(node->id(), node->token_index()); 2669 MarkDeoptPoint(node->id(), node->token_pos());
2670 GenerateInstanceGetterCall(node->id(), 2670 GenerateInstanceGetterCall(node->id(),
2671 node->token_index(), 2671 node->token_pos(),
2672 node->field_name()); 2672 node->field_name());
2673 if (IsResultNeeded(node)) { 2673 if (IsResultNeeded(node)) {
2674 __ pushl(EAX); 2674 __ pushl(EAX);
2675 } 2675 }
2676 } 2676 }
2677 2677
2678 2678
2679 // Expects receiver and value on stack. 2679 // Expects receiver and value on stack.
2680 void CodeGenerator::GenerateInstanceSetterCall(intptr_t node_id, 2680 void CodeGenerator::GenerateInstanceSetterCall(intptr_t node_id,
2681 intptr_t token_index, 2681 intptr_t token_pos,
2682 const String& field_name) { 2682 const String& field_name) {
2683 const String& setter_name = 2683 const String& setter_name =
2684 String::ZoneHandle(Field::SetterSymbol(field_name)); 2684 String::ZoneHandle(Field::SetterSymbol(field_name));
2685 const int kNumberOfArguments = 2; // receiver + value. 2685 const int kNumberOfArguments = 2; // receiver + value.
2686 const Array& kNoArgumentNames = Array::Handle(); 2686 const Array& kNoArgumentNames = Array::Handle();
2687 const int kNumArgumentsChecked = 1; 2687 const int kNumArgumentsChecked = 1;
2688 GenerateInstanceCall(node_id, 2688 GenerateInstanceCall(node_id,
2689 token_index, 2689 token_pos,
2690 setter_name, 2690 setter_name,
2691 kNumberOfArguments, 2691 kNumberOfArguments,
2692 kNoArgumentNames, 2692 kNoArgumentNames,
2693 kNumArgumentsChecked); 2693 kNumArgumentsChecked);
2694 } 2694 }
2695 2695
2696 2696
2697 // The call to the instance setter implements the assignment to a field. 2697 // The call to the instance setter implements the assignment to a field.
2698 // The result of the assignment to a field is the value being stored. 2698 // The result of the assignment to a field is the value being stored.
2699 void CodeGenerator::VisitInstanceSetterNode(InstanceSetterNode* node) { 2699 void CodeGenerator::VisitInstanceSetterNode(InstanceSetterNode* node) {
2700 // Compute the receiver object and pass it as first argument to call. 2700 // Compute the receiver object and pass it as first argument to call.
2701 node->receiver()->Visit(this); 2701 node->receiver()->Visit(this);
2702 node->value()->Visit(this); 2702 node->value()->Visit(this);
2703 MarkDeoptPoint(node->id(), node->token_index()); 2703 MarkDeoptPoint(node->id(), node->token_pos());
2704 if (IsResultNeeded(node)) { 2704 if (IsResultNeeded(node)) {
2705 __ popl(EAX); // value. 2705 __ popl(EAX); // value.
2706 __ popl(EDX); // receiver. 2706 __ popl(EDX); // receiver.
2707 __ pushl(EAX); // Preserve value. 2707 __ pushl(EAX); // Preserve value.
2708 __ pushl(EDX); // arg0: receiver. 2708 __ pushl(EDX); // arg0: receiver.
2709 __ pushl(EAX); // arg1: value. 2709 __ pushl(EAX); // arg1: value.
2710 } 2710 }
2711 // It is not necessary to generate a type test of the assigned value here, 2711 // It is not necessary to generate a type test of the assigned value here,
2712 // because the setter will check the type of its incoming arguments. 2712 // because the setter will check the type of its incoming arguments.
2713 GenerateInstanceSetterCall(node->id(), 2713 GenerateInstanceSetterCall(node->id(),
2714 node->token_index(), 2714 node->token_pos(),
2715 node->field_name()); 2715 node->field_name());
2716 } 2716 }
2717 2717
2718 2718
2719 // Return result in EAX. 2719 // Return result in EAX.
2720 void CodeGenerator::GenerateStaticGetterCall(intptr_t token_index, 2720 void CodeGenerator::GenerateStaticGetterCall(intptr_t token_pos,
2721 const Class& field_class, 2721 const Class& field_class,
2722 const String& field_name) { 2722 const String& field_name) {
2723 const String& getter_name = String::Handle(Field::GetterName(field_name)); 2723 const String& getter_name = String::Handle(Field::GetterName(field_name));
2724 const Function& function = 2724 const Function& function =
2725 Function::ZoneHandle(field_class.LookupStaticFunction(getter_name)); 2725 Function::ZoneHandle(field_class.LookupStaticFunction(getter_name));
2726 ASSERT(!function.IsNull()); 2726 ASSERT(!function.IsNull());
2727 __ LoadObject(ECX, function); 2727 __ LoadObject(ECX, function);
2728 const int kNumberOfArguments = 0; 2728 const int kNumberOfArguments = 0;
2729 const Array& kNoArgumentNames = Array::Handle(); 2729 const Array& kNoArgumentNames = Array::Handle();
2730 __ LoadObject(EDX, ArgumentsDescriptor(kNumberOfArguments, kNoArgumentNames)); 2730 __ LoadObject(EDX, ArgumentsDescriptor(kNumberOfArguments, kNoArgumentNames));
2731 GenerateCall(token_index, 2731 GenerateCall(token_pos,
2732 &StubCode::CallStaticFunctionLabel(), 2732 &StubCode::CallStaticFunctionLabel(),
2733 PcDescriptors::kFuncCall); 2733 PcDescriptors::kFuncCall);
2734 // No arguments were pushed, hence nothing to pop. 2734 // No arguments were pushed, hence nothing to pop.
2735 } 2735 }
2736 2736
2737 2737
2738 // Call to static getter. 2738 // Call to static getter.
2739 void CodeGenerator::VisitStaticGetterNode(StaticGetterNode* node) { 2739 void CodeGenerator::VisitStaticGetterNode(StaticGetterNode* node) {
2740 GenerateStaticGetterCall(node->token_index(), 2740 GenerateStaticGetterCall(node->token_pos(),
2741 node->cls(), 2741 node->cls(),
2742 node->field_name()); 2742 node->field_name());
2743 // Result is in EAX. 2743 // Result is in EAX.
2744 if (IsResultNeeded(node)) { 2744 if (IsResultNeeded(node)) {
2745 __ pushl(EAX); 2745 __ pushl(EAX);
2746 } 2746 }
2747 } 2747 }
2748 2748
2749 2749
2750 // Expects value on stack. 2750 // Expects value on stack.
2751 void CodeGenerator::GenerateStaticSetterCall(intptr_t token_index, 2751 void CodeGenerator::GenerateStaticSetterCall(intptr_t token_pos,
2752 const Class& field_class, 2752 const Class& field_class,
2753 const String& field_name) { 2753 const String& field_name) {
2754 const String& setter_name = String::Handle(Field::SetterName(field_name)); 2754 const String& setter_name = String::Handle(Field::SetterName(field_name));
2755 const Function& function = 2755 const Function& function =
2756 Function::ZoneHandle(field_class.LookupStaticFunction(setter_name)); 2756 Function::ZoneHandle(field_class.LookupStaticFunction(setter_name));
2757 ASSERT(!function.IsNull()); 2757 ASSERT(!function.IsNull());
2758 __ LoadObject(ECX, function); 2758 __ LoadObject(ECX, function);
2759 const int kNumberOfArguments = 1; // value. 2759 const int kNumberOfArguments = 1; // value.
2760 const Array& kNoArgumentNames = Array::Handle(); 2760 const Array& kNoArgumentNames = Array::Handle();
2761 __ LoadObject(EDX, ArgumentsDescriptor(kNumberOfArguments, kNoArgumentNames)); 2761 __ LoadObject(EDX, ArgumentsDescriptor(kNumberOfArguments, kNoArgumentNames));
2762 GenerateCall(token_index, 2762 GenerateCall(token_pos,
2763 &StubCode::CallStaticFunctionLabel(), 2763 &StubCode::CallStaticFunctionLabel(),
2764 PcDescriptors::kFuncCall); 2764 PcDescriptors::kFuncCall);
2765 __ addl(ESP, Immediate(kNumberOfArguments * kWordSize)); 2765 __ addl(ESP, Immediate(kNumberOfArguments * kWordSize));
2766 } 2766 }
2767 2767
2768 2768
2769 // The call to static setter implements assignment to a static field. 2769 // The call to static setter implements assignment to a static field.
2770 // The result of the assignment is the value being stored. 2770 // The result of the assignment is the value being stored.
2771 void CodeGenerator::VisitStaticSetterNode(StaticSetterNode* node) { 2771 void CodeGenerator::VisitStaticSetterNode(StaticSetterNode* node) {
2772 node->value()->Visit(this); 2772 node->value()->Visit(this);
2773 if (IsResultNeeded(node)) { 2773 if (IsResultNeeded(node)) {
2774 // Preserve the original value when returning from setter. 2774 // Preserve the original value when returning from setter.
2775 __ movl(EAX, Address(ESP, 0)); 2775 __ movl(EAX, Address(ESP, 0));
2776 __ pushl(EAX); // arg0: value. 2776 __ pushl(EAX); // arg0: value.
2777 } 2777 }
2778 // It is not necessary to generate a type test of the assigned value here, 2778 // It is not necessary to generate a type test of the assigned value here,
2779 // because the setter will check the type of its incoming arguments. 2779 // because the setter will check the type of its incoming arguments.
2780 GenerateStaticSetterCall(node->token_index(), 2780 GenerateStaticSetterCall(node->token_pos(),
2781 node->cls(), 2781 node->cls(),
2782 node->field_name()); 2782 node->field_name());
2783 } 2783 }
2784 2784
2785 2785
2786 void CodeGenerator::VisitNativeBodyNode(NativeBodyNode* node) { 2786 void CodeGenerator::VisitNativeBodyNode(NativeBodyNode* node) {
2787 intptr_t argument_count = node->argument_count(); 2787 intptr_t argument_count = node->argument_count();
2788 if (node->is_native_instance_closure()) { 2788 if (node->is_native_instance_closure()) {
2789 argument_count += 1; 2789 argument_count += 1;
2790 } 2790 }
2791 2791
2792 // Push the result place holder initialized to NULL. 2792 // Push the result place holder initialized to NULL.
2793 __ PushObject(Object::ZoneHandle()); 2793 __ PushObject(Object::ZoneHandle());
2794 // Pass a pointer to the first argument in EAX. 2794 // Pass a pointer to the first argument in EAX.
2795 if (!node->has_optional_parameters() && !node->is_native_instance_closure()) { 2795 if (!node->has_optional_parameters() && !node->is_native_instance_closure()) {
2796 __ leal(EAX, Address(EBP, (1 + argument_count) * kWordSize)); 2796 __ leal(EAX, Address(EBP, (1 + argument_count) * kWordSize));
2797 } else { 2797 } else {
2798 __ leal(EAX, 2798 __ leal(EAX,
2799 Address(EBP, ParsedFunction::kFirstLocalSlotIndex * kWordSize)); 2799 Address(EBP, ParsedFunction::kFirstLocalSlotIndex * kWordSize));
2800 } 2800 }
2801 __ movl(ECX, Immediate(reinterpret_cast<uword>(node->native_c_function()))); 2801 __ movl(ECX, Immediate(reinterpret_cast<uword>(node->native_c_function())));
2802 __ movl(EDX, Immediate(argument_count)); 2802 __ movl(EDX, Immediate(argument_count));
2803 GenerateCall(node->token_index(), 2803 GenerateCall(node->token_pos(),
2804 &StubCode::CallNativeCFunctionLabel(), 2804 &StubCode::CallNativeCFunctionLabel(),
2805 PcDescriptors::kOther); 2805 PcDescriptors::kOther);
2806 // Result is on the stack. 2806 // Result is on the stack.
2807 if (!IsResultNeeded(node)) { 2807 if (!IsResultNeeded(node)) {
2808 __ popl(EAX); 2808 __ popl(EAX);
2809 } 2809 }
2810 } 2810 }
2811 2811
2812 2812
2813 void CodeGenerator::VisitCatchClauseNode(CatchClauseNode* node) { 2813 void CodeGenerator::VisitCatchClauseNode(CatchClauseNode* node) {
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
2886 node->finally_block()->Visit(this); 2886 node->finally_block()->Visit(this);
2887 } 2887 }
2888 } 2888 }
2889 2889
2890 2890
2891 void CodeGenerator::VisitThrowNode(ThrowNode* node) { 2891 void CodeGenerator::VisitThrowNode(ThrowNode* node) {
2892 node->exception()->Visit(this); 2892 node->exception()->Visit(this);
2893 // Exception object is on TOS. 2893 // Exception object is on TOS.
2894 if (node->stacktrace() != NULL) { 2894 if (node->stacktrace() != NULL) {
2895 node->stacktrace()->Visit(this); 2895 node->stacktrace()->Visit(this);
2896 GenerateCallRuntime(node->id(), node->token_index(), kReThrowRuntimeEntry); 2896 GenerateCallRuntime(node->id(), node->token_pos(), kReThrowRuntimeEntry);
2897 } else { 2897 } else {
2898 GenerateCallRuntime(node->id(), node->token_index(), kThrowRuntimeEntry); 2898 GenerateCallRuntime(node->id(), node->token_pos(), kThrowRuntimeEntry);
2899 } 2899 }
2900 // We should never return here. 2900 // We should never return here.
2901 __ int3(); 2901 __ int3();
2902 } 2902 }
2903 2903
2904 2904
2905 void CodeGenerator::VisitInlinedFinallyNode(InlinedFinallyNode* node) { 2905 void CodeGenerator::VisitInlinedFinallyNode(InlinedFinallyNode* node) {
2906 int try_index = state()->try_index(); 2906 int try_index = state()->try_index();
2907 if (try_index >= 0) { 2907 if (try_index >= 0) {
2908 // We are about to generate code for an inlined finally block. Exceptions 2908 // We are about to generate code for an inlined finally block. Exceptions
2909 // thrown in this block of code should be treated as though they are 2909 // thrown in this block of code should be treated as though they are
2910 // thrown not from the current try block but the outer try block if any. 2910 // thrown not from the current try block but the outer try block if any.
2911 // the code generator state. 2911 // the code generator state.
2912 state()->set_try_index((try_index - 1)); 2912 state()->set_try_index((try_index - 1));
2913 } 2913 }
2914 2914
2915 // Restore CTX from local variable ':saved_context'. 2915 // Restore CTX from local variable ':saved_context'.
2916 GenerateLoadVariable(CTX, node->context_var()); 2916 GenerateLoadVariable(CTX, node->context_var());
2917 node->finally_block()->Visit(this); 2917 node->finally_block()->Visit(this);
2918 2918
2919 if (try_index >= 0) { 2919 if (try_index >= 0) {
2920 state()->set_try_index(try_index); 2920 state()->set_try_index(try_index);
2921 } 2921 }
2922 } 2922 }
2923 2923
2924 2924
2925 void CodeGenerator::GenerateCall(intptr_t token_index, 2925 void CodeGenerator::GenerateCall(intptr_t token_pos,
2926 const ExternalLabel* ext_label, 2926 const ExternalLabel* ext_label,
2927 PcDescriptors::Kind desc_kind) { 2927 PcDescriptors::Kind desc_kind) {
2928 __ call(ext_label); 2928 __ call(ext_label);
2929 AddCurrentDescriptor(desc_kind, AstNode::kNoId, token_index); 2929 AddCurrentDescriptor(desc_kind, AstNode::kNoId, token_pos);
2930 } 2930 }
2931 2931
2932 2932
2933 void CodeGenerator::GenerateCallRuntime(intptr_t node_id, 2933 void CodeGenerator::GenerateCallRuntime(intptr_t node_id,
2934 intptr_t token_index, 2934 intptr_t token_pos,
2935 const RuntimeEntry& entry) { 2935 const RuntimeEntry& entry) {
2936 __ CallRuntime(entry); 2936 __ CallRuntime(entry);
2937 AddCurrentDescriptor(PcDescriptors::kOther, node_id, token_index); 2937 AddCurrentDescriptor(PcDescriptors::kOther, node_id, token_pos);
2938 } 2938 }
2939 2939
2940 2940
2941 void CodeGenerator::MarkDeoptPoint(intptr_t node_id, 2941 void CodeGenerator::MarkDeoptPoint(intptr_t node_id,
2942 intptr_t token_index) { 2942 intptr_t token_pos) {
2943 ASSERT(node_id != AstNode::kNoId); 2943 ASSERT(node_id != AstNode::kNoId);
2944 AddCurrentDescriptor(PcDescriptors::kDeopt, node_id, token_index); 2944 AddCurrentDescriptor(PcDescriptors::kDeopt, node_id, token_pos);
2945 } 2945 }
2946 2946
2947 2947
2948 // Uses current pc position and try-index. 2948 // Uses current pc position and try-index.
2949 void CodeGenerator::AddCurrentDescriptor(PcDescriptors::Kind kind, 2949 void CodeGenerator::AddCurrentDescriptor(PcDescriptors::Kind kind,
2950 intptr_t node_id, 2950 intptr_t node_id,
2951 intptr_t token_index) { 2951 intptr_t token_pos) {
2952 pc_descriptors_list_->AddDescriptor(kind, 2952 pc_descriptors_list_->AddDescriptor(kind,
2953 assembler_->CodeSize(), 2953 assembler_->CodeSize(),
2954 node_id, 2954 node_id,
2955 token_index, 2955 token_pos,
2956 state()->try_index()); 2956 state()->try_index());
2957 } 2957 }
2958 2958
2959 2959
2960 void CodeGenerator::ErrorMsg(intptr_t token_index, const char* format, ...) { 2960 void CodeGenerator::ErrorMsg(intptr_t token_pos, const char* format, ...) {
2961 va_list args; 2961 va_list args;
2962 va_start(args, format); 2962 va_start(args, format);
2963 const Class& cls = Class::Handle(parsed_function_.function().owner()); 2963 const Class& cls = Class::Handle(parsed_function_.function().owner());
2964 const Script& script = Script::Handle(cls.script()); 2964 const Script& script = Script::Handle(cls.script());
2965 const Error& error = Error::Handle( 2965 const Error& error = Error::Handle(
2966 Parser::FormatError(script, token_index, "Error", format, args)); 2966 Parser::FormatError(script, token_pos, "Error", format, args));
2967 va_end(args); 2967 va_end(args);
2968 Isolate::Current()->long_jump_base()->Jump(1, error); 2968 Isolate::Current()->long_jump_base()->Jump(1, error);
2969 UNREACHABLE(); 2969 UNREACHABLE();
2970 } 2970 }
2971 2971
2972 } // namespace dart 2972 } // namespace dart
2973 2973
2974 #endif // defined TARGET_ARCH_IA32 2974 #endif // defined TARGET_ARCH_IA32
OLDNEW
« no previous file with comments | « vm/class_finalizer.cc ('k') | vm/compiler.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698