OLD | NEW |
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/flow_graph_compiler.h" | 8 #include "vm/flow_graph_compiler.h" |
9 | 9 |
10 #include "lib/error.h" | 10 #include "lib/error.h" |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 intptr_t token_index, | 99 intptr_t token_index, |
100 intptr_t try_index, | 100 intptr_t try_index, |
101 const RuntimeEntry& entry) { | 101 const RuntimeEntry& entry) { |
102 __ CallRuntime(entry); | 102 __ CallRuntime(entry); |
103 AddCurrentDescriptor(PcDescriptors::kOther, cid, token_index, try_index); | 103 AddCurrentDescriptor(PcDescriptors::kOther, cid, token_index, try_index); |
104 } | 104 } |
105 | 105 |
106 | 106 |
107 void FlowGraphCompiler::CopyParameters() { | 107 void FlowGraphCompiler::CopyParameters() { |
108 const Function& function = parsed_function().function(); | 108 const Function& function = parsed_function().function(); |
| 109 const bool is_native_instance_closure = |
| 110 function.is_native() && function.IsImplicitInstanceClosureFunction(); |
109 LocalScope* scope = parsed_function().node_sequence()->scope(); | 111 LocalScope* scope = parsed_function().node_sequence()->scope(); |
110 const int num_fixed_params = function.num_fixed_parameters(); | 112 const int num_fixed_params = function.num_fixed_parameters(); |
111 const int num_opt_params = function.num_optional_parameters(); | 113 const int num_opt_params = function.num_optional_parameters(); |
112 ASSERT(parsed_function().first_parameter_index() == | 114 ASSERT(parsed_function().first_parameter_index() == |
113 ParsedFunction::kFirstLocalSlotIndex); | 115 ParsedFunction::kFirstLocalSlotIndex); |
114 // Copy positional arguments. | 116 // Copy positional arguments. |
115 // Check that no fewer than num_fixed_params positional arguments are passed | 117 // Check that no fewer than num_fixed_params positional arguments are passed |
116 // in and that no more than num_params arguments are passed in. | 118 // in and that no more than num_params arguments are passed in. |
117 // Passed argument i at fp[1 + argc - i] | 119 // Passed argument i at fp[1 + argc - i] |
118 // copied to fp[ParsedFunction::kFirstLocalSlotIndex - i]. | 120 // copied to fp[ParsedFunction::kFirstLocalSlotIndex - i]. |
119 const int num_params = num_fixed_params + num_opt_params; | 121 const int num_params = num_fixed_params + num_opt_params; |
120 | 122 |
121 // Total number of args is the first Smi in args descriptor array (EDX). | 123 // Total number of args is the first Smi in args descriptor array (EDX). |
122 __ movl(EBX, FieldAddress(EDX, Array::data_offset())); | 124 __ movl(EBX, FieldAddress(EDX, Array::data_offset())); |
123 // Check that num_args <= num_params. | 125 // Check that num_args <= num_params. |
124 Label wrong_num_arguments; | 126 Label wrong_num_arguments; |
125 __ cmpl(EBX, Immediate(Smi::RawValue(num_params))); | 127 __ cmpl(EBX, Immediate(Smi::RawValue(num_params))); |
126 __ j(GREATER, &wrong_num_arguments); | 128 __ j(GREATER, &wrong_num_arguments); |
127 // Number of positional args is the second Smi in descriptor array (EDX). | 129 // Number of positional args is the second Smi in descriptor array (EDX). |
128 __ movl(ECX, FieldAddress(EDX, Array::data_offset() + (1 * kWordSize))); | 130 __ movl(ECX, FieldAddress(EDX, Array::data_offset() + (1 * kWordSize))); |
129 // Check that num_pos_args >= num_fixed_params. | 131 // Check that num_pos_args >= num_fixed_params. |
130 __ cmpl(ECX, Immediate(Smi::RawValue(num_fixed_params))); | 132 __ cmpl(ECX, Immediate(Smi::RawValue(num_fixed_params))); |
131 __ j(LESS, &wrong_num_arguments); | 133 __ j(LESS, &wrong_num_arguments); |
132 // Since EBX and ECX are Smi, use TIMES_2 instead of TIMES_4. | 134 // Since EBX and ECX are Smi, use TIMES_2 instead of TIMES_4. |
133 // Let EBX point to the last passed positional argument, i.e. to | 135 // Let EBX point to the last passed positional argument, i.e. to |
134 // fp[1 + num_args - (num_pos_args - 1)]. | 136 // fp[1 + num_args - (num_pos_args - 1)]. |
135 __ subl(EBX, ECX); | 137 __ subl(EBX, ECX); |
136 __ leal(EBX, Address(EBP, EBX, TIMES_2, 2 * kWordSize)); | 138 __ leal(EBX, Address(EBP, EBX, TIMES_2, 2 * kWordSize)); |
| 139 |
137 // Let EDI point to the last copied positional argument, i.e. to | 140 // Let EDI point to the last copied positional argument, i.e. to |
138 // fp[ParsedFunction::kFirstLocalSlotIndex - (num_pos_args - 1)]. | 141 // fp[ParsedFunction::kFirstLocalSlotIndex - (num_pos_args - 1)]. |
139 const int index = ParsedFunction::kFirstLocalSlotIndex + 1; | 142 int implicit_this_param_pos = is_native_instance_closure ? -1 : 0; |
| 143 const int index = |
| 144 ParsedFunction::kFirstLocalSlotIndex + 1 + implicit_this_param_pos; |
| 145 // First copy captured receiver if function is an implicit native closure. |
| 146 if (is_native_instance_closure) { |
| 147 __ movl(EAX, FieldAddress(CTX, Context::variable_offset(0))); |
| 148 __ movl(Address(EBP, (index * kWordSize)), EAX); |
| 149 } |
140 __ leal(EDI, Address(EBP, (index * kWordSize))); | 150 __ leal(EDI, Address(EBP, (index * kWordSize))); |
141 __ subl(EDI, ECX); // ECX is a Smi, subtract twice for TIMES_4 scaling. | 151 __ subl(EDI, ECX); // ECX is a Smi, subtract twice for TIMES_4 scaling. |
142 __ subl(EDI, ECX); | 152 __ subl(EDI, ECX); |
143 __ SmiUntag(ECX); | 153 __ SmiUntag(ECX); |
144 Label loop, loop_condition; | 154 Label loop, loop_condition; |
145 __ jmp(&loop_condition, Assembler::kNearJump); | 155 __ jmp(&loop_condition, Assembler::kNearJump); |
146 // We do not use the final allocation index of the variable here, i.e. | 156 // We do not use the final allocation index of the variable here, i.e. |
147 // scope->VariableAt(i)->index(), because captured variables still need | 157 // scope->VariableAt(i)->index(), because captured variables still need |
148 // to be copied to the context that is not yet allocated. | 158 // to be copied to the context that is not yet allocated. |
149 const Address argument_addr(EBX, ECX, TIMES_4, 0); | 159 const Address argument_addr(EBX, ECX, TIMES_4, 0); |
150 const Address copy_addr(EDI, ECX, TIMES_4, 0); | 160 const Address copy_addr(EDI, ECX, TIMES_4, 0); |
151 __ Bind(&loop); | 161 __ Bind(&loop); |
152 __ movl(EAX, argument_addr); | 162 __ movl(EAX, argument_addr); |
153 __ movl(copy_addr, EAX); | 163 __ movl(copy_addr, EAX); |
154 __ Bind(&loop_condition); | 164 __ Bind(&loop_condition); |
155 __ decl(ECX); | 165 __ decl(ECX); |
156 __ j(POSITIVE, &loop, Assembler::kNearJump); | 166 __ j(POSITIVE, &loop, Assembler::kNearJump); |
157 | 167 |
158 // Copy or initialize optional named arguments. | 168 // Copy or initialize optional named arguments. |
159 ASSERT(num_opt_params > 0); // Or we would not have to copy arguments. | 169 Label all_arguments_processed; |
160 // Start by alphabetically sorting the names of the optional parameters. | |
161 LocalVariable** opt_param = new LocalVariable*[num_opt_params]; | |
162 int* opt_param_position = new int[num_opt_params]; | |
163 for (int pos = num_fixed_params; pos < num_params; pos++) { | |
164 LocalVariable* parameter = scope->VariableAt(pos); | |
165 const String& opt_param_name = parameter->name(); | |
166 int i = pos - num_fixed_params; | |
167 while (--i >= 0) { | |
168 LocalVariable* param_i = opt_param[i]; | |
169 const intptr_t result = opt_param_name.CompareTo(param_i->name()); | |
170 ASSERT(result != 0); | |
171 if (result > 0) break; | |
172 opt_param[i + 1] = opt_param[i]; | |
173 opt_param_position[i + 1] = opt_param_position[i]; | |
174 } | |
175 opt_param[i + 1] = parameter; | |
176 opt_param_position[i + 1] = pos; | |
177 } | |
178 // Generate code handling each optional parameter in alphabetical order. | |
179 // Total number of args is the first Smi in args descriptor array (EDX). | |
180 __ movl(EBX, FieldAddress(EDX, Array::data_offset())); | |
181 // Number of positional args is the second Smi in descriptor array (EDX). | |
182 __ movl(ECX, FieldAddress(EDX, Array::data_offset() + (1 * kWordSize))); | |
183 __ SmiUntag(ECX); | |
184 // Let EBX point to the first passed argument, i.e. to fp[1 + argc - 0]. | |
185 __ leal(EBX, Address(EBP, EBX, TIMES_2, kWordSize)); // EBX is Smi. | |
186 // Let EDI point to the name/pos pair of the first named argument. | |
187 __ leal(EDI, FieldAddress(EDX, Array::data_offset() + (2 * kWordSize))); | |
188 for (int i = 0; i < num_opt_params; i++) { | |
189 // Handle this optional parameter only if k or fewer positional arguments | |
190 // have been passed, where k is the position of this optional parameter in | |
191 // the formal parameter list. | |
192 Label load_default_value, assign_optional_parameter, next_parameter; | |
193 const int param_pos = opt_param_position[i]; | |
194 __ cmpl(ECX, Immediate(param_pos)); | |
195 __ j(GREATER, &next_parameter, Assembler::kNearJump); | |
196 // Check if this named parameter was passed in. | |
197 __ movl(EAX, Address(EDI, 0)); // Load EAX with the name of the argument. | |
198 __ CompareObject(EAX, opt_param[i]->name()); | |
199 __ j(NOT_EQUAL, &load_default_value, Assembler::kNearJump); | |
200 // Load EAX with passed-in argument at provided arg_pos, i.e. at | |
201 // fp[1 + argc - arg_pos]. | |
202 __ movl(EAX, Address(EDI, kWordSize)); // EAX is arg_pos as Smi. | |
203 __ addl(EDI, Immediate(2 * kWordSize)); // Point to next name/pos pair. | |
204 __ negl(EAX); | |
205 Address argument_addr(EBX, EAX, TIMES_2, 0); // EAX is a negative Smi. | |
206 __ movl(EAX, argument_addr); | |
207 __ jmp(&assign_optional_parameter, Assembler::kNearJump); | |
208 __ Bind(&load_default_value); | |
209 // Load EAX with default argument at pos. | |
210 const Object& value = Object::ZoneHandle( | |
211 parsed_function().default_parameter_values().At( | |
212 param_pos - num_fixed_params)); | |
213 __ LoadObject(EAX, value); | |
214 __ Bind(&assign_optional_parameter); | |
215 // Assign EAX to fp[ParsedFunction::kFirstLocalSlotIndex - param_pos]. | |
216 // We do not use the final allocation index of the variable here, i.e. | |
217 // scope->VariableAt(i)->index(), because captured variables still need | |
218 // to be copied to the context that is not yet allocated. | |
219 const Address param_addr( | |
220 EBP, (ParsedFunction::kFirstLocalSlotIndex - param_pos) * kWordSize); | |
221 __ movl(param_addr, EAX); | |
222 __ Bind(&next_parameter); | |
223 } | |
224 delete[] opt_param; | |
225 delete[] opt_param_position; | |
226 // Check that EDI now points to the null terminator in the array descriptor. | |
227 const Immediate raw_null = | 170 const Immediate raw_null = |
228 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 171 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
229 Label all_arguments_processed; | 172 if (num_opt_params > 0) { |
230 __ cmpl(Address(EDI, 0), raw_null); | 173 // Start by alphabetically sorting the names of the optional parameters. |
231 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); | 174 LocalVariable** opt_param = new LocalVariable*[num_opt_params]; |
| 175 int* opt_param_position = new int[num_opt_params]; |
| 176 for (int pos = num_fixed_params; pos < num_params; pos++) { |
| 177 LocalVariable* parameter = scope->VariableAt(pos); |
| 178 const String& opt_param_name = parameter->name(); |
| 179 int i = pos - num_fixed_params; |
| 180 while (--i >= 0) { |
| 181 LocalVariable* param_i = opt_param[i]; |
| 182 const intptr_t result = opt_param_name.CompareTo(param_i->name()); |
| 183 ASSERT(result != 0); |
| 184 if (result > 0) break; |
| 185 opt_param[i + 1] = opt_param[i]; |
| 186 opt_param_position[i + 1] = opt_param_position[i]; |
| 187 } |
| 188 opt_param[i + 1] = parameter; |
| 189 opt_param_position[i + 1] = pos; |
| 190 } |
| 191 // Generate code handling each optional parameter in alphabetical order. |
| 192 // Total number of args is the first Smi in args descriptor array (EDX). |
| 193 __ movl(EBX, FieldAddress(EDX, Array::data_offset())); |
| 194 // Number of positional args is the second Smi in descriptor array (EDX). |
| 195 __ movl(ECX, FieldAddress(EDX, Array::data_offset() + (1 * kWordSize))); |
| 196 __ SmiUntag(ECX); |
| 197 // Let EBX point to the first passed argument, i.e. to fp[1 + argc - 0]. |
| 198 __ leal(EBX, Address(EBP, EBX, TIMES_2, kWordSize)); // EBX is Smi. |
| 199 // Let EDI point to the name/pos pair of the first named argument. |
| 200 __ leal(EDI, FieldAddress(EDX, Array::data_offset() + (2 * kWordSize))); |
| 201 for (int i = 0; i < num_opt_params; i++) { |
| 202 // Handle this optional parameter only if k or fewer positional arguments |
| 203 // have been passed, where k is the position of this optional parameter in |
| 204 // the formal parameter list. |
| 205 Label load_default_value, assign_optional_parameter, next_parameter; |
| 206 const int param_pos = opt_param_position[i]; |
| 207 __ cmpl(ECX, Immediate(param_pos)); |
| 208 __ j(GREATER, &next_parameter, Assembler::kNearJump); |
| 209 // Check if this named parameter was passed in. |
| 210 __ movl(EAX, Address(EDI, 0)); // Load EAX with the name of the argument. |
| 211 __ CompareObject(EAX, opt_param[i]->name()); |
| 212 __ j(NOT_EQUAL, &load_default_value, Assembler::kNearJump); |
| 213 // Load EAX with passed-in argument at provided arg_pos, i.e. at |
| 214 // fp[1 + argc - arg_pos]. |
| 215 __ movl(EAX, Address(EDI, kWordSize)); // EAX is arg_pos as Smi. |
| 216 __ addl(EDI, Immediate(2 * kWordSize)); // Point to next name/pos pair. |
| 217 __ negl(EAX); |
| 218 Address argument_addr(EBX, EAX, TIMES_2, 0); // EAX is a negative Smi. |
| 219 __ movl(EAX, argument_addr); |
| 220 __ jmp(&assign_optional_parameter, Assembler::kNearJump); |
| 221 __ Bind(&load_default_value); |
| 222 // Load EAX with default argument at pos. |
| 223 const Object& value = Object::ZoneHandle( |
| 224 parsed_function().default_parameter_values().At( |
| 225 param_pos - num_fixed_params)); |
| 226 __ LoadObject(EAX, value); |
| 227 __ Bind(&assign_optional_parameter); |
| 228 // Assign EAX to fp[ParsedFunction::kFirstLocalSlotIndex - param_pos]. |
| 229 // We do not use the final allocation index of the variable here, i.e. |
| 230 // scope->VariableAt(i)->index(), because captured variables still need |
| 231 // to be copied to the context that is not yet allocated. |
| 232 intptr_t computed_param_pos = (ParsedFunction::kFirstLocalSlotIndex - |
| 233 param_pos + implicit_this_param_pos); |
| 234 const Address param_addr(EBP, (computed_param_pos * kWordSize)); |
| 235 __ movl(param_addr, EAX); |
| 236 __ Bind(&next_parameter); |
| 237 } |
| 238 delete[] opt_param; |
| 239 delete[] opt_param_position; |
| 240 // Check that EDI now points to the null terminator in the array descriptor. |
| 241 __ cmpl(Address(EDI, 0), raw_null); |
| 242 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); |
| 243 } else { |
| 244 ASSERT(is_native_instance_closure); |
| 245 __ jmp(&all_arguments_processed, Assembler::kNearJump); |
| 246 } |
232 | 247 |
233 __ Bind(&wrong_num_arguments); | 248 __ Bind(&wrong_num_arguments); |
234 if (StackSize() != 0) { | 249 if (StackSize() != 0) { |
235 // We need to unwind the space we reserved for locals and copied parameters. | 250 // We need to unwind the space we reserved for locals and copied parameters. |
236 // The NoSuchMethodFunction stub does not expect to see that area on the | 251 // The NoSuchMethodFunction stub does not expect to see that area on the |
237 // stack. | 252 // stack. |
238 __ addl(ESP, Immediate(StackSize() * kWordSize)); | 253 __ addl(ESP, Immediate(StackSize() * kWordSize)); |
239 } | 254 } |
240 if (function.IsClosureFunction()) { | 255 if (function.IsClosureFunction()) { |
241 GenerateCallRuntime(AstNode::kNoId, | 256 GenerateCallRuntime(AstNode::kNoId, |
(...skipping 788 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1030 __ cvtsi2sd(result, temp); | 1045 __ cvtsi2sd(result, temp); |
1031 __ Bind(&done); | 1046 __ Bind(&done); |
1032 } | 1047 } |
1033 | 1048 |
1034 | 1049 |
1035 #undef __ | 1050 #undef __ |
1036 | 1051 |
1037 } // namespace dart | 1052 } // namespace dart |
1038 | 1053 |
1039 #endif // defined TARGET_ARCH_IA32 | 1054 #endif // defined TARGET_ARCH_IA32 |
OLD | NEW |