OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 500 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
511 break_stack_height_(0) { | 511 break_stack_height_(0) { |
512 } | 512 } |
513 | 513 |
514 | 514 |
515 // Calling conventions: | 515 // Calling conventions: |
516 // ebp: frame pointer | 516 // ebp: frame pointer |
517 // esp: stack pointer | 517 // esp: stack pointer |
518 // edi: caller's parameter pointer | 518 // edi: caller's parameter pointer |
519 // esi: callee's context | 519 // esi: callee's context |
520 | 520 |
521 | |
522 void Ia32CodeGenerator::GenCode(FunctionLiteral* fun) { | 521 void Ia32CodeGenerator::GenCode(FunctionLiteral* fun) { |
523 // Record the position for debugging purposes. | 522 // Record the position for debugging purposes. |
524 __ RecordPosition(fun->start_position()); | 523 __ RecordPosition(fun->start_position()); |
525 | 524 |
526 Scope* scope = fun->scope(); | 525 Scope* scope = fun->scope(); |
527 ZoneList<Statement*>* body = fun->body(); | 526 ZoneList<Statement*>* body = fun->body(); |
528 | 527 |
529 // Initialize state. | 528 // Initialize state. |
530 { CodeGenState state(this); | 529 { CodeGenState state(this); |
531 scope_ = scope; | 530 scope_ = scope; |
(...skipping 26 matching lines...) Expand all Loading... |
558 // when the push has happened. | 557 // when the push has happened. |
559 bool arguments_object_allocated = false; | 558 bool arguments_object_allocated = false; |
560 bool arguments_object_saved = false; | 559 bool arguments_object_saved = false; |
561 | 560 |
562 // Allocate arguments object. | 561 // Allocate arguments object. |
563 // The arguments object pointer needs to be saved in ecx, since we need | 562 // The arguments object pointer needs to be saved in ecx, since we need |
564 // to store arguments into the context. | 563 // to store arguments into the context. |
565 if (scope->arguments() != NULL) { | 564 if (scope->arguments() != NULL) { |
566 ASSERT(scope->arguments_shadow() != NULL); | 565 ASSERT(scope->arguments_shadow() != NULL); |
567 Comment cmnt(masm_, "[ allocate arguments object"); | 566 Comment cmnt(masm_, "[ allocate arguments object"); |
| 567 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
| 568 __ lea(eax, ReceiverOperand()); |
568 __ push(FunctionOperand()); | 569 __ push(FunctionOperand()); |
569 __ CallRuntime(Runtime::kNewArguments, 1); | 570 __ push(eax); |
| 571 __ push(Immediate(Smi::FromInt(scope->num_parameters()))); |
| 572 __ CallStub(&stub); |
570 __ mov(ecx, Operand(eax)); | 573 __ mov(ecx, Operand(eax)); |
571 arguments_object_allocated = true; | 574 arguments_object_allocated = true; |
572 } | 575 } |
573 | 576 |
574 // Allocate space for locals and initialize them. | 577 // Allocate space for locals and initialize them. |
575 if (scope->num_stack_slots() > 0) { | 578 if (scope->num_stack_slots() > 0) { |
576 Comment cmnt(masm_, "[ allocate space for locals"); | 579 Comment cmnt(masm_, "[ allocate space for locals"); |
577 __ Set(eax, Immediate(Factory::undefined_value())); | 580 __ Set(eax, Immediate(Factory::undefined_value())); |
578 for (int i = scope->num_stack_slots(); i-- > 0; ) __ push(eax); | 581 for (int i = scope->num_stack_slots(); i-- > 0; ) __ push(eax); |
579 } | 582 } |
(...skipping 481 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1061 case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND"; | 1064 case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND"; |
1062 case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR"; | 1065 case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR"; |
1063 case Token::SAR: return "GenericBinaryOpStub_SAR"; | 1066 case Token::SAR: return "GenericBinaryOpStub_SAR"; |
1064 case Token::SHL: return "GenericBinaryOpStub_SHL"; | 1067 case Token::SHL: return "GenericBinaryOpStub_SHL"; |
1065 case Token::SHR: return "GenericBinaryOpStub_SHR"; | 1068 case Token::SHR: return "GenericBinaryOpStub_SHR"; |
1066 default: return "GenericBinaryOpStub"; | 1069 default: return "GenericBinaryOpStub"; |
1067 } | 1070 } |
1068 } | 1071 } |
1069 | 1072 |
1070 | 1073 |
1071 class ArgumentsAccessStub: public CodeStub { | |
1072 public: | |
1073 explicit ArgumentsAccessStub(bool is_length) : is_length_(is_length) { } | |
1074 | |
1075 private: | |
1076 bool is_length_; | |
1077 | |
1078 Major MajorKey() { return ArgumentsAccess; } | |
1079 int MinorKey() { return is_length_ ? 1 : 0; } | |
1080 void Generate(MacroAssembler* masm); | |
1081 | |
1082 const char* GetName() { return "ArgumentsAccessStub"; } | |
1083 | |
1084 #ifdef DEBUG | |
1085 void Print() { | |
1086 PrintF("ArgumentsAccessStub (is_length %s)\n", | |
1087 is_length_ ? "true" : "false"); | |
1088 } | |
1089 #endif | |
1090 }; | |
1091 | |
1092 | |
1093 void Ia32CodeGenerator::GenericBinaryOperation(Token::Value op, | 1074 void Ia32CodeGenerator::GenericBinaryOperation(Token::Value op, |
1094 OverwriteMode overwrite_mode) { | 1075 OverwriteMode overwrite_mode) { |
1095 Comment cmnt(masm_, "[ BinaryOperation"); | 1076 Comment cmnt(masm_, "[ BinaryOperation"); |
1096 Comment cmnt_token(masm_, Token::String(op)); | 1077 Comment cmnt_token(masm_, Token::String(op)); |
1097 switch (op) { | 1078 switch (op) { |
1098 case Token::ADD: | 1079 case Token::ADD: |
1099 case Token::SUB: | 1080 case Token::SUB: |
1100 case Token::MUL: | 1081 case Token::MUL: |
1101 case Token::DIV: | 1082 case Token::DIV: |
1102 case Token::MOD: { | 1083 case Token::MOD: { |
(...skipping 2203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3306 | 3287 |
3307 void Ia32CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { | 3288 void Ia32CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { |
3308 ASSERT(args->length() == 0); | 3289 ASSERT(args->length() == 0); |
3309 | 3290 |
3310 // Seed the result with the formal parameters count, which will be | 3291 // Seed the result with the formal parameters count, which will be |
3311 // used in case no arguments adaptor frame is found below the | 3292 // used in case no arguments adaptor frame is found below the |
3312 // current frame. | 3293 // current frame. |
3313 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); | 3294 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); |
3314 | 3295 |
3315 // Call the shared stub to get to the arguments.length. | 3296 // Call the shared stub to get to the arguments.length. |
3316 ArgumentsAccessStub stub(true); | 3297 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); |
3317 __ CallStub(&stub); | 3298 __ CallStub(&stub); |
3318 __ push(eax); | 3299 __ push(eax); |
3319 } | 3300 } |
3320 | 3301 |
3321 | 3302 |
3322 void Ia32CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { | 3303 void Ia32CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { |
3323 ASSERT(args->length() == 1); | 3304 ASSERT(args->length() == 1); |
3324 Label leave; | 3305 Label leave; |
3325 Load(args->at(0)); // Load the object. | 3306 Load(args->at(0)); // Load the object. |
3326 __ mov(eax, TOS); | 3307 __ mov(eax, TOS); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3369 | 3350 |
3370 void Ia32CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { | 3351 void Ia32CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { |
3371 ASSERT(args->length() == 1); | 3352 ASSERT(args->length() == 1); |
3372 | 3353 |
3373 // Load the key onto the stack and set register eax to the formal | 3354 // Load the key onto the stack and set register eax to the formal |
3374 // parameters count for the currently executing function. | 3355 // parameters count for the currently executing function. |
3375 Load(args->at(0)); | 3356 Load(args->at(0)); |
3376 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); | 3357 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); |
3377 | 3358 |
3378 // Call the shared stub to get to arguments[key]. | 3359 // Call the shared stub to get to arguments[key]. |
3379 ArgumentsAccessStub stub(false); | 3360 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); |
3380 __ CallStub(&stub); | 3361 __ CallStub(&stub); |
3381 __ mov(TOS, eax); | 3362 __ mov(TOS, eax); |
3382 } | 3363 } |
3383 | 3364 |
3384 | 3365 |
3385 void Ia32CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { | 3366 void Ia32CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { |
3386 ASSERT(args->length() == 2); | 3367 ASSERT(args->length() == 2); |
3387 | 3368 |
3388 // Load the two objects into registers and perform the comparison. | 3369 // Load the two objects into registers and perform the comparison. |
3389 Load(args->at(0)); | 3370 Load(args->at(0)); |
(...skipping 1418 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4808 __ fchs(); | 4789 __ fchs(); |
4809 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 4790 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
4810 | 4791 |
4811 __ bind(&done); | 4792 __ bind(&done); |
4812 | 4793 |
4813 __ StubReturn(1); | 4794 __ StubReturn(1); |
4814 } | 4795 } |
4815 | 4796 |
4816 | 4797 |
4817 void ArgumentsAccessStub::Generate(MacroAssembler* masm) { | 4798 void ArgumentsAccessStub::Generate(MacroAssembler* masm) { |
4818 // Check that the key is a smi for non-length access. | 4799 // If we're reading an element we need to check that the key is a smi. |
4819 Label slow; | 4800 Label slow; |
4820 if (!is_length_) { | 4801 if (type_ == READ_ELEMENT) { |
4821 __ mov(ebx, Operand(esp, 1 * kPointerSize)); // skip return address | 4802 __ mov(ebx, Operand(esp, 1 * kPointerSize)); // skip return address |
4822 __ test(ebx, Immediate(kSmiTagMask)); | 4803 __ test(ebx, Immediate(kSmiTagMask)); |
4823 __ j(not_zero, &slow, not_taken); | 4804 __ j(not_zero, &slow, not_taken); |
4824 } | 4805 } |
4825 | 4806 |
4826 // Check if the calling frame is an arguments adaptor frame. | 4807 // Check if the calling frame is an arguments adaptor frame. |
4827 Label adaptor; | 4808 Label adaptor; |
4828 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); | 4809 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); |
4829 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); | 4810 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); |
4830 __ cmp(ecx, ArgumentsAdaptorFrame::SENTINEL); | 4811 __ cmp(ecx, ArgumentsAdaptorFrame::SENTINEL); |
4831 __ j(equal, &adaptor); | 4812 if (type_ == NEW_OBJECT) { |
| 4813 __ j(not_equal, &slow); |
| 4814 } else { |
| 4815 __ j(equal, &adaptor); |
| 4816 } |
4832 | 4817 |
4833 // The displacement is used for skipping the return address on the | 4818 // The displacement is used for skipping the return address on the |
4834 // stack. It is the offset of the last parameter (if any) relative | 4819 // stack. It is the offset of the last parameter (if any) relative |
4835 // to the frame pointer. | 4820 // to the frame pointer. |
4836 static const int kDisplacement = 1 * kPointerSize; | 4821 static const int kDisplacement = 1 * kPointerSize; |
4837 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); // shifting code depends on this | 4822 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); // shifting code depends on this |
4838 | 4823 |
4839 if (is_length_) { | 4824 if (type_ == READ_LENGTH) { |
4840 // Do nothing. The length is already in register eax. | 4825 // Nothing to do: The formal number of parameters has already been |
4841 } else { | 4826 // passed in register eax by calling function. Just return it. |
| 4827 __ ret(0); |
| 4828 } else if (type_ == READ_ELEMENT) { |
4842 // Check index against formal parameters count limit passed in | 4829 // Check index against formal parameters count limit passed in |
4843 // through register eax. Use unsigned comparison to get negative | 4830 // through register eax. Use unsigned comparison to get negative |
4844 // check for free. | 4831 // check for free. |
4845 __ cmp(ebx, Operand(eax)); | 4832 __ cmp(ebx, Operand(eax)); |
4846 __ j(above_equal, &slow, not_taken); | 4833 __ j(above_equal, &slow, not_taken); |
4847 | 4834 |
4848 // Read the argument from the stack. | 4835 // Read the argument from the stack and return it. |
4849 __ lea(edx, Operand(ebp, eax, times_2, 0)); | 4836 __ lea(edx, Operand(ebp, eax, times_2, 0)); |
4850 __ neg(ebx); | 4837 __ neg(ebx); |
4851 __ mov(eax, Operand(edx, ebx, times_2, kDisplacement)); | 4838 __ mov(eax, Operand(edx, ebx, times_2, kDisplacement)); |
| 4839 __ ret(0); |
| 4840 } else { |
| 4841 ASSERT(type_ == NEW_OBJECT); |
| 4842 // Do nothing here. |
4852 } | 4843 } |
4853 | 4844 |
4854 // Return the length or the argument. | |
4855 __ ret(0); | |
4856 | |
4857 // Arguments adaptor case: Find the length or the actual argument in | 4845 // Arguments adaptor case: Find the length or the actual argument in |
4858 // the calling frame. | 4846 // the calling frame. |
4859 __ bind(&adaptor); | 4847 __ bind(&adaptor); |
4860 if (is_length_) { | 4848 if (type_ == READ_LENGTH) { |
4861 // Read the arguments length from the adaptor frame. | 4849 // Read the arguments length from the adaptor frame and return it. |
4862 __ mov(eax, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 4850 __ mov(eax, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
4863 } else { | 4851 __ ret(0); |
| 4852 } else if (type_ == READ_ELEMENT) { |
4864 // Check index against actual arguments limit found in the | 4853 // Check index against actual arguments limit found in the |
4865 // arguments adaptor frame. Use unsigned comparison to get | 4854 // arguments adaptor frame. Use unsigned comparison to get |
4866 // negative check for free. | 4855 // negative check for free. |
4867 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 4856 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
4868 __ cmp(ebx, Operand(ecx)); | 4857 __ cmp(ebx, Operand(ecx)); |
4869 __ j(above_equal, &slow, not_taken); | 4858 __ j(above_equal, &slow, not_taken); |
4870 | 4859 |
4871 // Read the argument from the stack. | 4860 // Read the argument from the stack and return it. |
4872 __ lea(edx, Operand(edx, ecx, times_2, 0)); | 4861 __ lea(edx, Operand(edx, ecx, times_2, 0)); |
4873 __ neg(ebx); | 4862 __ neg(ebx); |
4874 __ mov(eax, Operand(edx, ebx, times_2, kDisplacement)); | 4863 __ mov(eax, Operand(edx, ebx, times_2, kDisplacement)); |
| 4864 __ ret(0); |
| 4865 } else { |
| 4866 ASSERT(type_ == NEW_OBJECT); |
| 4867 // Patch the arguments.length and the parameters pointer. |
| 4868 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 4869 __ mov(Operand(esp, 1 * kPointerSize), ecx); |
| 4870 __ lea(edx, Operand(edx, ecx, times_2, kDisplacement + 1 * kPointerSize)); |
| 4871 __ mov(Operand(esp, 2 * kPointerSize), edx); |
| 4872 __ bind(&slow); |
| 4873 __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3); |
4875 } | 4874 } |
4876 | 4875 |
4877 // Return the length or the argument. | |
4878 __ ret(0); | |
4879 | |
4880 // Slow-case: Handle non-smi or out-of-bounds access to arguments | 4876 // Slow-case: Handle non-smi or out-of-bounds access to arguments |
4881 // by calling the runtime system. | 4877 // by calling the runtime system. |
4882 if (!is_length_) { | 4878 if (type_ == READ_ELEMENT) { |
4883 __ bind(&slow); | 4879 __ bind(&slow); |
4884 __ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1); | 4880 __ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1); |
4885 } | 4881 } |
4886 } | 4882 } |
4887 | 4883 |
4888 | 4884 |
4889 void CompareStub::Generate(MacroAssembler* masm) { | 4885 void CompareStub::Generate(MacroAssembler* masm) { |
4890 Label call_builtin, done; | 4886 Label call_builtin, done; |
4891 // Save the return address (and get it off the stack). | 4887 // Save the return address (and get it off the stack). |
4892 __ pop(ecx); | 4888 __ pop(ecx); |
(...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5341 bool is_eval) { | 5337 bool is_eval) { |
5342 Handle<Code> code = Ia32CodeGenerator::MakeCode(fun, script, is_eval); | 5338 Handle<Code> code = Ia32CodeGenerator::MakeCode(fun, script, is_eval); |
5343 if (!code.is_null()) { | 5339 if (!code.is_null()) { |
5344 Counters::total_compiled_code_size.Increment(code->instruction_size()); | 5340 Counters::total_compiled_code_size.Increment(code->instruction_size()); |
5345 } | 5341 } |
5346 return code; | 5342 return code; |
5347 } | 5343 } |
5348 | 5344 |
5349 | 5345 |
5350 } } // namespace v8::internal | 5346 } } // namespace v8::internal |
OLD | NEW |