| 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 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 92 | 92 |
| 93 | 93 |
| 94 void VirtualFrame::Drop(int count) { | 94 void VirtualFrame::Drop(int count) { |
| 95 ASSERT(count >= 0); | 95 ASSERT(count >= 0); |
| 96 if (count > 0) { | 96 if (count > 0) { |
| 97 __ add(Operand(esp), Immediate(count * kPointerSize)); | 97 __ add(Operand(esp), Immediate(count * kPointerSize)); |
| 98 } | 98 } |
| 99 } | 99 } |
| 100 | 100 |
| 101 | 101 |
| 102 void VirtualFrame::Pop() { | 102 void VirtualFrame::Pop() { Drop(1); } |
| 103 __ add(Operand(esp), Immediate(kPointerSize)); | |
| 104 } | |
| 105 | 103 |
| 106 | 104 |
| 107 void VirtualFrame::Pop(Register reg) { | 105 void VirtualFrame::Pop(Register reg) { |
| 108 __ pop(reg); | 106 __ pop(reg); |
| 109 } | 107 } |
| 110 | 108 |
| 111 | 109 |
| 112 void VirtualFrame::Pop(Operand operand) { | 110 void VirtualFrame::Pop(Operand operand) { |
| 113 __ pop(operand); | 111 __ pop(operand); |
| 114 } | 112 } |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 260 __ CallRuntime(Runtime::kNewContext, 1); // eax holds the result | 258 __ CallRuntime(Runtime::kNewContext, 1); // eax holds the result |
| 261 | 259 |
| 262 if (kDebug) { | 260 if (kDebug) { |
| 263 Label verified_true; | 261 Label verified_true; |
| 264 // Verify eax and esi are the same in debug mode | 262 // Verify eax and esi are the same in debug mode |
| 265 __ cmp(eax, Operand(esi)); | 263 __ cmp(eax, Operand(esi)); |
| 266 __ j(equal, &verified_true); | 264 __ j(equal, &verified_true); |
| 267 __ int3(); | 265 __ int3(); |
| 268 __ bind(&verified_true); | 266 __ bind(&verified_true); |
| 269 } | 267 } |
| 270 | |
| 271 // Update context local. | 268 // Update context local. |
| 272 __ mov(frame_->Context(), esi); | 269 __ mov(frame_->Context(), esi); |
| 273 // Restore the arguments array pointer, if any. | |
| 274 } | 270 } |
| 275 | 271 |
| 276 // TODO(1241774): Improve this code: | 272 // TODO(1241774): Improve this code: |
| 277 // 1) only needed if we have a context | 273 // 1) only needed if we have a context |
| 278 // 2) no need to recompute context ptr every single time | 274 // 2) no need to recompute context ptr every single time |
| 279 // 3) don't copy parameter operand code from SlotOperand! | 275 // 3) don't copy parameter operand code from SlotOperand! |
| 280 { | 276 { |
| 281 Comment cmnt2(masm_, "[ copy context parameters into .context"); | 277 Comment cmnt2(masm_, "[ copy context parameters into .context"); |
| 282 | 278 |
| 283 // Note that iteration order is relevant here! If we have the same | 279 // Note that iteration order is relevant here! If we have the same |
| (...skipping 19 matching lines...) Expand all Loading... |
| 303 __ mov(SlotOperand(slot, ecx), eax); | 299 __ mov(SlotOperand(slot, ecx), eax); |
| 304 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 300 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
| 305 __ RecordWrite(ecx, offset, eax, ebx); | 301 __ RecordWrite(ecx, offset, eax, ebx); |
| 306 } | 302 } |
| 307 } | 303 } |
| 308 } | 304 } |
| 309 | 305 |
| 310 // This section stores the pointer to the arguments object that | 306 // This section stores the pointer to the arguments object that |
| 311 // was allocated and copied into above. If the address was not | 307 // was allocated and copied into above. If the address was not |
| 312 // saved to TOS, we push ecx onto the stack. | 308 // saved to TOS, we push ecx onto the stack. |
| 313 | 309 // |
| 314 // Store the arguments object. | 310 // Store the arguments object. This must happen after context |
| 315 // This must happen after context initialization because | 311 // initialization because the arguments object may be stored in the |
| 316 // the arguments object may be stored in the context | 312 // context. |
| 317 if (arguments_object_allocated) { | 313 if (arguments_object_allocated) { |
| 318 ASSERT(scope_->arguments() != NULL); | 314 ASSERT(scope_->arguments() != NULL); |
| 319 ASSERT(scope_->arguments_shadow() != NULL); | 315 ASSERT(scope_->arguments_shadow() != NULL); |
| 320 Comment cmnt(masm_, "[ store arguments object"); | 316 Comment cmnt(masm_, "[ store arguments object"); |
| 321 { Reference shadow_ref(this, scope_->arguments_shadow()); | 317 { Reference shadow_ref(this, scope_->arguments_shadow()); |
| 322 ASSERT(shadow_ref.is_slot()); | 318 ASSERT(shadow_ref.is_slot()); |
| 323 { Reference arguments_ref(this, scope_->arguments()); | 319 { Reference arguments_ref(this, scope_->arguments()); |
| 324 ASSERT(arguments_ref.is_slot()); | 320 ASSERT(arguments_ref.is_slot()); |
| 325 // If the newly-allocated arguments object is already on the | 321 // If the newly-allocated arguments object is already on the |
| 326 // stack, we make use of the convenient property that references | 322 // stack, we make use of the convenient property that references |
| 327 // representing slots take up no space on the expression stack | 323 // representing slots take up no space on the expression stack |
| 328 // (ie, it doesn't matter that the stored value is actually below | 324 // (ie, it doesn't matter that the stored value is actually below |
| 329 // the reference). | 325 // the reference). |
| 330 // | 326 // |
| 331 // If the newly-allocated argument object is not already on | 327 // If the newly-allocated argument object is not already on |
| 332 // the stack, we rely on the property that loading a | 328 // the stack, we rely on the property that loading a |
| 333 // zero-sized reference will not clobber the ecx register. | 329 // zero-sized reference will not clobber the ecx register. |
| 334 if (!arguments_object_saved) { | 330 if (!arguments_object_saved) { |
| 335 frame_->Push(ecx); | 331 frame_->Push(ecx); |
| 336 } | 332 } |
| 337 arguments_ref.SetValue(NOT_CONST_INIT); | 333 arguments_ref.SetValue(NOT_CONST_INIT); |
| 338 } | 334 } |
| 339 shadow_ref.SetValue(NOT_CONST_INIT); | 335 shadow_ref.SetValue(NOT_CONST_INIT); |
| 340 } | 336 } |
| 341 frame_->Pop(); // Value is no longer needed. | 337 frame_->Pop(); // Value is no longer needed. |
| 342 } | 338 } |
| 343 | 339 |
| 344 // Generate code to 'execute' declarations and initialize | 340 // Generate code to 'execute' declarations and initialize functions |
| 345 // functions (source elements). In case of an illegal | 341 // (source elements). In case of an illegal redeclaration we need to |
| 346 // redeclaration we need to handle that instead of processing the | 342 // handle that instead of processing the declarations. |
| 347 // declarations. | |
| 348 if (scope_->HasIllegalRedeclaration()) { | 343 if (scope_->HasIllegalRedeclaration()) { |
| 349 Comment cmnt(masm_, "[ illegal redeclarations"); | 344 Comment cmnt(masm_, "[ illegal redeclarations"); |
| 350 scope_->VisitIllegalRedeclaration(this); | 345 scope_->VisitIllegalRedeclaration(this); |
| 351 } else { | 346 } else { |
| 352 Comment cmnt(masm_, "[ declarations"); | 347 Comment cmnt(masm_, "[ declarations"); |
| 353 ProcessDeclarations(scope_->declarations()); | 348 ProcessDeclarations(scope_->declarations()); |
| 354 // Bail out if a stack-overflow exception occurred when | 349 // Bail out if a stack-overflow exception occurred when processing |
| 355 // processing declarations. | 350 // declarations. |
| 356 if (HasStackOverflow()) return; | 351 if (HasStackOverflow()) return; |
| 357 } | 352 } |
| 358 | 353 |
| 359 if (FLAG_trace) { | 354 if (FLAG_trace) { |
| 360 __ CallRuntime(Runtime::kTraceEnter, 0); | 355 __ CallRuntime(Runtime::kTraceEnter, 0); |
| 361 // Ignore the return value. | 356 // Ignore the return value. |
| 362 } | 357 } |
| 363 CheckStack(); | 358 CheckStack(); |
| 364 | 359 |
| 365 // Compile the body of the function in a vanilla state. Don't | 360 // Compile the body of the function in a vanilla state. Don't |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 441 } | 436 } |
| 442 | 437 |
| 443 default: | 438 default: |
| 444 UNREACHABLE(); | 439 UNREACHABLE(); |
| 445 return Operand(eax); | 440 return Operand(eax); |
| 446 } | 441 } |
| 447 } | 442 } |
| 448 | 443 |
| 449 | 444 |
| 450 // Loads a value on TOS. If it is a boolean value, the result may have been | 445 // Loads a value on TOS. If it is a boolean value, the result may have been |
| 451 // (partially) translated into branches, or it may have set the condition code | 446 // (partially) translated into branches, or it may have set the condition |
| 452 // register. If force_cc is set, the value is forced to set the condition code | 447 // code register. If force_cc is set, the value is forced to set the |
| 453 // register and no value is pushed. If the condition code register was set, | 448 // condition code register and no value is pushed. If the condition code |
| 454 // has_cc() is true and cc_reg_ contains the condition to test for 'true'. | 449 // register was set, has_cc() is true and cc_reg_ contains the condition to |
| 450 // test for 'true'. |
| 455 void CodeGenerator::LoadCondition(Expression* x, | 451 void CodeGenerator::LoadCondition(Expression* x, |
| 456 TypeofState typeof_state, | 452 TypeofState typeof_state, |
| 457 Label* true_target, | 453 Label* true_target, |
| 458 Label* false_target, | 454 Label* false_target, |
| 459 bool force_cc) { | 455 bool force_cc) { |
| 460 ASSERT(!has_cc()); | 456 ASSERT(!has_cc()); |
| 461 | 457 |
| 462 { CodeGenState new_state(this, typeof_state, true_target, false_target); | 458 { CodeGenState new_state(this, typeof_state, true_target, false_target); |
| 463 Visit(x); | 459 Visit(x); |
| 464 } | 460 } |
| 465 if (force_cc && !has_cc()) { | 461 if (force_cc && !has_cc()) { |
| 462 // Convert the TOS value to a boolean in the condition code register. |
| 463 // Visiting an expression may possibly choose neither (a) to leave a |
| 464 // value in the condition code register nor (b) to leave a value in TOS |
| 465 // (eg, by compiling to only jumps to the targets). In that case the |
| 466 // code generated by ToBoolean is wrong because it assumes the value of |
| 467 // the expression in TOS. So long as there is always a value in TOS or |
| 468 // the condition code register when control falls through to here (there |
| 469 // is), the code generated by ToBoolean is dead and therefore safe. |
| 466 ToBoolean(true_target, false_target); | 470 ToBoolean(true_target, false_target); |
| 467 } | 471 } |
| 468 ASSERT(has_cc() || !force_cc); | 472 ASSERT(has_cc() || !force_cc); |
| 469 } | 473 } |
| 470 | 474 |
| 471 | 475 |
| 472 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { | 476 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { |
| 473 Label true_target; | 477 Label true_target; |
| 474 Label false_target; | 478 Label false_target; |
| 475 LoadCondition(x, typeof_state, &true_target, &false_target, false); | 479 LoadCondition(x, typeof_state, &true_target, &false_target, false); |
| 476 | 480 |
| 477 if (has_cc()) { | 481 if (has_cc()) { |
| 478 // convert cc_reg_ into a bool | 482 // convert cc_reg_ into a bool |
| 479 | |
| 480 Label loaded, materialize_true; | 483 Label loaded, materialize_true; |
| 481 __ j(cc_reg_, &materialize_true); | 484 __ j(cc_reg_, &materialize_true); |
| 482 frame_->Push(Immediate(Factory::false_value())); | 485 frame_->Push(Immediate(Factory::false_value())); |
| 483 __ jmp(&loaded); | 486 __ jmp(&loaded); |
| 484 __ bind(&materialize_true); | 487 __ bind(&materialize_true); |
| 485 frame_->Push(Immediate(Factory::true_value())); | 488 frame_->Push(Immediate(Factory::true_value())); |
| 486 __ bind(&loaded); | 489 __ bind(&loaded); |
| 487 cc_reg_ = no_condition; | 490 cc_reg_ = no_condition; |
| 488 } | 491 } |
| 489 | 492 |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 597 Load(e); | 600 Load(e); |
| 598 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 601 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
| 599 } | 602 } |
| 600 } | 603 } |
| 601 | 604 |
| 602 | 605 |
| 603 void CodeGenerator::UnloadReference(Reference* ref) { | 606 void CodeGenerator::UnloadReference(Reference* ref) { |
| 604 // Pop a reference from the stack while preserving TOS. | 607 // Pop a reference from the stack while preserving TOS. |
| 605 Comment cmnt(masm_, "[ UnloadReference"); | 608 Comment cmnt(masm_, "[ UnloadReference"); |
| 606 int size = ref->size(); | 609 int size = ref->size(); |
| 607 if (size <= 0) { | 610 if (size == 1) { |
| 608 // Do nothing. No popping is necessary. | |
| 609 } else if (size == 1) { | |
| 610 frame_->Pop(eax); | 611 frame_->Pop(eax); |
| 611 __ mov(frame_->Top(), eax); | 612 __ mov(frame_->Top(), eax); |
| 612 } else { | 613 } else if (size > 1) { |
| 613 frame_->Pop(eax); | 614 frame_->Pop(eax); |
| 614 frame_->Drop(size); | 615 frame_->Drop(size); |
| 615 frame_->Push(eax); | 616 frame_->Push(eax); |
| 616 } | 617 } |
| 617 } | 618 } |
| 618 | 619 |
| 619 | 620 |
| 620 class ToBooleanStub: public CodeStub { | 621 class ToBooleanStub: public CodeStub { |
| 621 public: | 622 public: |
| 622 ToBooleanStub() { } | 623 ToBooleanStub() { } |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 656 ASSERT(kSmiTag == 0); | 657 ASSERT(kSmiTag == 0); |
| 657 __ test(eax, Operand(eax)); | 658 __ test(eax, Operand(eax)); |
| 658 __ j(zero, false_target); | 659 __ j(zero, false_target); |
| 659 __ test(eax, Immediate(kSmiTagMask)); | 660 __ test(eax, Immediate(kSmiTagMask)); |
| 660 __ j(zero, true_target); | 661 __ j(zero, true_target); |
| 661 | 662 |
| 662 // Call the stub for all other cases. | 663 // Call the stub for all other cases. |
| 663 frame_->Push(eax); // Undo the pop(eax) from above. | 664 frame_->Push(eax); // Undo the pop(eax) from above. |
| 664 ToBooleanStub stub; | 665 ToBooleanStub stub; |
| 665 __ CallStub(&stub); | 666 __ CallStub(&stub); |
| 666 // Convert result (eax) to condition code. | 667 // Convert the result (eax) to condition code. |
| 667 __ test(eax, Operand(eax)); | 668 __ test(eax, Operand(eax)); |
| 668 | 669 |
| 669 ASSERT(not_equal == not_zero); | 670 ASSERT(not_equal == not_zero); |
| 670 cc_reg_ = not_equal; | 671 cc_reg_ = not_equal; |
| 671 } | 672 } |
| 672 | 673 |
| 673 | 674 |
| 674 class FloatingPointHelper : public AllStatic { | 675 class FloatingPointHelper : public AllStatic { |
| 675 public: | 676 public: |
| 676 // Code pattern for loading floating point values. Input values must | 677 // Code pattern for loading floating point values. Input values must |
| (...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1033 | 1034 |
| 1034 case Token::SUB: { | 1035 case Token::SUB: { |
| 1035 DeferredCode* deferred = NULL; | 1036 DeferredCode* deferred = NULL; |
| 1036 frame_->Pop(eax); | 1037 frame_->Pop(eax); |
| 1037 if (!reversed) { | 1038 if (!reversed) { |
| 1038 deferred = new DeferredInlinedSmiSub(this, int_value, overwrite_mode); | 1039 deferred = new DeferredInlinedSmiSub(this, int_value, overwrite_mode); |
| 1039 __ sub(Operand(eax), Immediate(value)); | 1040 __ sub(Operand(eax), Immediate(value)); |
| 1040 } else { | 1041 } else { |
| 1041 deferred = new DeferredInlinedSmiSubReversed(this, edx, overwrite_mode); | 1042 deferred = new DeferredInlinedSmiSubReversed(this, edx, overwrite_mode); |
| 1042 __ mov(edx, Operand(eax)); | 1043 __ mov(edx, Operand(eax)); |
| 1043 __ mov(Operand(eax), Immediate(value)); | 1044 __ mov(eax, Immediate(value)); |
| 1044 __ sub(eax, Operand(edx)); | 1045 __ sub(eax, Operand(edx)); |
| 1045 } | 1046 } |
| 1046 __ j(overflow, deferred->enter(), not_taken); | 1047 __ j(overflow, deferred->enter(), not_taken); |
| 1047 __ test(eax, Immediate(kSmiTagMask)); | 1048 __ test(eax, Immediate(kSmiTagMask)); |
| 1048 __ j(not_zero, deferred->enter(), not_taken); | 1049 __ j(not_zero, deferred->enter(), not_taken); |
| 1049 __ bind(deferred->exit()); | 1050 __ bind(deferred->exit()); |
| 1050 frame_->Push(eax); | 1051 frame_->Push(eax); |
| 1051 break; | 1052 break; |
| 1052 } | 1053 } |
| 1053 | 1054 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1087 frame_->Pop(eax); | 1088 frame_->Pop(eax); |
| 1088 __ test(eax, Immediate(kSmiTagMask)); | 1089 __ test(eax, Immediate(kSmiTagMask)); |
| 1089 __ mov(ebx, Operand(eax)); | 1090 __ mov(ebx, Operand(eax)); |
| 1090 __ j(not_zero, deferred->enter(), not_taken); | 1091 __ j(not_zero, deferred->enter(), not_taken); |
| 1091 __ sar(ebx, kSmiTagSize); | 1092 __ sar(ebx, kSmiTagSize); |
| 1092 __ shr(ebx, shift_value); | 1093 __ shr(ebx, shift_value); |
| 1093 __ test(ebx, Immediate(0xc0000000)); | 1094 __ test(ebx, Immediate(0xc0000000)); |
| 1094 __ j(not_zero, deferred->enter(), not_taken); | 1095 __ j(not_zero, deferred->enter(), not_taken); |
| 1095 // tag result and store it in TOS (eax) | 1096 // tag result and store it in TOS (eax) |
| 1096 ASSERT(kSmiTagSize == times_2); // adjust code if not the case | 1097 ASSERT(kSmiTagSize == times_2); // adjust code if not the case |
| 1097 __ lea(eax, Operand(ebx, times_2, kSmiTag)); | 1098 __ lea(eax, Operand(ebx, ebx, times_1, kSmiTag)); |
| 1098 __ bind(deferred->exit()); | 1099 __ bind(deferred->exit()); |
| 1099 frame_->Push(eax); | 1100 frame_->Push(eax); |
| 1100 } | 1101 } |
| 1101 break; | 1102 break; |
| 1102 } | 1103 } |
| 1103 | 1104 |
| 1104 case Token::SHL: { | 1105 case Token::SHL: { |
| 1105 if (reversed) { | 1106 if (reversed) { |
| 1106 frame_->Pop(eax); | 1107 frame_->Pop(eax); |
| 1107 frame_->Push(Immediate(value)); | 1108 frame_->Push(Immediate(value)); |
| 1108 frame_->Push(eax); | 1109 frame_->Push(eax); |
| 1109 GenericBinaryOperation(op, type, overwrite_mode); | 1110 GenericBinaryOperation(op, type, overwrite_mode); |
| 1110 } else { | 1111 } else { |
| 1111 int shift_value = int_value & 0x1f; // only least significant 5 bits | 1112 int shift_value = int_value & 0x1f; // only least significant 5 bits |
| 1112 DeferredCode* deferred = | 1113 DeferredCode* deferred = |
| 1113 new DeferredInlinedSmiOperation(this, Token::SHL, shift_value, | 1114 new DeferredInlinedSmiOperation(this, Token::SHL, shift_value, |
| 1114 overwrite_mode); | 1115 overwrite_mode); |
| 1115 frame_->Pop(eax); | 1116 frame_->Pop(eax); |
| 1116 __ test(eax, Immediate(kSmiTagMask)); | 1117 __ test(eax, Immediate(kSmiTagMask)); |
| 1117 __ mov(ebx, Operand(eax)); | 1118 __ mov(ebx, Operand(eax)); |
| 1118 __ j(not_zero, deferred->enter(), not_taken); | 1119 __ j(not_zero, deferred->enter(), not_taken); |
| 1119 __ sar(ebx, kSmiTagSize); | 1120 __ sar(ebx, kSmiTagSize); |
| 1120 __ shl(ebx, shift_value); | 1121 __ shl(ebx, shift_value); |
| 1121 __ lea(ecx, Operand(ebx, 0x40000000)); | 1122 __ lea(ecx, Operand(ebx, 0x40000000)); |
| 1122 __ test(ecx, Immediate(0x80000000)); | 1123 __ test(ecx, Immediate(0x80000000)); |
| 1123 __ j(not_zero, deferred->enter(), not_taken); | 1124 __ j(not_zero, deferred->enter(), not_taken); |
| 1124 // tag result and store it in TOS (eax) | 1125 // tag result and store it in TOS (eax) |
| 1125 ASSERT(kSmiTagSize == times_2); // adjust code if not the case | 1126 ASSERT(kSmiTagSize == times_2); // adjust code if not the case |
| 1126 __ lea(eax, Operand(ebx, times_2, kSmiTag)); | 1127 __ lea(eax, Operand(ebx, ebx, times_1, kSmiTag)); |
| 1127 __ bind(deferred->exit()); | 1128 __ bind(deferred->exit()); |
| 1128 frame_->Push(eax); | 1129 frame_->Push(eax); |
| 1129 } | 1130 } |
| 1130 break; | 1131 break; |
| 1131 } | 1132 } |
| 1132 | 1133 |
| 1133 case Token::BIT_OR: | 1134 case Token::BIT_OR: |
| 1134 case Token::BIT_XOR: | 1135 case Token::BIT_XOR: |
| 1135 case Token::BIT_AND: { | 1136 case Token::BIT_AND: { |
| 1136 DeferredCode* deferred = NULL; | 1137 DeferredCode* deferred = NULL; |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1257 Condition cc_; | 1258 Condition cc_; |
| 1258 bool strict_; | 1259 bool strict_; |
| 1259 int value_; | 1260 int value_; |
| 1260 }; | 1261 }; |
| 1261 | 1262 |
| 1262 | 1263 |
| 1263 void SmiComparisonDeferred::Generate() { | 1264 void SmiComparisonDeferred::Generate() { |
| 1264 CompareStub stub(cc_, strict_); | 1265 CompareStub stub(cc_, strict_); |
| 1265 // Setup parameters and call stub. | 1266 // Setup parameters and call stub. |
| 1266 __ mov(edx, Operand(eax)); | 1267 __ mov(edx, Operand(eax)); |
| 1267 __ mov(Operand(eax), Immediate(Smi::FromInt(value_))); | 1268 __ Set(eax, Immediate(Smi::FromInt(value_))); |
| 1268 __ CallStub(&stub); | 1269 __ CallStub(&stub); |
| 1269 __ cmp(eax, 0); | 1270 __ cmp(eax, 0); |
| 1270 // "result" is returned in the flags | 1271 // "result" is returned in the flags |
| 1271 } | 1272 } |
| 1272 | 1273 |
| 1273 | 1274 |
| 1274 void CodeGenerator::SmiComparison(Condition cc, | 1275 void CodeGenerator::SmiComparison(Condition cc, |
| 1275 Handle<Object> value, | 1276 Handle<Object> value, |
| 1276 bool strict) { | 1277 bool strict) { |
| 1277 // Strict only makes sense for equality comparisons. | 1278 // Strict only makes sense for equality comparisons. |
| (...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1643 | 1644 |
| 1644 if (min_index != 0) { | 1645 if (min_index != 0) { |
| 1645 __ sub(Operand(eax), Immediate(min_index << kSmiTagSize)); | 1646 __ sub(Operand(eax), Immediate(min_index << kSmiTagSize)); |
| 1646 } | 1647 } |
| 1647 __ test(eax, Immediate(0x80000000 | kSmiTagMask)); // negative or not Smi | 1648 __ test(eax, Immediate(0x80000000 | kSmiTagMask)); // negative or not Smi |
| 1648 __ j(not_equal, fail_label, not_taken); | 1649 __ j(not_equal, fail_label, not_taken); |
| 1649 __ cmp(eax, range << kSmiTagSize); | 1650 __ cmp(eax, range << kSmiTagSize); |
| 1650 __ j(greater_equal, fail_label, not_taken); | 1651 __ j(greater_equal, fail_label, not_taken); |
| 1651 | 1652 |
| 1652 // 0 is placeholder. | 1653 // 0 is placeholder. |
| 1653 __ jmp(Operand(eax, times_2, 0x0, RelocInfo::INTERNAL_REFERENCE)); | 1654 __ jmp(Operand(eax, eax, times_1, 0x0, RelocInfo::INTERNAL_REFERENCE)); |
| 1654 // calculate address to overwrite later with actual address of table. | 1655 // calculate address to overwrite later with actual address of table. |
| 1655 int32_t jump_table_ref = __ pc_offset() - sizeof(int32_t); | 1656 int32_t jump_table_ref = __ pc_offset() - sizeof(int32_t); |
| 1656 | 1657 |
| 1657 __ Align(4); | 1658 __ Align(4); |
| 1658 Label table_start; | 1659 Label table_start; |
| 1659 __ bind(&table_start); | 1660 __ bind(&table_start); |
| 1660 __ WriteInternalReference(jump_table_ref, table_start); | 1661 __ WriteInternalReference(jump_table_ref, table_start); |
| 1661 | 1662 |
| 1662 for (int i = 0; i < range; i++) { | 1663 for (int i = 0; i < range; i++) { |
| 1663 // table entry, 0 is placeholder for case address | 1664 // table entry, 0 is placeholder for case address |
| (...skipping 527 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2191 frame_->Pop(eax); | 2192 frame_->Pop(eax); |
| 2192 ExternalReference handler_address(Top::k_handler_address); | 2193 ExternalReference handler_address(Top::k_handler_address); |
| 2193 __ mov(edx, Operand::StaticVariable(handler_address)); | 2194 __ mov(edx, Operand::StaticVariable(handler_address)); |
| 2194 const int kNextOffset = StackHandlerConstants::kNextOffset + | 2195 const int kNextOffset = StackHandlerConstants::kNextOffset + |
| 2195 StackHandlerConstants::kAddressDisplacement; | 2196 StackHandlerConstants::kAddressDisplacement; |
| 2196 __ lea(esp, Operand(edx, kNextOffset)); | 2197 __ lea(esp, Operand(edx, kNextOffset)); |
| 2197 | 2198 |
| 2198 frame_->Pop(Operand::StaticVariable(handler_address)); | 2199 frame_->Pop(Operand::StaticVariable(handler_address)); |
| 2199 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 2200 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
| 2200 // Next_sp popped. | 2201 // Next_sp popped. |
| 2201 // Preserve the TOS in a register across stack manipulation. | |
| 2202 frame_->Push(eax); | 2202 frame_->Push(eax); |
| 2203 | 2203 |
| 2204 // --- Finally block --- | 2204 // --- Finally block --- |
| 2205 __ bind(&finally_block); | 2205 __ bind(&finally_block); |
| 2206 | 2206 |
| 2207 // Push the state on the stack. | 2207 // Push the state on the stack. |
| 2208 frame_->Push(ecx); | 2208 frame_->Push(ecx); |
| 2209 | 2209 |
| 2210 // We keep two elements on the stack - the (possibly faked) result | 2210 // We keep two elements on the stack - the (possibly faked) result |
| 2211 // and the state - while evaluating the finally block. Record it, so | 2211 // and the state - while evaluating the finally block. Record it, so |
| (...skipping 1303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3515 | 3515 |
| 3516 | 3516 |
| 3517 void CodeGenerator::VisitCompareOperation(CompareOperation* node) { | 3517 void CodeGenerator::VisitCompareOperation(CompareOperation* node) { |
| 3518 Comment cmnt(masm_, "[ CompareOperation"); | 3518 Comment cmnt(masm_, "[ CompareOperation"); |
| 3519 | 3519 |
| 3520 // Get the expressions from the node. | 3520 // Get the expressions from the node. |
| 3521 Expression* left = node->left(); | 3521 Expression* left = node->left(); |
| 3522 Expression* right = node->right(); | 3522 Expression* right = node->right(); |
| 3523 Token::Value op = node->op(); | 3523 Token::Value op = node->op(); |
| 3524 | 3524 |
| 3525 // NOTE: To make null checks efficient, we check if either left or | 3525 // To make null checks efficient, we check if either left or right is the |
| 3526 // right is the literal 'null'. If so, we optimize the code by | 3526 // literal 'null'. If so, we optimize the code by inlining a null check |
| 3527 // inlining a null check instead of calling the (very) general | 3527 // instead of calling the (very) general runtime routine for checking |
| 3528 // runtime routine for checking equality. | 3528 // equality. |
| 3529 | |
| 3530 if (op == Token::EQ || op == Token::EQ_STRICT) { | 3529 if (op == Token::EQ || op == Token::EQ_STRICT) { |
| 3531 bool left_is_null = | 3530 bool left_is_null = |
| 3532 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); | 3531 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); |
| 3533 bool right_is_null = | 3532 bool right_is_null = |
| 3534 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); | 3533 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); |
| 3535 // The 'null' value is only equal to 'null' or 'undefined'. | 3534 // The 'null' value can only be equal to 'null' or 'undefined'. |
| 3536 if (left_is_null || right_is_null) { | 3535 if (left_is_null || right_is_null) { |
| 3537 Load(left_is_null ? right : left); | 3536 Load(left_is_null ? right : left); |
| 3538 Label exit, undetectable; | |
| 3539 frame_->Pop(eax); | 3537 frame_->Pop(eax); |
| 3540 __ cmp(eax, Factory::null_value()); | 3538 __ cmp(eax, Factory::null_value()); |
| 3541 | 3539 |
| 3542 // The 'null' value is only equal to 'undefined' if using | 3540 // The 'null' value is only equal to 'undefined' if using non-strict |
| 3543 // non-strict comparisons. | 3541 // comparisons. |
| 3544 if (op != Token::EQ_STRICT) { | 3542 if (op != Token::EQ_STRICT) { |
| 3545 __ j(equal, &exit); | 3543 __ j(equal, true_target()); |
| 3544 |
| 3546 __ cmp(eax, Factory::undefined_value()); | 3545 __ cmp(eax, Factory::undefined_value()); |
| 3546 __ j(equal, true_target()); |
| 3547 | 3547 |
| 3548 // NOTE: it can be an undetectable object. | |
| 3549 __ j(equal, &exit); | |
| 3550 __ test(eax, Immediate(kSmiTagMask)); | 3548 __ test(eax, Immediate(kSmiTagMask)); |
| 3549 __ j(equal, false_target()); |
| 3551 | 3550 |
| 3552 __ j(not_equal, &undetectable); | 3551 // It can be an undetectable object. |
| 3553 __ jmp(false_target()); | 3552 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); |
| 3554 | 3553 __ movzx_b(eax, FieldOperand(eax, Map::kBitFieldOffset)); |
| 3555 __ bind(&undetectable); | 3554 __ and_(eax, 1 << Map::kIsUndetectable); |
| 3556 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 3555 __ cmp(eax, 1 << Map::kIsUndetectable); |
| 3557 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | |
| 3558 __ and_(ecx, 1 << Map::kIsUndetectable); | |
| 3559 __ cmp(ecx, 1 << Map::kIsUndetectable); | |
| 3560 } | 3556 } |
| 3561 | 3557 |
| 3562 __ bind(&exit); | |
| 3563 | |
| 3564 cc_reg_ = equal; | 3558 cc_reg_ = equal; |
| 3565 return; | 3559 return; |
| 3566 } | 3560 } |
| 3567 } | 3561 } |
| 3568 | 3562 |
| 3569 // NOTE: To make typeof testing for natives implemented in | 3563 // To make typeof testing for natives implemented in JavaScript really |
| 3570 // JavaScript really efficient, we generate special code for | 3564 // efficient, we generate special code for expressions of the form: |
| 3571 // expressions of the form: 'typeof <expression> == <string>'. | 3565 // 'typeof <expression> == <string>'. |
| 3572 | |
| 3573 UnaryOperation* operation = left->AsUnaryOperation(); | 3566 UnaryOperation* operation = left->AsUnaryOperation(); |
| 3574 if ((op == Token::EQ || op == Token::EQ_STRICT) && | 3567 if ((op == Token::EQ || op == Token::EQ_STRICT) && |
| 3575 (operation != NULL && operation->op() == Token::TYPEOF) && | 3568 (operation != NULL && operation->op() == Token::TYPEOF) && |
| 3576 (right->AsLiteral() != NULL && | 3569 (right->AsLiteral() != NULL && |
| 3577 right->AsLiteral()->handle()->IsString())) { | 3570 right->AsLiteral()->handle()->IsString())) { |
| 3578 Handle<String> check(String::cast(*right->AsLiteral()->handle())); | 3571 Handle<String> check(String::cast(*right->AsLiteral()->handle())); |
| 3579 | 3572 |
| 3580 // Load the operand, move it to register edx, and restore TOS. | 3573 // Load the operand and move it to register edx. |
| 3581 LoadTypeofExpression(operation->expression()); | 3574 LoadTypeofExpression(operation->expression()); |
| 3582 frame_->Pop(edx); | 3575 frame_->Pop(edx); |
| 3583 | 3576 |
| 3584 if (check->Equals(Heap::number_symbol())) { | 3577 if (check->Equals(Heap::number_symbol())) { |
| 3585 __ test(edx, Immediate(kSmiTagMask)); | 3578 __ test(edx, Immediate(kSmiTagMask)); |
| 3586 __ j(zero, true_target()); | 3579 __ j(zero, true_target()); |
| 3587 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 3580 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3588 __ cmp(edx, Factory::heap_number_map()); | 3581 __ cmp(edx, Factory::heap_number_map()); |
| 3589 cc_reg_ = equal; | 3582 cc_reg_ = equal; |
| 3590 | 3583 |
| 3591 } else if (check->Equals(Heap::string_symbol())) { | 3584 } else if (check->Equals(Heap::string_symbol())) { |
| 3592 __ test(edx, Immediate(kSmiTagMask)); | 3585 __ test(edx, Immediate(kSmiTagMask)); |
| 3593 __ j(zero, false_target()); | 3586 __ j(zero, false_target()); |
| 3594 | 3587 |
| 3595 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 3588 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3596 | 3589 |
| 3597 // NOTE: it might be an undetectable string object | 3590 // It can be an undetectable string object. |
| 3598 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | 3591 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); |
| 3599 __ and_(ecx, 1 << Map::kIsUndetectable); | 3592 __ and_(ecx, 1 << Map::kIsUndetectable); |
| 3600 __ cmp(ecx, 1 << Map::kIsUndetectable); | 3593 __ cmp(ecx, 1 << Map::kIsUndetectable); |
| 3601 __ j(equal, false_target()); | 3594 __ j(equal, false_target()); |
| 3602 | 3595 |
| 3603 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset)); | 3596 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset)); |
| 3604 __ cmp(ecx, FIRST_NONSTRING_TYPE); | 3597 __ cmp(ecx, FIRST_NONSTRING_TYPE); |
| 3605 cc_reg_ = less; | 3598 cc_reg_ = less; |
| 3606 | 3599 |
| 3607 } else if (check->Equals(Heap::boolean_symbol())) { | 3600 } else if (check->Equals(Heap::boolean_symbol())) { |
| 3608 __ cmp(edx, Factory::true_value()); | 3601 __ cmp(edx, Factory::true_value()); |
| 3609 __ j(equal, true_target()); | 3602 __ j(equal, true_target()); |
| 3610 __ cmp(edx, Factory::false_value()); | 3603 __ cmp(edx, Factory::false_value()); |
| 3611 cc_reg_ = equal; | 3604 cc_reg_ = equal; |
| 3612 | 3605 |
| 3613 } else if (check->Equals(Heap::undefined_symbol())) { | 3606 } else if (check->Equals(Heap::undefined_symbol())) { |
| 3614 __ cmp(edx, Factory::undefined_value()); | 3607 __ cmp(edx, Factory::undefined_value()); |
| 3615 __ j(equal, true_target()); | 3608 __ j(equal, true_target()); |
| 3616 | 3609 |
| 3617 __ test(edx, Immediate(kSmiTagMask)); | 3610 __ test(edx, Immediate(kSmiTagMask)); |
| 3618 __ j(zero, false_target()); | 3611 __ j(zero, false_target()); |
| 3619 | 3612 |
| 3620 // NOTE: it can be an undetectable object. | 3613 // It can be an undetectable object. |
| 3621 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 3614 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3622 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | 3615 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); |
| 3623 __ and_(ecx, 1 << Map::kIsUndetectable); | 3616 __ and_(ecx, 1 << Map::kIsUndetectable); |
| 3624 __ cmp(ecx, 1 << Map::kIsUndetectable); | 3617 __ cmp(ecx, 1 << Map::kIsUndetectable); |
| 3625 | 3618 |
| 3626 cc_reg_ = equal; | 3619 cc_reg_ = equal; |
| 3627 | 3620 |
| 3628 } else if (check->Equals(Heap::function_symbol())) { | 3621 } else if (check->Equals(Heap::function_symbol())) { |
| 3629 __ test(edx, Immediate(kSmiTagMask)); | 3622 __ test(edx, Immediate(kSmiTagMask)); |
| 3630 __ j(zero, false_target()); | 3623 __ j(zero, false_target()); |
| 3631 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 3624 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3632 __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset)); | 3625 __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset)); |
| 3633 __ cmp(edx, JS_FUNCTION_TYPE); | 3626 __ cmp(edx, JS_FUNCTION_TYPE); |
| 3634 cc_reg_ = equal; | 3627 cc_reg_ = equal; |
| 3635 | 3628 |
| 3636 } else if (check->Equals(Heap::object_symbol())) { | 3629 } else if (check->Equals(Heap::object_symbol())) { |
| 3637 __ test(edx, Immediate(kSmiTagMask)); | 3630 __ test(edx, Immediate(kSmiTagMask)); |
| 3638 __ j(zero, false_target()); | 3631 __ j(zero, false_target()); |
| 3639 | 3632 |
| 3640 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 3633 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3641 __ cmp(edx, Factory::null_value()); | 3634 __ cmp(edx, Factory::null_value()); |
| 3642 __ j(equal, true_target()); | 3635 __ j(equal, true_target()); |
| 3643 | 3636 |
| 3644 // NOTE: it might be an undetectable object | 3637 // It can be an undetectable object. |
| 3645 __ movzx_b(edx, FieldOperand(ecx, Map::kBitFieldOffset)); | 3638 __ movzx_b(edx, FieldOperand(ecx, Map::kBitFieldOffset)); |
| 3646 __ and_(edx, 1 << Map::kIsUndetectable); | 3639 __ and_(edx, 1 << Map::kIsUndetectable); |
| 3647 __ cmp(edx, 1 << Map::kIsUndetectable); | 3640 __ cmp(edx, 1 << Map::kIsUndetectable); |
| 3648 __ j(equal, false_target()); | 3641 __ j(equal, false_target()); |
| 3649 | 3642 |
| 3650 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 3643 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
| 3651 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | 3644 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); |
| 3652 __ j(less, false_target()); | 3645 __ j(less, false_target()); |
| 3653 __ cmp(ecx, LAST_JS_OBJECT_TYPE); | 3646 __ cmp(ecx, LAST_JS_OBJECT_TYPE); |
| 3654 cc_reg_ = less_equal; | 3647 cc_reg_ = less_equal; |
| 3655 | 3648 |
| 3656 } else { | 3649 } else { |
| 3657 // Uncommon case: Typeof testing against a string literal that | 3650 // Uncommon case: typeof testing against a string literal that is |
| 3658 // is never returned from the typeof operator. | 3651 // never returned from the typeof operator. |
| 3659 __ jmp(false_target()); | 3652 __ jmp(false_target()); |
| 3660 } | 3653 } |
| 3661 return; | 3654 return; |
| 3662 } | 3655 } |
| 3663 | 3656 |
| 3664 Condition cc = no_condition; | 3657 Condition cc = no_condition; |
| 3665 bool strict = false; | 3658 bool strict = false; |
| 3666 switch (op) { | 3659 switch (op) { |
| 3667 case Token::EQ_STRICT: | 3660 case Token::EQ_STRICT: |
| 3668 strict = true; | 3661 strict = true; |
| (...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4055 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); | 4048 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
| 4056 __ cmp(eax, 0x40000000); | 4049 __ cmp(eax, 0x40000000); |
| 4057 __ j(equal, slow); | 4050 __ j(equal, slow); |
| 4058 // Check for negative zero result. | 4051 // Check for negative zero result. |
| 4059 __ NegativeZeroTest(eax, ecx, slow); // use ecx = x | y | 4052 __ NegativeZeroTest(eax, ecx, slow); // use ecx = x | y |
| 4060 // Check that the remainder is zero. | 4053 // Check that the remainder is zero. |
| 4061 __ test(edx, Operand(edx)); | 4054 __ test(edx, Operand(edx)); |
| 4062 __ j(not_zero, slow); | 4055 __ j(not_zero, slow); |
| 4063 // Tag the result and store it in register eax. | 4056 // Tag the result and store it in register eax. |
| 4064 ASSERT(kSmiTagSize == times_2); // adjust code if not the case | 4057 ASSERT(kSmiTagSize == times_2); // adjust code if not the case |
| 4065 __ lea(eax, Operand(eax, times_2, kSmiTag)); | 4058 __ lea(eax, Operand(eax, eax, times_1, kSmiTag)); |
| 4066 break; | 4059 break; |
| 4067 | 4060 |
| 4068 case Token::MOD: | 4061 case Token::MOD: |
| 4069 // Divide edx:eax by ebx. | 4062 // Divide edx:eax by ebx. |
| 4070 __ idiv(ebx); | 4063 __ idiv(ebx); |
| 4071 // Check for negative zero result. | 4064 // Check for negative zero result. |
| 4072 __ NegativeZeroTest(edx, ecx, slow); // use ecx = x | y | 4065 __ NegativeZeroTest(edx, ecx, slow); // use ecx = x | y |
| 4073 // Move remainder to register eax. | 4066 // Move remainder to register eax. |
| 4074 __ mov(eax, Operand(edx)); | 4067 __ mov(eax, Operand(edx)); |
| 4075 break; | 4068 break; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4116 // Check that the *signed* result fits in a smi. | 4109 // Check that the *signed* result fits in a smi. |
| 4117 __ lea(ecx, Operand(eax, 0x40000000)); | 4110 __ lea(ecx, Operand(eax, 0x40000000)); |
| 4118 __ test(ecx, Immediate(0x80000000)); | 4111 __ test(ecx, Immediate(0x80000000)); |
| 4119 __ j(not_zero, slow, not_taken); | 4112 __ j(not_zero, slow, not_taken); |
| 4120 break; | 4113 break; |
| 4121 default: | 4114 default: |
| 4122 UNREACHABLE(); | 4115 UNREACHABLE(); |
| 4123 } | 4116 } |
| 4124 // Tag the result and store it in register eax. | 4117 // Tag the result and store it in register eax. |
| 4125 ASSERT(kSmiTagSize == times_2); // adjust code if not the case | 4118 ASSERT(kSmiTagSize == times_2); // adjust code if not the case |
| 4126 __ lea(eax, Operand(eax, times_2, kSmiTag)); | 4119 __ lea(eax, Operand(eax, eax, times_1, kSmiTag)); |
| 4127 break; | 4120 break; |
| 4128 | 4121 |
| 4129 default: | 4122 default: |
| 4130 UNREACHABLE(); | 4123 UNREACHABLE(); |
| 4131 break; | 4124 break; |
| 4132 } | 4125 } |
| 4133 } | 4126 } |
| 4134 | 4127 |
| 4135 | 4128 |
| 4136 void GenericBinaryOpStub::Generate(MacroAssembler* masm) { | 4129 void GenericBinaryOpStub::Generate(MacroAssembler* masm) { |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4243 case Token::SHR: __ shr(eax); break; | 4236 case Token::SHR: __ shr(eax); break; |
| 4244 default: UNREACHABLE(); | 4237 default: UNREACHABLE(); |
| 4245 } | 4238 } |
| 4246 | 4239 |
| 4247 // Check if result is non-negative and fits in a smi. | 4240 // Check if result is non-negative and fits in a smi. |
| 4248 __ test(eax, Immediate(0xc0000000)); | 4241 __ test(eax, Immediate(0xc0000000)); |
| 4249 __ j(not_zero, &non_smi_result); | 4242 __ j(not_zero, &non_smi_result); |
| 4250 | 4243 |
| 4251 // Tag smi result and return. | 4244 // Tag smi result and return. |
| 4252 ASSERT(kSmiTagSize == times_2); // adjust code if not the case | 4245 ASSERT(kSmiTagSize == times_2); // adjust code if not the case |
| 4253 __ lea(eax, Operand(eax, times_2, kSmiTag)); | 4246 __ lea(eax, Operand(eax, eax, times_1, kSmiTag)); |
| 4254 __ ret(2 * kPointerSize); | 4247 __ ret(2 * kPointerSize); |
| 4255 | 4248 |
| 4256 // All ops except SHR return a signed int32 that we load in a HeapNumber. | 4249 // All ops except SHR return a signed int32 that we load in a HeapNumber. |
| 4257 if (op_ != Token::SHR) { | 4250 if (op_ != Token::SHR) { |
| 4258 __ bind(&non_smi_result); | 4251 __ bind(&non_smi_result); |
| 4259 // Allocate a heap number if needed. | 4252 // Allocate a heap number if needed. |
| 4260 __ mov(ebx, Operand(eax)); // ebx: result | 4253 __ mov(ebx, Operand(eax)); // ebx: result |
| 4261 switch (mode_) { | 4254 switch (mode_) { |
| 4262 case OVERWRITE_LEFT: | 4255 case OVERWRITE_LEFT: |
| 4263 case OVERWRITE_RIGHT: | 4256 case OVERWRITE_RIGHT: |
| (...skipping 713 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4977 // edi: number of arguments including receiver (C callee-saved) | 4970 // edi: number of arguments including receiver (C callee-saved) |
| 4978 // esi: argv pointer (C callee-saved) | 4971 // esi: argv pointer (C callee-saved) |
| 4979 | 4972 |
| 4980 Label throw_out_of_memory_exception; | 4973 Label throw_out_of_memory_exception; |
| 4981 Label throw_normal_exception; | 4974 Label throw_normal_exception; |
| 4982 | 4975 |
| 4983 // Call into the runtime system. Collect garbage before the call if | 4976 // Call into the runtime system. Collect garbage before the call if |
| 4984 // running with --gc-greedy set. | 4977 // running with --gc-greedy set. |
| 4985 if (FLAG_gc_greedy) { | 4978 if (FLAG_gc_greedy) { |
| 4986 Failure* failure = Failure::RetryAfterGC(0); | 4979 Failure* failure = Failure::RetryAfterGC(0); |
| 4987 __ mov(Operand(eax), Immediate(reinterpret_cast<int32_t>(failure))); | 4980 __ mov(eax, Immediate(reinterpret_cast<int32_t>(failure))); |
| 4988 } | 4981 } |
| 4989 GenerateCore(masm, &throw_normal_exception, | 4982 GenerateCore(masm, &throw_normal_exception, |
| 4990 &throw_out_of_memory_exception, | 4983 &throw_out_of_memory_exception, |
| 4991 frame_type, | 4984 frame_type, |
| 4992 FLAG_gc_greedy, | 4985 FLAG_gc_greedy, |
| 4993 false); | 4986 false); |
| 4994 | 4987 |
| 4995 // Do space-specific GC and retry runtime call. | 4988 // Do space-specific GC and retry runtime call. |
| 4996 GenerateCore(masm, | 4989 GenerateCore(masm, |
| 4997 &throw_normal_exception, | 4990 &throw_normal_exception, |
| 4998 &throw_out_of_memory_exception, | 4991 &throw_out_of_memory_exception, |
| 4999 frame_type, | 4992 frame_type, |
| 5000 true, | 4993 true, |
| 5001 false); | 4994 false); |
| 5002 | 4995 |
| 5003 // Do full GC and retry runtime call one final time. | 4996 // Do full GC and retry runtime call one final time. |
| 5004 Failure* failure = Failure::InternalError(); | 4997 Failure* failure = Failure::InternalError(); |
| 5005 __ mov(Operand(eax), Immediate(reinterpret_cast<int32_t>(failure))); | 4998 __ mov(eax, Immediate(reinterpret_cast<int32_t>(failure))); |
| 5006 GenerateCore(masm, | 4999 GenerateCore(masm, |
| 5007 &throw_normal_exception, | 5000 &throw_normal_exception, |
| 5008 &throw_out_of_memory_exception, | 5001 &throw_out_of_memory_exception, |
| 5009 frame_type, | 5002 frame_type, |
| 5010 true, | 5003 true, |
| 5011 true); | 5004 true); |
| 5012 | 5005 |
| 5013 __ bind(&throw_out_of_memory_exception); | 5006 __ bind(&throw_out_of_memory_exception); |
| 5014 GenerateThrowOutOfMemory(masm); | 5007 GenerateThrowOutOfMemory(masm); |
| 5015 // control flow for generated will not return. | 5008 // control flow for generated will not return. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 5039 ExternalReference c_entry_fp(Top::k_c_entry_fp_address); | 5032 ExternalReference c_entry_fp(Top::k_c_entry_fp_address); |
| 5040 __ push(Operand::StaticVariable(c_entry_fp)); | 5033 __ push(Operand::StaticVariable(c_entry_fp)); |
| 5041 | 5034 |
| 5042 // Call a faked try-block that does the invoke. | 5035 // Call a faked try-block that does the invoke. |
| 5043 __ call(&invoke); | 5036 __ call(&invoke); |
| 5044 | 5037 |
| 5045 // Caught exception: Store result (exception) in the pending | 5038 // Caught exception: Store result (exception) in the pending |
| 5046 // exception field in the JSEnv and return a failure sentinel. | 5039 // exception field in the JSEnv and return a failure sentinel. |
| 5047 ExternalReference pending_exception(Top::k_pending_exception_address); | 5040 ExternalReference pending_exception(Top::k_pending_exception_address); |
| 5048 __ mov(Operand::StaticVariable(pending_exception), eax); | 5041 __ mov(Operand::StaticVariable(pending_exception), eax); |
| 5049 __ mov(eax, Handle<Failure>(Failure::Exception())); | 5042 __ mov(eax, reinterpret_cast<int32_t>(Failure::Exception())); |
| 5050 __ jmp(&exit); | 5043 __ jmp(&exit); |
| 5051 | 5044 |
| 5052 // Invoke: Link this frame into the handler chain. | 5045 // Invoke: Link this frame into the handler chain. |
| 5053 __ bind(&invoke); | 5046 __ bind(&invoke); |
| 5054 __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER); | 5047 __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER); |
| 5055 __ push(eax); // flush TOS | 5048 __ push(eax); // flush TOS |
| 5056 | 5049 |
| 5057 // Clear any pending exceptions. | 5050 // Clear any pending exceptions. |
| 5058 __ mov(edx, | 5051 __ mov(edx, |
| 5059 Operand::StaticVariable(ExternalReference::the_hole_value_location())); | 5052 Operand::StaticVariable(ExternalReference::the_hole_value_location())); |
| 5060 __ mov(Operand::StaticVariable(pending_exception), edx); | 5053 __ mov(Operand::StaticVariable(pending_exception), edx); |
| 5061 | 5054 |
| 5062 // Fake a receiver (NULL). | 5055 // Fake a receiver (NULL). |
| 5063 __ push(Immediate(0)); // receiver | 5056 __ push(Immediate(0)); // receiver |
| 5064 | 5057 |
| 5065 // Invoke the function by calling through JS entry trampoline | 5058 // Invoke the function by calling through JS entry trampoline |
| 5066 // builtin and pop the faked function when we return. Notice that we | 5059 // builtin and pop the faked function when we return. Notice that we |
| 5067 // cannot store a reference to the trampoline code directly in this | 5060 // cannot store a reference to the trampoline code directly in this |
| 5068 // stub, because the builtin stubs may not have been generated yet. | 5061 // stub, because the builtin stubs may not have been generated yet. |
| 5069 if (is_construct) { | 5062 if (is_construct) { |
| 5070 ExternalReference construct_entry(Builtins::JSConstructEntryTrampoline); | 5063 ExternalReference construct_entry(Builtins::JSConstructEntryTrampoline); |
| 5071 __ mov(Operand(edx), Immediate(construct_entry)); | 5064 __ mov(edx, Immediate(construct_entry)); |
| 5072 } else { | 5065 } else { |
| 5073 ExternalReference entry(Builtins::JSEntryTrampoline); | 5066 ExternalReference entry(Builtins::JSEntryTrampoline); |
| 5074 __ mov(Operand(edx), Immediate(entry)); | 5067 __ mov(edx, Immediate(entry)); |
| 5075 } | 5068 } |
| 5076 __ mov(edx, Operand(edx, 0)); // deref address | 5069 __ mov(edx, Operand(edx, 0)); // deref address |
| 5077 __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); | 5070 __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); |
| 5078 __ call(Operand(edx)); | 5071 __ call(Operand(edx)); |
| 5079 | 5072 |
| 5080 // Unlink this frame from the handler chain. | 5073 // Unlink this frame from the handler chain. |
| 5081 __ pop(Operand::StaticVariable(ExternalReference(Top::k_handler_address))); | 5074 __ pop(Operand::StaticVariable(ExternalReference(Top::k_handler_address))); |
| 5082 // Pop next_sp. | 5075 // Pop next_sp. |
| 5083 __ add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize)); | 5076 __ add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize)); |
| 5084 | 5077 |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5149 | 5142 |
| 5150 // Slow-case: Go through the JavaScript implementation. | 5143 // Slow-case: Go through the JavaScript implementation. |
| 5151 __ bind(&slow); | 5144 __ bind(&slow); |
| 5152 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 5145 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 5153 } | 5146 } |
| 5154 | 5147 |
| 5155 | 5148 |
| 5156 #undef __ | 5149 #undef __ |
| 5157 | 5150 |
| 5158 } } // namespace v8::internal | 5151 } } // namespace v8::internal |
| OLD | NEW |