| 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/code_generator.h" | 8 #include "vm/code_generator.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| 11 #include "vm/assembler_macros.h" |
| 11 #include "vm/ast_printer.h" | 12 #include "vm/ast_printer.h" |
| 12 #include "vm/class_finalizer.h" | 13 #include "vm/class_finalizer.h" |
| 13 #include "vm/code_descriptors.h" | 14 #include "vm/code_descriptors.h" |
| 14 #include "vm/dart_entry.h" | 15 #include "vm/dart_entry.h" |
| 15 #include "vm/debugger.h" | 16 #include "vm/debugger.h" |
| 16 #include "vm/intrinsifier.h" | 17 #include "vm/intrinsifier.h" |
| 17 #include "vm/longjump.h" | 18 #include "vm/longjump.h" |
| 18 #include "vm/object.h" | 19 #include "vm/object.h" |
| 19 #include "vm/object_store.h" | 20 #include "vm/object_store.h" |
| 20 #include "vm/parser.h" | 21 #include "vm/parser.h" |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 178 __ popl(EDX); | 179 __ popl(EDX); |
| 179 __ popl(ECX); | 180 __ popl(ECX); |
| 180 } | 181 } |
| 181 | 182 |
| 182 const bool code_generation_finished = TryIntrinsify(); | 183 const bool code_generation_finished = TryIntrinsify(); |
| 183 // In some cases intrinsifier can generate all code and no AST based | 184 // In some cases intrinsifier can generate all code and no AST based |
| 184 // code generation is needed. In some cases slow-paths (e.g., overflows) are | 185 // code generation is needed. In some cases slow-paths (e.g., overflows) are |
| 185 // implemented by the AST based code generation and 'code_generation_finished' | 186 // implemented by the AST based code generation and 'code_generation_finished' |
| 186 // is false. | 187 // is false. |
| 187 if (!code_generation_finished) { | 188 if (!code_generation_finished) { |
| 188 GeneratePreEntryCode(); | |
| 189 GenerateEntryCode(); | 189 GenerateEntryCode(); |
| 190 if (FLAG_print_scopes) { | 190 if (FLAG_print_scopes) { |
| 191 // Print the function scope (again) after generating the prologue in order | 191 // Print the function scope (again) after generating the prologue in order |
| 192 // to see annotations such as allocation indices of locals. | 192 // to see annotations such as allocation indices of locals. |
| 193 if (FLAG_print_ast) { | 193 if (FLAG_print_ast) { |
| 194 // Second printing. | 194 // Second printing. |
| 195 OS::Print("Annotated "); | 195 OS::Print("Annotated "); |
| 196 } | 196 } |
| 197 AstPrinter::PrintFunctionScope(parsed_function_); | 197 AstPrinter::PrintFunctionScope(parsed_function_); |
| 198 } | 198 } |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 389 // | 389 // |
| 390 // TODO(regis): We may give up reserving space on stack for args/locals | 390 // TODO(regis): We may give up reserving space on stack for args/locals |
| 391 // because pushes of initial values may be more effective than moves. | 391 // because pushes of initial values may be more effective than moves. |
| 392 LocalScope* scope = parsed_function_.node_sequence()->scope(); | 392 LocalScope* scope = parsed_function_.node_sequence()->scope(); |
| 393 const int num_fixed_params = function.num_fixed_parameters(); | 393 const int num_fixed_params = function.num_fixed_parameters(); |
| 394 const int num_opt_params = function.num_optional_parameters(); | 394 const int num_opt_params = function.num_optional_parameters(); |
| 395 const int num_copied_params = parsed_function_.copied_parameter_count(); | 395 const int num_copied_params = parsed_function_.copied_parameter_count(); |
| 396 const int stack_slot_count = | 396 const int stack_slot_count = |
| 397 num_copied_params + parsed_function_.stack_local_count(); | 397 num_copied_params + parsed_function_.stack_local_count(); |
| 398 set_locals_space_size(stack_slot_count * kWordSize); | 398 set_locals_space_size(stack_slot_count * kWordSize); |
| 399 __ EnterFrame(locals_space_size()); | 399 AssemblerMacros::EnterDartFrame(assembler_, locals_space_size()); |
| 400 | 400 |
| 401 // 2. Optionally check if the number of arguments matches. We check the | 401 // 2. Optionally check if the number of arguments matches. We check the |
| 402 // number of passed arguments when we have to copy them due to the | 402 // number of passed arguments when we have to copy them due to the |
| 403 // presence of optional named parameters. No such checking code is | 403 // presence of optional named parameters. No such checking code is |
| 404 // generated if only fixed parameters are declared, unless we are in debug | 404 // generated if only fixed parameters are declared, unless we are in debug |
| 405 // mode or unless we are compiling a closure. | 405 // mode or unless we are compiling a closure. |
| 406 if (num_copied_params == 0) { | 406 if (num_copied_params == 0) { |
| 407 ASSERT(num_opt_params == 0); | 407 ASSERT(num_opt_params == 0); |
| 408 #if defined(DEBUG) | 408 #if defined(DEBUG) |
| 409 const bool check_arguments = true; // Always check arguments in debug mode. | 409 const bool check_arguments = true; // Always check arguments in debug mode. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 423 if (function.IsClosureFunction()) { | 423 if (function.IsClosureFunction()) { |
| 424 GenerateCallRuntime(AstNode::kNoId, | 424 GenerateCallRuntime(AstNode::kNoId, |
| 425 0, | 425 0, |
| 426 kClosureArgumentMismatchRuntimeEntry); | 426 kClosureArgumentMismatchRuntimeEntry); |
| 427 } else { | 427 } else { |
| 428 __ Stop("Wrong number of arguments"); | 428 __ Stop("Wrong number of arguments"); |
| 429 } | 429 } |
| 430 __ Bind(&argc_in_range); | 430 __ Bind(&argc_in_range); |
| 431 } | 431 } |
| 432 } else { | 432 } else { |
| 433 ASSERT(parsed_function_.first_parameter_index() == -1); | 433 ASSERT(parsed_function_.first_parameter_index() == |
| 434 ParsedFunction::kFirstLocalSlotIndex); |
| 434 // Copy positional arguments. | 435 // Copy positional arguments. |
| 435 // Check that no fewer than num_fixed_params positional arguments are passed | 436 // Check that no fewer than num_fixed_params positional arguments are passed |
| 436 // in and that no more than num_params arguments are passed in. | 437 // in and that no more than num_params arguments are passed in. |
| 437 // Passed argument i at fp[1 + argc - i] copied to fp[-1 - i]. | 438 // Passed argument i at fp[1 + argc - i] copied to |
| 439 // fp[ParsedFunction::kFirstLocalSlotIndex - i]. |
| 438 const int num_params = num_fixed_params + num_opt_params; | 440 const int num_params = num_fixed_params + num_opt_params; |
| 439 | 441 |
| 440 // Total number of args is the first Smi in args descriptor array (EDX). | 442 // Total number of args is the first Smi in args descriptor array (EDX). |
| 441 __ movl(EBX, FieldAddress(EDX, Array::data_offset())); | 443 __ movl(EBX, FieldAddress(EDX, Array::data_offset())); |
| 442 // Check that num_args <= num_params. | 444 // Check that num_args <= num_params. |
| 443 Label wrong_num_arguments; | 445 Label wrong_num_arguments; |
| 444 __ cmpl(EBX, Immediate(Smi::RawValue(num_params))); | 446 __ cmpl(EBX, Immediate(Smi::RawValue(num_params))); |
| 445 __ j(GREATER, &wrong_num_arguments); | 447 __ j(GREATER, &wrong_num_arguments); |
| 446 // Number of positional args is the second Smi in descriptor array (EDX). | 448 // Number of positional args is the second Smi in descriptor array (EDX). |
| 447 __ movl(ECX, FieldAddress(EDX, Array::data_offset() + (1 * kWordSize))); | 449 __ movl(ECX, FieldAddress(EDX, Array::data_offset() + (1 * kWordSize))); |
| 448 // Check that num_pos_args >= num_fixed_params. | 450 // Check that num_pos_args >= num_fixed_params. |
| 449 __ cmpl(ECX, Immediate(Smi::RawValue(num_fixed_params))); | 451 __ cmpl(ECX, Immediate(Smi::RawValue(num_fixed_params))); |
| 450 __ j(LESS, &wrong_num_arguments); | 452 __ j(LESS, &wrong_num_arguments); |
| 451 // Since EBX and ECX are Smi, use TIMES_2 instead of TIMES_4. | 453 // Since EBX and ECX are Smi, use TIMES_2 instead of TIMES_4. |
| 452 // Let EBX point to the last passed positional argument, i.e. to | 454 // Let EBX point to the last passed positional argument, i.e. to |
| 453 // fp[1 + num_args - (num_pos_args - 1)]. | 455 // fp[1 + num_args - (num_pos_args - 1)]. |
| 454 __ subl(EBX, ECX); | 456 __ subl(EBX, ECX); |
| 455 __ leal(EBX, Address(EBP, EBX, TIMES_2, 2 * kWordSize)); | 457 __ leal(EBX, Address(EBP, EBX, TIMES_2, 2 * kWordSize)); |
| 456 // Let EDI point to the last copied positional argument, i.e. to | 458 // Let EDI point to the last copied positional argument, i.e. to |
| 457 // fp[-1 - (num_pos_args - 1)]. | 459 // fp[ParsedFunction::kFirstLocalSlotIndex - (num_pos_args - 1)]. |
| 458 __ movl(EDI, EBP); | 460 const int index = ParsedFunction::kFirstLocalSlotIndex + 1; |
| 461 __ leal(EDI, Address(EBP, (index * kWordSize))); |
| 459 __ subl(EDI, ECX); // ECX is a Smi, subtract twice for TIMES_4 scaling. | 462 __ subl(EDI, ECX); // ECX is a Smi, subtract twice for TIMES_4 scaling. |
| 460 __ subl(EDI, ECX); | 463 __ subl(EDI, ECX); |
| 461 __ SmiUntag(ECX); | 464 __ SmiUntag(ECX); |
| 462 Label loop, loop_condition; | 465 Label loop, loop_condition; |
| 463 __ jmp(&loop_condition, Assembler::kNearJump); | 466 __ jmp(&loop_condition, Assembler::kNearJump); |
| 464 // We do not use the final allocation index of the variable here, i.e. | 467 // We do not use the final allocation index of the variable here, i.e. |
| 465 // scope->VariableAt(i)->index(), because captured variables still need | 468 // scope->VariableAt(i)->index(), because captured variables still need |
| 466 // to be copied to the context that is not yet allocated. | 469 // to be copied to the context that is not yet allocated. |
| 467 const Address argument_addr(EBX, ECX, TIMES_4, 0); | 470 const Address argument_addr(EBX, ECX, TIMES_4, 0); |
| 468 const Address copy_addr(EDI, ECX, TIMES_4, 0); | 471 const Address copy_addr(EDI, ECX, TIMES_4, 0); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 523 Address argument_addr(EBX, EAX, TIMES_2, 0); // EAX is a negative Smi. | 526 Address argument_addr(EBX, EAX, TIMES_2, 0); // EAX is a negative Smi. |
| 524 __ movl(EAX, argument_addr); | 527 __ movl(EAX, argument_addr); |
| 525 __ jmp(&assign_optional_parameter, Assembler::kNearJump); | 528 __ jmp(&assign_optional_parameter, Assembler::kNearJump); |
| 526 __ Bind(&load_default_value); | 529 __ Bind(&load_default_value); |
| 527 // Load EAX with default argument at pos. | 530 // Load EAX with default argument at pos. |
| 528 const Object& value = Object::ZoneHandle( | 531 const Object& value = Object::ZoneHandle( |
| 529 parsed_function_.default_parameter_values().At( | 532 parsed_function_.default_parameter_values().At( |
| 530 param_pos - num_fixed_params)); | 533 param_pos - num_fixed_params)); |
| 531 __ LoadObject(EAX, value); | 534 __ LoadObject(EAX, value); |
| 532 __ Bind(&assign_optional_parameter); | 535 __ Bind(&assign_optional_parameter); |
| 533 // Assign EAX to fp[-1 - param_pos]. | 536 // Assign EAX to fp[ParsedFunction::kFirstLocalSlotIndex - param_pos]. |
| 534 // We do not use the final allocation index of the variable here, i.e. | 537 // We do not use the final allocation index of the variable here, i.e. |
| 535 // scope->VariableAt(i)->index(), because captured variables still need | 538 // scope->VariableAt(i)->index(), because captured variables still need |
| 536 // to be copied to the context that is not yet allocated. | 539 // to be copied to the context that is not yet allocated. |
| 537 const Address param_addr(EBP, (-1 - param_pos) * kWordSize); | 540 const Address param_addr( |
| 541 EBP, (ParsedFunction::kFirstLocalSlotIndex - param_pos) * kWordSize); |
| 538 __ movl(param_addr, EAX); | 542 __ movl(param_addr, EAX); |
| 539 __ Bind(&next_parameter); | 543 __ Bind(&next_parameter); |
| 540 } | 544 } |
| 541 delete[] opt_param; | 545 delete[] opt_param; |
| 542 delete[] opt_param_position; | 546 delete[] opt_param_position; |
| 543 // Check that EDI now points to the null terminator in the array descriptor. | 547 // Check that EDI now points to the null terminator in the array descriptor. |
| 544 Label all_arguments_processed; | 548 Label all_arguments_processed; |
| 545 __ cmpl(Address(EDI, 0), raw_null); | 549 __ cmpl(Address(EDI, 0), raw_null); |
| 546 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); | 550 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); |
| 547 | 551 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 558 kClosureArgumentMismatchRuntimeEntry); | 562 kClosureArgumentMismatchRuntimeEntry); |
| 559 } else { | 563 } else { |
| 560 // Invoke noSuchMethod function. | 564 // Invoke noSuchMethod function. |
| 561 const int kNumArgsChecked = 1; | 565 const int kNumArgsChecked = 1; |
| 562 ICData& ic_data = ICData::ZoneHandle(); | 566 ICData& ic_data = ICData::ZoneHandle(); |
| 563 ic_data = ICData::New(parsed_function().function(), | 567 ic_data = ICData::New(parsed_function().function(), |
| 564 String::Handle(function.name()), | 568 String::Handle(function.name()), |
| 565 AstNode::kNoId, | 569 AstNode::kNoId, |
| 566 kNumArgsChecked); | 570 kNumArgsChecked); |
| 567 __ LoadObject(ECX, ic_data); | 571 __ LoadObject(ECX, ic_data); |
| 572 // EBP - 4 : PC marker, allows easy identification of RawInstruction obj. |
| 568 // EBP : points to previous frame pointer. | 573 // EBP : points to previous frame pointer. |
| 569 // EBP + 4 : points to return address. | 574 // EBP + 4 : points to return address. |
| 570 // EBP + 8 : address of last argument (arg n-1). | 575 // EBP + 8 : address of last argument (arg n-1). |
| 571 // ESP + 8 + 4*(n-1) : address of first argument (arg 0). | 576 // ESP + 8 + 4*(n-1) : address of first argument (arg 0). |
| 572 // ECX : ic-data. | 577 // ECX : ic-data. |
| 573 // EDX : arguments descriptor array. | 578 // EDX : arguments descriptor array. |
| 574 __ call(&StubCode::CallNoSuchMethodFunctionLabel()); | 579 __ call(&StubCode::CallNoSuchMethodFunctionLabel()); |
| 575 } | 580 } |
| 576 | 581 |
| 577 if (FLAG_trace_functions) { | 582 if (FLAG_trace_functions) { |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 639 if (parsed_function_.saved_context_var() != NULL) { | 644 if (parsed_function_.saved_context_var() != NULL) { |
| 640 // CTX on entry was saved, but not linked as context parent. | 645 // CTX on entry was saved, but not linked as context parent. |
| 641 GenerateLoadVariable(CTX, *parsed_function_.saved_context_var()); | 646 GenerateLoadVariable(CTX, *parsed_function_.saved_context_var()); |
| 642 } else { | 647 } else { |
| 643 while (current_context_level-- > 0) { | 648 while (current_context_level-- > 0) { |
| 644 __ movl(CTX, FieldAddress(CTX, Context::parent_offset())); | 649 __ movl(CTX, FieldAddress(CTX, Context::parent_offset())); |
| 645 } | 650 } |
| 646 } | 651 } |
| 647 #ifdef DEBUG | 652 #ifdef DEBUG |
| 648 // Check that the entry stack size matches the exit stack size. | 653 // Check that the entry stack size matches the exit stack size. |
| 649 __ movl(EDX, EBP); | 654 __ leal(EDX, Address(EBP, kLocalsOffsetFromFP)); |
| 650 __ subl(EDX, ESP); | 655 __ subl(EDX, ESP); |
| 651 ASSERT(locals_space_size() >= 0); | 656 ASSERT(locals_space_size() >= 0); |
| 652 __ cmpl(EDX, Immediate(locals_space_size())); | 657 __ cmpl(EDX, Immediate(locals_space_size())); |
| 653 Label wrong_stack; | 658 Label wrong_stack; |
| 654 __ j(NOT_EQUAL, &wrong_stack, Assembler::kNearJump); | 659 __ j(NOT_EQUAL, &wrong_stack, Assembler::kNearJump); |
| 655 #endif // DEBUG. | 660 #endif // DEBUG. |
| 656 | 661 |
| 657 if (!IsOptimizing()) { | 662 if (!IsOptimizing()) { |
| 658 // Count only in unoptimized code. | 663 // Count only in unoptimized code. |
| 659 // TODO(srdjan): Replace the counting code with a type feedback | 664 // TODO(srdjan): Replace the counting code with a type feedback |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 874 set_context_level(scope->context_level()); | 879 set_context_level(scope->context_level()); |
| 875 | 880 |
| 876 // If this node_sequence is the body of the function being compiled, copy | 881 // If this node_sequence is the body of the function being compiled, copy |
| 877 // the captured parameters from the frame into the context. | 882 // the captured parameters from the frame into the context. |
| 878 if (node_sequence == parsed_function_.node_sequence()) { | 883 if (node_sequence == parsed_function_.node_sequence()) { |
| 879 ASSERT(scope->context_level() == 1); | 884 ASSERT(scope->context_level() == 1); |
| 880 const Immediate raw_null = | 885 const Immediate raw_null = |
| 881 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 886 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 882 const Function& function = parsed_function_.function(); | 887 const Function& function = parsed_function_.function(); |
| 883 const int num_params = function.NumberOfParameters(); | 888 const int num_params = function.NumberOfParameters(); |
| 884 int param_frame_index = | 889 int param_frame_index = (num_params == function.num_fixed_parameters()) ? |
| 885 (num_params == function.num_fixed_parameters()) ? 1 + num_params : -1; | 890 (1 + num_params) : ParsedFunction::kFirstLocalSlotIndex; |
| 886 for (int pos = 0; pos < num_params; param_frame_index--, pos++) { | 891 for (int pos = 0; pos < num_params; param_frame_index--, pos++) { |
| 887 LocalVariable* parameter = scope->VariableAt(pos); | 892 LocalVariable* parameter = scope->VariableAt(pos); |
| 888 ASSERT(parameter->owner() == scope); | 893 ASSERT(parameter->owner() == scope); |
| 889 if (parameter->is_captured()) { | 894 if (parameter->is_captured()) { |
| 890 // Copy parameter from local frame to current context. | 895 // Copy parameter from local frame to current context. |
| 891 const Address local_addr(EBP, param_frame_index * kWordSize); | 896 const Address local_addr(EBP, param_frame_index * kWordSize); |
| 892 __ movl(EAX, local_addr); | 897 __ movl(EAX, local_addr); |
| 893 GenerateStoreVariable(*parameter, EAX, EDX); | 898 GenerateStoreVariable(*parameter, EAX, EDX); |
| 894 // Write NULL to the source location to detect buggy accesses and | 899 // Write NULL to the source location to detect buggy accesses and |
| 895 // allow GC of passed value if it gets overwritten by a new value in | 900 // allow GC of passed value if it gets overwritten by a new value in |
| (...skipping 1890 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2786 } | 2791 } |
| 2787 | 2792 |
| 2788 | 2793 |
| 2789 void CodeGenerator::VisitNativeBodyNode(NativeBodyNode* node) { | 2794 void CodeGenerator::VisitNativeBodyNode(NativeBodyNode* node) { |
| 2790 // Push the result place holder initialized to NULL. | 2795 // Push the result place holder initialized to NULL. |
| 2791 __ PushObject(Object::ZoneHandle()); | 2796 __ PushObject(Object::ZoneHandle()); |
| 2792 // Pass a pointer to the first argument in EAX. | 2797 // Pass a pointer to the first argument in EAX. |
| 2793 if (!node->has_optional_parameters()) { | 2798 if (!node->has_optional_parameters()) { |
| 2794 __ leal(EAX, Address(EBP, (1 + node->argument_count()) * kWordSize)); | 2799 __ leal(EAX, Address(EBP, (1 + node->argument_count()) * kWordSize)); |
| 2795 } else { | 2800 } else { |
| 2796 __ leal(EAX, Address(EBP, -1 * kWordSize)); | 2801 __ leal(EAX, |
| 2802 Address(EBP, ParsedFunction::kFirstLocalSlotIndex * kWordSize)); |
| 2797 } | 2803 } |
| 2798 __ movl(ECX, Immediate(reinterpret_cast<uword>(node->native_c_function()))); | 2804 __ movl(ECX, Immediate(reinterpret_cast<uword>(node->native_c_function()))); |
| 2799 __ movl(EDX, Immediate(node->argument_count())); | 2805 __ movl(EDX, Immediate(node->argument_count())); |
| 2800 GenerateCall(node->token_index(), | 2806 GenerateCall(node->token_index(), |
| 2801 &StubCode::CallNativeCFunctionLabel(), | 2807 &StubCode::CallNativeCFunctionLabel(), |
| 2802 PcDescriptors::kOther); | 2808 PcDescriptors::kOther); |
| 2803 // Result is on the stack. | 2809 // Result is on the stack. |
| 2804 if (!IsResultNeeded(node)) { | 2810 if (!IsResultNeeded(node)) { |
| 2805 __ popl(EAX); | 2811 __ popl(EAX); |
| 2806 } | 2812 } |
| 2807 } | 2813 } |
| 2808 | 2814 |
| 2809 | 2815 |
| 2810 void CodeGenerator::VisitCatchClauseNode(CatchClauseNode* node) { | 2816 void CodeGenerator::VisitCatchClauseNode(CatchClauseNode* node) { |
| 2811 // NOTE: The implicit variables ':saved_context', ':exception_var' | 2817 // NOTE: The implicit variables ':saved_context', ':exception_var' |
| 2812 // and ':stacktrace_var' can never be captured variables. | 2818 // and ':stacktrace_var' can never be captured variables. |
| 2813 // Restore CTX from local variable ':saved_context'. | 2819 // Restore CTX from local variable ':saved_context'. |
| 2814 GenerateLoadVariable(CTX, node->context_var()); | 2820 GenerateLoadVariable(CTX, node->context_var()); |
| 2815 | 2821 |
| 2816 // Restore ESP from EBP as we are coming from a throw and the code for | 2822 // Restore ESP from EBP as we are coming from a throw and the code for |
| 2817 // popping arguments has not been run. | 2823 // popping arguments has not been run. |
| 2818 ASSERT(locals_space_size() >= 0); | 2824 ASSERT(locals_space_size() >= 0); |
| 2819 if (locals_space_size() == 0) { | 2825 intptr_t offset_size = -locals_space_size() + kLocalsOffsetFromFP; |
| 2820 __ movl(ESP, EBP); | 2826 __ leal(ESP, Address(EBP, offset_size)); |
| 2821 } else { | |
| 2822 __ leal(ESP, Address(EBP, -locals_space_size())); | |
| 2823 } | |
| 2824 | 2827 |
| 2825 // The JumpToExceptionHandler trampoline code sets up | 2828 // The JumpToExceptionHandler trampoline code sets up |
| 2826 // - the exception object in EAX (kExceptionObjectReg) | 2829 // - the exception object in EAX (kExceptionObjectReg) |
| 2827 // - the stacktrace object in register EDX (kStackTraceObjectReg) | 2830 // - the stacktrace object in register EDX (kStackTraceObjectReg) |
| 2828 // We now setup the exception object and the trace object | 2831 // We now setup the exception object and the trace object |
| 2829 // so that the handler code has access to these objects. | 2832 // so that the handler code has access to these objects. |
| 2830 GenerateStoreVariable(node->exception_var(), | 2833 GenerateStoreVariable(node->exception_var(), |
| 2831 kExceptionObjectReg, | 2834 kExceptionObjectReg, |
| 2832 kNoRegister); | 2835 kNoRegister); |
| 2833 GenerateStoreVariable(node->stacktrace_var(), | 2836 GenerateStoreVariable(node->stacktrace_var(), |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2965 const Error& error = Error::Handle( | 2968 const Error& error = Error::Handle( |
| 2966 Parser::FormatError(script, token_index, "Error", format, args)); | 2969 Parser::FormatError(script, token_index, "Error", format, args)); |
| 2967 va_end(args); | 2970 va_end(args); |
| 2968 Isolate::Current()->long_jump_base()->Jump(1, error); | 2971 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2969 UNREACHABLE(); | 2972 UNREACHABLE(); |
| 2970 } | 2973 } |
| 2971 | 2974 |
| 2972 } // namespace dart | 2975 } // namespace dart |
| 2973 | 2976 |
| 2974 #endif // defined TARGET_ARCH_IA32 | 2977 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |