Chromium Code Reviews| 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 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 151 frame_->EmitPush(Immediate(Smi::FromInt(scope_->num_parameters()))); | 151 frame_->EmitPush(Immediate(Smi::FromInt(scope_->num_parameters()))); |
| 152 frame_->CallStub(&stub, 3); | 152 frame_->CallStub(&stub, 3); |
| 153 __ mov(ecx, Operand(eax)); | 153 __ mov(ecx, Operand(eax)); |
| 154 arguments_object_allocated = true; | 154 arguments_object_allocated = true; |
| 155 } | 155 } |
| 156 | 156 |
| 157 // Allocate space for locals and initialize them. | 157 // Allocate space for locals and initialize them. |
| 158 frame_->AllocateStackSlots(scope_->num_stack_slots()); | 158 frame_->AllocateStackSlots(scope_->num_stack_slots()); |
| 159 | 159 |
| 160 if (scope_->num_heap_slots() > 0) { | 160 if (scope_->num_heap_slots() > 0) { |
| 161 frame_->SpillAll(); | |
| 161 Comment cmnt(masm_, "[ allocate local context"); | 162 Comment cmnt(masm_, "[ allocate local context"); |
| 162 // Save the arguments object pointer, if any. | 163 // Save the arguments object pointer, if any. |
| 163 if (arguments_object_allocated && !arguments_object_saved) { | 164 if (arguments_object_allocated && !arguments_object_saved) { |
| 164 frame_->EmitPush(ecx); | 165 frame_->EmitPush(ecx); |
| 165 arguments_object_saved = true; | 166 arguments_object_saved = true; |
| 166 } | 167 } |
| 167 // Allocate local context. | 168 // Allocate local context. |
| 168 // Get outer context and create a new context based on it. | 169 // Get outer context and create a new context based on it. |
| 169 frame_->EmitPush(frame_->Function()); | 170 frame_->EmitPush(frame_->Function()); |
| 170 frame_->CallRuntime(Runtime::kNewContext, 1); // eax holds the result | 171 frame_->CallRuntime(Runtime::kNewContext, 1); // eax holds the result |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 193 // needs to be copied into the context, it must be the last argument | 194 // needs to be copied into the context, it must be the last argument |
| 194 // passed to the parameter that needs to be copied. This is a rare | 195 // passed to the parameter that needs to be copied. This is a rare |
| 195 // case so we don't check for it, instead we rely on the copying | 196 // case so we don't check for it, instead we rely on the copying |
| 196 // order: such a parameter is copied repeatedly into the same | 197 // order: such a parameter is copied repeatedly into the same |
| 197 // context location and thus the last value is what is seen inside | 198 // context location and thus the last value is what is seen inside |
| 198 // the function. | 199 // the function. |
| 199 for (int i = 0; i < scope_->num_parameters(); i++) { | 200 for (int i = 0; i < scope_->num_parameters(); i++) { |
| 200 Variable* par = scope_->parameter(i); | 201 Variable* par = scope_->parameter(i); |
| 201 Slot* slot = par->slot(); | 202 Slot* slot = par->slot(); |
| 202 if (slot != NULL && slot->type() == Slot::CONTEXT) { | 203 if (slot != NULL && slot->type() == Slot::CONTEXT) { |
| 203 // Save the arguments object pointer, if any. | |
|
William Hesse
2008/11/18 16:37:34
What is this change?
Kevin Millikin (Chromium)
2008/11/18 19:12:06
As far as I can tell, the only reason to save ecx
| |
| 204 if (arguments_object_allocated && !arguments_object_saved) { | |
| 205 frame_->EmitPush(ecx); | |
| 206 arguments_object_saved = true; | |
| 207 } | |
| 208 ASSERT(!scope_->is_global_scope()); // no parameters in global scope | 204 ASSERT(!scope_->is_global_scope()); // no parameters in global scope |
| 209 __ mov(eax, frame_->ParameterAt(i)); | 205 __ mov(eax, frame_->ParameterAt(i)); |
| 210 // Loads ecx with context; used below in RecordWrite. | 206 // Loads ecx with context; used below in RecordWrite. |
| 211 __ mov(SlotOperand(slot, ecx), eax); | 207 __ mov(SlotOperand(slot, edx), eax); |
| 212 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 208 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
| 213 __ RecordWrite(ecx, offset, eax, ebx); | 209 __ RecordWrite(edx, offset, eax, ebx); |
| 214 } | 210 } |
| 215 } | 211 } |
| 216 } | 212 } |
| 217 | 213 |
| 218 // This section stores the pointer to the arguments object that | 214 // This section stores the pointer to the arguments object that |
| 219 // was allocated and copied into above. If the address was not | 215 // was allocated and copied into above. If the address was not |
| 220 // saved to TOS, we push ecx onto the stack. | 216 // saved to TOS, we push ecx onto the stack. |
| 221 // | 217 // |
| 222 // Store the arguments object. This must happen after context | 218 // Store the arguments object. This must happen after context |
| 223 // initialization because the arguments object may be stored in the | 219 // initialization because the arguments object may be stored in the |
| 224 // context. | 220 // context. |
| 225 if (arguments_object_allocated) { | 221 if (arguments_object_allocated) { |
| 226 ASSERT(scope_->arguments() != NULL); | 222 ASSERT(scope_->arguments() != NULL); |
| 227 ASSERT(scope_->arguments_shadow() != NULL); | 223 ASSERT(scope_->arguments_shadow() != NULL); |
| 228 Comment cmnt(masm_, "[ store arguments object"); | 224 Comment cmnt(masm_, "[ store arguments object"); |
| 229 { Reference shadow_ref(this, scope_->arguments_shadow()); | 225 { Reference shadow_ref(this, scope_->arguments_shadow()); |
| 230 ASSERT(shadow_ref.is_slot()); | 226 ASSERT(shadow_ref.is_slot()); |
| 231 { Reference arguments_ref(this, scope_->arguments()); | 227 { Reference arguments_ref(this, scope_->arguments()); |
| 232 ASSERT(arguments_ref.is_slot()); | 228 ASSERT(arguments_ref.is_slot()); |
| 233 // If the newly-allocated arguments object is already on the | 229 // If the newly-allocated arguments object is already on the |
| 234 // stack, we make use of the convenient property that references | 230 // stack, we make use of the convenient property that references |
| 235 // representing slots take up no space on the expression stack | 231 // representing slots take up no space on the expression stack |
| 236 // (ie, it doesn't matter that the stored value is actually below | 232 // (ie, it doesn't matter that the stored value is actually below |
| 237 // the reference). | 233 // the reference). |
| 238 // | 234 // |
| 239 // If the newly-allocated argument object is not already on | 235 // If the newly-allocated argument object is not already on |
| 240 // the stack, we rely on the property that loading a | 236 // the stack, we rely on the property that loading a |
| 241 // zero-sized reference will not clobber the ecx register. | 237 // zero-sized reference will not clobber the ecx register. |
| 242 if (!arguments_object_saved) { | 238 if (!arguments_object_saved) { |
| 239 frame_->SpillAll(); | |
| 243 frame_->EmitPush(ecx); | 240 frame_->EmitPush(ecx); |
| 244 } | 241 } |
| 245 arguments_ref.SetValue(NOT_CONST_INIT); | 242 arguments_ref.SetValue(NOT_CONST_INIT); |
| 246 } | 243 } |
| 247 shadow_ref.SetValue(NOT_CONST_INIT); | 244 shadow_ref.SetValue(NOT_CONST_INIT); |
| 248 } | 245 } |
| 249 frame_->Drop(); // Value is no longer needed. | 246 frame_->Drop(); // Value is no longer needed. |
| 250 } | 247 } |
| 251 | 248 |
| 252 // Generate code to 'execute' declarations and initialize functions | 249 // Generate code to 'execute' declarations and initialize functions |
| (...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 517 frame_->CallRuntime(Runtime::kThrowReferenceError, 1); | 514 frame_->CallRuntime(Runtime::kThrowReferenceError, 1); |
| 518 } | 515 } |
| 519 } | 516 } |
| 520 | 517 |
| 521 | 518 |
| 522 void CodeGenerator::UnloadReference(Reference* ref) { | 519 void CodeGenerator::UnloadReference(Reference* ref) { |
| 523 // Pop a reference from the stack while preserving TOS. | 520 // Pop a reference from the stack while preserving TOS. |
| 524 Comment cmnt(masm_, "[ UnloadReference"); | 521 Comment cmnt(masm_, "[ UnloadReference"); |
| 525 int size = ref->size(); | 522 int size = ref->size(); |
| 526 if (size == 1) { | 523 if (size == 1) { |
| 527 frame_->Pop(eax); | 524 frame_->EmitPop(eax); |
| 528 __ mov(frame_->Top(), eax); | 525 __ mov(frame_->Top(), eax); |
| 529 } else if (size > 1) { | 526 } else if (size > 1) { |
| 530 frame_->Pop(eax); | 527 frame_->EmitPop(eax); |
| 531 frame_->Drop(size); | 528 frame_->Drop(size); |
| 532 frame_->EmitPush(eax); | 529 frame_->EmitPush(eax); |
| 533 } | 530 } |
| 534 } | 531 } |
| 535 | 532 |
| 536 | 533 |
| 537 class ToBooleanStub: public CodeStub { | 534 class ToBooleanStub: public CodeStub { |
| 538 public: | 535 public: |
| 539 ToBooleanStub() { } | 536 ToBooleanStub() { } |
| 540 | 537 |
| 541 void Generate(MacroAssembler* masm); | 538 void Generate(MacroAssembler* masm); |
| 542 | 539 |
| 543 private: | 540 private: |
| 544 Major MajorKey() { return ToBoolean; } | 541 Major MajorKey() { return ToBoolean; } |
| 545 int MinorKey() { return 0; } | 542 int MinorKey() { return 0; } |
| 546 }; | 543 }; |
| 547 | 544 |
| 548 | 545 |
| 549 // ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and | 546 // ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and |
| 550 // convert it to a boolean in the condition code register or jump to | 547 // convert it to a boolean in the condition code register or jump to |
| 551 // 'false_target'/'true_target' as appropriate. | 548 // 'false_target'/'true_target' as appropriate. |
| 552 void CodeGenerator::ToBoolean(JumpTarget* true_target, JumpTarget* false_target) { | 549 void CodeGenerator::ToBoolean(JumpTarget* true_target, JumpTarget* false_target) { |
| 553 Comment cmnt(masm_, "[ ToBoolean"); | 550 Comment cmnt(masm_, "[ ToBoolean"); |
| 554 | 551 |
| 555 // The value to convert should be popped from the stack. | 552 // The value to convert should be popped from the stack. |
| 556 frame_->Pop(eax); | 553 frame_->EmitPop(eax); |
| 557 | 554 |
| 558 // Fast case checks. | 555 // Fast case checks. |
| 559 | 556 |
| 560 // 'false' => false. | 557 // 'false' => false. |
| 561 __ cmp(eax, Factory::false_value()); | 558 __ cmp(eax, Factory::false_value()); |
| 562 false_target->Branch(equal); | 559 false_target->Branch(equal); |
| 563 | 560 |
| 564 // 'true' => true. | 561 // 'true' => true. |
| 565 __ cmp(eax, Factory::true_value()); | 562 __ cmp(eax, Factory::true_value()); |
| 566 true_target->Branch(equal); | 563 true_target->Branch(equal); |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 704 | 701 |
| 705 | 702 |
| 706 void CodeGenerator::GenericBinaryOperation(Token::Value op, | 703 void CodeGenerator::GenericBinaryOperation(Token::Value op, |
| 707 StaticType* type, | 704 StaticType* type, |
| 708 OverwriteMode overwrite_mode) { | 705 OverwriteMode overwrite_mode) { |
| 709 Comment cmnt(masm_, "[ BinaryOperation"); | 706 Comment cmnt(masm_, "[ BinaryOperation"); |
| 710 Comment cmnt_token(masm_, Token::String(op)); | 707 Comment cmnt_token(masm_, Token::String(op)); |
| 711 | 708 |
| 712 if (op == Token::COMMA) { | 709 if (op == Token::COMMA) { |
| 713 // Simply discard left value. | 710 // Simply discard left value. |
| 714 frame_->Pop(eax); | 711 frame_->EmitPop(eax); |
| 715 frame_->Drop(); | 712 frame_->Drop(); |
| 716 frame_->EmitPush(eax); | 713 frame_->EmitPush(eax); |
| 717 return; | 714 return; |
| 718 } | 715 } |
| 719 | 716 |
| 720 // Set the flags based on the operation, type and loop nesting level. | 717 // Set the flags based on the operation, type and loop nesting level. |
| 721 GenericBinaryFlags flags; | 718 GenericBinaryFlags flags; |
| 722 switch (op) { | 719 switch (op) { |
| 723 case Token::BIT_OR: | 720 case Token::BIT_OR: |
| 724 case Token::BIT_AND: | 721 case Token::BIT_AND: |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 740 ? SMI_CODE_INLINED | 737 ? SMI_CODE_INLINED |
| 741 : SMI_CODE_IN_STUB; | 738 : SMI_CODE_IN_STUB; |
| 742 break; | 739 break; |
| 743 } | 740 } |
| 744 | 741 |
| 745 if (flags == SMI_CODE_INLINED) { | 742 if (flags == SMI_CODE_INLINED) { |
| 746 // Create a new deferred code for the slow-case part. | 743 // Create a new deferred code for the slow-case part. |
| 747 DeferredInlineBinaryOperation* deferred = | 744 DeferredInlineBinaryOperation* deferred = |
| 748 new DeferredInlineBinaryOperation(this, op, overwrite_mode, flags); | 745 new DeferredInlineBinaryOperation(this, op, overwrite_mode, flags); |
| 749 // Fetch the operands from the stack. | 746 // Fetch the operands from the stack. |
| 750 frame_->Pop(ebx); // get y | 747 frame_->EmitPop(ebx); // get y |
| 751 __ mov(eax, frame_->Top()); // get x | 748 __ mov(eax, frame_->Top()); // get x |
| 752 // Generate the inline part of the code. | 749 // Generate the inline part of the code. |
| 753 deferred->GenerateInlineCode(); | 750 deferred->GenerateInlineCode(); |
| 754 // Put result back on the stack. It seems somewhat weird to let | 751 // Put result back on the stack. It seems somewhat weird to let |
| 755 // the deferred code jump back before the assignment to the frame | 752 // the deferred code jump back before the assignment to the frame |
| 756 // top, but this is just to let the peephole optimizer get rid of | 753 // top, but this is just to let the peephole optimizer get rid of |
| 757 // more code. | 754 // more code. |
| 758 __ bind(deferred->exit()); | 755 __ bind(deferred->exit()); |
| 759 __ mov(frame_->Top(), eax); | 756 __ mov(frame_->Top(), eax); |
| 760 } else { | 757 } else { |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 931 | 928 |
| 932 switch (op) { | 929 switch (op) { |
| 933 case Token::ADD: { | 930 case Token::ADD: { |
| 934 DeferredCode* deferred = NULL; | 931 DeferredCode* deferred = NULL; |
| 935 if (!reversed) { | 932 if (!reversed) { |
| 936 deferred = new DeferredInlinedSmiAdd(this, int_value, overwrite_mode); | 933 deferred = new DeferredInlinedSmiAdd(this, int_value, overwrite_mode); |
| 937 } else { | 934 } else { |
| 938 deferred = new DeferredInlinedSmiAddReversed(this, int_value, | 935 deferred = new DeferredInlinedSmiAddReversed(this, int_value, |
| 939 overwrite_mode); | 936 overwrite_mode); |
| 940 } | 937 } |
| 941 frame_->Pop(eax); | 938 frame_->EmitPop(eax); |
| 942 __ add(Operand(eax), Immediate(value)); | 939 __ add(Operand(eax), Immediate(value)); |
| 943 __ j(overflow, deferred->enter(), not_taken); | 940 __ j(overflow, deferred->enter(), not_taken); |
| 944 __ test(eax, Immediate(kSmiTagMask)); | 941 __ test(eax, Immediate(kSmiTagMask)); |
| 945 __ j(not_zero, deferred->enter(), not_taken); | 942 __ j(not_zero, deferred->enter(), not_taken); |
| 946 __ bind(deferred->exit()); | 943 __ bind(deferred->exit()); |
| 947 frame_->EmitPush(eax); | 944 frame_->EmitPush(eax); |
| 948 break; | 945 break; |
| 949 } | 946 } |
| 950 | 947 |
| 951 case Token::SUB: { | 948 case Token::SUB: { |
| 952 DeferredCode* deferred = NULL; | 949 DeferredCode* deferred = NULL; |
| 953 frame_->Pop(eax); | 950 frame_->EmitPop(eax); |
| 954 if (!reversed) { | 951 if (!reversed) { |
| 955 deferred = new DeferredInlinedSmiSub(this, int_value, overwrite_mode); | 952 deferred = new DeferredInlinedSmiSub(this, int_value, overwrite_mode); |
| 956 __ sub(Operand(eax), Immediate(value)); | 953 __ sub(Operand(eax), Immediate(value)); |
| 957 } else { | 954 } else { |
| 958 deferred = new DeferredInlinedSmiSubReversed(this, edx, overwrite_mode); | 955 deferred = new DeferredInlinedSmiSubReversed(this, edx, overwrite_mode); |
| 959 __ mov(edx, Operand(eax)); | 956 __ mov(edx, Operand(eax)); |
| 960 __ mov(eax, Immediate(value)); | 957 __ mov(eax, Immediate(value)); |
| 961 __ sub(eax, Operand(edx)); | 958 __ sub(eax, Operand(edx)); |
| 962 } | 959 } |
| 963 __ j(overflow, deferred->enter(), not_taken); | 960 __ j(overflow, deferred->enter(), not_taken); |
| 964 __ test(eax, Immediate(kSmiTagMask)); | 961 __ test(eax, Immediate(kSmiTagMask)); |
| 965 __ j(not_zero, deferred->enter(), not_taken); | 962 __ j(not_zero, deferred->enter(), not_taken); |
| 966 __ bind(deferred->exit()); | 963 __ bind(deferred->exit()); |
| 967 frame_->EmitPush(eax); | 964 frame_->EmitPush(eax); |
| 968 break; | 965 break; |
| 969 } | 966 } |
| 970 | 967 |
| 971 case Token::SAR: { | 968 case Token::SAR: { |
| 972 if (reversed) { | 969 if (reversed) { |
| 973 frame_->Pop(eax); | 970 frame_->EmitPop(eax); |
| 974 frame_->EmitPush(Immediate(value)); | 971 frame_->EmitPush(Immediate(value)); |
| 975 frame_->EmitPush(eax); | 972 frame_->EmitPush(eax); |
| 976 GenericBinaryOperation(op, type, overwrite_mode); | 973 GenericBinaryOperation(op, type, overwrite_mode); |
| 977 } else { | 974 } else { |
| 978 int shift_value = int_value & 0x1f; // only least significant 5 bits | 975 int shift_value = int_value & 0x1f; // only least significant 5 bits |
| 979 DeferredCode* deferred = | 976 DeferredCode* deferred = |
| 980 new DeferredInlinedSmiOperation(this, Token::SAR, shift_value, | 977 new DeferredInlinedSmiOperation(this, Token::SAR, shift_value, |
| 981 overwrite_mode); | 978 overwrite_mode); |
| 982 frame_->Pop(eax); | 979 frame_->EmitPop(eax); |
| 983 __ test(eax, Immediate(kSmiTagMask)); | 980 __ test(eax, Immediate(kSmiTagMask)); |
| 984 __ j(not_zero, deferred->enter(), not_taken); | 981 __ j(not_zero, deferred->enter(), not_taken); |
| 985 __ sar(eax, shift_value); | 982 __ sar(eax, shift_value); |
| 986 __ and_(eax, ~kSmiTagMask); | 983 __ and_(eax, ~kSmiTagMask); |
| 987 __ bind(deferred->exit()); | 984 __ bind(deferred->exit()); |
| 988 frame_->EmitPush(eax); | 985 frame_->EmitPush(eax); |
| 989 } | 986 } |
| 990 break; | 987 break; |
| 991 } | 988 } |
| 992 | 989 |
| 993 case Token::SHR: { | 990 case Token::SHR: { |
| 994 if (reversed) { | 991 if (reversed) { |
| 995 frame_->Pop(eax); | 992 frame_->EmitPop(eax); |
| 996 frame_->EmitPush(Immediate(value)); | 993 frame_->EmitPush(Immediate(value)); |
| 997 frame_->EmitPush(eax); | 994 frame_->EmitPush(eax); |
| 998 GenericBinaryOperation(op, type, overwrite_mode); | 995 GenericBinaryOperation(op, type, overwrite_mode); |
| 999 } else { | 996 } else { |
| 1000 int shift_value = int_value & 0x1f; // only least significant 5 bits | 997 int shift_value = int_value & 0x1f; // only least significant 5 bits |
| 1001 DeferredCode* deferred = | 998 DeferredCode* deferred = |
| 1002 new DeferredInlinedSmiOperation(this, Token::SHR, shift_value, | 999 new DeferredInlinedSmiOperation(this, Token::SHR, shift_value, |
| 1003 overwrite_mode); | 1000 overwrite_mode); |
| 1004 frame_->Pop(eax); | 1001 frame_->EmitPop(eax); |
| 1005 __ test(eax, Immediate(kSmiTagMask)); | 1002 __ test(eax, Immediate(kSmiTagMask)); |
| 1006 __ mov(ebx, Operand(eax)); | 1003 __ mov(ebx, Operand(eax)); |
| 1007 __ j(not_zero, deferred->enter(), not_taken); | 1004 __ j(not_zero, deferred->enter(), not_taken); |
| 1008 __ sar(ebx, kSmiTagSize); | 1005 __ sar(ebx, kSmiTagSize); |
| 1009 __ shr(ebx, shift_value); | 1006 __ shr(ebx, shift_value); |
| 1010 __ test(ebx, Immediate(0xc0000000)); | 1007 __ test(ebx, Immediate(0xc0000000)); |
| 1011 __ j(not_zero, deferred->enter(), not_taken); | 1008 __ j(not_zero, deferred->enter(), not_taken); |
| 1012 // tag result and store it in TOS (eax) | 1009 // tag result and store it in TOS (eax) |
| 1013 ASSERT(kSmiTagSize == times_2); // adjust code if not the case | 1010 ASSERT(kSmiTagSize == times_2); // adjust code if not the case |
| 1014 __ lea(eax, Operand(ebx, ebx, times_1, kSmiTag)); | 1011 __ lea(eax, Operand(ebx, ebx, times_1, kSmiTag)); |
| 1015 __ bind(deferred->exit()); | 1012 __ bind(deferred->exit()); |
| 1016 frame_->EmitPush(eax); | 1013 frame_->EmitPush(eax); |
| 1017 } | 1014 } |
| 1018 break; | 1015 break; |
| 1019 } | 1016 } |
| 1020 | 1017 |
| 1021 case Token::SHL: { | 1018 case Token::SHL: { |
| 1022 if (reversed) { | 1019 if (reversed) { |
| 1023 frame_->Pop(eax); | 1020 frame_->EmitPop(eax); |
| 1024 frame_->EmitPush(Immediate(value)); | 1021 frame_->EmitPush(Immediate(value)); |
| 1025 frame_->EmitPush(eax); | 1022 frame_->EmitPush(eax); |
| 1026 GenericBinaryOperation(op, type, overwrite_mode); | 1023 GenericBinaryOperation(op, type, overwrite_mode); |
| 1027 } else { | 1024 } else { |
| 1028 int shift_value = int_value & 0x1f; // only least significant 5 bits | 1025 int shift_value = int_value & 0x1f; // only least significant 5 bits |
| 1029 DeferredCode* deferred = | 1026 DeferredCode* deferred = |
| 1030 new DeferredInlinedSmiOperation(this, Token::SHL, shift_value, | 1027 new DeferredInlinedSmiOperation(this, Token::SHL, shift_value, |
| 1031 overwrite_mode); | 1028 overwrite_mode); |
| 1032 frame_->Pop(eax); | 1029 frame_->EmitPop(eax); |
| 1033 __ test(eax, Immediate(kSmiTagMask)); | 1030 __ test(eax, Immediate(kSmiTagMask)); |
| 1034 __ mov(ebx, Operand(eax)); | 1031 __ mov(ebx, Operand(eax)); |
| 1035 __ j(not_zero, deferred->enter(), not_taken); | 1032 __ j(not_zero, deferred->enter(), not_taken); |
| 1036 __ sar(ebx, kSmiTagSize); | 1033 __ sar(ebx, kSmiTagSize); |
| 1037 __ shl(ebx, shift_value); | 1034 __ shl(ebx, shift_value); |
| 1038 __ lea(ecx, Operand(ebx, 0x40000000)); | 1035 __ lea(ecx, Operand(ebx, 0x40000000)); |
| 1039 __ test(ecx, Immediate(0x80000000)); | 1036 __ test(ecx, Immediate(0x80000000)); |
| 1040 __ j(not_zero, deferred->enter(), not_taken); | 1037 __ j(not_zero, deferred->enter(), not_taken); |
| 1041 // tag result and store it in TOS (eax) | 1038 // tag result and store it in TOS (eax) |
| 1042 ASSERT(kSmiTagSize == times_2); // adjust code if not the case | 1039 ASSERT(kSmiTagSize == times_2); // adjust code if not the case |
| 1043 __ lea(eax, Operand(ebx, ebx, times_1, kSmiTag)); | 1040 __ lea(eax, Operand(ebx, ebx, times_1, kSmiTag)); |
| 1044 __ bind(deferred->exit()); | 1041 __ bind(deferred->exit()); |
| 1045 frame_->EmitPush(eax); | 1042 frame_->EmitPush(eax); |
| 1046 } | 1043 } |
| 1047 break; | 1044 break; |
| 1048 } | 1045 } |
| 1049 | 1046 |
| 1050 case Token::BIT_OR: | 1047 case Token::BIT_OR: |
| 1051 case Token::BIT_XOR: | 1048 case Token::BIT_XOR: |
| 1052 case Token::BIT_AND: { | 1049 case Token::BIT_AND: { |
| 1053 DeferredCode* deferred = NULL; | 1050 DeferredCode* deferred = NULL; |
| 1054 if (!reversed) { | 1051 if (!reversed) { |
| 1055 deferred = new DeferredInlinedSmiOperation(this, op, int_value, | 1052 deferred = new DeferredInlinedSmiOperation(this, op, int_value, |
| 1056 overwrite_mode); | 1053 overwrite_mode); |
| 1057 } else { | 1054 } else { |
| 1058 deferred = new DeferredInlinedSmiOperationReversed(this, op, int_value, | 1055 deferred = new DeferredInlinedSmiOperationReversed(this, op, int_value, |
| 1059 overwrite_mode); | 1056 overwrite_mode); |
| 1060 } | 1057 } |
| 1061 frame_->Pop(eax); | 1058 frame_->EmitPop(eax); |
| 1062 __ test(eax, Immediate(kSmiTagMask)); | 1059 __ test(eax, Immediate(kSmiTagMask)); |
| 1063 __ j(not_zero, deferred->enter(), not_taken); | 1060 __ j(not_zero, deferred->enter(), not_taken); |
| 1064 if (op == Token::BIT_AND) { | 1061 if (op == Token::BIT_AND) { |
| 1065 __ and_(Operand(eax), Immediate(value)); | 1062 __ and_(Operand(eax), Immediate(value)); |
| 1066 } else if (op == Token::BIT_XOR) { | 1063 } else if (op == Token::BIT_XOR) { |
| 1067 __ xor_(Operand(eax), Immediate(value)); | 1064 __ xor_(Operand(eax), Immediate(value)); |
| 1068 } else { | 1065 } else { |
| 1069 ASSERT(op == Token::BIT_OR); | 1066 ASSERT(op == Token::BIT_OR); |
| 1070 __ or_(Operand(eax), Immediate(value)); | 1067 __ or_(Operand(eax), Immediate(value)); |
| 1071 } | 1068 } |
| 1072 __ bind(deferred->exit()); | 1069 __ bind(deferred->exit()); |
| 1073 frame_->EmitPush(eax); | 1070 frame_->EmitPush(eax); |
| 1074 break; | 1071 break; |
| 1075 } | 1072 } |
| 1076 | 1073 |
| 1077 default: { | 1074 default: { |
| 1078 if (!reversed) { | 1075 if (!reversed) { |
| 1079 frame_->EmitPush(Immediate(value)); | 1076 frame_->EmitPush(Immediate(value)); |
| 1080 } else { | 1077 } else { |
| 1081 frame_->Pop(eax); | 1078 frame_->EmitPop(eax); |
| 1082 frame_->EmitPush(Immediate(value)); | 1079 frame_->EmitPush(Immediate(value)); |
| 1083 frame_->EmitPush(eax); | 1080 frame_->EmitPush(eax); |
| 1084 } | 1081 } |
| 1085 GenericBinaryOperation(op, type, overwrite_mode); | 1082 GenericBinaryOperation(op, type, overwrite_mode); |
| 1086 break; | 1083 break; |
| 1087 } | 1084 } |
| 1088 } | 1085 } |
| 1089 } | 1086 } |
| 1090 | 1087 |
| 1091 | 1088 |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 1117 }; | 1114 }; |
| 1118 | 1115 |
| 1119 | 1116 |
| 1120 void CodeGenerator::Comparison(Condition cc, bool strict) { | 1117 void CodeGenerator::Comparison(Condition cc, bool strict) { |
| 1121 // Strict only makes sense for equality comparisons. | 1118 // Strict only makes sense for equality comparisons. |
| 1122 ASSERT(!strict || cc == equal); | 1119 ASSERT(!strict || cc == equal); |
| 1123 | 1120 |
| 1124 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. | 1121 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. |
| 1125 if (cc == greater || cc == less_equal) { | 1122 if (cc == greater || cc == less_equal) { |
| 1126 cc = ReverseCondition(cc); | 1123 cc = ReverseCondition(cc); |
| 1127 frame_->Pop(edx); | 1124 frame_->EmitPop(edx); |
| 1128 frame_->Pop(eax); | 1125 frame_->EmitPop(eax); |
| 1129 } else { | 1126 } else { |
| 1130 frame_->Pop(eax); | 1127 frame_->EmitPop(eax); |
| 1131 frame_->Pop(edx); | 1128 frame_->EmitPop(edx); |
| 1132 } | 1129 } |
| 1133 | 1130 |
| 1134 // Check for the smi case. | 1131 // Check for the smi case. |
| 1135 JumpTarget is_smi(this); | 1132 JumpTarget is_smi(this); |
| 1136 JumpTarget done(this); | 1133 JumpTarget done(this); |
| 1137 __ mov(ecx, Operand(eax)); | 1134 __ mov(ecx, Operand(eax)); |
| 1138 __ or_(ecx, Operand(edx)); | 1135 __ or_(ecx, Operand(edx)); |
| 1139 __ test(ecx, Immediate(kSmiTagMask)); | 1136 __ test(ecx, Immediate(kSmiTagMask)); |
| 1140 is_smi.Branch(zero, taken); | 1137 is_smi.Branch(zero, taken); |
| 1141 | 1138 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1193 Handle<Object> value, | 1190 Handle<Object> value, |
| 1194 bool strict) { | 1191 bool strict) { |
| 1195 // Strict only makes sense for equality comparisons. | 1192 // Strict only makes sense for equality comparisons. |
| 1196 ASSERT(!strict || cc == equal); | 1193 ASSERT(!strict || cc == equal); |
| 1197 | 1194 |
| 1198 int int_value = Smi::cast(*value)->value(); | 1195 int int_value = Smi::cast(*value)->value(); |
| 1199 ASSERT(is_intn(int_value, kMaxSmiInlinedBits)); | 1196 ASSERT(is_intn(int_value, kMaxSmiInlinedBits)); |
| 1200 | 1197 |
| 1201 SmiComparisonDeferred* deferred = | 1198 SmiComparisonDeferred* deferred = |
| 1202 new SmiComparisonDeferred(this, cc, strict, int_value); | 1199 new SmiComparisonDeferred(this, cc, strict, int_value); |
| 1203 frame_->Pop(eax); | 1200 frame_->EmitPop(eax); |
| 1204 __ test(eax, Immediate(kSmiTagMask)); | 1201 __ test(eax, Immediate(kSmiTagMask)); |
| 1205 __ j(not_zero, deferred->enter(), not_taken); | 1202 __ j(not_zero, deferred->enter(), not_taken); |
| 1206 // Test smi equality by pointer comparison. | 1203 // Test smi equality by pointer comparison. |
| 1207 __ cmp(Operand(eax), Immediate(value)); | 1204 __ cmp(Operand(eax), Immediate(value)); |
| 1208 __ bind(deferred->exit()); | 1205 __ bind(deferred->exit()); |
| 1209 cc_reg_ = cc; | 1206 cc_reg_ = cc; |
| 1210 } | 1207 } |
| 1211 | 1208 |
| 1212 | 1209 |
| 1213 class CallFunctionStub: public CodeStub { | 1210 class CallFunctionStub: public CodeStub { |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1274 | 1271 |
| 1275 | 1272 |
| 1276 void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { | 1273 void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { |
| 1277 for (int i = 0; frame_ != NULL && i < statements->length(); i++) { | 1274 for (int i = 0; frame_ != NULL && i < statements->length(); i++) { |
| 1278 Visit(statements->at(i)); | 1275 Visit(statements->at(i)); |
| 1279 } | 1276 } |
| 1280 } | 1277 } |
| 1281 | 1278 |
| 1282 | 1279 |
| 1283 void CodeGenerator::VisitBlock(Block* node) { | 1280 void CodeGenerator::VisitBlock(Block* node) { |
| 1281 frame_->SpillAll(); | |
| 1284 Comment cmnt(masm_, "[ Block"); | 1282 Comment cmnt(masm_, "[ Block"); |
| 1285 RecordStatementPosition(node); | 1283 RecordStatementPosition(node); |
| 1286 node->set_break_stack_height(break_stack_height_); | 1284 node->set_break_stack_height(break_stack_height_); |
| 1287 node->break_target()->set_code_generator(this); | 1285 node->break_target()->set_code_generator(this); |
| 1288 VisitStatements(node->statements()); | 1286 VisitStatements(node->statements()); |
| 1289 if (node->break_target()->is_linked()) { | 1287 if (node->break_target()->is_linked()) { |
| 1290 node->break_target()->Bind(); | 1288 node->break_target()->Bind(); |
| 1291 } | 1289 } |
| 1292 } | 1290 } |
| 1293 | 1291 |
| 1294 | 1292 |
| 1295 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 1293 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 1294 frame_->SpillAll(); | |
| 1296 frame_->EmitPush(Immediate(pairs)); | 1295 frame_->EmitPush(Immediate(pairs)); |
| 1297 frame_->EmitPush(esi); | 1296 frame_->EmitPush(esi); |
| 1298 frame_->EmitPush(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); | 1297 frame_->EmitPush(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); |
| 1299 frame_->CallRuntime(Runtime::kDeclareGlobals, 3); | 1298 frame_->CallRuntime(Runtime::kDeclareGlobals, 3); |
| 1300 // Return value is ignored. | 1299 // Return value is ignored. |
| 1301 } | 1300 } |
| 1302 | 1301 |
| 1303 | 1302 |
| 1304 void CodeGenerator::VisitDeclaration(Declaration* node) { | 1303 void CodeGenerator::VisitDeclaration(Declaration* node) { |
| 1304 frame_->SpillAll(); | |
| 1305 | |
| 1305 Comment cmnt(masm_, "[ Declaration"); | 1306 Comment cmnt(masm_, "[ Declaration"); |
| 1306 Variable* var = node->proxy()->var(); | 1307 Variable* var = node->proxy()->var(); |
| 1307 ASSERT(var != NULL); // must have been resolved | 1308 ASSERT(var != NULL); // must have been resolved |
| 1308 Slot* slot = var->slot(); | 1309 Slot* slot = var->slot(); |
| 1309 | 1310 |
| 1310 // If it was not possible to allocate the variable at compile time, | 1311 // If it was not possible to allocate the variable at compile time, |
| 1311 // we need to "declare" it at runtime to make sure it actually | 1312 // we need to "declare" it at runtime to make sure it actually |
| 1312 // exists in the local context. | 1313 // exists in the local context. |
| 1313 if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1314 if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 1314 // Variables with a "LOOKUP" slot were introduced as non-locals | 1315 // Variables with a "LOOKUP" slot were introduced as non-locals |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1356 // Get rid of the assigned value (declarations are statements). It's | 1357 // Get rid of the assigned value (declarations are statements). It's |
| 1357 // safe to pop the value lying on top of the reference before unloading | 1358 // safe to pop the value lying on top of the reference before unloading |
| 1358 // the reference itself (which preserves the top of stack) because we | 1359 // the reference itself (which preserves the top of stack) because we |
| 1359 // know that it is a zero-sized reference. | 1360 // know that it is a zero-sized reference. |
| 1360 frame_->Drop(); | 1361 frame_->Drop(); |
| 1361 } | 1362 } |
| 1362 } | 1363 } |
| 1363 | 1364 |
| 1364 | 1365 |
| 1365 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { | 1366 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { |
| 1367 frame_->SpillAll(); | |
| 1366 Comment cmnt(masm_, "[ ExpressionStatement"); | 1368 Comment cmnt(masm_, "[ ExpressionStatement"); |
| 1367 RecordStatementPosition(node); | 1369 RecordStatementPosition(node); |
| 1368 Expression* expression = node->expression(); | 1370 Expression* expression = node->expression(); |
| 1369 expression->MarkAsStatement(); | 1371 expression->MarkAsStatement(); |
| 1370 Load(expression); | 1372 Load(expression); |
| 1371 // Remove the lingering expression result from the top of stack. | 1373 // Remove the lingering expression result from the top of stack. |
| 1372 frame_->Drop(); | 1374 frame_->Drop(); |
| 1373 } | 1375 } |
| 1374 | 1376 |
| 1375 | 1377 |
| 1376 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { | 1378 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { |
| 1379 frame_->SpillAll(); | |
| 1377 Comment cmnt(masm_, "// EmptyStatement"); | 1380 Comment cmnt(masm_, "// EmptyStatement"); |
| 1378 // nothing to do | 1381 // nothing to do |
| 1379 } | 1382 } |
| 1380 | 1383 |
| 1381 | 1384 |
| 1382 void CodeGenerator::VisitIfStatement(IfStatement* node) { | 1385 void CodeGenerator::VisitIfStatement(IfStatement* node) { |
| 1386 frame_->SpillAll(); | |
| 1383 Comment cmnt(masm_, "[ IfStatement"); | 1387 Comment cmnt(masm_, "[ IfStatement"); |
| 1384 // Generate different code depending on which parts of the if statement | 1388 // Generate different code depending on which parts of the if statement |
| 1385 // are present or not. | 1389 // are present or not. |
| 1386 bool has_then_stm = node->HasThenStatement(); | 1390 bool has_then_stm = node->HasThenStatement(); |
| 1387 bool has_else_stm = node->HasElseStatement(); | 1391 bool has_else_stm = node->HasElseStatement(); |
| 1388 | 1392 |
| 1389 RecordStatementPosition(node); | 1393 RecordStatementPosition(node); |
| 1390 JumpTarget exit(this); | 1394 JumpTarget exit(this); |
| 1391 if (has_then_stm && has_else_stm) { | 1395 if (has_then_stm && has_else_stm) { |
| 1392 JumpTarget then(this); | 1396 JumpTarget then(this); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1470 } | 1474 } |
| 1471 | 1475 |
| 1472 | 1476 |
| 1473 void CodeGenerator::CleanStack(int num_bytes) { | 1477 void CodeGenerator::CleanStack(int num_bytes) { |
| 1474 ASSERT(num_bytes % kPointerSize == 0); | 1478 ASSERT(num_bytes % kPointerSize == 0); |
| 1475 frame_->Drop(num_bytes / kPointerSize); | 1479 frame_->Drop(num_bytes / kPointerSize); |
| 1476 } | 1480 } |
| 1477 | 1481 |
| 1478 | 1482 |
| 1479 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { | 1483 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { |
| 1484 frame_->SpillAll(); | |
| 1480 Comment cmnt(masm_, "[ ContinueStatement"); | 1485 Comment cmnt(masm_, "[ ContinueStatement"); |
| 1481 RecordStatementPosition(node); | 1486 RecordStatementPosition(node); |
| 1482 CleanStack(break_stack_height_ - node->target()->break_stack_height()); | 1487 CleanStack(break_stack_height_ - node->target()->break_stack_height()); |
| 1483 node->target()->continue_target()->Jump(); | 1488 node->target()->continue_target()->Jump(); |
| 1484 } | 1489 } |
| 1485 | 1490 |
| 1486 | 1491 |
| 1487 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { | 1492 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { |
| 1493 frame_->SpillAll(); | |
| 1488 Comment cmnt(masm_, "[ BreakStatement"); | 1494 Comment cmnt(masm_, "[ BreakStatement"); |
| 1489 RecordStatementPosition(node); | 1495 RecordStatementPosition(node); |
| 1490 CleanStack(break_stack_height_ - node->target()->break_stack_height()); | 1496 CleanStack(break_stack_height_ - node->target()->break_stack_height()); |
| 1491 node->target()->break_target()->Jump(); | 1497 node->target()->break_target()->Jump(); |
| 1492 } | 1498 } |
| 1493 | 1499 |
| 1494 | 1500 |
| 1495 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { | 1501 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { |
| 1502 frame_->SpillAll(); | |
| 1496 Comment cmnt(masm_, "[ ReturnStatement"); | 1503 Comment cmnt(masm_, "[ ReturnStatement"); |
| 1497 RecordStatementPosition(node); | 1504 RecordStatementPosition(node); |
| 1498 Load(node->expression()); | 1505 Load(node->expression()); |
| 1499 | 1506 |
| 1500 // Move the function result into eax | 1507 // Move the function result into eax |
| 1501 frame_->Pop(eax); | 1508 frame_->EmitPop(eax); |
| 1502 | 1509 |
| 1503 // If we're inside a try statement or the return instruction | 1510 // If we're inside a try statement or the return instruction |
| 1504 // sequence has been generated, we just jump to that | 1511 // sequence has been generated, we just jump to that |
| 1505 // point. Otherwise, we generate the return instruction sequence and | 1512 // point. Otherwise, we generate the return instruction sequence and |
| 1506 // bind the function return label. | 1513 // bind the function return label. |
| 1507 if (is_inside_try_ || function_return_.is_bound()) { | 1514 if (is_inside_try_ || function_return_.is_bound()) { |
| 1508 function_return_.Jump(); | 1515 function_return_.Jump(); |
| 1509 } else { | 1516 } else { |
| 1510 function_return_.Bind(); | 1517 function_return_.Bind(); |
| 1511 if (FLAG_trace) { | 1518 if (FLAG_trace) { |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 1525 | 1532 |
| 1526 // Check that the size of the code used for returning matches what is | 1533 // Check that the size of the code used for returning matches what is |
| 1527 // expected by the debugger. | 1534 // expected by the debugger. |
| 1528 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength, | 1535 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength, |
| 1529 __ SizeOfCodeGeneratedSince(&check_exit_codesize)); | 1536 __ SizeOfCodeGeneratedSince(&check_exit_codesize)); |
| 1530 } | 1537 } |
| 1531 } | 1538 } |
| 1532 | 1539 |
| 1533 | 1540 |
| 1534 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { | 1541 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { |
| 1542 frame_->SpillAll(); | |
| 1535 Comment cmnt(masm_, "[ WithEnterStatement"); | 1543 Comment cmnt(masm_, "[ WithEnterStatement"); |
| 1536 RecordStatementPosition(node); | 1544 RecordStatementPosition(node); |
| 1537 Load(node->expression()); | 1545 Load(node->expression()); |
| 1538 frame_->CallRuntime(Runtime::kPushContext, 1); | 1546 frame_->CallRuntime(Runtime::kPushContext, 1); |
| 1539 | 1547 |
| 1540 if (kDebug) { | 1548 if (kDebug) { |
| 1541 JumpTarget verified_true(this); | 1549 JumpTarget verified_true(this); |
| 1542 // Verify eax and esi are the same in debug mode | 1550 // Verify eax and esi are the same in debug mode |
| 1543 __ cmp(eax, Operand(esi)); | 1551 __ cmp(eax, Operand(esi)); |
| 1544 verified_true.Branch(equal); | 1552 verified_true.Branch(equal); |
| 1545 __ int3(); | 1553 __ int3(); |
| 1546 verified_true.Bind(); | 1554 verified_true.Bind(); |
| 1547 } | 1555 } |
| 1548 | 1556 |
| 1549 // Update context local. | 1557 // Update context local. |
| 1550 __ mov(frame_->Context(), esi); | 1558 __ mov(frame_->Context(), esi); |
| 1551 } | 1559 } |
| 1552 | 1560 |
| 1553 | 1561 |
| 1554 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { | 1562 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { |
| 1563 frame_->SpillAll(); | |
| 1555 Comment cmnt(masm_, "[ WithExitStatement"); | 1564 Comment cmnt(masm_, "[ WithExitStatement"); |
| 1556 // Pop context. | 1565 // Pop context. |
| 1557 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX)); | 1566 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX)); |
| 1558 // Update context local. | 1567 // Update context local. |
| 1559 __ mov(frame_->Context(), esi); | 1568 __ mov(frame_->Context(), esi); |
| 1560 } | 1569 } |
| 1561 | 1570 |
| 1562 | 1571 |
| 1563 int CodeGenerator::FastCaseSwitchMaxOverheadFactor() { | 1572 int CodeGenerator::FastCaseSwitchMaxOverheadFactor() { |
| 1564 return kFastSwitchMaxOverheadFactor; | 1573 return kFastSwitchMaxOverheadFactor; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 1579 Vector<JumpTarget*> case_targets, | 1588 Vector<JumpTarget*> case_targets, |
| 1580 Vector<JumpTarget> case_labels) { | 1589 Vector<JumpTarget> case_labels) { |
| 1581 // Notice: Internal references, used by both the jmp instruction and | 1590 // Notice: Internal references, used by both the jmp instruction and |
| 1582 // the table entries, need to be relocated if the buffer grows. This | 1591 // the table entries, need to be relocated if the buffer grows. This |
| 1583 // prevents the forward use of Labels, since a displacement cannot | 1592 // prevents the forward use of Labels, since a displacement cannot |
| 1584 // survive relocation, and it also cannot safely be distinguished | 1593 // survive relocation, and it also cannot safely be distinguished |
| 1585 // from a real address. Instead we put in zero-values as | 1594 // from a real address. Instead we put in zero-values as |
| 1586 // placeholders, and fill in the addresses after the labels have been | 1595 // placeholders, and fill in the addresses after the labels have been |
| 1587 // bound. | 1596 // bound. |
| 1588 | 1597 |
| 1589 frame_->Pop(eax); // supposed Smi | 1598 frame_->EmitPop(eax); // supposed Smi |
| 1590 // check range of value, if outside [0..length-1] jump to default/end label. | 1599 // check range of value, if outside [0..length-1] jump to default/end label. |
| 1591 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); | 1600 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
| 1592 | 1601 |
| 1593 // Test whether input is a HeapNumber that is really a Smi | 1602 // Test whether input is a HeapNumber that is really a Smi |
| 1594 JumpTarget is_smi(this); | 1603 JumpTarget is_smi(this); |
| 1595 __ test(eax, Immediate(kSmiTagMask)); | 1604 __ test(eax, Immediate(kSmiTagMask)); |
| 1596 is_smi.Branch(equal); | 1605 is_smi.Branch(equal); |
| 1597 // It's a heap object, not a Smi or a Failure | 1606 // It's a heap object, not a Smi or a Failure |
| 1598 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 1607 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 1599 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | 1608 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1631 | 1640 |
| 1632 for (int i = 0, entry_pos = table_start.label()->pos(); | 1641 for (int i = 0, entry_pos = table_start.label()->pos(); |
| 1633 i < range; | 1642 i < range; |
| 1634 i++, entry_pos += sizeof(uint32_t)) { | 1643 i++, entry_pos += sizeof(uint32_t)) { |
| 1635 __ WriteInternalReference(entry_pos, *case_targets[i]->label()); | 1644 __ WriteInternalReference(entry_pos, *case_targets[i]->label()); |
| 1636 } | 1645 } |
| 1637 } | 1646 } |
| 1638 | 1647 |
| 1639 | 1648 |
| 1640 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { | 1649 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { |
| 1650 frame_->SpillAll(); | |
| 1641 Comment cmnt(masm_, "[ SwitchStatement"); | 1651 Comment cmnt(masm_, "[ SwitchStatement"); |
| 1642 RecordStatementPosition(node); | 1652 RecordStatementPosition(node); |
| 1643 node->set_break_stack_height(break_stack_height_); | 1653 node->set_break_stack_height(break_stack_height_); |
| 1644 node->break_target()->set_code_generator(this); | 1654 node->break_target()->set_code_generator(this); |
| 1645 | 1655 |
| 1646 Load(node->tag()); | 1656 Load(node->tag()); |
| 1647 | 1657 |
| 1648 if (TryGenerateFastCaseSwitchStatement(node)) { | 1658 if (TryGenerateFastCaseSwitchStatement(node)) { |
| 1649 return; | 1659 return; |
| 1650 } | 1660 } |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1720 fall_through.Bind(); | 1730 fall_through.Bind(); |
| 1721 } | 1731 } |
| 1722 | 1732 |
| 1723 if (node->break_target()->is_linked()) { | 1733 if (node->break_target()->is_linked()) { |
| 1724 node->break_target()->Bind(); | 1734 node->break_target()->Bind(); |
| 1725 } | 1735 } |
| 1726 } | 1736 } |
| 1727 | 1737 |
| 1728 | 1738 |
| 1729 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { | 1739 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { |
| 1740 frame_->SpillAll(); | |
| 1730 Comment cmnt(masm_, "[ LoopStatement"); | 1741 Comment cmnt(masm_, "[ LoopStatement"); |
| 1731 RecordStatementPosition(node); | 1742 RecordStatementPosition(node); |
| 1732 node->set_break_stack_height(break_stack_height_); | 1743 node->set_break_stack_height(break_stack_height_); |
| 1733 node->break_target()->set_code_generator(this); | 1744 node->break_target()->set_code_generator(this); |
| 1734 node->continue_target()->set_code_generator(this); | 1745 node->continue_target()->set_code_generator(this); |
| 1735 | 1746 |
| 1736 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a | 1747 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a |
| 1737 // known result for the test expression, with no side effects. | 1748 // known result for the test expression, with no side effects. |
| 1738 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; | 1749 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; |
| 1739 if (node->cond() == NULL) { | 1750 if (node->cond() == NULL) { |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1898 } | 1909 } |
| 1899 | 1910 |
| 1900 DecrementLoopNesting(); | 1911 DecrementLoopNesting(); |
| 1901 if (node->break_target()->is_linked()) { | 1912 if (node->break_target()->is_linked()) { |
| 1902 node->break_target()->Bind(); | 1913 node->break_target()->Bind(); |
| 1903 } | 1914 } |
| 1904 } | 1915 } |
| 1905 | 1916 |
| 1906 | 1917 |
| 1907 void CodeGenerator::VisitForInStatement(ForInStatement* node) { | 1918 void CodeGenerator::VisitForInStatement(ForInStatement* node) { |
| 1919 frame_->SpillAll(); | |
| 1908 Comment cmnt(masm_, "[ ForInStatement"); | 1920 Comment cmnt(masm_, "[ ForInStatement"); |
| 1909 RecordStatementPosition(node); | 1921 RecordStatementPosition(node); |
| 1910 | 1922 |
| 1911 // We keep stuff on the stack while the body is executing. | 1923 // We keep stuff on the stack while the body is executing. |
| 1912 // Record it, so that a break/continue crossing this statement | 1924 // Record it, so that a break/continue crossing this statement |
| 1913 // can restore the stack. | 1925 // can restore the stack. |
| 1914 const int kForInStackSize = 5 * kPointerSize; | 1926 const int kForInStackSize = 5 * kPointerSize; |
| 1915 break_stack_height_ += kForInStackSize; | 1927 break_stack_height_ += kForInStackSize; |
| 1916 node->set_break_stack_height(break_stack_height_); | 1928 node->set_break_stack_height(break_stack_height_); |
| 1917 node->break_target()->set_code_generator(this); | 1929 node->break_target()->set_code_generator(this); |
| 1918 node->continue_target()->set_code_generator(this); | 1930 node->continue_target()->set_code_generator(this); |
| 1919 | 1931 |
| 1920 JumpTarget primitive(this); | 1932 JumpTarget primitive(this); |
| 1921 JumpTarget jsobject(this); | 1933 JumpTarget jsobject(this); |
| 1922 JumpTarget fixed_array(this); | 1934 JumpTarget fixed_array(this); |
| 1923 JumpTarget entry(this); | 1935 JumpTarget entry(this); |
| 1924 JumpTarget end_del_check(this); | 1936 JumpTarget end_del_check(this); |
| 1925 JumpTarget cleanup(this); | 1937 JumpTarget cleanup(this); |
| 1926 JumpTarget exit(this); | 1938 JumpTarget exit(this); |
| 1927 | 1939 |
| 1928 // Get the object to enumerate over (converted to JSObject). | 1940 // Get the object to enumerate over (converted to JSObject). |
| 1929 Load(node->enumerable()); | 1941 Load(node->enumerable()); |
| 1930 | 1942 |
| 1931 // Both SpiderMonkey and kjs ignore null and undefined in contrast | 1943 // Both SpiderMonkey and kjs ignore null and undefined in contrast |
| 1932 // to the specification. 12.6.4 mandates a call to ToObject. | 1944 // to the specification. 12.6.4 mandates a call to ToObject. |
| 1933 frame_->Pop(eax); | 1945 frame_->EmitPop(eax); |
| 1934 | 1946 |
| 1935 // eax: value to be iterated over | 1947 // eax: value to be iterated over |
| 1936 __ cmp(eax, Factory::undefined_value()); | 1948 __ cmp(eax, Factory::undefined_value()); |
| 1937 exit.Branch(equal); | 1949 exit.Branch(equal); |
| 1938 __ cmp(eax, Factory::null_value()); | 1950 __ cmp(eax, Factory::null_value()); |
| 1939 exit.Branch(equal); | 1951 exit.Branch(equal); |
| 1940 | 1952 |
| 1941 // Stack layout in body: | 1953 // Stack layout in body: |
| 1942 // [iteration counter (smi)] <- slot 0 | 1954 // [iteration counter (smi)] <- slot 0 |
| 1943 // [length of array] <- slot 1 | 1955 // [length of array] <- slot 1 |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2065 // Discard the i'th entry pushed above or else the remainder of the | 2077 // Discard the i'th entry pushed above or else the remainder of the |
| 2066 // reference, whichever is currently on top of the stack. | 2078 // reference, whichever is currently on top of the stack. |
| 2067 frame_->Drop(); | 2079 frame_->Drop(); |
| 2068 | 2080 |
| 2069 // Body. | 2081 // Body. |
| 2070 CheckStack(); // TODO(1222600): ignore if body contains calls. | 2082 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 2071 Visit(node->body()); | 2083 Visit(node->body()); |
| 2072 | 2084 |
| 2073 // Next. | 2085 // Next. |
| 2074 node->continue_target()->Bind(); | 2086 node->continue_target()->Bind(); |
| 2075 frame_->Pop(eax); | 2087 frame_->EmitPop(eax); |
| 2076 __ add(Operand(eax), Immediate(Smi::FromInt(1))); | 2088 __ add(Operand(eax), Immediate(Smi::FromInt(1))); |
| 2077 frame_->EmitPush(eax); | 2089 frame_->EmitPush(eax); |
| 2078 entry.Jump(); | 2090 entry.Jump(); |
| 2079 | 2091 |
| 2080 // Cleanup. | 2092 // Cleanup. |
| 2081 cleanup.Bind(); | 2093 cleanup.Bind(); |
| 2082 node->break_target()->Bind(); | 2094 node->break_target()->Bind(); |
| 2083 frame_->Drop(5); | 2095 frame_->Drop(5); |
| 2084 | 2096 |
| 2085 // Exit. | 2097 // Exit. |
| 2086 exit.Bind(); | 2098 exit.Bind(); |
| 2087 | 2099 |
| 2088 break_stack_height_ -= kForInStackSize; | 2100 break_stack_height_ -= kForInStackSize; |
| 2089 } | 2101 } |
| 2090 | 2102 |
| 2091 | 2103 |
| 2092 void CodeGenerator::VisitTryCatch(TryCatch* node) { | 2104 void CodeGenerator::VisitTryCatch(TryCatch* node) { |
| 2105 frame_->SpillAll(); | |
| 2093 Comment cmnt(masm_, "[ TryCatch"); | 2106 Comment cmnt(masm_, "[ TryCatch"); |
| 2094 | 2107 |
| 2095 JumpTarget try_block(this); | 2108 JumpTarget try_block(this); |
| 2096 JumpTarget exit(this); | 2109 JumpTarget exit(this); |
| 2097 | 2110 |
| 2098 try_block.Call(); | 2111 try_block.Call(); |
| 2099 // --- Catch block --- | 2112 // --- Catch block --- |
| 2100 frame_->EmitPush(eax); | 2113 frame_->EmitPush(eax); |
| 2101 | 2114 |
| 2102 // Store the caught exception in the catch variable. | 2115 // Store the caught exception in the catch variable. |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2162 // handler structure. | 2175 // handler structure. |
| 2163 if (FLAG_debug_code) { | 2176 if (FLAG_debug_code) { |
| 2164 __ mov(eax, Operand::StaticVariable(handler_address)); | 2177 __ mov(eax, Operand::StaticVariable(handler_address)); |
| 2165 __ lea(eax, Operand(eax, StackHandlerConstants::kAddressDisplacement)); | 2178 __ lea(eax, Operand(eax, StackHandlerConstants::kAddressDisplacement)); |
| 2166 __ cmp(esp, Operand(eax)); | 2179 __ cmp(esp, Operand(eax)); |
| 2167 __ Assert(equal, "stack pointer should point to top handler"); | 2180 __ Assert(equal, "stack pointer should point to top handler"); |
| 2168 } | 2181 } |
| 2169 | 2182 |
| 2170 // If we can fall off the end of the try block, unlink from try chain. | 2183 // If we can fall off the end of the try block, unlink from try chain. |
| 2171 if (frame_ != NULL) { | 2184 if (frame_ != NULL) { |
| 2172 frame_->Pop(eax); | 2185 frame_->EmitPop(eax); |
| 2173 __ mov(Operand::StaticVariable(handler_address), eax); // TOS == next_sp | 2186 __ mov(Operand::StaticVariable(handler_address), eax); // TOS == next_sp |
| 2174 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 2187 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
| 2175 // next_sp popped. | 2188 // next_sp popped. |
| 2176 if (nof_unlinks > 0) { | 2189 if (nof_unlinks > 0) { |
| 2177 exit.Jump(); | 2190 exit.Jump(); |
| 2178 } | 2191 } |
| 2179 } | 2192 } |
| 2180 | 2193 |
| 2181 // Generate unlink code for the (formerly) shadowing targets that have been | 2194 // Generate unlink code for the (formerly) shadowing targets that have been |
| 2182 // jumped to. | 2195 // jumped to. |
| 2183 for (int i = 0; i <= nof_escapes; i++) { | 2196 for (int i = 0; i <= nof_escapes; i++) { |
| 2184 if (shadows[i]->is_linked()) { | 2197 if (shadows[i]->is_linked()) { |
| 2185 // Unlink from try chain; be careful not to destroy the TOS. | 2198 // Unlink from try chain; be careful not to destroy the TOS. |
| 2186 shadows[i]->Bind(); | 2199 shadows[i]->Bind(); |
| 2187 | 2200 |
| 2188 // Reload sp from the top handler, because some statements that we | 2201 // Reload sp from the top handler, because some statements that we |
| 2189 // break from (eg, for...in) may have left stuff on the stack. | 2202 // break from (eg, for...in) may have left stuff on the stack. |
| 2190 __ mov(edx, Operand::StaticVariable(handler_address)); | 2203 __ mov(edx, Operand::StaticVariable(handler_address)); |
| 2191 const int kNextOffset = StackHandlerConstants::kNextOffset + | 2204 const int kNextOffset = StackHandlerConstants::kNextOffset + |
| 2192 StackHandlerConstants::kAddressDisplacement; | 2205 StackHandlerConstants::kAddressDisplacement; |
| 2193 __ lea(esp, Operand(edx, kNextOffset)); | 2206 __ lea(esp, Operand(edx, kNextOffset)); |
| 2194 frame_->Forget(frame_->height() - handler_height); | 2207 frame_->Forget(frame_->height() - handler_height); |
| 2195 | 2208 |
| 2196 frame_->Pop(Operand::StaticVariable(handler_address)); | 2209 frame_->EmitPop(Operand::StaticVariable(handler_address)); |
| 2197 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 2210 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
| 2198 // next_sp popped. | 2211 // next_sp popped. |
| 2199 shadows[i]->original_target()->Jump(); | 2212 shadows[i]->original_target()->Jump(); |
| 2200 } | 2213 } |
| 2201 } | 2214 } |
| 2202 | 2215 |
| 2203 exit.Bind(); | 2216 exit.Bind(); |
| 2204 } | 2217 } |
| 2205 | 2218 |
| 2206 | 2219 |
| 2207 void CodeGenerator::VisitTryFinally(TryFinally* node) { | 2220 void CodeGenerator::VisitTryFinally(TryFinally* node) { |
| 2221 frame_->SpillAll(); | |
| 2208 Comment cmnt(masm_, "[ TryFinally"); | 2222 Comment cmnt(masm_, "[ TryFinally"); |
| 2209 | 2223 |
| 2210 // State: Used to keep track of reason for entering the finally | 2224 // State: Used to keep track of reason for entering the finally |
| 2211 // block. Should probably be extended to hold information for | 2225 // block. Should probably be extended to hold information for |
| 2212 // break/continue from within the try block. | 2226 // break/continue from within the try block. |
| 2213 enum { FALLING, THROWING, JUMPING }; | 2227 enum { FALLING, THROWING, JUMPING }; |
| 2214 | 2228 |
| 2215 JumpTarget unlink(this); | 2229 JumpTarget unlink(this); |
| 2216 JumpTarget try_block(this); | 2230 JumpTarget try_block(this); |
| 2217 JumpTarget finally_block(this); | 2231 JumpTarget finally_block(this); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2288 __ Set(ecx, Immediate(Smi::FromInt(JUMPING + i))); | 2302 __ Set(ecx, Immediate(Smi::FromInt(JUMPING + i))); |
| 2289 unlink.Jump(); | 2303 unlink.Jump(); |
| 2290 } | 2304 } |
| 2291 } | 2305 } |
| 2292 | 2306 |
| 2293 // Unlink from try chain; be careful not to destroy the TOS. | 2307 // Unlink from try chain; be careful not to destroy the TOS. |
| 2294 unlink.Bind(); | 2308 unlink.Bind(); |
| 2295 // Reload sp from the top handler, because some statements that we | 2309 // Reload sp from the top handler, because some statements that we |
| 2296 // break from (eg, for...in) may have left stuff on the stack. | 2310 // break from (eg, for...in) may have left stuff on the stack. |
| 2297 // Preserve the TOS in a register across stack manipulation. | 2311 // Preserve the TOS in a register across stack manipulation. |
| 2298 frame_->Pop(eax); | 2312 frame_->EmitPop(eax); |
| 2299 ExternalReference handler_address(Top::k_handler_address); | 2313 ExternalReference handler_address(Top::k_handler_address); |
| 2300 __ mov(edx, Operand::StaticVariable(handler_address)); | 2314 __ mov(edx, Operand::StaticVariable(handler_address)); |
| 2301 const int kNextOffset = StackHandlerConstants::kNextOffset + | 2315 const int kNextOffset = StackHandlerConstants::kNextOffset + |
| 2302 StackHandlerConstants::kAddressDisplacement; | 2316 StackHandlerConstants::kAddressDisplacement; |
| 2303 __ lea(esp, Operand(edx, kNextOffset)); | 2317 __ lea(esp, Operand(edx, kNextOffset)); |
| 2304 frame_->Forget(frame_->height() - handler_height); | 2318 frame_->Forget(frame_->height() - handler_height); |
| 2305 | 2319 |
| 2306 frame_->Pop(Operand::StaticVariable(handler_address)); | 2320 frame_->EmitPop(Operand::StaticVariable(handler_address)); |
| 2307 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 2321 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
| 2308 // Next_sp popped. | 2322 // Next_sp popped. |
| 2309 frame_->EmitPush(eax); | 2323 frame_->EmitPush(eax); |
| 2310 | 2324 |
| 2311 // --- Finally block --- | 2325 // --- Finally block --- |
| 2312 finally_block.Bind(); | 2326 finally_block.Bind(); |
| 2313 | 2327 |
| 2314 // Push the state on the stack. | 2328 // Push the state on the stack. |
| 2315 frame_->EmitPush(ecx); | 2329 frame_->EmitPush(ecx); |
| 2316 | 2330 |
| 2317 // We keep two elements on the stack - the (possibly faked) result | 2331 // We keep two elements on the stack - the (possibly faked) result |
| 2318 // and the state - while evaluating the finally block. Record it, so | 2332 // and the state - while evaluating the finally block. Record it, so |
| 2319 // that a break/continue crossing this statement can restore the | 2333 // that a break/continue crossing this statement can restore the |
| 2320 // stack. | 2334 // stack. |
| 2321 const int kFinallyStackSize = 2 * kPointerSize; | 2335 const int kFinallyStackSize = 2 * kPointerSize; |
| 2322 break_stack_height_ += kFinallyStackSize; | 2336 break_stack_height_ += kFinallyStackSize; |
| 2323 | 2337 |
| 2324 // Generate code for the statements in the finally block. | 2338 // Generate code for the statements in the finally block. |
| 2325 VisitStatements(node->finally_block()->statements()); | 2339 VisitStatements(node->finally_block()->statements()); |
| 2326 | 2340 |
| 2327 break_stack_height_ -= kFinallyStackSize; | 2341 break_stack_height_ -= kFinallyStackSize; |
| 2328 if (frame_ != NULL) { | 2342 if (frame_ != NULL) { |
| 2329 JumpTarget exit(this); | 2343 JumpTarget exit(this); |
| 2330 // Restore state and return value or faked TOS. | 2344 // Restore state and return value or faked TOS. |
| 2331 frame_->Pop(ecx); | 2345 frame_->EmitPop(ecx); |
| 2332 frame_->Pop(eax); | 2346 frame_->EmitPop(eax); |
| 2333 | 2347 |
| 2334 // Generate code to jump to the right destination for all used | 2348 // Generate code to jump to the right destination for all used |
| 2335 // (formerly) shadowing targets. | 2349 // (formerly) shadowing targets. |
| 2336 for (int i = 0; i <= nof_escapes; i++) { | 2350 for (int i = 0; i <= nof_escapes; i++) { |
| 2337 if (shadows[i]->is_bound()) { | 2351 if (shadows[i]->is_bound()) { |
| 2338 __ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i))); | 2352 __ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i))); |
| 2339 shadows[i]->original_target()->Branch(equal); | 2353 shadows[i]->original_target()->Branch(equal); |
| 2340 } | 2354 } |
| 2341 } | 2355 } |
| 2342 | 2356 |
| 2343 // Check if we need to rethrow the exception. | 2357 // Check if we need to rethrow the exception. |
| 2344 __ cmp(Operand(ecx), Immediate(Smi::FromInt(THROWING))); | 2358 __ cmp(Operand(ecx), Immediate(Smi::FromInt(THROWING))); |
| 2345 exit.Branch(not_equal); | 2359 exit.Branch(not_equal); |
| 2346 | 2360 |
| 2347 // Rethrow exception. | 2361 // Rethrow exception. |
| 2348 frame_->EmitPush(eax); // undo pop from above | 2362 frame_->EmitPush(eax); // undo pop from above |
| 2349 frame_->CallRuntime(Runtime::kReThrow, 1); | 2363 frame_->CallRuntime(Runtime::kReThrow, 1); |
| 2350 | 2364 |
| 2351 // Done. | 2365 // Done. |
| 2352 exit.Bind(); | 2366 exit.Bind(); |
| 2353 } | 2367 } |
| 2354 } | 2368 } |
| 2355 | 2369 |
| 2356 | 2370 |
| 2357 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { | 2371 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { |
| 2372 frame_->SpillAll(); | |
| 2358 Comment cmnt(masm_, "[ DebuggerStatement"); | 2373 Comment cmnt(masm_, "[ DebuggerStatement"); |
| 2359 RecordStatementPosition(node); | 2374 RecordStatementPosition(node); |
| 2360 frame_->CallRuntime(Runtime::kDebugBreak, 0); | 2375 frame_->CallRuntime(Runtime::kDebugBreak, 0); |
| 2361 // Ignore the return value. | 2376 // Ignore the return value. |
| 2362 } | 2377 } |
| 2363 | 2378 |
| 2364 | 2379 |
| 2365 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { | 2380 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { |
| 2366 ASSERT(boilerplate->IsBoilerplate()); | 2381 ASSERT(boilerplate->IsBoilerplate()); |
| 2367 | 2382 |
| 2368 // Push the boilerplate on the stack. | 2383 // Push the boilerplate on the stack. |
| 2369 frame_->EmitPush(Immediate(boilerplate)); | 2384 frame_->EmitPush(Immediate(boilerplate)); |
| 2370 | 2385 |
| 2371 // Create a new closure. | 2386 // Create a new closure. |
| 2372 frame_->EmitPush(esi); | 2387 frame_->EmitPush(esi); |
| 2373 frame_->CallRuntime(Runtime::kNewClosure, 2); | 2388 frame_->CallRuntime(Runtime::kNewClosure, 2); |
| 2374 frame_->EmitPush(eax); | 2389 frame_->EmitPush(eax); |
| 2375 } | 2390 } |
| 2376 | 2391 |
| 2377 | 2392 |
| 2378 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { | 2393 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { |
| 2394 frame_->SpillAll(); | |
| 2379 Comment cmnt(masm_, "[ FunctionLiteral"); | 2395 Comment cmnt(masm_, "[ FunctionLiteral"); |
| 2380 | 2396 |
| 2381 // Build the function boilerplate and instantiate it. | 2397 // Build the function boilerplate and instantiate it. |
| 2382 Handle<JSFunction> boilerplate = BuildBoilerplate(node); | 2398 Handle<JSFunction> boilerplate = BuildBoilerplate(node); |
| 2383 // Check for stack-overflow exception. | 2399 // Check for stack-overflow exception. |
| 2384 if (HasStackOverflow()) return; | 2400 if (HasStackOverflow()) return; |
| 2385 InstantiateBoilerplate(boilerplate); | 2401 InstantiateBoilerplate(boilerplate); |
| 2386 } | 2402 } |
| 2387 | 2403 |
| 2388 | 2404 |
| 2389 void CodeGenerator::VisitFunctionBoilerplateLiteral( | 2405 void CodeGenerator::VisitFunctionBoilerplateLiteral( |
| 2390 FunctionBoilerplateLiteral* node) { | 2406 FunctionBoilerplateLiteral* node) { |
| 2407 frame_->SpillAll(); | |
| 2391 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); | 2408 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); |
| 2392 InstantiateBoilerplate(node->boilerplate()); | 2409 InstantiateBoilerplate(node->boilerplate()); |
| 2393 } | 2410 } |
| 2394 | 2411 |
| 2395 | 2412 |
| 2396 void CodeGenerator::VisitConditional(Conditional* node) { | 2413 void CodeGenerator::VisitConditional(Conditional* node) { |
| 2414 frame_->SpillAll(); | |
| 2397 Comment cmnt(masm_, "[ Conditional"); | 2415 Comment cmnt(masm_, "[ Conditional"); |
| 2398 JumpTarget then(this); | 2416 JumpTarget then(this); |
| 2399 JumpTarget else_(this); | 2417 JumpTarget else_(this); |
| 2400 JumpTarget exit(this); | 2418 JumpTarget exit(this); |
| 2401 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); | 2419 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); |
| 2402 if (frame_ != NULL) { | 2420 if (frame_ != NULL) { |
| 2403 Branch(false, &else_); | 2421 Branch(false, &else_); |
| 2404 } | 2422 } |
| 2405 if (frame_ != NULL || then.is_linked()) { | 2423 if (frame_ != NULL || then.is_linked()) { |
| 2406 then.Bind(); | 2424 then.Bind(); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2447 exit.Bind(); | 2465 exit.Bind(); |
| 2448 frame_->EmitPush(eax); | 2466 frame_->EmitPush(eax); |
| 2449 } else { | 2467 } else { |
| 2450 frame_->EmitPush(SlotOperand(slot, ecx)); | 2468 frame_->EmitPush(SlotOperand(slot, ecx)); |
| 2451 } | 2469 } |
| 2452 } | 2470 } |
| 2453 } | 2471 } |
| 2454 | 2472 |
| 2455 | 2473 |
| 2456 void CodeGenerator::VisitSlot(Slot* node) { | 2474 void CodeGenerator::VisitSlot(Slot* node) { |
| 2475 frame_->SpillAll(); | |
| 2457 Comment cmnt(masm_, "[ Slot"); | 2476 Comment cmnt(masm_, "[ Slot"); |
| 2458 LoadFromSlot(node, typeof_state()); | 2477 LoadFromSlot(node, typeof_state()); |
| 2459 } | 2478 } |
| 2460 | 2479 |
| 2461 | 2480 |
| 2462 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { | 2481 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { |
| 2482 frame_->SpillAll(); | |
| 2463 Comment cmnt(masm_, "[ VariableProxy"); | 2483 Comment cmnt(masm_, "[ VariableProxy"); |
| 2464 Variable* var = node->var(); | 2484 Variable* var = node->var(); |
| 2465 Expression* expr = var->rewrite(); | 2485 Expression* expr = var->rewrite(); |
| 2466 if (expr != NULL) { | 2486 if (expr != NULL) { |
| 2467 // We have to be wary of calling Visit directly on expressions. Because | 2487 // We have to be wary of calling Visit directly on expressions. Because |
| 2468 // of special casing comparisons of the form typeof<expr> === "string", | 2488 // of special casing comparisons of the form typeof<expr> === "string", |
| 2469 // we can return from a call from Visit (to a comparison or a unary | 2489 // we can return from a call from Visit (to a comparison or a unary |
| 2470 // operation) without a virtual frame; which will probably crash if we | 2490 // operation) without a virtual frame; which will probably crash if we |
| 2471 // try to emit frame code before reestablishing a frame. Here we're | 2491 // try to emit frame code before reestablishing a frame. Here we're |
| 2472 // safe as long as variable proxies can't rewrite into typeof | 2492 // safe as long as variable proxies can't rewrite into typeof |
| 2473 // comparisons or unary logical not expressions. | 2493 // comparisons or unary logical not expressions. |
| 2474 Visit(expr); | 2494 Visit(expr); |
| 2475 ASSERT(frame_ != NULL); | 2495 ASSERT(frame_ != NULL); |
| 2476 } else { | 2496 } else { |
| 2477 ASSERT(var->is_global()); | 2497 ASSERT(var->is_global()); |
| 2478 Reference ref(this, node); | 2498 Reference ref(this, node); |
| 2479 ref.GetValue(typeof_state()); | 2499 ref.GetValue(typeof_state()); |
| 2480 } | 2500 } |
| 2481 } | 2501 } |
| 2482 | 2502 |
| 2483 | 2503 |
| 2484 void CodeGenerator::VisitLiteral(Literal* node) { | 2504 void CodeGenerator::VisitLiteral(Literal* node) { |
| 2505 frame_->SpillAll(); | |
| 2485 Comment cmnt(masm_, "[ Literal"); | 2506 Comment cmnt(masm_, "[ Literal"); |
| 2486 if (node->handle()->IsSmi() && !IsInlineSmi(node)) { | 2507 if (node->handle()->IsSmi() && !IsInlineSmi(node)) { |
| 2487 // To prevent long attacker-controlled byte sequences in code, larger | 2508 // To prevent long attacker-controlled byte sequences in code, larger |
| 2488 // Smis are loaded in two steps. | 2509 // Smis are loaded in two steps. |
| 2489 int bits = reinterpret_cast<int>(*node->handle()); | 2510 int bits = reinterpret_cast<int>(*node->handle()); |
| 2490 __ mov(eax, bits & 0x0000FFFF); | 2511 __ mov(eax, bits & 0x0000FFFF); |
| 2491 __ xor_(eax, bits & 0xFFFF0000); | 2512 __ xor_(eax, bits & 0xFFFF0000); |
| 2492 frame_->EmitPush(eax); | 2513 frame_->EmitPush(eax); |
| 2493 } else { | 2514 } else { |
| 2494 frame_->EmitPush(Immediate(node->handle())); | 2515 frame_->EmitPush(Immediate(node->handle())); |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 2519 // RegExp pattern (2). | 2540 // RegExp pattern (2). |
| 2520 __ push(Immediate(node_->pattern())); | 2541 __ push(Immediate(node_->pattern())); |
| 2521 // RegExp flags (3). | 2542 // RegExp flags (3). |
| 2522 __ push(Immediate(node_->flags())); | 2543 __ push(Immediate(node_->flags())); |
| 2523 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | 2544 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
| 2524 __ mov(ebx, Operand(eax)); // "caller" expects result in ebx | 2545 __ mov(ebx, Operand(eax)); // "caller" expects result in ebx |
| 2525 } | 2546 } |
| 2526 | 2547 |
| 2527 | 2548 |
| 2528 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { | 2549 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { |
| 2550 frame_->SpillAll(); | |
| 2529 Comment cmnt(masm_, "[ RegExp Literal"); | 2551 Comment cmnt(masm_, "[ RegExp Literal"); |
| 2530 RegExpDeferred* deferred = new RegExpDeferred(this, node); | 2552 RegExpDeferred* deferred = new RegExpDeferred(this, node); |
| 2531 | 2553 |
| 2532 // Retrieve the literal array and check the allocated entry. | 2554 // Retrieve the literal array and check the allocated entry. |
| 2533 | 2555 |
| 2534 // Load the function of this activation. | 2556 // Load the function of this activation. |
| 2535 __ mov(ecx, frame_->Function()); | 2557 __ mov(ecx, frame_->Function()); |
| 2536 | 2558 |
| 2537 // Load the literals array of the function. | 2559 // Load the literals array of the function. |
| 2538 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); | 2560 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2579 // Literal index (1). | 2601 // Literal index (1). |
| 2580 __ push(Immediate(Smi::FromInt(node_->literal_index()))); | 2602 __ push(Immediate(Smi::FromInt(node_->literal_index()))); |
| 2581 // Constant properties (2). | 2603 // Constant properties (2). |
| 2582 __ push(Immediate(node_->constant_properties())); | 2604 __ push(Immediate(node_->constant_properties())); |
| 2583 __ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3); | 2605 __ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3); |
| 2584 __ mov(ebx, Operand(eax)); | 2606 __ mov(ebx, Operand(eax)); |
| 2585 } | 2607 } |
| 2586 | 2608 |
| 2587 | 2609 |
| 2588 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { | 2610 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { |
| 2611 frame_->SpillAll(); | |
| 2589 Comment cmnt(masm_, "[ ObjectLiteral"); | 2612 Comment cmnt(masm_, "[ ObjectLiteral"); |
| 2590 ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node); | 2613 ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node); |
| 2591 | 2614 |
| 2592 // Retrieve the literal array and check the allocated entry. | 2615 // Retrieve the literal array and check the allocated entry. |
| 2593 | 2616 |
| 2594 // Load the function of this activation. | 2617 // Load the function of this activation. |
| 2595 __ mov(ecx, frame_->Function()); | 2618 __ mov(ecx, frame_->Function()); |
| 2596 | 2619 |
| 2597 // Load the literals array of the function. | 2620 // Load the literals array of the function. |
| 2598 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); | 2621 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 2620 ObjectLiteral::Property* property = node->properties()->at(i); | 2643 ObjectLiteral::Property* property = node->properties()->at(i); |
| 2621 switch (property->kind()) { | 2644 switch (property->kind()) { |
| 2622 case ObjectLiteral::Property::CONSTANT: break; | 2645 case ObjectLiteral::Property::CONSTANT: break; |
| 2623 case ObjectLiteral::Property::COMPUTED: { | 2646 case ObjectLiteral::Property::COMPUTED: { |
| 2624 Handle<Object> key(property->key()->handle()); | 2647 Handle<Object> key(property->key()->handle()); |
| 2625 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 2648 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 2626 if (key->IsSymbol()) { | 2649 if (key->IsSymbol()) { |
| 2627 __ mov(eax, frame_->Top()); | 2650 __ mov(eax, frame_->Top()); |
| 2628 frame_->EmitPush(eax); | 2651 frame_->EmitPush(eax); |
| 2629 Load(property->value()); | 2652 Load(property->value()); |
| 2630 frame_->Pop(eax); | 2653 frame_->EmitPop(eax); |
| 2631 __ Set(ecx, Immediate(key)); | 2654 __ Set(ecx, Immediate(key)); |
| 2632 frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 2655 frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 2633 frame_->Drop(); | 2656 frame_->Drop(); |
| 2634 // Ignore result. | 2657 // Ignore result. |
| 2635 break; | 2658 break; |
| 2636 } | 2659 } |
| 2637 // Fall through | 2660 // Fall through |
| 2638 } | 2661 } |
| 2639 case ObjectLiteral::Property::PROTOTYPE: { | 2662 case ObjectLiteral::Property::PROTOTYPE: { |
| 2640 __ mov(eax, frame_->Top()); | 2663 __ mov(eax, frame_->Top()); |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 2669 // Ignore result. | 2692 // Ignore result. |
| 2670 break; | 2693 break; |
| 2671 } | 2694 } |
| 2672 default: UNREACHABLE(); | 2695 default: UNREACHABLE(); |
| 2673 } | 2696 } |
| 2674 } | 2697 } |
| 2675 } | 2698 } |
| 2676 | 2699 |
| 2677 | 2700 |
| 2678 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { | 2701 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { |
| 2702 frame_->SpillAll(); | |
| 2679 Comment cmnt(masm_, "[ ArrayLiteral"); | 2703 Comment cmnt(masm_, "[ ArrayLiteral"); |
| 2680 | 2704 |
| 2681 // Call runtime to create the array literal. | 2705 // Call runtime to create the array literal. |
| 2682 frame_->EmitPush(Immediate(node->literals())); | 2706 frame_->EmitPush(Immediate(node->literals())); |
| 2683 // Load the function of this frame. | 2707 // Load the function of this frame. |
| 2684 __ mov(ecx, frame_->Function()); | 2708 __ mov(ecx, frame_->Function()); |
| 2685 // Load the literals array of the function. | 2709 // Load the literals array of the function. |
| 2686 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); | 2710 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); |
| 2687 frame_->EmitPush(ecx); | 2711 frame_->EmitPush(ecx); |
| 2688 frame_->CallRuntime(Runtime::kCreateArrayLiteral, 2); | 2712 frame_->CallRuntime(Runtime::kCreateArrayLiteral, 2); |
| 2689 | 2713 |
| 2690 // Push the resulting array literal on the stack. | 2714 // Push the resulting array literal on the stack. |
| 2691 frame_->EmitPush(eax); | 2715 frame_->EmitPush(eax); |
| 2692 | 2716 |
| 2693 // Generate code to set the elements in the array that are not | 2717 // Generate code to set the elements in the array that are not |
| 2694 // literals. | 2718 // literals. |
| 2695 for (int i = 0; i < node->values()->length(); i++) { | 2719 for (int i = 0; i < node->values()->length(); i++) { |
| 2696 Expression* value = node->values()->at(i); | 2720 Expression* value = node->values()->at(i); |
| 2697 | 2721 |
| 2698 // If value is literal the property value is already | 2722 // If value is literal the property value is already |
| 2699 // set in the boilerplate object. | 2723 // set in the boilerplate object. |
| 2700 if (value->AsLiteral() == NULL) { | 2724 if (value->AsLiteral() == NULL) { |
| 2701 // The property must be set by generated code. | 2725 // The property must be set by generated code. |
| 2702 Load(value); | 2726 Load(value); |
| 2703 | 2727 |
| 2704 // Get the value off the stack. | 2728 // Get the value off the stack. |
| 2705 frame_->Pop(eax); | 2729 frame_->EmitPop(eax); |
| 2706 // Fetch the object literal while leaving on the stack. | 2730 // Fetch the object literal while leaving on the stack. |
| 2707 __ mov(ecx, frame_->Top()); | 2731 __ mov(ecx, frame_->Top()); |
| 2708 // Get the elements array. | 2732 // Get the elements array. |
| 2709 __ mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset)); | 2733 __ mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset)); |
| 2710 | 2734 |
| 2711 // Write to the indexed properties array. | 2735 // Write to the indexed properties array. |
| 2712 int offset = i * kPointerSize + Array::kHeaderSize; | 2736 int offset = i * kPointerSize + Array::kHeaderSize; |
| 2713 __ mov(FieldOperand(ecx, offset), eax); | 2737 __ mov(FieldOperand(ecx, offset), eax); |
| 2714 | 2738 |
| 2715 // Update the write barrier for the array address. | 2739 // Update the write barrier for the array address. |
| 2716 __ RecordWrite(ecx, offset, eax, ebx); | 2740 __ RecordWrite(ecx, offset, eax, ebx); |
| 2717 } | 2741 } |
| 2718 } | 2742 } |
| 2719 } | 2743 } |
| 2720 | 2744 |
| 2721 | 2745 |
| 2722 bool CodeGenerator::IsInlineSmi(Literal* literal) { | 2746 bool CodeGenerator::IsInlineSmi(Literal* literal) { |
| 2723 if (literal == NULL || !literal->handle()->IsSmi()) return false; | 2747 if (literal == NULL || !literal->handle()->IsSmi()) return false; |
| 2724 int int_value = Smi::cast(*literal->handle())->value(); | 2748 int int_value = Smi::cast(*literal->handle())->value(); |
| 2725 return is_intn(int_value, kMaxSmiInlinedBits); | 2749 return is_intn(int_value, kMaxSmiInlinedBits); |
| 2726 } | 2750 } |
| 2727 | 2751 |
| 2728 | 2752 |
| 2729 void CodeGenerator::VisitAssignment(Assignment* node) { | 2753 void CodeGenerator::VisitAssignment(Assignment* node) { |
| 2754 frame_->SpillAll(); | |
| 2730 Comment cmnt(masm_, "[ Assignment"); | 2755 Comment cmnt(masm_, "[ Assignment"); |
| 2731 | 2756 |
| 2732 RecordStatementPosition(node); | 2757 RecordStatementPosition(node); |
| 2733 { Reference target(this, node->target()); | 2758 { Reference target(this, node->target()); |
| 2734 if (target.is_illegal()) { | 2759 if (target.is_illegal()) { |
| 2735 // Fool the virtual frame into thinking that we left the assignment's | 2760 // Fool the virtual frame into thinking that we left the assignment's |
| 2736 // value on the frame. | 2761 // value on the frame. |
| 2737 frame_->EmitPush(Immediate(Smi::FromInt(0))); | 2762 frame_->EmitPush(Immediate(Smi::FromInt(0))); |
| 2738 return; | 2763 return; |
| 2739 } | 2764 } |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 2769 target.SetValue(CONST_INIT); | 2794 target.SetValue(CONST_INIT); |
| 2770 } else { | 2795 } else { |
| 2771 target.SetValue(NOT_CONST_INIT); | 2796 target.SetValue(NOT_CONST_INIT); |
| 2772 } | 2797 } |
| 2773 } | 2798 } |
| 2774 } | 2799 } |
| 2775 } | 2800 } |
| 2776 | 2801 |
| 2777 | 2802 |
| 2778 void CodeGenerator::VisitThrow(Throw* node) { | 2803 void CodeGenerator::VisitThrow(Throw* node) { |
| 2804 frame_->SpillAll(); | |
| 2779 Comment cmnt(masm_, "[ Throw"); | 2805 Comment cmnt(masm_, "[ Throw"); |
| 2780 | 2806 |
| 2781 Load(node->exception()); | 2807 Load(node->exception()); |
| 2782 __ RecordPosition(node->position()); | 2808 __ RecordPosition(node->position()); |
| 2783 frame_->CallRuntime(Runtime::kThrow, 1); | 2809 frame_->CallRuntime(Runtime::kThrow, 1); |
| 2784 frame_->EmitPush(eax); | 2810 frame_->EmitPush(eax); |
| 2785 } | 2811 } |
| 2786 | 2812 |
| 2787 | 2813 |
| 2788 void CodeGenerator::VisitProperty(Property* node) { | 2814 void CodeGenerator::VisitProperty(Property* node) { |
| 2815 frame_->SpillAll(); | |
| 2789 Comment cmnt(masm_, "[ Property"); | 2816 Comment cmnt(masm_, "[ Property"); |
| 2790 Reference property(this, node); | 2817 Reference property(this, node); |
| 2791 property.GetValue(typeof_state()); | 2818 property.GetValue(typeof_state()); |
| 2792 } | 2819 } |
| 2793 | 2820 |
| 2794 | 2821 |
| 2795 void CodeGenerator::VisitCall(Call* node) { | 2822 void CodeGenerator::VisitCall(Call* node) { |
| 2823 frame_->SpillAll(); | |
| 2796 Comment cmnt(masm_, "[ Call"); | 2824 Comment cmnt(masm_, "[ Call"); |
| 2797 | 2825 |
| 2798 ZoneList<Expression*>* args = node->arguments(); | 2826 ZoneList<Expression*>* args = node->arguments(); |
| 2799 | 2827 |
| 2800 RecordStatementPosition(node); | 2828 RecordStatementPosition(node); |
| 2801 | 2829 |
| 2802 // Check if the function is a variable or a property. | 2830 // Check if the function is a variable or a property. |
| 2803 Expression* function = node->expression(); | 2831 Expression* function = node->expression(); |
| 2804 Variable* var = function->AsVariableProxy()->AsVariable(); | 2832 Variable* var = function->AsVariableProxy()->AsVariable(); |
| 2805 Property* property = function->AsProperty(); | 2833 Property* property = function->AsProperty(); |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2917 // Pass the global proxy as the receiver. | 2945 // Pass the global proxy as the receiver. |
| 2918 LoadGlobalReceiver(eax); | 2946 LoadGlobalReceiver(eax); |
| 2919 | 2947 |
| 2920 // Call the function. | 2948 // Call the function. |
| 2921 CallWithArguments(args, node->position()); | 2949 CallWithArguments(args, node->position()); |
| 2922 } | 2950 } |
| 2923 } | 2951 } |
| 2924 | 2952 |
| 2925 | 2953 |
| 2926 void CodeGenerator::VisitCallNew(CallNew* node) { | 2954 void CodeGenerator::VisitCallNew(CallNew* node) { |
| 2955 frame_->SpillAll(); | |
| 2927 Comment cmnt(masm_, "[ CallNew"); | 2956 Comment cmnt(masm_, "[ CallNew"); |
| 2928 | 2957 |
| 2929 // According to ECMA-262, section 11.2.2, page 44, the function | 2958 // According to ECMA-262, section 11.2.2, page 44, the function |
| 2930 // expression in new calls must be evaluated before the | 2959 // expression in new calls must be evaluated before the |
| 2931 // arguments. This is different from ordinary calls, where the | 2960 // arguments. This is different from ordinary calls, where the |
| 2932 // actual function to call is resolved after the arguments have been | 2961 // actual function to call is resolved after the arguments have been |
| 2933 // evaluated. | 2962 // evaluated. |
| 2934 | 2963 |
| 2935 // Compute function to call and use the global object as the | 2964 // Compute function to call and use the global object as the |
| 2936 // receiver. There is no need to use the global proxy here because | 2965 // receiver. There is no need to use the global proxy here because |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 2960 Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall)); | 2989 Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall)); |
| 2961 frame_->CallCodeObject(ic, RelocInfo::CONSTRUCT_CALL, args->length() + 1); | 2990 frame_->CallCodeObject(ic, RelocInfo::CONSTRUCT_CALL, args->length() + 1); |
| 2962 // Discard the function and "push" the newly created object. | 2991 // Discard the function and "push" the newly created object. |
| 2963 __ mov(frame_->Top(), eax); | 2992 __ mov(frame_->Top(), eax); |
| 2964 } | 2993 } |
| 2965 | 2994 |
| 2966 | 2995 |
| 2967 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { | 2996 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { |
| 2968 ASSERT(args->length() == 1); | 2997 ASSERT(args->length() == 1); |
| 2969 Load(args->at(0)); | 2998 Load(args->at(0)); |
| 2970 frame_->Pop(eax); | 2999 frame_->EmitPop(eax); |
| 2971 __ test(eax, Immediate(kSmiTagMask)); | 3000 __ test(eax, Immediate(kSmiTagMask)); |
| 2972 cc_reg_ = zero; | 3001 cc_reg_ = zero; |
| 2973 } | 3002 } |
| 2974 | 3003 |
| 2975 | 3004 |
| 2976 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { | 3005 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
| 2977 ASSERT(args->length() == 1); | 3006 ASSERT(args->length() == 1); |
| 2978 Load(args->at(0)); | 3007 Load(args->at(0)); |
| 2979 frame_->Pop(eax); | 3008 frame_->EmitPop(eax); |
| 2980 __ test(eax, Immediate(kSmiTagMask | 0x80000000)); | 3009 __ test(eax, Immediate(kSmiTagMask | 0x80000000)); |
| 2981 cc_reg_ = zero; | 3010 cc_reg_ = zero; |
| 2982 } | 3011 } |
| 2983 | 3012 |
| 2984 | 3013 |
| 2985 // This generates code that performs a charCodeAt() call or returns | 3014 // This generates code that performs a charCodeAt() call or returns |
| 2986 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. | 3015 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. |
| 2987 // It can handle flat and sliced strings, 8 and 16 bit characters and | 3016 // It can handle flat and sliced strings, 8 and 16 bit characters and |
| 2988 // cons strings where the answer is found in the left hand branch of the | 3017 // cons strings where the answer is found in the left hand branch of the |
| 2989 // cons. The slow case will flatten the string, which will ensure that | 3018 // cons. The slow case will flatten the string, which will ensure that |
| 2990 // the answer is in the left hand side the next time around. | 3019 // the answer is in the left hand side the next time around. |
| 2991 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { | 3020 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
| 2992 ASSERT(args->length() == 2); | 3021 ASSERT(args->length() == 2); |
| 2993 | 3022 |
| 2994 JumpTarget slow_case(this); | 3023 JumpTarget slow_case(this); |
| 2995 JumpTarget end(this); | 3024 JumpTarget end(this); |
| 2996 JumpTarget not_a_flat_string(this); | 3025 JumpTarget not_a_flat_string(this); |
| 2997 JumpTarget not_a_cons_string_either(this); | 3026 JumpTarget not_a_cons_string_either(this); |
| 2998 JumpTarget try_again_with_new_string(this); | 3027 JumpTarget try_again_with_new_string(this); |
| 2999 JumpTarget ascii_string(this); | 3028 JumpTarget ascii_string(this); |
| 3000 JumpTarget got_char_code(this); | 3029 JumpTarget got_char_code(this); |
| 3001 | 3030 |
| 3002 // Load the string into eax. | 3031 // Load the string into eax. |
| 3003 Load(args->at(0)); | 3032 Load(args->at(0)); |
| 3004 frame_->Pop(eax); | 3033 frame_->EmitPop(eax); |
| 3005 // If the receiver is a smi return undefined. | 3034 // If the receiver is a smi return undefined. |
| 3006 ASSERT(kSmiTag == 0); | 3035 ASSERT(kSmiTag == 0); |
| 3007 __ test(eax, Immediate(kSmiTagMask)); | 3036 __ test(eax, Immediate(kSmiTagMask)); |
| 3008 slow_case.Branch(zero, not_taken); | 3037 slow_case.Branch(zero, not_taken); |
| 3009 | 3038 |
| 3010 // Load the index into ebx. | 3039 // Load the index into ebx. |
| 3011 Load(args->at(1)); | 3040 Load(args->at(1)); |
| 3012 frame_->Pop(ebx); | 3041 frame_->EmitPop(ebx); |
| 3013 | 3042 |
| 3014 // Check for negative or non-smi index. | 3043 // Check for negative or non-smi index. |
| 3015 ASSERT(kSmiTag == 0); | 3044 ASSERT(kSmiTag == 0); |
| 3016 __ test(ebx, Immediate(kSmiTagMask | 0x80000000)); | 3045 __ test(ebx, Immediate(kSmiTagMask | 0x80000000)); |
| 3017 slow_case.Branch(not_zero, not_taken); | 3046 slow_case.Branch(not_zero, not_taken); |
| 3018 // Get rid of the smi tag on the index. | 3047 // Get rid of the smi tag on the index. |
| 3019 __ sar(ebx, kSmiTagSize); | 3048 __ sar(ebx, kSmiTagSize); |
| 3020 | 3049 |
| 3021 try_again_with_new_string.Bind(); | 3050 try_again_with_new_string.Bind(); |
| 3022 // Get the type of the heap object into edi. | 3051 // Get the type of the heap object into edi. |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3102 | 3131 |
| 3103 | 3132 |
| 3104 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { | 3133 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { |
| 3105 ASSERT(args->length() == 1); | 3134 ASSERT(args->length() == 1); |
| 3106 Load(args->at(0)); | 3135 Load(args->at(0)); |
| 3107 JumpTarget answer(this); | 3136 JumpTarget answer(this); |
| 3108 // We need the CC bits to come out as not_equal in the case where the | 3137 // We need the CC bits to come out as not_equal in the case where the |
| 3109 // object is a smi. This can't be done with the usual test opcode so | 3138 // object is a smi. This can't be done with the usual test opcode so |
| 3110 // we copy the object to ecx and do some destructive ops on it that | 3139 // we copy the object to ecx and do some destructive ops on it that |
| 3111 // result in the right CC bits. | 3140 // result in the right CC bits. |
| 3112 frame_->Pop(eax); | 3141 frame_->EmitPop(eax); |
| 3113 __ mov(ecx, Operand(eax)); | 3142 __ mov(ecx, Operand(eax)); |
| 3114 __ and_(ecx, kSmiTagMask); | 3143 __ and_(ecx, kSmiTagMask); |
| 3115 __ xor_(ecx, kSmiTagMask); | 3144 __ xor_(ecx, kSmiTagMask); |
| 3116 answer.Branch(not_equal, not_taken); | 3145 answer.Branch(not_equal, not_taken); |
| 3117 // It is a heap object - get map. | 3146 // It is a heap object - get map. |
| 3118 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); | 3147 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); |
| 3119 __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset)); | 3148 __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset)); |
| 3120 // Check if the object is a JS array or not. | 3149 // Check if the object is a JS array or not. |
| 3121 __ cmp(eax, JS_ARRAY_TYPE); | 3150 __ cmp(eax, JS_ARRAY_TYPE); |
| 3122 answer.Bind(); | 3151 answer.Bind(); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3201 __ mov(frame_->Top(), eax); | 3230 __ mov(frame_->Top(), eax); |
| 3202 } | 3231 } |
| 3203 | 3232 |
| 3204 | 3233 |
| 3205 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { | 3234 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { |
| 3206 ASSERT(args->length() == 2); | 3235 ASSERT(args->length() == 2); |
| 3207 | 3236 |
| 3208 // Load the two objects into registers and perform the comparison. | 3237 // Load the two objects into registers and perform the comparison. |
| 3209 Load(args->at(0)); | 3238 Load(args->at(0)); |
| 3210 Load(args->at(1)); | 3239 Load(args->at(1)); |
| 3211 frame_->Pop(eax); | 3240 frame_->EmitPop(eax); |
| 3212 frame_->Pop(ecx); | 3241 frame_->EmitPop(ecx); |
| 3213 __ cmp(eax, Operand(ecx)); | 3242 __ cmp(eax, Operand(ecx)); |
| 3214 cc_reg_ = equal; | 3243 cc_reg_ = equal; |
| 3215 } | 3244 } |
| 3216 | 3245 |
| 3217 | 3246 |
| 3218 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { | 3247 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { |
| 3248 frame_->SpillAll(); | |
| 3219 if (CheckForInlineRuntimeCall(node)) { | 3249 if (CheckForInlineRuntimeCall(node)) { |
| 3220 return; | 3250 return; |
| 3221 } | 3251 } |
| 3222 | 3252 |
| 3223 ZoneList<Expression*>* args = node->arguments(); | 3253 ZoneList<Expression*>* args = node->arguments(); |
| 3224 Comment cmnt(masm_, "[ CallRuntime"); | 3254 Comment cmnt(masm_, "[ CallRuntime"); |
| 3225 Runtime::Function* function = node->function(); | 3255 Runtime::Function* function = node->function(); |
| 3226 | 3256 |
| 3227 if (function == NULL) { | 3257 if (function == NULL) { |
| 3228 // Prepare stack for calling JS runtime function. | 3258 // Prepare stack for calling JS runtime function. |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 3247 __ mov(frame_->Top(), eax); | 3277 __ mov(frame_->Top(), eax); |
| 3248 } else { | 3278 } else { |
| 3249 // Call the C runtime function. | 3279 // Call the C runtime function. |
| 3250 frame_->CallRuntime(function, arg_count); | 3280 frame_->CallRuntime(function, arg_count); |
| 3251 frame_->EmitPush(eax); | 3281 frame_->EmitPush(eax); |
| 3252 } | 3282 } |
| 3253 } | 3283 } |
| 3254 | 3284 |
| 3255 | 3285 |
| 3256 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { | 3286 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { |
| 3287 frame_->SpillAll(); | |
| 3257 // Note that because of NOT and an optimization in comparison of a typeof | 3288 // Note that because of NOT and an optimization in comparison of a typeof |
| 3258 // expression to a literal string, this function can fail to leave a value | 3289 // expression to a literal string, this function can fail to leave a value |
| 3259 // on top of the frame or in the cc register. | 3290 // on top of the frame or in the cc register. |
| 3260 Comment cmnt(masm_, "[ UnaryOperation"); | 3291 Comment cmnt(masm_, "[ UnaryOperation"); |
| 3261 | 3292 |
| 3262 Token::Value op = node->op(); | 3293 Token::Value op = node->op(); |
| 3263 | 3294 |
| 3264 if (op == Token::NOT) { | 3295 if (op == Token::NOT) { |
| 3265 LoadCondition(node->expression(), NOT_INSIDE_TYPEOF, | 3296 LoadCondition(node->expression(), NOT_INSIDE_TYPEOF, |
| 3266 false_target(), true_target(), true); | 3297 false_target(), true_target(), true); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3321 switch (op) { | 3352 switch (op) { |
| 3322 case Token::NOT: | 3353 case Token::NOT: |
| 3323 case Token::DELETE: | 3354 case Token::DELETE: |
| 3324 case Token::TYPEOF: | 3355 case Token::TYPEOF: |
| 3325 UNREACHABLE(); // handled above | 3356 UNREACHABLE(); // handled above |
| 3326 break; | 3357 break; |
| 3327 | 3358 |
| 3328 case Token::SUB: { | 3359 case Token::SUB: { |
| 3329 UnarySubStub stub; | 3360 UnarySubStub stub; |
| 3330 // TODO(1222589): remove dependency of TOS being cached inside stub | 3361 // TODO(1222589): remove dependency of TOS being cached inside stub |
| 3331 frame_->Pop(eax); | 3362 frame_->EmitPop(eax); |
| 3332 frame_->CallStub(&stub, 0); | 3363 frame_->CallStub(&stub, 0); |
| 3333 frame_->EmitPush(eax); | 3364 frame_->EmitPush(eax); |
| 3334 break; | 3365 break; |
| 3335 } | 3366 } |
| 3336 | 3367 |
| 3337 case Token::BIT_NOT: { | 3368 case Token::BIT_NOT: { |
| 3338 // Smi check. | 3369 // Smi check. |
| 3339 JumpTarget smi_label(this); | 3370 JumpTarget smi_label(this); |
| 3340 JumpTarget continue_label(this); | 3371 JumpTarget continue_label(this); |
| 3341 frame_->Pop(eax); | 3372 frame_->EmitPop(eax); |
| 3342 __ test(eax, Immediate(kSmiTagMask)); | 3373 __ test(eax, Immediate(kSmiTagMask)); |
| 3343 smi_label.Branch(zero, taken); | 3374 smi_label.Branch(zero, taken); |
| 3344 | 3375 |
| 3345 frame_->EmitPush(eax); // undo popping of TOS | 3376 frame_->EmitPush(eax); // undo popping of TOS |
| 3346 frame_->InvokeBuiltin(Builtins::BIT_NOT, CALL_FUNCTION, 1); | 3377 frame_->InvokeBuiltin(Builtins::BIT_NOT, CALL_FUNCTION, 1); |
| 3347 | 3378 |
| 3348 continue_label.Jump(); | 3379 continue_label.Jump(); |
| 3349 smi_label.Bind(); | 3380 smi_label.Bind(); |
| 3350 __ not_(eax); | 3381 __ not_(eax); |
| 3351 __ and_(eax, ~kSmiTagMask); // Remove inverted smi-tag. | 3382 __ and_(eax, ~kSmiTagMask); // Remove inverted smi-tag. |
| 3352 continue_label.Bind(); | 3383 continue_label.Bind(); |
| 3353 frame_->EmitPush(eax); | 3384 frame_->EmitPush(eax); |
| 3354 break; | 3385 break; |
| 3355 } | 3386 } |
| 3356 | 3387 |
| 3357 case Token::VOID: | 3388 case Token::VOID: |
| 3358 __ mov(frame_->Top(), Factory::undefined_value()); | 3389 __ mov(frame_->Top(), Factory::undefined_value()); |
| 3359 break; | 3390 break; |
| 3360 | 3391 |
| 3361 case Token::ADD: { | 3392 case Token::ADD: { |
| 3362 // Smi check. | 3393 // Smi check. |
| 3363 JumpTarget continue_label(this); | 3394 JumpTarget continue_label(this); |
| 3364 frame_->Pop(eax); | 3395 frame_->EmitPop(eax); |
| 3365 __ test(eax, Immediate(kSmiTagMask)); | 3396 __ test(eax, Immediate(kSmiTagMask)); |
| 3366 continue_label.Branch(zero); | 3397 continue_label.Branch(zero); |
| 3367 | 3398 |
| 3368 frame_->EmitPush(eax); | 3399 frame_->EmitPush(eax); |
| 3369 frame_->InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION, 1); | 3400 frame_->InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION, 1); |
| 3370 | 3401 |
| 3371 continue_label.Bind(); | 3402 continue_label.Bind(); |
| 3372 frame_->EmitPush(eax); | 3403 frame_->EmitPush(eax); |
| 3373 break; | 3404 break; |
| 3374 } | 3405 } |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3459 if (is_postfix_) { | 3490 if (is_postfix_) { |
| 3460 RevertToNumberStub to_number_stub(is_increment_); | 3491 RevertToNumberStub to_number_stub(is_increment_); |
| 3461 __ CallStub(&to_number_stub); | 3492 __ CallStub(&to_number_stub); |
| 3462 } | 3493 } |
| 3463 CounterOpStub stub(result_offset_, is_postfix_, is_increment_); | 3494 CounterOpStub stub(result_offset_, is_postfix_, is_increment_); |
| 3464 __ CallStub(&stub); | 3495 __ CallStub(&stub); |
| 3465 } | 3496 } |
| 3466 | 3497 |
| 3467 | 3498 |
| 3468 void CodeGenerator::VisitCountOperation(CountOperation* node) { | 3499 void CodeGenerator::VisitCountOperation(CountOperation* node) { |
| 3500 frame_->SpillAll(); | |
| 3469 Comment cmnt(masm_, "[ CountOperation"); | 3501 Comment cmnt(masm_, "[ CountOperation"); |
| 3470 | 3502 |
| 3471 bool is_postfix = node->is_postfix(); | 3503 bool is_postfix = node->is_postfix(); |
| 3472 bool is_increment = node->op() == Token::INC; | 3504 bool is_increment = node->op() == Token::INC; |
| 3473 | 3505 |
| 3474 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); | 3506 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); |
| 3475 bool is_const = (var != NULL && var->mode() == Variable::CONST); | 3507 bool is_const = (var != NULL && var->mode() == Variable::CONST); |
| 3476 | 3508 |
| 3477 // Postfix: Make room for the result. | 3509 // Postfix: Make room for the result. |
| 3478 if (is_postfix) { | 3510 if (is_postfix) { |
| 3479 frame_->EmitPush(Immediate(0)); | 3511 frame_->EmitPush(Immediate(0)); |
| 3480 } | 3512 } |
| 3481 | 3513 |
| 3482 { Reference target(this, node->expression()); | 3514 { Reference target(this, node->expression()); |
| 3483 if (target.is_illegal()) { | 3515 if (target.is_illegal()) { |
| 3484 // Spoof the virtual frame to have the expected height (one higher | 3516 // Spoof the virtual frame to have the expected height (one higher |
| 3485 // than on entry). | 3517 // than on entry). |
| 3486 if (!is_postfix) { | 3518 if (!is_postfix) { |
| 3487 frame_->EmitPush(Immediate(Smi::FromInt(0))); | 3519 frame_->EmitPush(Immediate(Smi::FromInt(0))); |
| 3488 } | 3520 } |
| 3489 return; | 3521 return; |
| 3490 } | 3522 } |
| 3491 target.GetValue(NOT_INSIDE_TYPEOF); | 3523 target.GetValue(NOT_INSIDE_TYPEOF); |
| 3492 | 3524 |
| 3493 CountOperationDeferred* deferred = | 3525 CountOperationDeferred* deferred = |
| 3494 new CountOperationDeferred(this, is_postfix, is_increment, | 3526 new CountOperationDeferred(this, is_postfix, is_increment, |
| 3495 target.size() * kPointerSize); | 3527 target.size() * kPointerSize); |
| 3496 | 3528 |
| 3497 frame_->Pop(eax); // Load TOS into eax for calculations below | 3529 frame_->EmitPop(eax); // Load TOS into eax for calculations below |
| 3498 | 3530 |
| 3499 // Postfix: Store the old value as the result. | 3531 // Postfix: Store the old value as the result. |
| 3500 if (is_postfix) { | 3532 if (is_postfix) { |
| 3501 __ mov(frame_->ElementAt(target.size()), eax); | 3533 __ mov(frame_->ElementAt(target.size()), eax); |
| 3502 } | 3534 } |
| 3503 | 3535 |
| 3504 // Perform optimistic increment/decrement. | 3536 // Perform optimistic increment/decrement. |
| 3505 if (is_increment) { | 3537 if (is_increment) { |
| 3506 __ add(Operand(eax), Immediate(Smi::FromInt(1))); | 3538 __ add(Operand(eax), Immediate(Smi::FromInt(1))); |
| 3507 } else { | 3539 } else { |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 3522 } | 3554 } |
| 3523 | 3555 |
| 3524 // Postfix: Discard the new value and use the old. | 3556 // Postfix: Discard the new value and use the old. |
| 3525 if (is_postfix) { | 3557 if (is_postfix) { |
| 3526 frame_->Drop(); | 3558 frame_->Drop(); |
| 3527 } | 3559 } |
| 3528 } | 3560 } |
| 3529 | 3561 |
| 3530 | 3562 |
| 3531 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { | 3563 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { |
| 3564 frame_->SpillAll(); | |
| 3532 // Note that due to an optimization in comparison operations (typeof | 3565 // Note that due to an optimization in comparison operations (typeof |
| 3533 // compared to a string literal), we can evaluate a binary expression such | 3566 // compared to a string literal), we can evaluate a binary expression such |
| 3534 // as AND or OR and not leave a value on the frame or in the cc register. | 3567 // as AND or OR and not leave a value on the frame or in the cc register. |
| 3535 Comment cmnt(masm_, "[ BinaryOperation"); | 3568 Comment cmnt(masm_, "[ BinaryOperation"); |
| 3536 Token::Value op = node->op(); | 3569 Token::Value op = node->op(); |
| 3537 | 3570 |
| 3538 // According to ECMA-262 section 11.11, page 58, the binary logical | 3571 // According to ECMA-262 section 11.11, page 58, the binary logical |
| 3539 // operators must yield the result of one of the two expressions | 3572 // operators must yield the result of one of the two expressions |
| 3540 // before any ToBoolean() conversions. This means that the value | 3573 // before any ToBoolean() conversions. This means that the value |
| 3541 // produced by a && or || operator is not necessarily a boolean. | 3574 // produced by a && or || operator is not necessarily a boolean. |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3661 } else { | 3694 } else { |
| 3662 Load(node->left()); | 3695 Load(node->left()); |
| 3663 Load(node->right()); | 3696 Load(node->right()); |
| 3664 GenericBinaryOperation(node->op(), node->type(), overwrite_mode); | 3697 GenericBinaryOperation(node->op(), node->type(), overwrite_mode); |
| 3665 } | 3698 } |
| 3666 } | 3699 } |
| 3667 } | 3700 } |
| 3668 | 3701 |
| 3669 | 3702 |
| 3670 void CodeGenerator::VisitThisFunction(ThisFunction* node) { | 3703 void CodeGenerator::VisitThisFunction(ThisFunction* node) { |
| 3704 frame_->SpillAll(); | |
| 3671 frame_->EmitPush(frame_->Function()); | 3705 frame_->EmitPush(frame_->Function()); |
| 3672 } | 3706 } |
| 3673 | 3707 |
| 3674 | 3708 |
| 3675 class InstanceofStub: public CodeStub { | 3709 class InstanceofStub: public CodeStub { |
| 3676 public: | 3710 public: |
| 3677 InstanceofStub() { } | 3711 InstanceofStub() { } |
| 3678 | 3712 |
| 3679 void Generate(MacroAssembler* masm); | 3713 void Generate(MacroAssembler* masm); |
| 3680 | 3714 |
| 3681 private: | 3715 private: |
| 3682 Major MajorKey() { return Instanceof; } | 3716 Major MajorKey() { return Instanceof; } |
| 3683 int MinorKey() { return 0; } | 3717 int MinorKey() { return 0; } |
| 3684 }; | 3718 }; |
| 3685 | 3719 |
| 3686 | 3720 |
| 3687 void CodeGenerator::VisitCompareOperation(CompareOperation* node) { | 3721 void CodeGenerator::VisitCompareOperation(CompareOperation* node) { |
| 3722 frame_->SpillAll(); | |
| 3688 Comment cmnt(masm_, "[ CompareOperation"); | 3723 Comment cmnt(masm_, "[ CompareOperation"); |
| 3689 | 3724 |
| 3690 // Get the expressions from the node. | 3725 // Get the expressions from the node. |
| 3691 Expression* left = node->left(); | 3726 Expression* left = node->left(); |
| 3692 Expression* right = node->right(); | 3727 Expression* right = node->right(); |
| 3693 Token::Value op = node->op(); | 3728 Token::Value op = node->op(); |
| 3694 | 3729 |
| 3695 // To make null checks efficient, we check if either left or right is the | 3730 // To make null checks efficient, we check if either left or right is the |
| 3696 // literal 'null'. If so, we optimize the code by inlining a null check | 3731 // literal 'null'. If so, we optimize the code by inlining a null check |
| 3697 // instead of calling the (very) general runtime routine for checking | 3732 // instead of calling the (very) general runtime routine for checking |
| 3698 // equality. | 3733 // equality. |
| 3699 if (op == Token::EQ || op == Token::EQ_STRICT) { | 3734 if (op == Token::EQ || op == Token::EQ_STRICT) { |
| 3700 bool left_is_null = | 3735 bool left_is_null = |
| 3701 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); | 3736 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); |
| 3702 bool right_is_null = | 3737 bool right_is_null = |
| 3703 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); | 3738 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); |
| 3704 // The 'null' value can only be equal to 'null' or 'undefined'. | 3739 // The 'null' value can only be equal to 'null' or 'undefined'. |
| 3705 if (left_is_null || right_is_null) { | 3740 if (left_is_null || right_is_null) { |
| 3706 Load(left_is_null ? right : left); | 3741 Load(left_is_null ? right : left); |
| 3707 frame_->Pop(eax); | 3742 frame_->EmitPop(eax); |
| 3708 __ cmp(eax, Factory::null_value()); | 3743 __ cmp(eax, Factory::null_value()); |
| 3709 | 3744 |
| 3710 // The 'null' value is only equal to 'undefined' if using non-strict | 3745 // The 'null' value is only equal to 'undefined' if using non-strict |
| 3711 // comparisons. | 3746 // comparisons. |
| 3712 if (op != Token::EQ_STRICT) { | 3747 if (op != Token::EQ_STRICT) { |
| 3713 true_target()->Branch(equal); | 3748 true_target()->Branch(equal); |
| 3714 | 3749 |
| 3715 __ cmp(eax, Factory::undefined_value()); | 3750 __ cmp(eax, Factory::undefined_value()); |
| 3716 true_target()->Branch(equal); | 3751 true_target()->Branch(equal); |
| 3717 | 3752 |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 3735 // 'typeof <expression> == <string>'. | 3770 // 'typeof <expression> == <string>'. |
| 3736 UnaryOperation* operation = left->AsUnaryOperation(); | 3771 UnaryOperation* operation = left->AsUnaryOperation(); |
| 3737 if ((op == Token::EQ || op == Token::EQ_STRICT) && | 3772 if ((op == Token::EQ || op == Token::EQ_STRICT) && |
| 3738 (operation != NULL && operation->op() == Token::TYPEOF) && | 3773 (operation != NULL && operation->op() == Token::TYPEOF) && |
| 3739 (right->AsLiteral() != NULL && | 3774 (right->AsLiteral() != NULL && |
| 3740 right->AsLiteral()->handle()->IsString())) { | 3775 right->AsLiteral()->handle()->IsString())) { |
| 3741 Handle<String> check(String::cast(*right->AsLiteral()->handle())); | 3776 Handle<String> check(String::cast(*right->AsLiteral()->handle())); |
| 3742 | 3777 |
| 3743 // Load the operand and move it to register edx. | 3778 // Load the operand and move it to register edx. |
| 3744 LoadTypeofExpression(operation->expression()); | 3779 LoadTypeofExpression(operation->expression()); |
| 3745 frame_->Pop(edx); | 3780 frame_->EmitPop(edx); |
| 3746 | 3781 |
| 3747 if (check->Equals(Heap::number_symbol())) { | 3782 if (check->Equals(Heap::number_symbol())) { |
| 3748 __ test(edx, Immediate(kSmiTagMask)); | 3783 __ test(edx, Immediate(kSmiTagMask)); |
| 3749 true_target()->Branch(zero); | 3784 true_target()->Branch(zero); |
| 3750 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 3785 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3751 __ cmp(edx, Factory::heap_number_map()); | 3786 __ cmp(edx, Factory::heap_number_map()); |
| 3752 cc_reg_ = equal; | 3787 cc_reg_ = equal; |
| 3753 | 3788 |
| 3754 } else if (check->Equals(Heap::string_symbol())) { | 3789 } else if (check->Equals(Heap::string_symbol())) { |
| 3755 __ test(edx, Immediate(kSmiTagMask)); | 3790 __ test(edx, Immediate(kSmiTagMask)); |
| (...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4044 } | 4079 } |
| 4045 | 4080 |
| 4046 // We must execute the store. Storing a variable must keep the | 4081 // We must execute the store. Storing a variable must keep the |
| 4047 // (new) value on the stack. This is necessary for compiling | 4082 // (new) value on the stack. This is necessary for compiling |
| 4048 // assignment expressions. | 4083 // assignment expressions. |
| 4049 // | 4084 // |
| 4050 // Note: We will reach here even with slot->var()->mode() == | 4085 // Note: We will reach here even with slot->var()->mode() == |
| 4051 // Variable::CONST because of const declarations which will | 4086 // Variable::CONST because of const declarations which will |
| 4052 // initialize consts to 'the hole' value and by doing so, end up | 4087 // initialize consts to 'the hole' value and by doing so, end up |
| 4053 // calling this code. | 4088 // calling this code. |
| 4054 frame->Pop(eax); | 4089 frame->EmitPop(eax); |
| 4055 __ mov(cgen_->SlotOperand(slot, ecx), eax); | 4090 __ mov(cgen_->SlotOperand(slot, ecx), eax); |
| 4056 frame->EmitPush(eax); // RecordWrite may destroy the value in eax. | 4091 frame->EmitPush(eax); // RecordWrite may destroy the value in eax. |
| 4057 if (slot->type() == Slot::CONTEXT) { | 4092 if (slot->type() == Slot::CONTEXT) { |
| 4058 // ecx is loaded with context when calling SlotOperand above. | 4093 // ecx is loaded with context when calling SlotOperand above. |
| 4059 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 4094 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
| 4060 __ RecordWrite(ecx, offset, eax, ebx); | 4095 __ RecordWrite(ecx, offset, eax, ebx); |
| 4061 } | 4096 } |
| 4062 // If we definitely did not jump over the assignment, we do not need | 4097 // If we definitely did not jump over the assignment, we do not need |
| 4063 // to bind the exit label. Doing so can defeat peephole | 4098 // to bind the exit label. Doing so can defeat peephole |
| 4064 // optimization. | 4099 // optimization. |
| 4065 if (init_state == CONST_INIT) { | 4100 if (init_state == CONST_INIT) { |
| 4066 exit.Bind(); | 4101 exit.Bind(); |
| 4067 } | 4102 } |
| 4068 } | 4103 } |
| 4069 break; | 4104 break; |
| 4070 } | 4105 } |
| 4071 | 4106 |
| 4072 case NAMED: { | 4107 case NAMED: { |
| 4073 Comment cmnt(masm, "[ Store to named Property"); | 4108 Comment cmnt(masm, "[ Store to named Property"); |
| 4074 // Call the appropriate IC code. | 4109 // Call the appropriate IC code. |
| 4075 Handle<String> name(GetName()); | 4110 Handle<String> name(GetName()); |
| 4076 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 4111 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 4077 // TODO(1222589): Make the IC grab the values from the stack. | 4112 // TODO(1222589): Make the IC grab the values from the stack. |
| 4078 frame->Pop(eax); | 4113 frame->EmitPop(eax); |
| 4079 // Setup the name register. | 4114 // Setup the name register. |
| 4080 __ mov(ecx, name); | 4115 __ mov(ecx, name); |
| 4081 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 4116 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 4082 frame->EmitPush(eax); // IC call leaves result in eax, push it out | 4117 frame->EmitPush(eax); // IC call leaves result in eax, push it out |
| 4083 break; | 4118 break; |
| 4084 } | 4119 } |
| 4085 | 4120 |
| 4086 case KEYED: { | 4121 case KEYED: { |
| 4087 Comment cmnt(masm, "[ Store to keyed Property"); | 4122 Comment cmnt(masm, "[ Store to keyed Property"); |
| 4088 Property* property = expression_->AsProperty(); | 4123 Property* property = expression_->AsProperty(); |
| 4089 ASSERT(property != NULL); | 4124 ASSERT(property != NULL); |
| 4090 __ RecordPosition(property->position()); | 4125 __ RecordPosition(property->position()); |
| 4091 // Call IC code. | 4126 // Call IC code. |
| 4092 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 4127 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 4093 // TODO(1222589): Make the IC grab the values from the stack. | 4128 // TODO(1222589): Make the IC grab the values from the stack. |
| 4094 frame->Pop(eax); | 4129 frame->EmitPop(eax); |
| 4095 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 4130 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 4096 frame->EmitPush(eax); // IC call leaves result in eax, push it out | 4131 frame->EmitPush(eax); // IC call leaves result in eax, push it out |
| 4097 break; | 4132 break; |
| 4098 } | 4133 } |
| 4099 | 4134 |
| 4100 default: | 4135 default: |
| 4101 UNREACHABLE(); | 4136 UNREACHABLE(); |
| 4102 } | 4137 } |
| 4103 } | 4138 } |
| 4104 | 4139 |
| (...skipping 1216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5321 | 5356 |
| 5322 // Slow-case: Go through the JavaScript implementation. | 5357 // Slow-case: Go through the JavaScript implementation. |
| 5323 __ bind(&slow); | 5358 __ bind(&slow); |
| 5324 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 5359 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 5325 } | 5360 } |
| 5326 | 5361 |
| 5327 | 5362 |
| 5328 #undef __ | 5363 #undef __ |
| 5329 | 5364 |
| 5330 } } // namespace v8::internal | 5365 } } // namespace v8::internal |
| OLD | NEW |