OLD | NEW |
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 23 matching lines...) Expand all Loading... |
34 #include "register-allocator-inl.h" | 34 #include "register-allocator-inl.h" |
35 #include "runtime.h" | 35 #include "runtime.h" |
36 #include "scopes.h" | 36 #include "scopes.h" |
37 | 37 |
38 | 38 |
39 namespace v8 { | 39 namespace v8 { |
40 namespace internal { | 40 namespace internal { |
41 | 41 |
42 #define __ ACCESS_MASM(masm_) | 42 #define __ ACCESS_MASM(masm_) |
43 | 43 |
| 44 static void EmitIdenticalObjectComparison(MacroAssembler* masm, |
| 45 Label* slow, |
| 46 Condition cc); |
| 47 static void EmitSmiNonsmiComparison(MacroAssembler* masm, |
| 48 Label* rhs_not_nan, |
| 49 Label* slow, |
| 50 bool strict); |
| 51 static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc); |
| 52 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm); |
| 53 |
| 54 |
| 55 |
44 // ------------------------------------------------------------------------- | 56 // ------------------------------------------------------------------------- |
45 // Platform-specific DeferredCode functions. | 57 // Platform-specific DeferredCode functions. |
46 | 58 |
47 void DeferredCode::SaveRegisters() { | 59 void DeferredCode::SaveRegisters() { |
48 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) { | 60 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) { |
49 int action = registers_[i]; | 61 int action = registers_[i]; |
50 if (action == kPush) { | 62 if (action == kPush) { |
51 __ push(RegisterAllocator::ToRegister(i)); | 63 __ push(RegisterAllocator::ToRegister(i)); |
52 } else if (action != kIgnore && (action & kSyncedFlag) == 0) { | 64 } else if (action != kIgnore && (action & kSyncedFlag) == 0) { |
53 __ str(RegisterAllocator::ToRegister(i), MemOperand(fp, action)); | 65 __ str(RegisterAllocator::ToRegister(i), MemOperand(fp, action)); |
(...skipping 941 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
995 frame_->EmitPush(r0); | 1007 frame_->EmitPush(r0); |
996 } | 1008 } |
997 GenericBinaryOperation(op, mode); | 1009 GenericBinaryOperation(op, mode); |
998 break; | 1010 break; |
999 } | 1011 } |
1000 | 1012 |
1001 exit.Bind(); | 1013 exit.Bind(); |
1002 } | 1014 } |
1003 | 1015 |
1004 | 1016 |
1005 void CodeGenerator::Comparison(Condition cc, bool strict) { | 1017 void CodeGenerator::Comparison(Condition cc, |
| 1018 Expression* left, |
| 1019 Expression* right, |
| 1020 bool strict) { |
| 1021 if (left != NULL) LoadAndSpill(left); |
| 1022 if (right != NULL) LoadAndSpill(right); |
| 1023 |
1006 VirtualFrame::SpilledScope spilled_scope; | 1024 VirtualFrame::SpilledScope spilled_scope; |
1007 // sp[0] : y | 1025 // sp[0] : y |
1008 // sp[1] : x | 1026 // sp[1] : x |
1009 // result : cc register | 1027 // result : cc register |
1010 | 1028 |
1011 // Strict only makes sense for equality comparisons. | 1029 // Strict only makes sense for equality comparisons. |
1012 ASSERT(!strict || cc == eq); | 1030 ASSERT(!strict || cc == eq); |
1013 | 1031 |
1014 JumpTarget exit; | 1032 JumpTarget exit; |
1015 JumpTarget smi; | 1033 JumpTarget smi; |
1016 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. | 1034 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. |
1017 if (cc == gt || cc == le) { | 1035 if (cc == gt || cc == le) { |
1018 cc = ReverseCondition(cc); | 1036 cc = ReverseCondition(cc); |
1019 frame_->EmitPop(r1); | 1037 frame_->EmitPop(r1); |
1020 frame_->EmitPop(r0); | 1038 frame_->EmitPop(r0); |
1021 } else { | 1039 } else { |
1022 frame_->EmitPop(r0); | 1040 frame_->EmitPop(r0); |
1023 frame_->EmitPop(r1); | 1041 frame_->EmitPop(r1); |
1024 } | 1042 } |
1025 __ orr(r2, r0, Operand(r1)); | 1043 __ orr(r2, r0, Operand(r1)); |
1026 __ tst(r2, Operand(kSmiTagMask)); | 1044 __ tst(r2, Operand(kSmiTagMask)); |
1027 smi.Branch(eq); | 1045 smi.Branch(eq); |
1028 | 1046 |
1029 // Perform non-smi comparison by runtime call. | 1047 // Perform non-smi comparison by stub. |
1030 frame_->EmitPush(r1); | 1048 // CompareStub takes arguments in r0 and r1, returns <0, >0 or 0 in r0. |
| 1049 // We call with 0 args because there are 0 on the stack. |
| 1050 CompareStub stub(cc, strict); |
| 1051 frame_->CallStub(&stub, 0); |
1031 | 1052 |
1032 // Figure out which native to call and setup the arguments. | 1053 Result result = allocator_->Allocate(r0); |
1033 Builtins::JavaScript native; | 1054 ASSERT(result.is_valid()); |
1034 int arg_count = 1; | |
1035 if (cc == eq) { | |
1036 native = strict ? Builtins::STRICT_EQUALS : Builtins::EQUALS; | |
1037 } else { | |
1038 native = Builtins::COMPARE; | |
1039 int ncr; // NaN compare result | |
1040 if (cc == lt || cc == le) { | |
1041 ncr = GREATER; | |
1042 } else { | |
1043 ASSERT(cc == gt || cc == ge); // remaining cases | |
1044 ncr = LESS; | |
1045 } | |
1046 frame_->EmitPush(r0); | |
1047 arg_count++; | |
1048 __ mov(r0, Operand(Smi::FromInt(ncr))); | |
1049 } | |
1050 | |
1051 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) | |
1052 // tagged as a small integer. | |
1053 frame_->EmitPush(r0); | |
1054 Result arg_count_register = allocator_->Allocate(r0); | |
1055 ASSERT(arg_count_register.is_valid()); | |
1056 __ mov(arg_count_register.reg(), Operand(arg_count)); | |
1057 Result result = frame_->InvokeBuiltin(native, | |
1058 CALL_JS, | |
1059 &arg_count_register, | |
1060 arg_count + 1); | |
1061 __ cmp(result.reg(), Operand(0)); | 1055 __ cmp(result.reg(), Operand(0)); |
1062 result.Unuse(); | 1056 result.Unuse(); |
1063 exit.Jump(); | 1057 exit.Jump(); |
1064 | 1058 |
1065 // test smi equality by pointer comparison. | 1059 // Do smi comparisons by pointer comparison. |
1066 smi.Bind(); | 1060 smi.Bind(); |
1067 __ cmp(r1, Operand(r0)); | 1061 __ cmp(r1, Operand(r0)); |
1068 | 1062 |
1069 exit.Bind(); | 1063 exit.Bind(); |
1070 cc_reg_ = cc; | 1064 cc_reg_ = cc; |
1071 } | 1065 } |
1072 | 1066 |
1073 | 1067 |
1074 class CallFunctionStub: public CodeStub { | 1068 class CallFunctionStub: public CodeStub { |
1075 public: | 1069 public: |
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1498 continue; | 1492 continue; |
1499 } | 1493 } |
1500 | 1494 |
1501 Comment cmnt(masm_, "[ Case clause"); | 1495 Comment cmnt(masm_, "[ Case clause"); |
1502 // Compile the test. | 1496 // Compile the test. |
1503 next_test.Bind(); | 1497 next_test.Bind(); |
1504 next_test.Unuse(); | 1498 next_test.Unuse(); |
1505 // Duplicate TOS. | 1499 // Duplicate TOS. |
1506 __ ldr(r0, frame_->Top()); | 1500 __ ldr(r0, frame_->Top()); |
1507 frame_->EmitPush(r0); | 1501 frame_->EmitPush(r0); |
1508 LoadAndSpill(clause->label()); | 1502 Comparison(eq, NULL, clause->label(), true); |
1509 Comparison(eq, true); | |
1510 Branch(false, &next_test); | 1503 Branch(false, &next_test); |
1511 | 1504 |
1512 // Before entering the body from the test, remove the switch value from | 1505 // Before entering the body from the test, remove the switch value from |
1513 // the stack. | 1506 // the stack. |
1514 frame_->Drop(); | 1507 frame_->Drop(); |
1515 | 1508 |
1516 // Label the body so that fall through is enabled. | 1509 // Label the body so that fall through is enabled. |
1517 if (i > 0 && cases->at(i - 1)->is_default()) { | 1510 if (i > 0 && cases->at(i - 1)->is_default()) { |
1518 default_exit.Bind(); | 1511 default_exit.Bind(); |
1519 } else { | 1512 } else { |
(...skipping 1968 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3488 frame_->EmitPop(r0); | 3481 frame_->EmitPop(r0); |
3489 switch (op) { | 3482 switch (op) { |
3490 case Token::NOT: | 3483 case Token::NOT: |
3491 case Token::DELETE: | 3484 case Token::DELETE: |
3492 case Token::TYPEOF: | 3485 case Token::TYPEOF: |
3493 UNREACHABLE(); // handled above | 3486 UNREACHABLE(); // handled above |
3494 break; | 3487 break; |
3495 | 3488 |
3496 case Token::SUB: { | 3489 case Token::SUB: { |
3497 bool overwrite = | 3490 bool overwrite = |
3498 (node->AsBinaryOperation() != NULL && | 3491 (node->expression()->AsBinaryOperation() != NULL && |
3499 node->AsBinaryOperation()->ResultOverwriteAllowed()); | 3492 node->expression()->AsBinaryOperation()->ResultOverwriteAllowed()); |
3500 UnarySubStub stub(overwrite); | 3493 UnarySubStub stub(overwrite); |
3501 frame_->CallStub(&stub, 0); | 3494 frame_->CallStub(&stub, 0); |
3502 break; | 3495 break; |
3503 } | 3496 } |
3504 | 3497 |
3505 case Token::BIT_NOT: { | 3498 case Token::BIT_NOT: { |
3506 // smi check | 3499 // smi check |
3507 JumpTarget smi_label; | 3500 JumpTarget smi_label; |
3508 JumpTarget continue_label; | 3501 JumpTarget continue_label; |
3509 __ tst(r0, Operand(kSmiTagMask)); | 3502 __ tst(r0, Operand(kSmiTagMask)); |
(...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3953 } else { | 3946 } else { |
3954 // Uncommon case: typeof testing against a string literal that is | 3947 // Uncommon case: typeof testing against a string literal that is |
3955 // never returned from the typeof operator. | 3948 // never returned from the typeof operator. |
3956 false_target()->Jump(); | 3949 false_target()->Jump(); |
3957 } | 3950 } |
3958 ASSERT(!has_valid_frame() || | 3951 ASSERT(!has_valid_frame() || |
3959 (has_cc() && frame_->height() == original_height)); | 3952 (has_cc() && frame_->height() == original_height)); |
3960 return; | 3953 return; |
3961 } | 3954 } |
3962 | 3955 |
3963 LoadAndSpill(left); | |
3964 LoadAndSpill(right); | |
3965 switch (op) { | 3956 switch (op) { |
3966 case Token::EQ: | 3957 case Token::EQ: |
3967 Comparison(eq, false); | 3958 Comparison(eq, left, right, false); |
3968 break; | 3959 break; |
3969 | 3960 |
3970 case Token::LT: | 3961 case Token::LT: |
3971 Comparison(lt); | 3962 Comparison(lt, left, right); |
3972 break; | 3963 break; |
3973 | 3964 |
3974 case Token::GT: | 3965 case Token::GT: |
3975 Comparison(gt); | 3966 Comparison(gt, left, right); |
3976 break; | 3967 break; |
3977 | 3968 |
3978 case Token::LTE: | 3969 case Token::LTE: |
3979 Comparison(le); | 3970 Comparison(le, left, right); |
3980 break; | 3971 break; |
3981 | 3972 |
3982 case Token::GTE: | 3973 case Token::GTE: |
3983 Comparison(ge); | 3974 Comparison(ge, left, right); |
3984 break; | 3975 break; |
3985 | 3976 |
3986 case Token::EQ_STRICT: | 3977 case Token::EQ_STRICT: |
3987 Comparison(eq, true); | 3978 Comparison(eq, left, right, true); |
3988 break; | 3979 break; |
3989 | 3980 |
3990 case Token::IN: { | 3981 case Token::IN: { |
| 3982 LoadAndSpill(left); |
| 3983 LoadAndSpill(right); |
3991 Result arg_count = allocator_->Allocate(r0); | 3984 Result arg_count = allocator_->Allocate(r0); |
3992 ASSERT(arg_count.is_valid()); | 3985 ASSERT(arg_count.is_valid()); |
3993 __ mov(arg_count.reg(), Operand(1)); // not counting receiver | 3986 __ mov(arg_count.reg(), Operand(1)); // not counting receiver |
3994 Result result = frame_->InvokeBuiltin(Builtins::IN, | 3987 Result result = frame_->InvokeBuiltin(Builtins::IN, |
3995 CALL_JS, | 3988 CALL_JS, |
3996 &arg_count, | 3989 &arg_count, |
3997 2); | 3990 2); |
3998 frame_->EmitPush(result.reg()); | 3991 frame_->EmitPush(result.reg()); |
3999 break; | 3992 break; |
4000 } | 3993 } |
4001 | 3994 |
4002 case Token::INSTANCEOF: { | 3995 case Token::INSTANCEOF: { |
| 3996 LoadAndSpill(left); |
| 3997 LoadAndSpill(right); |
4003 InstanceofStub stub; | 3998 InstanceofStub stub; |
4004 Result result = frame_->CallStub(&stub, 2); | 3999 Result result = frame_->CallStub(&stub, 2); |
4005 // At this point if instanceof succeeded then r0 == 0. | 4000 // At this point if instanceof succeeded then r0 == 0. |
4006 __ tst(result.reg(), Operand(result.reg())); | 4001 __ tst(result.reg(), Operand(result.reg())); |
4007 cc_reg_ = eq; | 4002 cc_reg_ = eq; |
4008 break; | 4003 break; |
4009 } | 4004 } |
4010 | 4005 |
4011 default: | 4006 default: |
4012 UNREACHABLE(); | 4007 UNREACHABLE(); |
(...skipping 462 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4475 // significant 1 bit is not stored. | 4470 // significant 1 bit is not stored. |
4476 non_smi_exponent += 1 << HeapNumber::kExponentShift; | 4471 non_smi_exponent += 1 << HeapNumber::kExponentShift; |
4477 __ mov(ip, Operand(HeapNumber::kSignMask | non_smi_exponent)); | 4472 __ mov(ip, Operand(HeapNumber::kSignMask | non_smi_exponent)); |
4478 __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kExponentOffset)); | 4473 __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kExponentOffset)); |
4479 __ mov(ip, Operand(0)); | 4474 __ mov(ip, Operand(0)); |
4480 __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kMantissaOffset)); | 4475 __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kMantissaOffset)); |
4481 __ Ret(); | 4476 __ Ret(); |
4482 } | 4477 } |
4483 | 4478 |
4484 | 4479 |
| 4480 // Handle the case where the lhs and rhs are the same object. |
| 4481 // Equality is almost reflexive (everything but NaN), so this is a test |
| 4482 // for "identity and not NaN". |
| 4483 static void EmitIdenticalObjectComparison(MacroAssembler* masm, |
| 4484 Label* slow, |
| 4485 Condition cc) { |
| 4486 Label not_identical; |
| 4487 __ cmp(r0, Operand(r1)); |
| 4488 __ b(ne, ¬_identical); |
| 4489 |
| 4490 Register exp_mask_reg = r5; |
| 4491 __ mov(exp_mask_reg, Operand(HeapNumber::kExponentMask)); |
| 4492 |
| 4493 // Test for NaN. Sadly, we can't just compare to Factory::nan_value(), |
| 4494 // so we do the second best thing - test it ourselves. |
| 4495 Label heap_number, return_equal; |
| 4496 // They are both equal and they are not both Smis so both of them are not |
| 4497 // Smis. If it's not a heap number, then return equal. |
| 4498 if (cc == lt || cc == gt) { |
| 4499 __ CompareObjectType(r0, r4, r4, FIRST_JS_OBJECT_TYPE); |
| 4500 __ b(ge, slow); |
| 4501 } else { |
| 4502 __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE); |
| 4503 __ b(eq, &heap_number); |
| 4504 // Comparing JS objects with <=, >= is complicated. |
| 4505 if (cc != eq) { |
| 4506 __ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE)); |
| 4507 __ b(ge, slow); |
| 4508 } |
| 4509 } |
| 4510 __ bind(&return_equal); |
| 4511 if (cc == lt) { |
| 4512 __ mov(r0, Operand(GREATER)); // Things aren't less than themselves. |
| 4513 } else if (cc == gt) { |
| 4514 __ mov(r0, Operand(LESS)); // Things aren't greater than themselves. |
| 4515 } else { |
| 4516 __ mov(r0, Operand(0)); // Things are <=, >=, ==, === themselves. |
| 4517 } |
| 4518 __ mov(pc, Operand(lr)); // Return. |
| 4519 |
| 4520 // For less and greater we don't have to check for NaN since the result of |
| 4521 // x < x is false regardless. For the others here is some code to check |
| 4522 // for NaN. |
| 4523 if (cc != lt && cc != gt) { |
| 4524 __ bind(&heap_number); |
| 4525 // It is a heap number, so return non-equal if it's NaN and equal if it's |
| 4526 // not NaN. |
| 4527 // The representation of NaN values has all exponent bits (52..62) set, |
| 4528 // and not all mantissa bits (0..51) clear. |
| 4529 // Read top bits of double representation (second word of value). |
| 4530 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); |
| 4531 // Test that exponent bits are all set. |
| 4532 __ and_(r3, r2, Operand(exp_mask_reg)); |
| 4533 __ cmp(r3, Operand(exp_mask_reg)); |
| 4534 __ b(ne, &return_equal); |
| 4535 |
| 4536 // Shift out flag and all exponent bits, retaining only mantissa. |
| 4537 __ mov(r2, Operand(r2, LSL, HeapNumber::kNonMantissaBitsInTopWord)); |
| 4538 // Or with all low-bits of mantissa. |
| 4539 __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); |
| 4540 __ orr(r0, r3, Operand(r2), SetCC); |
| 4541 // For equal we already have the right value in r0: Return zero (equal) |
| 4542 // if all bits in mantissa are zero (it's an Infinity) and non-zero if not |
| 4543 // (it's a NaN). For <= and >= we need to load r0 with the failing value |
| 4544 // if it's a NaN. |
| 4545 if (cc != eq) { |
| 4546 // All-zero means Infinity means equal. |
| 4547 __ mov(pc, Operand(lr), LeaveCC, eq); // Return equal |
| 4548 if (cc == le) { |
| 4549 __ mov(r0, Operand(GREATER)); // NaN <= NaN should fail. |
| 4550 } else { |
| 4551 __ mov(r0, Operand(LESS)); // NaN >= NaN should fail. |
| 4552 } |
| 4553 } |
| 4554 __ mov(pc, Operand(lr)); // Return. |
| 4555 } |
| 4556 // No fall through here. |
| 4557 |
| 4558 __ bind(¬_identical); |
| 4559 } |
| 4560 |
| 4561 |
| 4562 // See comment at call site. |
| 4563 static void EmitSmiNonsmiComparison(MacroAssembler* masm, |
| 4564 Label* rhs_not_nan, |
| 4565 Label* slow, |
| 4566 bool strict) { |
| 4567 Label lhs_is_smi; |
| 4568 __ tst(r0, Operand(kSmiTagMask)); |
| 4569 __ b(eq, &lhs_is_smi); |
| 4570 |
| 4571 // Rhs is a Smi. Check whether the non-smi is a heap number. |
| 4572 __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE); |
| 4573 if (strict) { |
| 4574 // If lhs was not a number and rhs was a Smi then strict equality cannot |
| 4575 // succeed. Return non-equal (r0 is already not zero) |
| 4576 __ mov(pc, Operand(lr), LeaveCC, ne); // Return. |
| 4577 } else { |
| 4578 // Smi compared non-strictly with a non-Smi non-heap-number. Call |
| 4579 // the runtime. |
| 4580 __ b(ne, slow); |
| 4581 } |
| 4582 |
| 4583 // Rhs is a smi, lhs is a number. |
| 4584 __ push(lr); |
| 4585 __ mov(r7, Operand(r1)); |
| 4586 ConvertToDoubleStub stub1(r3, r2, r7, r6); |
| 4587 __ Call(stub1.GetCode(), RelocInfo::CODE_TARGET); |
| 4588 // r3 and r2 are rhs as double. |
| 4589 __ ldr(r1, FieldMemOperand(r0, HeapNumber::kValueOffset + kPointerSize)); |
| 4590 __ ldr(r0, FieldMemOperand(r0, HeapNumber::kValueOffset)); |
| 4591 // We now have both loaded as doubles but we can skip the lhs nan check |
| 4592 // since it's a Smi. |
| 4593 __ pop(lr); |
| 4594 __ jmp(rhs_not_nan); |
| 4595 |
| 4596 __ bind(&lhs_is_smi); |
| 4597 // Lhs is a Smi. Check whether the non-smi is a heap number. |
| 4598 __ CompareObjectType(r1, r4, r4, HEAP_NUMBER_TYPE); |
| 4599 if (strict) { |
| 4600 // If lhs was not a number and rhs was a Smi then strict equality cannot |
| 4601 // succeed. Return non-equal. |
| 4602 __ mov(r0, Operand(1), LeaveCC, ne); // Non-zero indicates not equal. |
| 4603 __ mov(pc, Operand(lr), LeaveCC, ne); // Return. |
| 4604 } else { |
| 4605 // Smi compared non-strictly with a non-Smi non-heap-number. Call |
| 4606 // the runtime. |
| 4607 __ b(ne, slow); |
| 4608 } |
| 4609 |
| 4610 // Lhs is a smi, rhs is a number. |
| 4611 // r0 is Smi and r1 is heap number. |
| 4612 __ push(lr); |
| 4613 __ ldr(r2, FieldMemOperand(r1, HeapNumber::kValueOffset)); |
| 4614 __ ldr(r3, FieldMemOperand(r1, HeapNumber::kValueOffset + kPointerSize)); |
| 4615 __ mov(r7, Operand(r0)); |
| 4616 ConvertToDoubleStub stub2(r1, r0, r7, r6); |
| 4617 __ Call(stub2.GetCode(), RelocInfo::CODE_TARGET); |
| 4618 __ pop(lr); |
| 4619 // Fall through to both_loaded_as_doubles. |
| 4620 } |
| 4621 |
| 4622 |
| 4623 void EmitNanCheck(MacroAssembler* masm, Label* rhs_not_nan, Condition cc) { |
| 4624 bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset); |
| 4625 Register lhs_exponent = exp_first ? r0 : r1; |
| 4626 Register rhs_exponent = exp_first ? r2 : r3; |
| 4627 Register lhs_mantissa = exp_first ? r1 : r0; |
| 4628 Register rhs_mantissa = exp_first ? r3 : r2; |
| 4629 Label one_is_nan, neither_is_nan; |
| 4630 |
| 4631 Register exp_mask_reg = r5; |
| 4632 |
| 4633 __ mov(exp_mask_reg, Operand(HeapNumber::kExponentMask)); |
| 4634 __ and_(r4, rhs_exponent, Operand(exp_mask_reg)); |
| 4635 __ cmp(r4, Operand(exp_mask_reg)); |
| 4636 __ b(ne, rhs_not_nan); |
| 4637 __ mov(r4, |
| 4638 Operand(rhs_exponent, LSL, HeapNumber::kNonMantissaBitsInTopWord), |
| 4639 SetCC); |
| 4640 __ b(ne, &one_is_nan); |
| 4641 __ cmp(rhs_mantissa, Operand(0)); |
| 4642 __ b(ne, &one_is_nan); |
| 4643 |
| 4644 __ bind(rhs_not_nan); |
| 4645 __ mov(exp_mask_reg, Operand(HeapNumber::kExponentMask)); |
| 4646 __ and_(r4, lhs_exponent, Operand(exp_mask_reg)); |
| 4647 __ cmp(r4, Operand(exp_mask_reg)); |
| 4648 __ b(ne, &neither_is_nan); |
| 4649 __ mov(r4, |
| 4650 Operand(lhs_exponent, LSL, HeapNumber::kNonMantissaBitsInTopWord), |
| 4651 SetCC); |
| 4652 __ b(ne, &one_is_nan); |
| 4653 __ cmp(lhs_mantissa, Operand(0)); |
| 4654 __ b(eq, &neither_is_nan); |
| 4655 |
| 4656 __ bind(&one_is_nan); |
| 4657 // NaN comparisons always fail. |
| 4658 // Load whatever we need in r0 to make the comparison fail. |
| 4659 if (cc == lt || cc == le) { |
| 4660 __ mov(r0, Operand(GREATER)); |
| 4661 } else { |
| 4662 __ mov(r0, Operand(LESS)); |
| 4663 } |
| 4664 __ mov(pc, Operand(lr)); // Return. |
| 4665 |
| 4666 __ bind(&neither_is_nan); |
| 4667 } |
| 4668 |
| 4669 |
| 4670 // See comment at call site. |
| 4671 static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc) { |
| 4672 bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset); |
| 4673 Register lhs_exponent = exp_first ? r0 : r1; |
| 4674 Register rhs_exponent = exp_first ? r2 : r3; |
| 4675 Register lhs_mantissa = exp_first ? r1 : r0; |
| 4676 Register rhs_mantissa = exp_first ? r3 : r2; |
| 4677 |
| 4678 // r0, r1, r2, r3 have the two doubles. Neither is a NaN. |
| 4679 if (cc == eq) { |
| 4680 // Doubles are not equal unless they have the same bit pattern. |
| 4681 // Exception: 0 and -0. |
| 4682 __ cmp(lhs_mantissa, Operand(rhs_mantissa)); |
| 4683 __ orr(r0, lhs_mantissa, Operand(rhs_mantissa), LeaveCC, ne); |
| 4684 // Return non-zero if the numbers are unequal. |
| 4685 __ mov(pc, Operand(lr), LeaveCC, ne); |
| 4686 |
| 4687 __ sub(r0, lhs_exponent, Operand(rhs_exponent), SetCC); |
| 4688 // If exponents are equal then return 0. |
| 4689 __ mov(pc, Operand(lr), LeaveCC, eq); |
| 4690 |
| 4691 // Exponents are unequal. The only way we can return that the numbers |
| 4692 // are equal is if one is -0 and the other is 0. We already dealt |
| 4693 // with the case where both are -0 or both are 0. |
| 4694 // We start by seeing if the mantissas (that are equal) or the bottom |
| 4695 // 31 bits of the rhs exponent are non-zero. If so we return not |
| 4696 // equal. |
| 4697 __ orr(r4, rhs_mantissa, Operand(rhs_exponent, LSL, kSmiTagSize), SetCC); |
| 4698 __ mov(r0, Operand(r4), LeaveCC, ne); |
| 4699 __ mov(pc, Operand(lr), LeaveCC, ne); // Return conditionally. |
| 4700 // Now they are equal if and only if the lhs exponent is zero in its |
| 4701 // low 31 bits. |
| 4702 __ mov(r0, Operand(lhs_exponent, LSL, kSmiTagSize)); |
| 4703 __ mov(pc, Operand(lr)); |
| 4704 } else { |
| 4705 // Call a native function to do a comparison between two non-NaNs. |
| 4706 // Call C routine that may not cause GC or other trouble. |
| 4707 __ mov(r5, Operand(ExternalReference::compare_doubles())); |
| 4708 __ Jump(r5); // Tail call. |
| 4709 } |
| 4710 } |
| 4711 |
| 4712 |
| 4713 // See comment at call site. |
| 4714 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm) { |
| 4715 // If either operand is a JSObject or an oddball value, then they are |
| 4716 // not equal since their pointers are different. |
| 4717 // There is no test for undetectability in strict equality. |
| 4718 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
| 4719 Label first_non_object; |
| 4720 // Get the type of the first operand into r2 and compare it with |
| 4721 // FIRST_JS_OBJECT_TYPE. |
| 4722 __ CompareObjectType(r0, r2, r2, FIRST_JS_OBJECT_TYPE); |
| 4723 __ b(lt, &first_non_object); |
| 4724 |
| 4725 // Return non-zero (r0 is not zero) |
| 4726 Label return_not_equal; |
| 4727 __ bind(&return_not_equal); |
| 4728 __ mov(pc, Operand(lr)); // Return. |
| 4729 |
| 4730 __ bind(&first_non_object); |
| 4731 // Check for oddballs: true, false, null, undefined. |
| 4732 __ cmp(r2, Operand(ODDBALL_TYPE)); |
| 4733 __ b(eq, &return_not_equal); |
| 4734 |
| 4735 __ CompareObjectType(r1, r3, r3, FIRST_JS_OBJECT_TYPE); |
| 4736 __ b(ge, &return_not_equal); |
| 4737 |
| 4738 // Check for oddballs: true, false, null, undefined. |
| 4739 __ cmp(r3, Operand(ODDBALL_TYPE)); |
| 4740 __ b(eq, &return_not_equal); |
| 4741 } |
| 4742 |
| 4743 |
| 4744 // See comment at call site. |
| 4745 static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm, |
| 4746 Label* both_loaded_as_doubles, |
| 4747 Label* not_heap_numbers, |
| 4748 Label* slow) { |
| 4749 __ CompareObjectType(r0, r2, r2, HEAP_NUMBER_TYPE); |
| 4750 __ b(ne, not_heap_numbers); |
| 4751 __ CompareObjectType(r1, r3, r3, HEAP_NUMBER_TYPE); |
| 4752 __ b(ne, slow); // First was a heap number, second wasn't. Go slow case. |
| 4753 |
| 4754 // Both are heap numbers. Load them up then jump to the code we have |
| 4755 // for that. |
| 4756 __ ldr(r2, FieldMemOperand(r1, HeapNumber::kValueOffset)); |
| 4757 __ ldr(r3, FieldMemOperand(r1, HeapNumber::kValueOffset + kPointerSize)); |
| 4758 __ ldr(r1, FieldMemOperand(r0, HeapNumber::kValueOffset + kPointerSize)); |
| 4759 __ ldr(r0, FieldMemOperand(r0, HeapNumber::kValueOffset)); |
| 4760 __ jmp(both_loaded_as_doubles); |
| 4761 } |
| 4762 |
| 4763 |
| 4764 // Fast negative check for symbol-to-symbol equality. |
| 4765 static void EmitCheckForSymbols(MacroAssembler* masm, Label* slow) { |
| 4766 // r2 is object type of r0. |
| 4767 __ tst(r2, Operand(kIsNotStringMask)); |
| 4768 __ b(ne, slow); |
| 4769 __ tst(r2, Operand(kIsSymbolMask)); |
| 4770 __ b(eq, slow); |
| 4771 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE); |
| 4772 __ b(ge, slow); |
| 4773 __ tst(r3, Operand(kIsSymbolMask)); |
| 4774 __ b(eq, slow); |
| 4775 |
| 4776 // Both are symbols. We already checked they weren't the same pointer |
| 4777 // so they are not equal. |
| 4778 __ mov(r0, Operand(1)); // Non-zero indicates not equal. |
| 4779 __ mov(pc, Operand(lr)); // Return. |
| 4780 } |
| 4781 |
| 4782 |
| 4783 // On entry r0 and r1 are the things to be compared. On exit r0 is 0, |
| 4784 // positive or negative to indicate the result of the comparison. |
| 4785 void CompareStub::Generate(MacroAssembler* masm) { |
| 4786 Label slow; // Call builtin. |
| 4787 Label not_smis, both_loaded_as_doubles, rhs_not_nan; |
| 4788 |
| 4789 // NOTICE! This code is only reached after a smi-fast-case check, so |
| 4790 // it is certain that at least one operand isn't a smi. |
| 4791 |
| 4792 // Handle the case where the objects are identical. Either returns the answer |
| 4793 // or goes to slow. Only falls through if the objects were not identical. |
| 4794 EmitIdenticalObjectComparison(masm, &slow, cc_); |
| 4795 |
| 4796 // If either is a Smi (we know that not both are), then they can only |
| 4797 // be strictly equal if the other is a HeapNumber. |
| 4798 ASSERT_EQ(0, kSmiTag); |
| 4799 ASSERT_EQ(0, Smi::FromInt(0)); |
| 4800 __ and_(r2, r0, Operand(r1)); |
| 4801 __ tst(r2, Operand(kSmiTagMask)); |
| 4802 __ b(ne, ¬_smis); |
| 4803 // One operand is a smi. EmitSmiNonsmiComparison generates code that can: |
| 4804 // 1) Return the answer. |
| 4805 // 2) Go to slow. |
| 4806 // 3) Fall through to both_loaded_as_doubles. |
| 4807 // 4) Jump to rhs_not_nan. |
| 4808 // In cases 3 and 4 we have found out we were dealing with a number-number |
| 4809 // comparison and the numbers have been loaded into r0, r1, r2, r3 as doubles. |
| 4810 EmitSmiNonsmiComparison(masm, &rhs_not_nan, &slow, strict_); |
| 4811 |
| 4812 __ bind(&both_loaded_as_doubles); |
| 4813 // r0, r1, r2, r3 are the double representations of the left hand side |
| 4814 // and the right hand side. |
| 4815 |
| 4816 // Checks for NaN in the doubles we have loaded. Can return the answer or |
| 4817 // fall through if neither is a NaN. Also binds rhs_not_nan. |
| 4818 EmitNanCheck(masm, &rhs_not_nan, cc_); |
| 4819 |
| 4820 // Compares two doubles in r0, r1, r2, r3 that are not NaNs. Returns the |
| 4821 // answer. Never falls through. |
| 4822 EmitTwoNonNanDoubleComparison(masm, cc_); |
| 4823 |
| 4824 __ bind(¬_smis); |
| 4825 // At this point we know we are dealing with two different objects, |
| 4826 // and neither of them is a Smi. The objects are in r0 and r1. |
| 4827 if (strict_) { |
| 4828 // This returns non-equal for some object types, or falls through if it |
| 4829 // was not lucky. |
| 4830 EmitStrictTwoHeapObjectCompare(masm); |
| 4831 } |
| 4832 |
| 4833 Label check_for_symbols; |
| 4834 // Check for heap-number-heap-number comparison. Can jump to slow case, |
| 4835 // or load both doubles into r0, r1, r2, r3 and jump to the code that handles |
| 4836 // that case. If the inputs are not doubles then jumps to check_for_symbols. |
| 4837 // In this case r2 will contain the type of r0. |
| 4838 EmitCheckForTwoHeapNumbers(masm, |
| 4839 &both_loaded_as_doubles, |
| 4840 &check_for_symbols, |
| 4841 &slow); |
| 4842 |
| 4843 __ bind(&check_for_symbols); |
| 4844 if (cc_ == eq) { |
| 4845 // Either jumps to slow or returns the answer. Assumes that r2 is the type |
| 4846 // of r0 on entry. |
| 4847 EmitCheckForSymbols(masm, &slow); |
| 4848 } |
| 4849 |
| 4850 __ bind(&slow); |
| 4851 __ push(lr); |
| 4852 __ push(r1); |
| 4853 __ push(r0); |
| 4854 // Figure out which native to call and setup the arguments. |
| 4855 Builtins::JavaScript native; |
| 4856 int arg_count = 1; // Not counting receiver. |
| 4857 if (cc_ == eq) { |
| 4858 native = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS; |
| 4859 } else { |
| 4860 native = Builtins::COMPARE; |
| 4861 int ncr; // NaN compare result |
| 4862 if (cc_ == lt || cc_ == le) { |
| 4863 ncr = GREATER; |
| 4864 } else { |
| 4865 ASSERT(cc_ == gt || cc_ == ge); // remaining cases |
| 4866 ncr = LESS; |
| 4867 } |
| 4868 arg_count++; |
| 4869 __ mov(r0, Operand(Smi::FromInt(ncr))); |
| 4870 __ push(r0); |
| 4871 } |
| 4872 |
| 4873 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) |
| 4874 // tagged as a small integer. |
| 4875 __ mov(r0, Operand(arg_count)); |
| 4876 __ InvokeBuiltin(native, CALL_JS); |
| 4877 __ cmp(r0, Operand(0)); |
| 4878 __ pop(pc); |
| 4879 } |
| 4880 |
| 4881 |
4485 // Allocates a heap number or jumps to the label if the young space is full and | 4882 // Allocates a heap number or jumps to the label if the young space is full and |
4486 // a scavenge is needed. | 4883 // a scavenge is needed. |
4487 static void AllocateHeapNumber( | 4884 static void AllocateHeapNumber( |
4488 MacroAssembler* masm, | 4885 MacroAssembler* masm, |
4489 Label* need_gc, // Jump here if young space is full. | 4886 Label* need_gc, // Jump here if young space is full. |
4490 Register result_reg, // The tagged address of the new heap number. | 4887 Register result_reg, // The tagged address of the new heap number. |
4491 Register allocation_top_addr_reg, // A scratch register. | 4888 Register allocation_top_addr_reg, // A scratch register. |
4492 Register scratch2) { // Another scratch register. | 4889 Register scratch2) { // Another scratch register. |
4493 ExternalReference allocation_top = | 4890 ExternalReference allocation_top = |
4494 ExternalReference::new_space_allocation_top_address(); | 4891 ExternalReference::new_space_allocation_top_address(); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4531 const Builtins::JavaScript& builtin, | 4928 const Builtins::JavaScript& builtin, |
4532 Token::Value operation, | 4929 Token::Value operation, |
4533 OverwriteMode mode) { | 4930 OverwriteMode mode) { |
4534 Label slow, slow_pop_2_first, do_the_call; | 4931 Label slow, slow_pop_2_first, do_the_call; |
4535 Label r0_is_smi, r1_is_smi, finished_loading_r0, finished_loading_r1; | 4932 Label r0_is_smi, r1_is_smi, finished_loading_r0, finished_loading_r1; |
4536 // Smi-smi case (overflow). | 4933 // Smi-smi case (overflow). |
4537 // Since both are Smis there is no heap number to overwrite, so allocate. | 4934 // Since both are Smis there is no heap number to overwrite, so allocate. |
4538 // The new heap number is in r5. r6 and r7 are scratch. | 4935 // The new heap number is in r5. r6 and r7 are scratch. |
4539 AllocateHeapNumber(masm, &slow, r5, r6, r7); | 4936 AllocateHeapNumber(masm, &slow, r5, r6, r7); |
4540 // Write Smi from r0 to r3 and r2 in double format. r6 is scratch. | 4937 // Write Smi from r0 to r3 and r2 in double format. r6 is scratch. |
4541 ConvertToDoubleStub stub1(r3, r2, r0, r6); | 4938 __ mov(r7, Operand(r0)); |
| 4939 ConvertToDoubleStub stub1(r3, r2, r7, r6); |
4542 __ push(lr); | 4940 __ push(lr); |
4543 __ Call(stub1.GetCode(), RelocInfo::CODE_TARGET); | 4941 __ Call(stub1.GetCode(), RelocInfo::CODE_TARGET); |
4544 // Write Smi from r1 to r1 and r0 in double format. r6 is scratch. | 4942 // Write Smi from r1 to r1 and r0 in double format. r6 is scratch. |
4545 __ mov(r7, Operand(r1)); | 4943 __ mov(r7, Operand(r1)); |
4546 ConvertToDoubleStub stub2(r1, r0, r7, r6); | 4944 ConvertToDoubleStub stub2(r1, r0, r7, r6); |
4547 __ Call(stub2.GetCode(), RelocInfo::CODE_TARGET); | 4945 __ Call(stub2.GetCode(), RelocInfo::CODE_TARGET); |
4548 __ pop(lr); | 4946 __ pop(lr); |
4549 __ jmp(&do_the_call); // Tail call. No return. | 4947 __ jmp(&do_the_call); // Tail call. No return. |
4550 | 4948 |
4551 // We jump to here if something goes wrong (one param is not a number of any | 4949 // We jump to here if something goes wrong (one param is not a number of any |
(...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5008 __ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1); | 5406 __ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1); |
5009 __ bind(&within_limit); | 5407 __ bind(&within_limit); |
5010 | 5408 |
5011 __ StubReturn(1); | 5409 __ StubReturn(1); |
5012 } | 5410 } |
5013 | 5411 |
5014 | 5412 |
5015 void UnarySubStub::Generate(MacroAssembler* masm) { | 5413 void UnarySubStub::Generate(MacroAssembler* masm) { |
5016 Label undo; | 5414 Label undo; |
5017 Label slow; | 5415 Label slow; |
5018 Label done; | |
5019 Label not_smi; | 5416 Label not_smi; |
5020 | 5417 |
5021 // Enter runtime system if the value is not a smi. | 5418 // Enter runtime system if the value is not a smi. |
5022 __ tst(r0, Operand(kSmiTagMask)); | 5419 __ tst(r0, Operand(kSmiTagMask)); |
5023 __ b(ne, ¬_smi); | 5420 __ b(ne, ¬_smi); |
5024 | 5421 |
5025 // Enter runtime system if the value of the expression is zero | 5422 // Enter runtime system if the value of the expression is zero |
5026 // to make sure that we switch between 0 and -0. | 5423 // to make sure that we switch between 0 and -0. |
5027 __ cmp(r0, Operand(0)); | 5424 __ cmp(r0, Operand(0)); |
5028 __ b(eq, &slow); | 5425 __ b(eq, &slow); |
5029 | 5426 |
5030 // The value of the expression is a smi that is not zero. Try | 5427 // The value of the expression is a smi that is not zero. Try |
5031 // optimistic subtraction '0 - value'. | 5428 // optimistic subtraction '0 - value'. |
5032 __ rsb(r1, r0, Operand(0), SetCC); | 5429 __ rsb(r1, r0, Operand(0), SetCC); |
5033 __ b(vs, &slow); | 5430 __ b(vs, &slow); |
5034 | 5431 |
5035 __ mov(r0, Operand(r1)); // Set r0 to result. | 5432 __ mov(r0, Operand(r1)); // Set r0 to result. |
5036 __ StubReturn(1); | 5433 __ StubReturn(1); |
5037 | 5434 |
5038 // Enter runtime system. | 5435 // Enter runtime system. |
5039 __ bind(&slow); | 5436 __ bind(&slow); |
5040 __ push(r0); | 5437 __ push(r0); |
5041 __ mov(r0, Operand(0)); // Set number of arguments. | 5438 __ mov(r0, Operand(0)); // Set number of arguments. |
5042 __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_JS); | 5439 __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_JS); |
5043 | 5440 |
5044 __ bind(&done); | |
5045 __ StubReturn(1); | |
5046 | |
5047 __ bind(¬_smi); | 5441 __ bind(¬_smi); |
5048 __ CompareObjectType(r0, r1, r1, HEAP_NUMBER_TYPE); | 5442 __ CompareObjectType(r0, r1, r1, HEAP_NUMBER_TYPE); |
5049 __ b(ne, &slow); | 5443 __ b(ne, &slow); |
5050 // r0 is a heap number. Get a new heap number in r1. | 5444 // r0 is a heap number. Get a new heap number in r1. |
5051 if (overwrite_) { | 5445 if (overwrite_) { |
5052 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); | 5446 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); |
5053 __ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign. | 5447 __ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign. |
5054 __ str(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); | 5448 __ str(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); |
5055 } else { | 5449 } else { |
5056 AllocateHeapNumber(masm, &slow, r1, r2, r3); | 5450 AllocateHeapNumber(masm, &slow, r1, r2, r3); |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5196 __ mov(r0, Operand(r4)); | 5590 __ mov(r0, Operand(r4)); |
5197 __ mov(r1, Operand(r6)); | 5591 __ mov(r1, Operand(r6)); |
5198 | 5592 |
5199 // TODO(1242173): To let the GC traverse the return address of the exit | 5593 // TODO(1242173): To let the GC traverse the return address of the exit |
5200 // frames, we need to know where the return address is. Right now, | 5594 // frames, we need to know where the return address is. Right now, |
5201 // we push it on the stack to be able to find it again, but we never | 5595 // we push it on the stack to be able to find it again, but we never |
5202 // restore from it in case of changes, which makes it impossible to | 5596 // restore from it in case of changes, which makes it impossible to |
5203 // support moving the C entry code stub. This should be fixed, but currently | 5597 // support moving the C entry code stub. This should be fixed, but currently |
5204 // this is OK because the CEntryStub gets generated so early in the V8 boot | 5598 // this is OK because the CEntryStub gets generated so early in the V8 boot |
5205 // sequence that it is not moving ever. | 5599 // sequence that it is not moving ever. |
5206 __ add(lr, pc, Operand(4)); // compute return address: (pc + 8) + 4 | 5600 masm->add(lr, pc, Operand(4)); // compute return address: (pc + 8) + 4 |
5207 __ push(lr); | 5601 masm->push(lr); |
5208 __ Jump(r5); | 5602 masm->Jump(r5); |
5209 | 5603 |
5210 if (always_allocate) { | 5604 if (always_allocate) { |
5211 // It's okay to clobber r2 and r3 here. Don't mess with r0 and r1 | 5605 // It's okay to clobber r2 and r3 here. Don't mess with r0 and r1 |
5212 // though (contain the result). | 5606 // though (contain the result). |
5213 __ mov(r2, Operand(scope_depth)); | 5607 __ mov(r2, Operand(scope_depth)); |
5214 __ ldr(r3, MemOperand(r2)); | 5608 __ ldr(r3, MemOperand(r2)); |
5215 __ sub(r3, r3, Operand(1)); | 5609 __ sub(r3, r3, Operand(1)); |
5216 __ str(r3, MemOperand(r2)); | 5610 __ str(r3, MemOperand(r2)); |
5217 } | 5611 } |
5218 | 5612 |
(...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5622 // Slow-case: Non-function called. | 6016 // Slow-case: Non-function called. |
5623 __ bind(&slow); | 6017 __ bind(&slow); |
5624 __ mov(r0, Operand(argc_)); // Setup the number of arguments. | 6018 __ mov(r0, Operand(argc_)); // Setup the number of arguments. |
5625 __ mov(r2, Operand(0)); | 6019 __ mov(r2, Operand(0)); |
5626 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); | 6020 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); |
5627 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)), | 6021 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)), |
5628 RelocInfo::CODE_TARGET); | 6022 RelocInfo::CODE_TARGET); |
5629 } | 6023 } |
5630 | 6024 |
5631 | 6025 |
| 6026 int CompareStub::MinorKey() { |
| 6027 // Encode the two parameters in a unique 16 bit value. |
| 6028 ASSERT(static_cast<unsigned>(cc_) >> 28 < (1 << 15)); |
| 6029 return (static_cast<unsigned>(cc_) >> 27) | (strict_ ? 1 : 0); |
| 6030 } |
| 6031 |
| 6032 |
5632 #undef __ | 6033 #undef __ |
5633 | 6034 |
5634 } } // namespace v8::internal | 6035 } } // namespace v8::internal |
OLD | NEW |