| 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 "vm/ast_printer.h" | 10 #include "vm/ast_printer.h" |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 DISALLOW_COPY_AND_ASSIGN(DeoptimizationStub); | 58 DISALLOW_COPY_AND_ASSIGN(DeoptimizationStub); |
| 59 }; | 59 }; |
| 60 | 60 |
| 61 | 61 |
| 62 void DeoptimizationStub::GenerateCode(FlowGraphCompiler* compiler) { | 62 void DeoptimizationStub::GenerateCode(FlowGraphCompiler* compiler) { |
| 63 Assembler* assem = compiler->assembler(); | 63 Assembler* assem = compiler->assembler(); |
| 64 #define __ assem-> | 64 #define __ assem-> |
| 65 __ Comment("Deopt stub for id %d", deopt_id_); | 65 __ Comment("Deopt stub for id %d", deopt_id_); |
| 66 __ Bind(entry_label()); | 66 __ Bind(entry_label()); |
| 67 for (intptr_t i = 0; i < registers_.length(); i++) { | 67 for (intptr_t i = 0; i < registers_.length(); i++) { |
| 68 __ pushl(registers_[i]); | 68 if (registers_[i] != kNoRegister) { |
| 69 __ pushl(registers_[i]); |
| 70 } |
| 69 } | 71 } |
| 70 __ movl(EAX, Immediate(Smi::RawValue(reason_))); | 72 __ movl(EAX, Immediate(Smi::RawValue(reason_))); |
| 71 __ call(&StubCode::DeoptimizeLabel()); | 73 __ call(&StubCode::DeoptimizeLabel()); |
| 72 compiler->AddCurrentDescriptor(PcDescriptors::kOther, | 74 compiler->AddCurrentDescriptor(PcDescriptors::kOther, |
| 73 deopt_id_, | 75 deopt_id_, |
| 74 deopt_token_index_, | 76 deopt_token_index_, |
| 75 try_index_); | 77 try_index_); |
| 76 #undef __ | 78 #undef __ |
| 77 } | 79 } |
| 78 | 80 |
| 79 | 81 |
| 80 FlowGraphCompiler::FlowGraphCompiler( | 82 FlowGraphCompiler::FlowGraphCompiler( |
| 81 Assembler* assembler, | 83 Assembler* assembler, |
| 82 const ParsedFunction& parsed_function, | 84 const ParsedFunction& parsed_function, |
| 83 const GrowableArray<BlockEntryInstr*>& block_order, | 85 const GrowableArray<BlockEntryInstr*>& block_order, |
| 84 bool is_optimizing) | 86 bool is_optimizing) |
| 85 : FlowGraphVisitor(block_order), | 87 : FlowGraphVisitor(block_order), |
| 86 assembler_(assembler), | 88 assembler_(assembler), |
| 87 parsed_function_(parsed_function), | 89 parsed_function_(parsed_function), |
| 88 block_info_(block_order.length()), | 90 block_info_(block_order.length()), |
| 89 current_block_(NULL), | 91 current_block_(NULL), |
| 90 pc_descriptors_list_(NULL), | 92 pc_descriptors_list_(NULL), |
| 91 stackmap_builder_(NULL), | 93 stackmap_builder_(NULL), |
| 92 exception_handlers_list_(NULL), | 94 exception_handlers_list_(NULL), |
| 93 deopt_stubs_(), | 95 deopt_stubs_(), |
| 94 is_optimizing_(is_optimizing) { | 96 is_optimizing_(is_optimizing) { |
| 95 } | 97 } |
| 96 | 98 |
| 97 | 99 |
| 100 void FlowGraphCompiler::InitCompiler() { |
| 101 pc_descriptors_list_ = new DescriptorList(); |
| 102 exception_handlers_list_ = new ExceptionHandlerList(); |
| 103 block_info_.Clear(); |
| 104 for (int i = 0; i < block_order_.length(); ++i) { |
| 105 block_info_.Add(new BlockInfo()); |
| 106 } |
| 107 } |
| 108 |
| 109 |
| 98 FlowGraphCompiler::~FlowGraphCompiler() { | 110 FlowGraphCompiler::~FlowGraphCompiler() { |
| 99 // BlockInfos are zone-allocated, so their destructors are not called. | 111 // BlockInfos are zone-allocated, so their destructors are not called. |
| 100 // Verify the labels explicitly here. | 112 // Verify the labels explicitly here. |
| 101 for (int i = 0; i < block_info_.length(); ++i) { | 113 for (int i = 0; i < block_info_.length(); ++i) { |
| 102 ASSERT(!block_info_[i]->label.IsLinked()); | 114 ASSERT(!block_info_[i]->label.IsLinked()); |
| 103 ASSERT(!block_info_[i]->label.HasNear()); | 115 ASSERT(!block_info_[i]->label.HasNear()); |
| 104 } | 116 } |
| 105 } | 117 } |
| 106 | 118 |
| 107 | 119 |
| 108 void FlowGraphCompiler::InitCompiler() { | 120 intptr_t FlowGraphCompiler::StackSize() const { |
| 109 pc_descriptors_list_ = new DescriptorList(); | 121 return parsed_function_.stack_local_count() + |
| 110 exception_handlers_list_ = new ExceptionHandlerList(); | 122 parsed_function_.copied_parameter_count(); |
| 111 block_info_.Clear(); | |
| 112 for (int i = 0; i < block_order_.length(); ++i) { | |
| 113 block_info_.Add(new BlockInfo()); | |
| 114 } | |
| 115 } | 123 } |
| 116 | 124 |
| 117 | 125 |
| 118 void FlowGraphCompiler::Bailout(const char* reason) { | 126 void FlowGraphCompiler::Bailout(const char* reason) { |
| 119 const char* kFormat = "FlowGraphCompiler Bailout: %s."; | 127 const char* kFormat = "FlowGraphCompiler Bailout: %s %s."; |
| 120 intptr_t len = OS::SNPrint(NULL, 0, kFormat, reason) + 1; | 128 const char* function_name = parsed_function_.function().ToCString(); |
| 129 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; |
| 121 char* chars = reinterpret_cast<char*>( | 130 char* chars = reinterpret_cast<char*>( |
| 122 Isolate::Current()->current_zone()->Allocate(len)); | 131 Isolate::Current()->current_zone()->Allocate(len)); |
| 123 OS::SNPrint(chars, len, kFormat, reason); | 132 OS::SNPrint(chars, len, kFormat, function_name, reason); |
| 124 const Error& error = Error::Handle( | 133 const Error& error = Error::Handle( |
| 125 LanguageError::New(String::Handle(String::New(chars)))); | 134 LanguageError::New(String::Handle(String::New(chars)))); |
| 126 Isolate::Current()->long_jump_base()->Jump(1, error); | 135 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 127 } | 136 } |
| 128 | 137 |
| 129 | 138 |
| 130 // Uses current pc position and try-index. | 139 // Uses current pc position and try-index. |
| 131 void FlowGraphCompiler::AddCurrentDescriptor(PcDescriptors::Kind kind, | 140 void FlowGraphCompiler::AddCurrentDescriptor(PcDescriptors::Kind kind, |
| 132 intptr_t cid, | 141 intptr_t cid, |
| 133 intptr_t token_index, | 142 intptr_t token_index, |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 172 __ movl(EAX, Address(ESP, 2 * kWordSize)); // Receiver. | 181 __ movl(EAX, Address(ESP, 2 * kWordSize)); // Receiver. |
| 173 __ movl(EBX, Address(ESP, 1 * kWordSize)); // Value. | 182 __ movl(EBX, Address(ESP, 1 * kWordSize)); // Value. |
| 174 __ StoreIntoObject(EAX, FieldAddress(EAX, store_node.field().Offset()), EBX); | 183 __ StoreIntoObject(EAX, FieldAddress(EAX, store_node.field().Offset()), EBX); |
| 175 const Immediate raw_null = | 184 const Immediate raw_null = |
| 176 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 185 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 177 __ movl(EAX, raw_null); | 186 __ movl(EAX, raw_null); |
| 178 __ ret(); | 187 __ ret(); |
| 179 } | 188 } |
| 180 | 189 |
| 181 | 190 |
| 182 intptr_t FlowGraphCompiler::StackSize() const { | |
| 183 return parsed_function_.stack_local_count() + | |
| 184 parsed_function_.copied_parameter_count(); | |
| 185 } | |
| 186 | |
| 187 | |
| 188 bool FlowGraphCompiler::CanOptimize() { | 191 bool FlowGraphCompiler::CanOptimize() { |
| 189 return | 192 return |
| 190 !FLAG_report_usage_count && | 193 !FLAG_report_usage_count && |
| 191 (FLAG_optimization_counter_threshold >= 0) && | 194 (FLAG_optimization_counter_threshold >= 0) && |
| 192 !Isolate::Current()->debugger()->IsActive(); | 195 !Isolate::Current()->debugger()->IsActive(); |
| 193 } | 196 } |
| 194 | 197 |
| 195 | 198 |
| 196 // Returns 'true' if code generation for this function is complete, i.e., | 199 // Returns 'true' if code generation for this function is complete, i.e., |
| 197 // no fall-through to regular code is needed. | 200 // no fall-through to regular code is needed. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 221 void FlowGraphCompiler::GenerateCallRuntime(intptr_t cid, | 224 void FlowGraphCompiler::GenerateCallRuntime(intptr_t cid, |
| 222 intptr_t token_index, | 225 intptr_t token_index, |
| 223 intptr_t try_index, | 226 intptr_t try_index, |
| 224 const RuntimeEntry& entry) { | 227 const RuntimeEntry& entry) { |
| 225 __ CallRuntime(entry); | 228 __ CallRuntime(entry); |
| 226 AddCurrentDescriptor(PcDescriptors::kOther, cid, token_index, try_index); | 229 AddCurrentDescriptor(PcDescriptors::kOther, cid, token_index, try_index); |
| 227 } | 230 } |
| 228 | 231 |
| 229 | 232 |
| 230 void FlowGraphCompiler::CopyParameters() { | 233 void FlowGraphCompiler::CopyParameters() { |
| 231 Bailout("Copy Parameters"); | 234 const Function& function = parsed_function_.function(); |
| 235 LocalScope* scope = parsed_function_.node_sequence()->scope(); |
| 236 const int num_fixed_params = function.num_fixed_parameters(); |
| 237 const int num_opt_params = function.num_optional_parameters(); |
| 238 ASSERT(parsed_function_.first_parameter_index() == |
| 239 ParsedFunction::kFirstLocalSlotIndex); |
| 240 // Copy positional arguments. |
| 241 // Check that no fewer than num_fixed_params positional arguments are passed |
| 242 // in and that no more than num_params arguments are passed in. |
| 243 // Passed argument i at fp[1 + argc - i] |
| 244 // copied to fp[ParsedFunction::kFirstLocalSlotIndex - i]. |
| 245 const int num_params = num_fixed_params + num_opt_params; |
| 246 |
| 247 // Total number of args is the first Smi in args descriptor array (EDX). |
| 248 __ movl(EBX, FieldAddress(EDX, Array::data_offset())); |
| 249 // Check that num_args <= num_params. |
| 250 Label wrong_num_arguments; |
| 251 __ cmpl(EBX, Immediate(Smi::RawValue(num_params))); |
| 252 __ j(GREATER, &wrong_num_arguments); |
| 253 // Number of positional args is the second Smi in descriptor array (EDX). |
| 254 __ movl(ECX, FieldAddress(EDX, Array::data_offset() + (1 * kWordSize))); |
| 255 // Check that num_pos_args >= num_fixed_params. |
| 256 __ cmpl(ECX, Immediate(Smi::RawValue(num_fixed_params))); |
| 257 __ j(LESS, &wrong_num_arguments); |
| 258 // Since EBX and ECX are Smi, use TIMES_2 instead of TIMES_4. |
| 259 // Let EBX point to the last passed positional argument, i.e. to |
| 260 // fp[1 + num_args - (num_pos_args - 1)]. |
| 261 __ subl(EBX, ECX); |
| 262 __ leal(EBX, Address(EBP, EBX, TIMES_2, 2 * kWordSize)); |
| 263 // Let EDI point to the last copied positional argument, i.e. to |
| 264 // fp[ParsedFunction::kFirstLocalSlotIndex - (num_pos_args - 1)]. |
| 265 const int index = ParsedFunction::kFirstLocalSlotIndex + 1; |
| 266 __ leal(EDI, Address(EBP, (index * kWordSize))); |
| 267 __ subl(EDI, ECX); // ECX is a Smi, subtract twice for TIMES_4 scaling. |
| 268 __ subl(EDI, ECX); |
| 269 __ SmiUntag(ECX); |
| 270 Label loop, loop_condition; |
| 271 __ jmp(&loop_condition, Assembler::kNearJump); |
| 272 // We do not use the final allocation index of the variable here, i.e. |
| 273 // scope->VariableAt(i)->index(), because captured variables still need |
| 274 // to be copied to the context that is not yet allocated. |
| 275 const Address argument_addr(EBX, ECX, TIMES_4, 0); |
| 276 const Address copy_addr(EDI, ECX, TIMES_4, 0); |
| 277 __ Bind(&loop); |
| 278 __ movl(EAX, argument_addr); |
| 279 __ movl(copy_addr, EAX); |
| 280 __ Bind(&loop_condition); |
| 281 __ decl(ECX); |
| 282 __ j(POSITIVE, &loop, Assembler::kNearJump); |
| 283 |
| 284 // Copy or initialize optional named arguments. |
| 285 ASSERT(num_opt_params > 0); // Or we would not have to copy arguments. |
| 286 // Start by alphabetically sorting the names of the optional parameters. |
| 287 LocalVariable** opt_param = new LocalVariable*[num_opt_params]; |
| 288 int* opt_param_position = new int[num_opt_params]; |
| 289 for (int pos = num_fixed_params; pos < num_params; pos++) { |
| 290 LocalVariable* parameter = scope->VariableAt(pos); |
| 291 const String& opt_param_name = parameter->name(); |
| 292 int i = pos - num_fixed_params; |
| 293 while (--i >= 0) { |
| 294 LocalVariable* param_i = opt_param[i]; |
| 295 const intptr_t result = opt_param_name.CompareTo(param_i->name()); |
| 296 ASSERT(result != 0); |
| 297 if (result > 0) break; |
| 298 opt_param[i + 1] = opt_param[i]; |
| 299 opt_param_position[i + 1] = opt_param_position[i]; |
| 300 } |
| 301 opt_param[i + 1] = parameter; |
| 302 opt_param_position[i + 1] = pos; |
| 303 } |
| 304 // Generate code handling each optional parameter in alphabetical order. |
| 305 // Total number of args is the first Smi in args descriptor array (EDX). |
| 306 __ movl(EBX, FieldAddress(EDX, Array::data_offset())); |
| 307 // Number of positional args is the second Smi in descriptor array (EDX). |
| 308 __ movl(ECX, FieldAddress(EDX, Array::data_offset() + (1 * kWordSize))); |
| 309 __ SmiUntag(ECX); |
| 310 // Let EBX point to the first passed argument, i.e. to fp[1 + argc - 0]. |
| 311 __ leal(EBX, Address(EBP, EBX, TIMES_2, kWordSize)); // EBX is Smi. |
| 312 // Let EDI point to the name/pos pair of the first named argument. |
| 313 __ leal(EDI, FieldAddress(EDX, Array::data_offset() + (2 * kWordSize))); |
| 314 for (int i = 0; i < num_opt_params; i++) { |
| 315 // Handle this optional parameter only if k or fewer positional arguments |
| 316 // have been passed, where k is the position of this optional parameter in |
| 317 // the formal parameter list. |
| 318 Label load_default_value, assign_optional_parameter, next_parameter; |
| 319 const int param_pos = opt_param_position[i]; |
| 320 __ cmpl(ECX, Immediate(param_pos)); |
| 321 __ j(GREATER, &next_parameter, Assembler::kNearJump); |
| 322 // Check if this named parameter was passed in. |
| 323 __ movl(EAX, Address(EDI, 0)); // Load EAX with the name of the argument. |
| 324 __ CompareObject(EAX, opt_param[i]->name()); |
| 325 __ j(NOT_EQUAL, &load_default_value, Assembler::kNearJump); |
| 326 // Load EAX with passed-in argument at provided arg_pos, i.e. at |
| 327 // fp[1 + argc - arg_pos]. |
| 328 __ movl(EAX, Address(EDI, kWordSize)); // EAX is arg_pos as Smi. |
| 329 __ addl(EDI, Immediate(2 * kWordSize)); // Point to next name/pos pair. |
| 330 __ negl(EAX); |
| 331 Address argument_addr(EBX, EAX, TIMES_2, 0); // EAX is a negative Smi. |
| 332 __ movl(EAX, argument_addr); |
| 333 __ jmp(&assign_optional_parameter, Assembler::kNearJump); |
| 334 __ Bind(&load_default_value); |
| 335 // Load EAX with default argument at pos. |
| 336 const Object& value = Object::ZoneHandle( |
| 337 parsed_function_.default_parameter_values().At( |
| 338 param_pos - num_fixed_params)); |
| 339 __ LoadObject(EAX, value); |
| 340 __ Bind(&assign_optional_parameter); |
| 341 // Assign EAX to fp[ParsedFunction::kFirstLocalSlotIndex - param_pos]. |
| 342 // We do not use the final allocation index of the variable here, i.e. |
| 343 // scope->VariableAt(i)->index(), because captured variables still need |
| 344 // to be copied to the context that is not yet allocated. |
| 345 const Address param_addr( |
| 346 EBP, (ParsedFunction::kFirstLocalSlotIndex - param_pos) * kWordSize); |
| 347 __ movl(param_addr, EAX); |
| 348 __ Bind(&next_parameter); |
| 349 } |
| 350 delete[] opt_param; |
| 351 delete[] opt_param_position; |
| 352 // Check that EDI now points to the null terminator in the array descriptor. |
| 353 const Immediate raw_null = |
| 354 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 355 Label all_arguments_processed; |
| 356 __ cmpl(Address(EDI, 0), raw_null); |
| 357 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); |
| 358 |
| 359 __ Bind(&wrong_num_arguments); |
| 360 if (StackSize() != 0) { |
| 361 // We need to unwind the space we reserved for locals and copied parameters. |
| 362 // The NoSuchMethodFunction stub does not expect to see that area on the |
| 363 // stack. |
| 364 __ addl(ESP, Immediate(StackSize() * kWordSize)); |
| 365 } |
| 366 if (function.IsClosureFunction()) { |
| 367 GenerateCallRuntime(AstNode::kNoId, |
| 368 0, |
| 369 CatchClauseNode::kInvalidTryIndex, |
| 370 kClosureArgumentMismatchRuntimeEntry); |
| 371 } else { |
| 372 // Invoke noSuchMethod function. |
| 373 const int kNumArgsChecked = 1; |
| 374 ICData& ic_data = ICData::ZoneHandle(); |
| 375 ic_data = ICData::New(function, |
| 376 String::Handle(function.name()), |
| 377 AstNode::kNoId, |
| 378 kNumArgsChecked); |
| 379 __ LoadObject(ECX, ic_data); |
| 380 // EBP - 4 : PC marker, allows easy identification of RawInstruction obj. |
| 381 // EBP : points to previous frame pointer. |
| 382 // EBP + 4 : points to return address. |
| 383 // EBP + 8 : address of last argument (arg n-1). |
| 384 // ESP + 8 + 4*(n-1) : address of first argument (arg 0). |
| 385 // ECX : ic-data. |
| 386 // EDX : arguments descriptor array. |
| 387 __ call(&StubCode::CallNoSuchMethodFunctionLabel()); |
| 388 } |
| 389 |
| 390 if (FLAG_trace_functions) { |
| 391 __ pushl(EAX); // Preserve result. |
| 392 __ PushObject(Function::ZoneHandle(function.raw())); |
| 393 GenerateCallRuntime(AstNode::kNoId, |
| 394 0, |
| 395 CatchClauseNode::kInvalidTryIndex, |
| 396 kTraceFunctionExitRuntimeEntry); |
| 397 __ popl(EAX); // Remove argument. |
| 398 __ popl(EAX); // Restore result. |
| 399 } |
| 400 __ LeaveFrame(); |
| 401 __ ret(); |
| 402 |
| 403 __ Bind(&all_arguments_processed); |
| 404 // Nullify originally passed arguments only after they have been copied and |
| 405 // checked, otherwise noSuchMethod would not see their original values. |
| 406 // This step can be skipped in case we decide that formal parameters are |
| 407 // implicitly final, since garbage collecting the unmodified value is not |
| 408 // an issue anymore. |
| 409 |
| 410 // EDX : arguments descriptor array. |
| 411 // Total number of args is the first Smi in args descriptor array (EDX). |
| 412 __ movl(ECX, FieldAddress(EDX, Array::data_offset())); |
| 413 __ SmiUntag(ECX); |
| 414 Label null_args_loop, null_args_loop_condition; |
| 415 __ jmp(&null_args_loop_condition, Assembler::kNearJump); |
| 416 const Address original_argument_addr(EBP, ECX, TIMES_4, 2 * kWordSize); |
| 417 __ Bind(&null_args_loop); |
| 418 __ movl(original_argument_addr, raw_null); |
| 419 __ Bind(&null_args_loop_condition); |
| 420 __ decl(ECX); |
| 421 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump); |
| 232 } | 422 } |
| 233 | 423 |
| 234 | 424 |
| 235 void FlowGraphCompiler::CompileGraph() { | 425 void FlowGraphCompiler::CompileGraph() { |
| 236 InitCompiler(); | 426 InitCompiler(); |
| 237 if (TryIntrinsify()) { | 427 if (TryIntrinsify()) { |
| 238 __ int3(); | 428 __ int3(); |
| 239 __ jmp(&StubCode::FixCallersTargetLabel()); | 429 __ jmp(&StubCode::FixCallersTargetLabel()); |
| 240 return; | 430 return; |
| 241 } | 431 } |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 492 | 682 |
| 493 void FlowGraphCompiler::FinalizeComments(const Code& code) { | 683 void FlowGraphCompiler::FinalizeComments(const Code& code) { |
| 494 code.set_comments(assembler_->GetCodeComments()); | 684 code.set_comments(assembler_->GetCodeComments()); |
| 495 } | 685 } |
| 496 | 686 |
| 497 #undef __ | 687 #undef __ |
| 498 | 688 |
| 499 } // namespace dart | 689 } // namespace dart |
| 500 | 690 |
| 501 #endif // defined TARGET_ARCH_IA32 | 691 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |