| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 v0, | 151 v0, |
| 152 a1, | 152 a1, |
| 153 a2, | 153 a2, |
| 154 &gc, | 154 &gc, |
| 155 TAG_OBJECT); | 155 TAG_OBJECT); |
| 156 | 156 |
| 157 // Load the function from the stack. | 157 // Load the function from the stack. |
| 158 __ lw(a3, MemOperand(sp, 0)); | 158 __ lw(a3, MemOperand(sp, 0)); |
| 159 | 159 |
| 160 // Setup the object header. | 160 // Setup the object header. |
| 161 __ LoadRoot(a2, Heap::kContextMapRootIndex); | 161 __ LoadRoot(a2, Heap::kFunctionContextMapRootIndex); |
| 162 __ sw(a2, FieldMemOperand(v0, HeapObject::kMapOffset)); | 162 __ sw(a2, FieldMemOperand(v0, HeapObject::kMapOffset)); |
| 163 __ li(a2, Operand(Smi::FromInt(length))); | 163 __ li(a2, Operand(Smi::FromInt(length))); |
| 164 __ sw(a2, FieldMemOperand(v0, FixedArray::kLengthOffset)); | 164 __ sw(a2, FieldMemOperand(v0, FixedArray::kLengthOffset)); |
| 165 | 165 |
| 166 // Setup the fixed slots. | 166 // Setup the fixed slots. |
| 167 __ li(a1, Operand(Smi::FromInt(0))); | 167 __ li(a1, Operand(Smi::FromInt(0))); |
| 168 __ sw(a3, MemOperand(v0, Context::SlotOffset(Context::CLOSURE_INDEX))); | 168 __ sw(a3, MemOperand(v0, Context::SlotOffset(Context::CLOSURE_INDEX))); |
| 169 __ sw(v0, MemOperand(v0, Context::SlotOffset(Context::FCONTEXT_INDEX))); | 169 __ sw(cp, MemOperand(v0, Context::SlotOffset(Context::PREVIOUS_INDEX))); |
| 170 __ sw(a1, MemOperand(v0, Context::SlotOffset(Context::PREVIOUS_INDEX))); | |
| 171 __ sw(a1, MemOperand(v0, Context::SlotOffset(Context::EXTENSION_INDEX))); | 170 __ sw(a1, MemOperand(v0, Context::SlotOffset(Context::EXTENSION_INDEX))); |
| 172 | 171 |
| 173 // Copy the global object from the surrounding context. | 172 // Copy the global object from the previous context. |
| 174 __ lw(a1, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); | 173 __ lw(a1, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 175 __ sw(a1, MemOperand(v0, Context::SlotOffset(Context::GLOBAL_INDEX))); | 174 __ sw(a1, MemOperand(v0, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 176 | 175 |
| 177 // Initialize the rest of the slots to undefined. | 176 // Initialize the rest of the slots to undefined. |
| 178 __ LoadRoot(a1, Heap::kUndefinedValueRootIndex); | 177 __ LoadRoot(a1, Heap::kUndefinedValueRootIndex); |
| 179 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { | 178 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { |
| 180 __ sw(a1, MemOperand(v0, Context::SlotOffset(i))); | 179 __ sw(a1, MemOperand(v0, Context::SlotOffset(i))); |
| 181 } | 180 } |
| 182 | 181 |
| 183 // Remove the on-stack argument and return. | 182 // Remove the on-stack argument and return. |
| 184 __ mov(cp, v0); | 183 __ mov(cp, v0); |
| 185 __ Pop(); | 184 __ Pop(); |
| 186 __ Ret(); | 185 __ Ret(); |
| 187 | 186 |
| 188 // Need to collect. Call into runtime system. | 187 // Need to collect. Call into runtime system. |
| 189 __ bind(&gc); | 188 __ bind(&gc); |
| 190 __ TailCallRuntime(Runtime::kNewContext, 1, 1); | 189 __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1); |
| 191 } | 190 } |
| 192 | 191 |
| 193 | 192 |
| 194 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { | 193 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { |
| 195 // Stack layout on entry: | 194 // Stack layout on entry: |
| 196 // [sp]: constant elements. | 195 // [sp]: constant elements. |
| 197 // [sp + kPointerSize]: literal index. | 196 // [sp + kPointerSize]: literal index. |
| 198 // [sp + (2 * kPointerSize)]: literals array. | 197 // [sp + (2 * kPointerSize)]: literals array. |
| 199 | 198 |
| 200 // All sizes here are multiples of kPointerSize. | 199 // All sizes here are multiples of kPointerSize. |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 Major MajorKey() { return ConvertToDouble; } | 298 Major MajorKey() { return ConvertToDouble; } |
| 300 int MinorKey() { | 299 int MinorKey() { |
| 301 // Encode the parameters in a unique 16 bit value. | 300 // Encode the parameters in a unique 16 bit value. |
| 302 return result1_.code() + | 301 return result1_.code() + |
| 303 (result2_.code() << 4) + | 302 (result2_.code() << 4) + |
| 304 (source_.code() << 8) + | 303 (source_.code() << 8) + |
| 305 (zeros_.code() << 12); | 304 (zeros_.code() << 12); |
| 306 } | 305 } |
| 307 | 306 |
| 308 void Generate(MacroAssembler* masm); | 307 void Generate(MacroAssembler* masm); |
| 309 | |
| 310 const char* GetName() { return "ConvertToDoubleStub"; } | |
| 311 | |
| 312 #ifdef DEBUG | |
| 313 void Print() { PrintF("ConvertToDoubleStub\n"); } | |
| 314 #endif | |
| 315 }; | 308 }; |
| 316 | 309 |
| 317 | 310 |
| 318 void ConvertToDoubleStub::Generate(MacroAssembler* masm) { | 311 void ConvertToDoubleStub::Generate(MacroAssembler* masm) { |
| 319 #ifndef BIG_ENDIAN_FLOATING_POINT | 312 #ifndef BIG_ENDIAN_FLOATING_POINT |
| 320 Register exponent = result1_; | 313 Register exponent = result1_; |
| 321 Register mantissa = result2_; | 314 Register mantissa = result2_; |
| 322 #else | 315 #else |
| 323 Register exponent = result2_; | 316 Register exponent = result2_; |
| 324 Register mantissa = result1_; | 317 Register mantissa = result1_; |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 390 if (destination == kCoreRegisters) { | 383 if (destination == kCoreRegisters) { |
| 391 __ Move(a2, a3, f14); | 384 __ Move(a2, a3, f14); |
| 392 __ Move(a0, a1, f12); | 385 __ Move(a0, a1, f12); |
| 393 } | 386 } |
| 394 } else { | 387 } else { |
| 395 ASSERT(destination == kCoreRegisters); | 388 ASSERT(destination == kCoreRegisters); |
| 396 // Write Smi from a0 to a3 and a2 in double format. | 389 // Write Smi from a0 to a3 and a2 in double format. |
| 397 __ mov(scratch1, a0); | 390 __ mov(scratch1, a0); |
| 398 ConvertToDoubleStub stub1(a3, a2, scratch1, scratch2); | 391 ConvertToDoubleStub stub1(a3, a2, scratch1, scratch2); |
| 399 __ push(ra); | 392 __ push(ra); |
| 400 __ Call(stub1.GetCode(), RelocInfo::CODE_TARGET); | 393 __ Call(stub1.GetCode()); |
| 401 // Write Smi from a1 to a1 and a0 in double format. | 394 // Write Smi from a1 to a1 and a0 in double format. |
| 402 __ mov(scratch1, a1); | 395 __ mov(scratch1, a1); |
| 403 ConvertToDoubleStub stub2(a1, a0, scratch1, scratch2); | 396 ConvertToDoubleStub stub2(a1, a0, scratch1, scratch2); |
| 404 __ Call(stub2.GetCode(), RelocInfo::CODE_TARGET); | 397 __ Call(stub2.GetCode()); |
| 405 __ pop(ra); | 398 __ pop(ra); |
| 406 } | 399 } |
| 407 } | 400 } |
| 408 | 401 |
| 409 | 402 |
| 410 void FloatingPointHelper::LoadOperands( | 403 void FloatingPointHelper::LoadOperands( |
| 411 MacroAssembler* masm, | 404 MacroAssembler* masm, |
| 412 FloatingPointHelper::Destination destination, | 405 FloatingPointHelper::Destination destination, |
| 413 Register heap_number_map, | 406 Register heap_number_map, |
| 414 Register scratch1, | 407 Register scratch1, |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 476 if (destination == kCoreRegisters) { | 469 if (destination == kCoreRegisters) { |
| 477 // Load the converted smi to dst1 and dst2 in double format. | 470 // Load the converted smi to dst1 and dst2 in double format. |
| 478 __ Move(dst1, dst2, dst); | 471 __ Move(dst1, dst2, dst); |
| 479 } | 472 } |
| 480 } else { | 473 } else { |
| 481 ASSERT(destination == kCoreRegisters); | 474 ASSERT(destination == kCoreRegisters); |
| 482 // Write smi to dst1 and dst2 double format. | 475 // Write smi to dst1 and dst2 double format. |
| 483 __ mov(scratch1, object); | 476 __ mov(scratch1, object); |
| 484 ConvertToDoubleStub stub(dst2, dst1, scratch1, scratch2); | 477 ConvertToDoubleStub stub(dst2, dst1, scratch1, scratch2); |
| 485 __ push(ra); | 478 __ push(ra); |
| 486 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET); | 479 __ Call(stub.GetCode()); |
| 487 __ pop(ra); | 480 __ pop(ra); |
| 488 } | 481 } |
| 489 | 482 |
| 490 __ bind(&done); | 483 __ bind(&done); |
| 491 } | 484 } |
| 492 | 485 |
| 493 | 486 |
| 494 void FloatingPointHelper::ConvertNumberToInt32(MacroAssembler* masm, | 487 void FloatingPointHelper::ConvertNumberToInt32(MacroAssembler* masm, |
| 495 Register object, | 488 Register object, |
| 496 Register dst, | 489 Register dst, |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 665 // Save FCSR. | 658 // Save FCSR. |
| 666 __ cfc1(scratch1, FCSR); | 659 __ cfc1(scratch1, FCSR); |
| 667 // Disable FPU exceptions. | 660 // Disable FPU exceptions. |
| 668 __ ctc1(zero_reg, FCSR); | 661 __ ctc1(zero_reg, FCSR); |
| 669 __ trunc_w_d(single_scratch, double_dst); | 662 __ trunc_w_d(single_scratch, double_dst); |
| 670 // Retrieve FCSR. | 663 // Retrieve FCSR. |
| 671 __ cfc1(scratch2, FCSR); | 664 __ cfc1(scratch2, FCSR); |
| 672 // Restore FCSR. | 665 // Restore FCSR. |
| 673 __ ctc1(scratch1, FCSR); | 666 __ ctc1(scratch1, FCSR); |
| 674 | 667 |
| 675 // Check for inexact conversion. | 668 // Check for inexact conversion or exception. |
| 676 __ srl(scratch2, scratch2, kFCSRFlagShift); | 669 __ And(scratch2, scratch2, kFCSRFlagMask); |
| 677 __ And(scratch2, scratch2, (kFCSRFlagMask | kFCSRInexactFlagBit)); | |
| 678 | 670 |
| 679 // Jump to not_int32 if the operation did not succeed. | 671 // Jump to not_int32 if the operation did not succeed. |
| 680 __ Branch(not_int32, ne, scratch2, Operand(zero_reg)); | 672 __ Branch(not_int32, ne, scratch2, Operand(zero_reg)); |
| 681 | 673 |
| 682 if (destination == kCoreRegisters) { | 674 if (destination == kCoreRegisters) { |
| 683 __ Move(dst1, dst2, double_dst); | 675 __ Move(dst1, dst2, double_dst); |
| 684 } | 676 } |
| 685 | 677 |
| 686 } else { | 678 } else { |
| 687 ASSERT(!scratch1.is(object) && !scratch2.is(object)); | 679 ASSERT(!scratch1.is(object) && !scratch2.is(object)); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 750 // Save FCSR. | 742 // Save FCSR. |
| 751 __ cfc1(scratch1, FCSR); | 743 __ cfc1(scratch1, FCSR); |
| 752 // Disable FPU exceptions. | 744 // Disable FPU exceptions. |
| 753 __ ctc1(zero_reg, FCSR); | 745 __ ctc1(zero_reg, FCSR); |
| 754 __ trunc_w_d(double_scratch, double_scratch); | 746 __ trunc_w_d(double_scratch, double_scratch); |
| 755 // Retrieve FCSR. | 747 // Retrieve FCSR. |
| 756 __ cfc1(scratch2, FCSR); | 748 __ cfc1(scratch2, FCSR); |
| 757 // Restore FCSR. | 749 // Restore FCSR. |
| 758 __ ctc1(scratch1, FCSR); | 750 __ ctc1(scratch1, FCSR); |
| 759 | 751 |
| 760 // Check for inexact conversion. | 752 // Check for inexact conversion or exception. |
| 761 __ srl(scratch2, scratch2, kFCSRFlagShift); | 753 __ And(scratch2, scratch2, kFCSRFlagMask); |
| 762 __ And(scratch2, scratch2, (kFCSRFlagMask | kFCSRInexactFlagBit)); | |
| 763 | 754 |
| 764 // Jump to not_int32 if the operation did not succeed. | 755 // Jump to not_int32 if the operation did not succeed. |
| 765 __ Branch(not_int32, ne, scratch2, Operand(zero_reg)); | 756 __ Branch(not_int32, ne, scratch2, Operand(zero_reg)); |
| 766 // Get the result in the destination register. | 757 // Get the result in the destination register. |
| 767 __ mfc1(dst, double_scratch); | 758 __ mfc1(dst, double_scratch); |
| 768 | 759 |
| 769 } else { | 760 } else { |
| 770 // Load the double value in the destination registers. | 761 // Load the double value in the destination registers. |
| 771 __ lw(scratch2, FieldMemOperand(object, HeapNumber::kExponentOffset)); | 762 __ lw(scratch2, FieldMemOperand(object, HeapNumber::kExponentOffset)); |
| 772 __ lw(scratch1, FieldMemOperand(object, HeapNumber::kMantissaOffset)); | 763 __ lw(scratch1, FieldMemOperand(object, HeapNumber::kMantissaOffset)); |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 978 // we now know they test equal. | 969 // we now know they test equal. |
| 979 if (cc != eq || !never_nan_nan) { | 970 if (cc != eq || !never_nan_nan) { |
| 980 __ li(exp_mask_reg, Operand(HeapNumber::kExponentMask)); | 971 __ li(exp_mask_reg, Operand(HeapNumber::kExponentMask)); |
| 981 | 972 |
| 982 // Test for NaN. Sadly, we can't just compare to factory->nan_value(), | 973 // Test for NaN. Sadly, we can't just compare to factory->nan_value(), |
| 983 // so we do the second best thing - test it ourselves. | 974 // so we do the second best thing - test it ourselves. |
| 984 // They are both equal and they are not both Smis so both of them are not | 975 // They are both equal and they are not both Smis so both of them are not |
| 985 // Smis. If it's not a heap number, then return equal. | 976 // Smis. If it's not a heap number, then return equal. |
| 986 if (cc == less || cc == greater) { | 977 if (cc == less || cc == greater) { |
| 987 __ GetObjectType(a0, t4, t4); | 978 __ GetObjectType(a0, t4, t4); |
| 988 __ Branch(slow, greater, t4, Operand(FIRST_JS_OBJECT_TYPE)); | 979 __ Branch(slow, greater, t4, Operand(FIRST_SPEC_OBJECT_TYPE)); |
| 989 } else { | 980 } else { |
| 990 __ GetObjectType(a0, t4, t4); | 981 __ GetObjectType(a0, t4, t4); |
| 991 __ Branch(&heap_number, eq, t4, Operand(HEAP_NUMBER_TYPE)); | 982 __ Branch(&heap_number, eq, t4, Operand(HEAP_NUMBER_TYPE)); |
| 992 // Comparing JS objects with <=, >= is complicated. | 983 // Comparing JS objects with <=, >= is complicated. |
| 993 if (cc != eq) { | 984 if (cc != eq) { |
| 994 __ Branch(slow, greater, t4, Operand(FIRST_JS_OBJECT_TYPE)); | 985 __ Branch(slow, greater, t4, Operand(FIRST_SPEC_OBJECT_TYPE)); |
| 995 // Normally here we fall through to return_equal, but undefined is | 986 // Normally here we fall through to return_equal, but undefined is |
| 996 // special: (undefined == undefined) == true, but | 987 // special: (undefined == undefined) == true, but |
| 997 // (undefined <= undefined) == false! See ECMAScript 11.8.5. | 988 // (undefined <= undefined) == false! See ECMAScript 11.8.5. |
| 998 if (cc == less_equal || cc == greater_equal) { | 989 if (cc == less_equal || cc == greater_equal) { |
| 999 __ Branch(&return_equal, ne, t4, Operand(ODDBALL_TYPE)); | 990 __ Branch(&return_equal, ne, t4, Operand(ODDBALL_TYPE)); |
| 1000 __ LoadRoot(t2, Heap::kUndefinedValueRootIndex); | 991 __ LoadRoot(t2, Heap::kUndefinedValueRootIndex); |
| 1001 __ Branch(&return_equal, ne, a0, Operand(t2)); | 992 __ Branch(&return_equal, ne, a0, Operand(t2)); |
| 1002 if (cc == le) { | 993 if (cc == le) { |
| 1003 // undefined <= undefined should fail. | 994 // undefined <= undefined should fail. |
| 1004 __ li(v0, Operand(GREATER)); | 995 __ li(v0, Operand(GREATER)); |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1103 __ ldc1(f12, FieldMemOperand(lhs, HeapNumber::kValueOffset)); | 1094 __ ldc1(f12, FieldMemOperand(lhs, HeapNumber::kValueOffset)); |
| 1104 } else { | 1095 } else { |
| 1105 // Load lhs to a double in a2, a3. | 1096 // Load lhs to a double in a2, a3. |
| 1106 __ lw(a3, FieldMemOperand(lhs, HeapNumber::kValueOffset + 4)); | 1097 __ lw(a3, FieldMemOperand(lhs, HeapNumber::kValueOffset + 4)); |
| 1107 __ lw(a2, FieldMemOperand(lhs, HeapNumber::kValueOffset)); | 1098 __ lw(a2, FieldMemOperand(lhs, HeapNumber::kValueOffset)); |
| 1108 | 1099 |
| 1109 // Write Smi from rhs to a1 and a0 in double format. t5 is scratch. | 1100 // Write Smi from rhs to a1 and a0 in double format. t5 is scratch. |
| 1110 __ mov(t6, rhs); | 1101 __ mov(t6, rhs); |
| 1111 ConvertToDoubleStub stub1(a1, a0, t6, t5); | 1102 ConvertToDoubleStub stub1(a1, a0, t6, t5); |
| 1112 __ push(ra); | 1103 __ push(ra); |
| 1113 __ Call(stub1.GetCode(), RelocInfo::CODE_TARGET); | 1104 __ Call(stub1.GetCode()); |
| 1114 | 1105 |
| 1115 __ pop(ra); | 1106 __ pop(ra); |
| 1116 } | 1107 } |
| 1117 | 1108 |
| 1118 // We now have both loaded as doubles. | 1109 // We now have both loaded as doubles. |
| 1119 __ jmp(both_loaded_as_doubles); | 1110 __ jmp(both_loaded_as_doubles); |
| 1120 | 1111 |
| 1121 __ bind(&lhs_is_smi); | 1112 __ bind(&lhs_is_smi); |
| 1122 // Lhs is a Smi. Check whether the non-smi is a heap number. | 1113 // Lhs is a Smi. Check whether the non-smi is a heap number. |
| 1123 __ GetObjectType(rhs, t4, t4); | 1114 __ GetObjectType(rhs, t4, t4); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1138 CpuFeatures::Scope scope(FPU); | 1129 CpuFeatures::Scope scope(FPU); |
| 1139 __ sra(at, lhs, kSmiTagSize); | 1130 __ sra(at, lhs, kSmiTagSize); |
| 1140 __ mtc1(at, f12); | 1131 __ mtc1(at, f12); |
| 1141 __ cvt_d_w(f12, f12); | 1132 __ cvt_d_w(f12, f12); |
| 1142 __ ldc1(f14, FieldMemOperand(rhs, HeapNumber::kValueOffset)); | 1133 __ ldc1(f14, FieldMemOperand(rhs, HeapNumber::kValueOffset)); |
| 1143 } else { | 1134 } else { |
| 1144 // Convert lhs to a double format. t5 is scratch. | 1135 // Convert lhs to a double format. t5 is scratch. |
| 1145 __ mov(t6, lhs); | 1136 __ mov(t6, lhs); |
| 1146 ConvertToDoubleStub stub2(a3, a2, t6, t5); | 1137 ConvertToDoubleStub stub2(a3, a2, t6, t5); |
| 1147 __ push(ra); | 1138 __ push(ra); |
| 1148 __ Call(stub2.GetCode(), RelocInfo::CODE_TARGET); | 1139 __ Call(stub2.GetCode()); |
| 1149 __ pop(ra); | 1140 __ pop(ra); |
| 1150 // Load rhs to a double in a1, a0. | 1141 // Load rhs to a double in a1, a0. |
| 1151 if (rhs.is(a0)) { | 1142 if (rhs.is(a0)) { |
| 1152 __ lw(a1, FieldMemOperand(rhs, HeapNumber::kValueOffset + 4)); | 1143 __ lw(a1, FieldMemOperand(rhs, HeapNumber::kValueOffset + 4)); |
| 1153 __ lw(a0, FieldMemOperand(rhs, HeapNumber::kValueOffset)); | 1144 __ lw(a0, FieldMemOperand(rhs, HeapNumber::kValueOffset)); |
| 1154 } else { | 1145 } else { |
| 1155 __ lw(a0, FieldMemOperand(rhs, HeapNumber::kValueOffset)); | 1146 __ lw(a0, FieldMemOperand(rhs, HeapNumber::kValueOffset)); |
| 1156 __ lw(a1, FieldMemOperand(rhs, HeapNumber::kValueOffset + 4)); | 1147 __ lw(a1, FieldMemOperand(rhs, HeapNumber::kValueOffset + 4)); |
| 1157 } | 1148 } |
| 1158 } | 1149 } |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1302 __ bind(&less_than); | 1293 __ bind(&less_than); |
| 1303 __ li(v0, Operand(LESS)); | 1294 __ li(v0, Operand(LESS)); |
| 1304 __ Ret(); | 1295 __ Ret(); |
| 1305 } | 1296 } |
| 1306 } | 1297 } |
| 1307 | 1298 |
| 1308 | 1299 |
| 1309 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, | 1300 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, |
| 1310 Register lhs, | 1301 Register lhs, |
| 1311 Register rhs) { | 1302 Register rhs) { |
| 1312 // If either operand is a JSObject or an oddball value, then they are | 1303 // If either operand is a JS object or an oddball value, then they are |
| 1313 // not equal since their pointers are different. | 1304 // not equal since their pointers are different. |
| 1314 // There is no test for undetectability in strict equality. | 1305 // There is no test for undetectability in strict equality. |
| 1315 STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 1306 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE); |
| 1316 Label first_non_object; | 1307 Label first_non_object; |
| 1317 // Get the type of the first operand into a2 and compare it with | 1308 // Get the type of the first operand into a2 and compare it with |
| 1318 // FIRST_JS_OBJECT_TYPE. | 1309 // FIRST_SPEC_OBJECT_TYPE. |
| 1319 __ GetObjectType(lhs, a2, a2); | 1310 __ GetObjectType(lhs, a2, a2); |
| 1320 __ Branch(&first_non_object, less, a2, Operand(FIRST_JS_OBJECT_TYPE)); | 1311 __ Branch(&first_non_object, less, a2, Operand(FIRST_SPEC_OBJECT_TYPE)); |
| 1321 | 1312 |
| 1322 // Return non-zero. | 1313 // Return non-zero. |
| 1323 Label return_not_equal; | 1314 Label return_not_equal; |
| 1324 __ bind(&return_not_equal); | 1315 __ bind(&return_not_equal); |
| 1325 __ li(v0, Operand(1)); | 1316 __ li(v0, Operand(1)); |
| 1326 __ Ret(); | 1317 __ Ret(); |
| 1327 | 1318 |
| 1328 __ bind(&first_non_object); | 1319 __ bind(&first_non_object); |
| 1329 // Check for oddballs: true, false, null, undefined. | 1320 // Check for oddballs: true, false, null, undefined. |
| 1330 __ Branch(&return_not_equal, eq, a2, Operand(ODDBALL_TYPE)); | 1321 __ Branch(&return_not_equal, eq, a2, Operand(ODDBALL_TYPE)); |
| 1331 | 1322 |
| 1332 __ GetObjectType(rhs, a3, a3); | 1323 __ GetObjectType(rhs, a3, a3); |
| 1333 __ Branch(&return_not_equal, greater, a3, Operand(FIRST_JS_OBJECT_TYPE)); | 1324 __ Branch(&return_not_equal, greater, a3, Operand(FIRST_SPEC_OBJECT_TYPE)); |
| 1334 | 1325 |
| 1335 // Check for oddballs: true, false, null, undefined. | 1326 // Check for oddballs: true, false, null, undefined. |
| 1336 __ Branch(&return_not_equal, eq, a3, Operand(ODDBALL_TYPE)); | 1327 __ Branch(&return_not_equal, eq, a3, Operand(ODDBALL_TYPE)); |
| 1337 | 1328 |
| 1338 // Now that we have the types we might as well check for symbol-symbol. | 1329 // Now that we have the types we might as well check for symbol-symbol. |
| 1339 // Ensure that no non-strings have the symbol bit set. | 1330 // Ensure that no non-strings have the symbol bit set. |
| 1340 STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsSymbolMask); | 1331 STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsSymbolMask); |
| 1341 STATIC_ASSERT(kSymbolTag != 0); | 1332 STATIC_ASSERT(kSymbolTag != 0); |
| 1342 __ And(t2, a2, Operand(a3)); | 1333 __ And(t2, a2, Operand(a3)); |
| 1343 __ And(t0, t2, Operand(kIsSymbolMask)); | 1334 __ And(t0, t2, Operand(kIsSymbolMask)); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1399 __ Branch(not_both_strings, ge, a3, Operand(FIRST_NONSTRING_TYPE)); | 1390 __ Branch(not_both_strings, ge, a3, Operand(FIRST_NONSTRING_TYPE)); |
| 1400 __ And(at, a3, Operand(kIsSymbolMask)); | 1391 __ And(at, a3, Operand(kIsSymbolMask)); |
| 1401 __ Branch(possible_strings, eq, at, Operand(zero_reg)); | 1392 __ Branch(possible_strings, eq, at, Operand(zero_reg)); |
| 1402 | 1393 |
| 1403 // Both are symbols. We already checked they weren't the same pointer | 1394 // Both are symbols. We already checked they weren't the same pointer |
| 1404 // so they are not equal. | 1395 // so they are not equal. |
| 1405 __ li(v0, Operand(1)); // Non-zero indicates not equal. | 1396 __ li(v0, Operand(1)); // Non-zero indicates not equal. |
| 1406 __ Ret(); | 1397 __ Ret(); |
| 1407 | 1398 |
| 1408 __ bind(&object_test); | 1399 __ bind(&object_test); |
| 1409 __ Branch(not_both_strings, lt, a2, Operand(FIRST_JS_OBJECT_TYPE)); | 1400 __ Branch(not_both_strings, lt, a2, Operand(FIRST_SPEC_OBJECT_TYPE)); |
| 1410 __ GetObjectType(rhs, a2, a3); | 1401 __ GetObjectType(rhs, a2, a3); |
| 1411 __ Branch(not_both_strings, lt, a3, Operand(FIRST_JS_OBJECT_TYPE)); | 1402 __ Branch(not_both_strings, lt, a3, Operand(FIRST_SPEC_OBJECT_TYPE)); |
| 1412 | 1403 |
| 1413 // If both objects are undetectable, they are equal. Otherwise, they | 1404 // If both objects are undetectable, they are equal. Otherwise, they |
| 1414 // are not equal, since they are different objects and an object is not | 1405 // are not equal, since they are different objects and an object is not |
| 1415 // equal to undefined. | 1406 // equal to undefined. |
| 1416 __ lw(a3, FieldMemOperand(lhs, HeapObject::kMapOffset)); | 1407 __ lw(a3, FieldMemOperand(lhs, HeapObject::kMapOffset)); |
| 1417 __ lbu(a2, FieldMemOperand(a2, Map::kBitFieldOffset)); | 1408 __ lbu(a2, FieldMemOperand(a2, Map::kBitFieldOffset)); |
| 1418 __ lbu(a3, FieldMemOperand(a3, Map::kBitFieldOffset)); | 1409 __ lbu(a3, FieldMemOperand(a3, Map::kBitFieldOffset)); |
| 1419 __ and_(a0, a2, a3); | 1410 __ and_(a0, a2, a3); |
| 1420 __ And(a0, a0, Operand(1 << Map::kIsUndetectable)); | 1411 __ And(a0, a0, Operand(1 << Map::kIsUndetectable)); |
| 1421 __ Xor(v0, a0, Operand(1 << Map::kIsUndetectable)); | 1412 __ Xor(v0, a0, Operand(1 << Map::kIsUndetectable)); |
| (...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1713 __ li(a0, Operand(Smi::FromInt(ncr))); | 1704 __ li(a0, Operand(Smi::FromInt(ncr))); |
| 1714 __ push(a0); | 1705 __ push(a0); |
| 1715 } | 1706 } |
| 1716 | 1707 |
| 1717 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) | 1708 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) |
| 1718 // tagged as a small integer. | 1709 // tagged as a small integer. |
| 1719 __ InvokeBuiltin(native, JUMP_FUNCTION); | 1710 __ InvokeBuiltin(native, JUMP_FUNCTION); |
| 1720 } | 1711 } |
| 1721 | 1712 |
| 1722 | 1713 |
| 1723 // This stub does not handle the inlined cases (Smis, Booleans, undefined). | |
| 1724 // The stub returns zero for false, and a non-zero value for true. | 1714 // The stub returns zero for false, and a non-zero value for true. |
| 1725 void ToBooleanStub::Generate(MacroAssembler* masm) { | 1715 void ToBooleanStub::Generate(MacroAssembler* masm) { |
| 1726 // This stub uses FPU instructions. | 1716 // This stub uses FPU instructions. |
| 1727 CpuFeatures::Scope scope(FPU); | 1717 CpuFeatures::Scope scope(FPU); |
| 1728 | 1718 |
| 1729 Label false_result; | 1719 Label false_result; |
| 1730 Label not_heap_number; | 1720 Label not_heap_number; |
| 1731 Register scratch0 = t5.is(tos_) ? t3 : t5; | 1721 Register scratch0 = t5.is(tos_) ? t3 : t5; |
| 1732 | 1722 |
| 1733 // undefined -> false | 1723 // undefined -> false |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1777 __ And(scratch0, scratch0, Operand(1 << Map::kIsUndetectable)); | 1767 __ And(scratch0, scratch0, Operand(1 << Map::kIsUndetectable)); |
| 1778 __ Branch(&false_result, eq, scratch0, Operand(1 << Map::kIsUndetectable)); | 1768 __ Branch(&false_result, eq, scratch0, Operand(1 << Map::kIsUndetectable)); |
| 1779 | 1769 |
| 1780 // JavaScript object => true. | 1770 // JavaScript object => true. |
| 1781 __ lw(scratch0, FieldMemOperand(tos_, HeapObject::kMapOffset)); | 1771 __ lw(scratch0, FieldMemOperand(tos_, HeapObject::kMapOffset)); |
| 1782 __ lbu(scratch0, FieldMemOperand(scratch0, Map::kInstanceTypeOffset)); | 1772 __ lbu(scratch0, FieldMemOperand(scratch0, Map::kInstanceTypeOffset)); |
| 1783 | 1773 |
| 1784 // "tos_" is a register and contains a non-zero value. | 1774 // "tos_" is a register and contains a non-zero value. |
| 1785 // Hence we implicitly return true if the greater than | 1775 // Hence we implicitly return true if the greater than |
| 1786 // condition is satisfied. | 1776 // condition is satisfied. |
| 1787 __ Ret(gt, scratch0, Operand(FIRST_JS_OBJECT_TYPE)); | 1777 __ Ret(ge, scratch0, Operand(FIRST_SPEC_OBJECT_TYPE)); |
| 1788 | 1778 |
| 1789 // Check for string. | 1779 // Check for string. |
| 1790 __ lw(scratch0, FieldMemOperand(tos_, HeapObject::kMapOffset)); | 1780 __ lw(scratch0, FieldMemOperand(tos_, HeapObject::kMapOffset)); |
| 1791 __ lbu(scratch0, FieldMemOperand(scratch0, Map::kInstanceTypeOffset)); | 1781 __ lbu(scratch0, FieldMemOperand(scratch0, Map::kInstanceTypeOffset)); |
| 1792 // "tos_" is a register and contains a non-zero value. | 1782 // "tos_" is a register and contains a non-zero value. |
| 1793 // Hence we implicitly return true if the greater than | 1783 // Hence we implicitly return true if the greater than |
| 1794 // condition is satisfied. | 1784 // condition is satisfied. |
| 1795 __ Ret(gt, scratch0, Operand(FIRST_NONSTRING_TYPE)); | 1785 __ Ret(ge, scratch0, Operand(FIRST_NONSTRING_TYPE)); |
| 1796 | 1786 |
| 1797 // String value => false iff empty, i.e., length is zero. | 1787 // String value => false iff empty, i.e., length is zero. |
| 1798 __ lw(tos_, FieldMemOperand(tos_, String::kLengthOffset)); | 1788 __ lw(tos_, FieldMemOperand(tos_, String::kLengthOffset)); |
| 1799 // If length is zero, "tos_" contains zero ==> false. | 1789 // If length is zero, "tos_" contains zero ==> false. |
| 1800 // If length is not zero, "tos_" contains a non-zero value ==> true. | 1790 // If length is not zero, "tos_" contains a non-zero value ==> true. |
| 1801 __ Ret(); | 1791 __ Ret(); |
| 1802 | 1792 |
| 1803 // Return 0 in "tos_" for false. | 1793 // Return 0 in "tos_" for false. |
| 1804 __ bind(&false_result); | 1794 __ bind(&false_result); |
| 1805 __ mov(tos_, zero_reg); | 1795 __ mov(tos_, zero_reg); |
| 1806 __ Ret(); | 1796 __ Ret(); |
| 1807 } | 1797 } |
| 1808 | 1798 |
| 1809 | 1799 |
| 1810 Handle<Code> GetUnaryOpStub(int key, UnaryOpIC::TypeInfo type_info) { | |
| 1811 UnaryOpStub stub(key, type_info); | |
| 1812 return stub.GetCode(); | |
| 1813 } | |
| 1814 | |
| 1815 | |
| 1816 const char* UnaryOpStub::GetName() { | 1800 const char* UnaryOpStub::GetName() { |
| 1817 if (name_ != NULL) return name_; | 1801 if (name_ != NULL) return name_; |
| 1818 const int kMaxNameLength = 100; | 1802 const int kMaxNameLength = 100; |
| 1819 name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray( | 1803 name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray( |
| 1820 kMaxNameLength); | 1804 kMaxNameLength); |
| 1821 if (name_ == NULL) return "OOM"; | 1805 if (name_ == NULL) return "OOM"; |
| 1822 const char* op_name = Token::Name(op_); | 1806 const char* op_name = Token::Name(op_); |
| 1823 const char* overwrite_name = NULL; // Make g++ happy. | 1807 const char* overwrite_name = NULL; // Make g++ happy. |
| 1824 switch (mode_) { | 1808 switch (mode_) { |
| 1825 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; | 1809 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1849 break; | 1833 break; |
| 1850 case UnaryOpIC::GENERIC: | 1834 case UnaryOpIC::GENERIC: |
| 1851 GenerateGenericStub(masm); | 1835 GenerateGenericStub(masm); |
| 1852 break; | 1836 break; |
| 1853 } | 1837 } |
| 1854 } | 1838 } |
| 1855 | 1839 |
| 1856 | 1840 |
| 1857 void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { | 1841 void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { |
| 1858 // Argument is in a0 and v0 at this point, so we can overwrite a0. | 1842 // Argument is in a0 and v0 at this point, so we can overwrite a0. |
| 1859 // Push this stub's key. Although the operation and the type info are | 1843 __ li(a2, Operand(Smi::FromInt(op_))); |
| 1860 // encoded into the key, the encoding is opaque, so push them too. | 1844 __ li(a1, Operand(Smi::FromInt(mode_))); |
| 1861 __ li(a2, Operand(Smi::FromInt(MinorKey()))); | |
| 1862 __ li(a1, Operand(Smi::FromInt(op_))); | |
| 1863 __ li(a0, Operand(Smi::FromInt(operand_type_))); | 1845 __ li(a0, Operand(Smi::FromInt(operand_type_))); |
| 1864 | |
| 1865 __ Push(v0, a2, a1, a0); | 1846 __ Push(v0, a2, a1, a0); |
| 1866 | 1847 |
| 1867 __ TailCallExternalReference( | 1848 __ TailCallExternalReference( |
| 1868 ExternalReference(IC_Utility(IC::kUnaryOp_Patch), | 1849 ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1); |
| 1869 masm->isolate()), | |
| 1870 4, | |
| 1871 1); | |
| 1872 } | 1850 } |
| 1873 | 1851 |
| 1874 | 1852 |
| 1875 // TODO(svenpanne): Use virtual functions instead of switch. | 1853 // TODO(svenpanne): Use virtual functions instead of switch. |
| 1876 void UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) { | 1854 void UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) { |
| 1877 switch (op_) { | 1855 switch (op_) { |
| 1878 case Token::SUB: | 1856 case Token::SUB: |
| 1879 GenerateSmiStubSub(masm); | 1857 GenerateSmiStubSub(masm); |
| 1880 break; | 1858 break; |
| 1881 case Token::BIT_NOT: | 1859 case Token::BIT_NOT: |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1959 | 1937 |
| 1960 void UnaryOpStub::GenerateHeapNumberStubBitNot(MacroAssembler* masm) { | 1938 void UnaryOpStub::GenerateHeapNumberStubBitNot(MacroAssembler* masm) { |
| 1961 Label non_smi, slow; | 1939 Label non_smi, slow; |
| 1962 GenerateSmiCodeBitNot(masm, &non_smi); | 1940 GenerateSmiCodeBitNot(masm, &non_smi); |
| 1963 __ bind(&non_smi); | 1941 __ bind(&non_smi); |
| 1964 GenerateHeapNumberCodeBitNot(masm, &slow); | 1942 GenerateHeapNumberCodeBitNot(masm, &slow); |
| 1965 __ bind(&slow); | 1943 __ bind(&slow); |
| 1966 GenerateTypeTransition(masm); | 1944 GenerateTypeTransition(masm); |
| 1967 } | 1945 } |
| 1968 | 1946 |
| 1947 |
| 1969 void UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm, | 1948 void UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm, |
| 1970 Label* slow) { | 1949 Label* slow) { |
| 1971 EmitCheckForHeapNumber(masm, a0, a1, t2, slow); | 1950 EmitCheckForHeapNumber(masm, a0, a1, t2, slow); |
| 1972 // a0 is a heap number. Get a new heap number in a1. | 1951 // a0 is a heap number. Get a new heap number in a1. |
| 1973 if (mode_ == UNARY_OVERWRITE) { | 1952 if (mode_ == UNARY_OVERWRITE) { |
| 1974 __ lw(a2, FieldMemOperand(a0, HeapNumber::kExponentOffset)); | 1953 __ lw(a2, FieldMemOperand(a0, HeapNumber::kExponentOffset)); |
| 1975 __ Xor(a2, a2, Operand(HeapNumber::kSignMask)); // Flip sign. | 1954 __ Xor(a2, a2, Operand(HeapNumber::kSignMask)); // Flip sign. |
| 1976 __ sw(a2, FieldMemOperand(a0, HeapNumber::kExponentOffset)); | 1955 __ sw(a2, FieldMemOperand(a0, HeapNumber::kExponentOffset)); |
| 1977 } else { | 1956 } else { |
| 1978 Label slow_allocate_heapnumber, heapnumber_allocated; | 1957 Label slow_allocate_heapnumber, heapnumber_allocated; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1995 __ sw(a2, FieldMemOperand(a1, HeapNumber::kExponentOffset)); | 1974 __ sw(a2, FieldMemOperand(a1, HeapNumber::kExponentOffset)); |
| 1996 __ mov(v0, a1); | 1975 __ mov(v0, a1); |
| 1997 } | 1976 } |
| 1998 __ Ret(); | 1977 __ Ret(); |
| 1999 } | 1978 } |
| 2000 | 1979 |
| 2001 | 1980 |
| 2002 void UnaryOpStub::GenerateHeapNumberCodeBitNot( | 1981 void UnaryOpStub::GenerateHeapNumberCodeBitNot( |
| 2003 MacroAssembler* masm, | 1982 MacroAssembler* masm, |
| 2004 Label* slow) { | 1983 Label* slow) { |
| 1984 Label impossible; |
| 1985 |
| 2005 EmitCheckForHeapNumber(masm, a0, a1, t2, slow); | 1986 EmitCheckForHeapNumber(masm, a0, a1, t2, slow); |
| 2006 // Convert the heap number in a0 to an untagged integer in a1. | 1987 // Convert the heap number in a0 to an untagged integer in a1. |
| 2007 __ ConvertToInt32(a0, a1, a2, a3, f0, slow); | 1988 __ ConvertToInt32(a0, a1, a2, a3, f0, slow); |
| 2008 | 1989 |
| 2009 // Do the bitwise operation and check if the result fits in a smi. | 1990 // Do the bitwise operation and check if the result fits in a smi. |
| 2010 Label try_float; | 1991 Label try_float; |
| 2011 __ Neg(a1, a1); | 1992 __ Neg(a1, a1); |
| 2012 __ Addu(a2, a1, Operand(0x40000000)); | 1993 __ Addu(a2, a1, Operand(0x40000000)); |
| 2013 __ Branch(&try_float, lt, a2, Operand(zero_reg)); | 1994 __ Branch(&try_float, lt, a2, Operand(zero_reg)); |
| 2014 | 1995 |
| 2015 // Tag the result as a smi and we're done. | 1996 // Tag the result as a smi and we're done. |
| 2016 __ SmiTag(v0, a1); | 1997 __ SmiTag(v0, a1); |
| 2017 __ Ret(); | 1998 __ Ret(); |
| 2018 | 1999 |
| 2019 // Try to store the result in a heap number. | 2000 // Try to store the result in a heap number. |
| 2020 __ bind(&try_float); | 2001 __ bind(&try_float); |
| 2021 if (mode_ == UNARY_NO_OVERWRITE) { | 2002 if (mode_ == UNARY_NO_OVERWRITE) { |
| 2022 Label slow_allocate_heapnumber, heapnumber_allocated; | 2003 Label slow_allocate_heapnumber, heapnumber_allocated; |
| 2023 __ AllocateHeapNumber(v0, a2, a3, t2, &slow_allocate_heapnumber); | 2004 // Allocate a new heap number without zapping v0, which we need if it fails. |
| 2005 __ AllocateHeapNumber(a2, a3, t0, t2, &slow_allocate_heapnumber); |
| 2024 __ jmp(&heapnumber_allocated); | 2006 __ jmp(&heapnumber_allocated); |
| 2025 | 2007 |
| 2026 __ bind(&slow_allocate_heapnumber); | 2008 __ bind(&slow_allocate_heapnumber); |
| 2027 __ EnterInternalFrame(); | 2009 __ EnterInternalFrame(); |
| 2028 __ push(a1); | 2010 __ push(v0); // Push the heap number, not the untagged int32. |
| 2029 __ CallRuntime(Runtime::kNumberAlloc, 0); | 2011 __ CallRuntime(Runtime::kNumberAlloc, 0); |
| 2030 __ pop(a1); | 2012 __ mov(a2, v0); // Move the new heap number into a2. |
| 2013 // Get the heap number into v0, now that the new heap number is in a2. |
| 2014 __ pop(v0); |
| 2031 __ LeaveInternalFrame(); | 2015 __ LeaveInternalFrame(); |
| 2032 | 2016 |
| 2017 // Convert the heap number in v0 to an untagged integer in a1. |
| 2018 // This can't go slow-case because it's the same number we already |
| 2019 // converted once again. |
| 2020 __ ConvertToInt32(v0, a1, a3, t0, f0, &impossible); |
| 2021 // Negate the result. |
| 2022 __ Xor(a1, a1, -1); |
| 2023 |
| 2033 __ bind(&heapnumber_allocated); | 2024 __ bind(&heapnumber_allocated); |
| 2025 __ mov(v0, a2); // Move newly allocated heap number to v0. |
| 2034 } | 2026 } |
| 2035 | 2027 |
| 2036 if (CpuFeatures::IsSupported(FPU)) { | 2028 if (CpuFeatures::IsSupported(FPU)) { |
| 2037 // Convert the int32 in a1 to the heap number in v0. a2 is corrupted. | 2029 // Convert the int32 in a1 to the heap number in v0. a2 is corrupted. |
| 2038 CpuFeatures::Scope scope(FPU); | 2030 CpuFeatures::Scope scope(FPU); |
| 2039 __ mtc1(a1, f0); | 2031 __ mtc1(a1, f0); |
| 2040 __ cvt_d_w(f0, f0); | 2032 __ cvt_d_w(f0, f0); |
| 2041 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset)); | 2033 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset)); |
| 2042 __ Ret(); | 2034 __ Ret(); |
| 2043 } else { | 2035 } else { |
| 2044 // WriteInt32ToHeapNumberStub does not trigger GC, so we do not | 2036 // WriteInt32ToHeapNumberStub does not trigger GC, so we do not |
| 2045 // have to set up a frame. | 2037 // have to set up a frame. |
| 2046 WriteInt32ToHeapNumberStub stub(a1, v0, a2, a3); | 2038 WriteInt32ToHeapNumberStub stub(a1, v0, a2, a3); |
| 2047 __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); | 2039 __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); |
| 2048 } | 2040 } |
| 2041 |
| 2042 __ bind(&impossible); |
| 2043 if (FLAG_debug_code) { |
| 2044 __ stop("Incorrect assumption in bit-not stub"); |
| 2045 } |
| 2049 } | 2046 } |
| 2050 | 2047 |
| 2051 | 2048 |
| 2052 // TODO(svenpanne): Use virtual functions instead of switch. | 2049 // TODO(svenpanne): Use virtual functions instead of switch. |
| 2053 void UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) { | 2050 void UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) { |
| 2054 switch (op_) { | 2051 switch (op_) { |
| 2055 case Token::SUB: | 2052 case Token::SUB: |
| 2056 GenerateGenericStubSub(masm); | 2053 GenerateGenericStubSub(masm); |
| 2057 break; | 2054 break; |
| 2058 case Token::BIT_NOT: | 2055 case Token::BIT_NOT: |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2094 break; | 2091 break; |
| 2095 case Token::BIT_NOT: | 2092 case Token::BIT_NOT: |
| 2096 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); | 2093 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); |
| 2097 break; | 2094 break; |
| 2098 default: | 2095 default: |
| 2099 UNREACHABLE(); | 2096 UNREACHABLE(); |
| 2100 } | 2097 } |
| 2101 } | 2098 } |
| 2102 | 2099 |
| 2103 | 2100 |
| 2104 Handle<Code> GetBinaryOpStub(int key, | |
| 2105 BinaryOpIC::TypeInfo type_info, | |
| 2106 BinaryOpIC::TypeInfo result_type_info) { | |
| 2107 BinaryOpStub stub(key, type_info, result_type_info); | |
| 2108 return stub.GetCode(); | |
| 2109 } | |
| 2110 | |
| 2111 | |
| 2112 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { | 2101 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { |
| 2113 Label get_result; | 2102 Label get_result; |
| 2114 | 2103 |
| 2115 __ Push(a1, a0); | 2104 __ Push(a1, a0); |
| 2116 | 2105 |
| 2117 __ li(a2, Operand(Smi::FromInt(MinorKey()))); | 2106 __ li(a2, Operand(Smi::FromInt(MinorKey()))); |
| 2118 __ li(a1, Operand(Smi::FromInt(op_))); | 2107 __ li(a1, Operand(Smi::FromInt(op_))); |
| 2119 __ li(a0, Operand(Smi::FromInt(operands_type_))); | 2108 __ li(a0, Operand(Smi::FromInt(operands_type_))); |
| 2120 __ Push(a2, a1, a0); | 2109 __ Push(a2, a1, a0); |
| 2121 | 2110 |
| (...skipping 558 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2680 GenerateSmiSmiOperation(masm); | 2669 GenerateSmiSmiOperation(masm); |
| 2681 // Fall through if the result is not a smi. | 2670 // Fall through if the result is not a smi. |
| 2682 __ bind(&skip); | 2671 __ bind(&skip); |
| 2683 | 2672 |
| 2684 switch (op_) { | 2673 switch (op_) { |
| 2685 case Token::ADD: | 2674 case Token::ADD: |
| 2686 case Token::SUB: | 2675 case Token::SUB: |
| 2687 case Token::MUL: | 2676 case Token::MUL: |
| 2688 case Token::DIV: | 2677 case Token::DIV: |
| 2689 case Token::MOD: { | 2678 case Token::MOD: { |
| 2690 // Load both operands and check that they are 32-bit integer. | 2679 // Load both operands and check that they are 32-bit integer. |
| 2691 // Jump to type transition if they are not. The registers a0 and a1 (right | 2680 // Jump to type transition if they are not. The registers a0 and a1 (right |
| 2692 // and left) are preserved for the runtime call. | 2681 // and left) are preserved for the runtime call. |
| 2693 FloatingPointHelper::Destination destination = | 2682 FloatingPointHelper::Destination destination = |
| 2694 CpuFeatures::IsSupported(FPU) && | 2683 (CpuFeatures::IsSupported(FPU) && op_ != Token::MOD) |
| 2695 op_ != Token::MOD ? | 2684 ? FloatingPointHelper::kFPURegisters |
| 2696 FloatingPointHelper::kFPURegisters : | 2685 : FloatingPointHelper::kCoreRegisters; |
| 2697 FloatingPointHelper::kCoreRegisters; | |
| 2698 | 2686 |
| 2699 FloatingPointHelper::LoadNumberAsInt32Double(masm, | 2687 FloatingPointHelper::LoadNumberAsInt32Double(masm, |
| 2700 right, | 2688 right, |
| 2701 destination, | 2689 destination, |
| 2702 f14, | 2690 f14, |
| 2703 a2, | 2691 a2, |
| 2704 a3, | 2692 a3, |
| 2705 heap_number_map, | 2693 heap_number_map, |
| 2706 scratch1, | 2694 scratch1, |
| 2707 scratch2, | 2695 scratch2, |
| 2708 f2, | 2696 f2, |
| 2709 &transition); | 2697 &transition); |
| 2710 FloatingPointHelper::LoadNumberAsInt32Double(masm, | 2698 FloatingPointHelper::LoadNumberAsInt32Double(masm, |
| 2711 left, | 2699 left, |
| 2712 destination, | 2700 destination, |
| 2713 f12, | 2701 f12, |
| 2714 t0, | 2702 t0, |
| 2715 t1, | 2703 t1, |
| 2716 heap_number_map, | 2704 heap_number_map, |
| 2717 scratch1, | 2705 scratch1, |
| 2718 scratch2, | 2706 scratch2, |
| 2719 f2, | 2707 f2, |
| 2720 &transition); | 2708 &transition); |
| 2721 | 2709 |
| 2722 if (destination == FloatingPointHelper::kFPURegisters) { | 2710 if (destination == FloatingPointHelper::kFPURegisters) { |
| 2723 CpuFeatures::Scope scope(FPU); | 2711 CpuFeatures::Scope scope(FPU); |
| 2724 Label return_heap_number; | 2712 Label return_heap_number; |
| 2725 switch (op_) { | 2713 switch (op_) { |
| 2726 case Token::ADD: | 2714 case Token::ADD: |
| 2727 __ add_d(f10, f12, f14); | 2715 __ add_d(f10, f12, f14); |
| 2728 break; | 2716 break; |
| 2729 case Token::SUB: | 2717 case Token::SUB: |
| 2730 __ sub_d(f10, f12, f14); | 2718 __ sub_d(f10, f12, f14); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 2752 // Save FCSR. | 2740 // Save FCSR. |
| 2753 __ cfc1(scratch1, FCSR); | 2741 __ cfc1(scratch1, FCSR); |
| 2754 // Disable FPU exceptions. | 2742 // Disable FPU exceptions. |
| 2755 __ ctc1(zero_reg, FCSR); | 2743 __ ctc1(zero_reg, FCSR); |
| 2756 __ trunc_w_d(single_scratch, f10); | 2744 __ trunc_w_d(single_scratch, f10); |
| 2757 // Retrieve FCSR. | 2745 // Retrieve FCSR. |
| 2758 __ cfc1(scratch2, FCSR); | 2746 __ cfc1(scratch2, FCSR); |
| 2759 // Restore FCSR. | 2747 // Restore FCSR. |
| 2760 __ ctc1(scratch1, FCSR); | 2748 __ ctc1(scratch1, FCSR); |
| 2761 | 2749 |
| 2762 // Check for inexact conversion. | 2750 // Check for inexact conversion or exception. |
| 2763 __ srl(scratch2, scratch2, kFCSRFlagShift); | |
| 2764 __ And(scratch2, scratch2, kFCSRFlagMask); | 2751 __ And(scratch2, scratch2, kFCSRFlagMask); |
| 2765 | 2752 |
| 2766 if (result_type_ <= BinaryOpIC::INT32) { | 2753 if (result_type_ <= BinaryOpIC::INT32) { |
| 2767 // If scratch2 != 0, result does not fit in a 32-bit integer. | 2754 // If scratch2 != 0, result does not fit in a 32-bit integer. |
| 2768 __ Branch(&transition, ne, scratch2, Operand(zero_reg)); | 2755 __ Branch(&transition, ne, scratch2, Operand(zero_reg)); |
| 2769 } | 2756 } |
| 2770 | 2757 |
| 2771 // Check if the result fits in a smi. | 2758 // Check if the result fits in a smi. |
| 2772 __ mfc1(scratch1, single_scratch); | 2759 __ mfc1(scratch1, single_scratch); |
| 2773 __ Addu(scratch2, scratch1, Operand(0x40000000)); | 2760 __ Addu(scratch2, scratch1, Operand(0x40000000)); |
| 2774 // If not try to return a heap number. | 2761 // If not try to return a heap number. |
| 2775 __ Branch(&return_heap_number, lt, scratch2, Operand(zero_reg)); | 2762 __ Branch(&return_heap_number, lt, scratch2, Operand(zero_reg)); |
| 2776 // Check for minus zero. Return heap number for minus zero. | 2763 // Check for minus zero. Return heap number for minus zero. |
| 2777 Label not_zero; | 2764 Label not_zero; |
| 2778 __ Branch(¬_zero, ne, scratch1, Operand(zero_reg)); | 2765 __ Branch(¬_zero, ne, scratch1, Operand(zero_reg)); |
| 2779 __ mfc1(scratch2, f11); | 2766 __ mfc1(scratch2, f11); |
| 2780 __ And(scratch2, scratch2, HeapNumber::kSignMask); | 2767 __ And(scratch2, scratch2, HeapNumber::kSignMask); |
| 2781 __ Branch(&return_heap_number, ne, scratch2, Operand(zero_reg)); | 2768 __ Branch(&return_heap_number, ne, scratch2, Operand(zero_reg)); |
| 2782 __ bind(¬_zero); | 2769 __ bind(¬_zero); |
| 2783 | 2770 |
| 2784 // Tag the result and return. | 2771 // Tag the result and return. |
| 2785 __ SmiTag(v0, scratch1); | 2772 __ SmiTag(v0, scratch1); |
| 2786 __ Ret(); | 2773 __ Ret(); |
| 2787 } else { | 2774 } else { |
| 2788 // DIV just falls through to allocating a heap number. | 2775 // DIV just falls through to allocating a heap number. |
| 2789 } | 2776 } |
| 2790 | 2777 |
| 2791 if (result_type_ >= (op_ == Token::DIV) ? BinaryOpIC::HEAP_NUMBER | 2778 __ bind(&return_heap_number); |
| 2792 : BinaryOpIC::INT32) { | 2779 // Return a heap number, or fall through to type transition or runtime |
| 2793 __ bind(&return_heap_number); | 2780 // call if we can't. |
| 2781 if (result_type_ >= ((op_ == Token::DIV) ? BinaryOpIC::HEAP_NUMBER |
| 2782 : BinaryOpIC::INT32)) { |
| 2794 // We are using FPU registers so s0 is available. | 2783 // We are using FPU registers so s0 is available. |
| 2795 heap_number_result = s0; | 2784 heap_number_result = s0; |
| 2796 GenerateHeapResultAllocation(masm, | 2785 GenerateHeapResultAllocation(masm, |
| 2797 heap_number_result, | 2786 heap_number_result, |
| 2798 heap_number_map, | 2787 heap_number_map, |
| 2799 scratch1, | 2788 scratch1, |
| 2800 scratch2, | 2789 scratch2, |
| 2801 &call_runtime); | 2790 &call_runtime); |
| 2802 __ mov(v0, heap_number_result); | 2791 __ mov(v0, heap_number_result); |
| 2803 __ sdc1(f10, FieldMemOperand(v0, HeapNumber::kValueOffset)); | 2792 __ sdc1(f10, FieldMemOperand(v0, HeapNumber::kValueOffset)); |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2962 __ TailCallStub(&stub); | 2951 __ TailCallStub(&stub); |
| 2963 } | 2952 } |
| 2964 | 2953 |
| 2965 break; | 2954 break; |
| 2966 } | 2955 } |
| 2967 | 2956 |
| 2968 default: | 2957 default: |
| 2969 UNREACHABLE(); | 2958 UNREACHABLE(); |
| 2970 } | 2959 } |
| 2971 | 2960 |
| 2972 if (transition.is_linked()) { | 2961 // We never expect DIV to yield an integer result, so we always generate |
| 2962 // type transition code for DIV operations expecting an integer result: the |
| 2963 // code will fall through to this type transition. |
| 2964 if (transition.is_linked() || |
| 2965 ((op_ == Token::DIV) && (result_type_ <= BinaryOpIC::INT32))) { |
| 2973 __ bind(&transition); | 2966 __ bind(&transition); |
| 2974 GenerateTypeTransition(masm); | 2967 GenerateTypeTransition(masm); |
| 2975 } | 2968 } |
| 2976 | 2969 |
| 2977 __ bind(&call_runtime); | 2970 __ bind(&call_runtime); |
| 2978 GenerateCallRuntime(masm); | 2971 GenerateCallRuntime(masm); |
| 2979 } | 2972 } |
| 2980 | 2973 |
| 2981 | 2974 |
| 2982 void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { | 2975 void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { |
| (...skipping 551 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3534 __ mov(a0, s0); | 3527 __ mov(a0, s0); |
| 3535 __ mov(a1, s1); | 3528 __ mov(a1, s1); |
| 3536 | 3529 |
| 3537 // We are calling compiled C/C++ code. a0 and a1 hold our two arguments. We | 3530 // We are calling compiled C/C++ code. a0 and a1 hold our two arguments. We |
| 3538 // also need to reserve the 4 argument slots on the stack. | 3531 // also need to reserve the 4 argument slots on the stack. |
| 3539 | 3532 |
| 3540 __ AssertStackIsAligned(); | 3533 __ AssertStackIsAligned(); |
| 3541 | 3534 |
| 3542 __ li(a2, Operand(ExternalReference::isolate_address())); | 3535 __ li(a2, Operand(ExternalReference::isolate_address())); |
| 3543 | 3536 |
| 3544 // From arm version of this function: | 3537 // To let the GC traverse the return address of the exit frames, we need to |
| 3545 // TODO(1242173): To let the GC traverse the return address of the exit | 3538 // know where the return address is. The CEntryStub is unmovable, so |
| 3546 // frames, we need to know where the return address is. Right now, | 3539 // we can store the address on the stack to be able to find it again and |
| 3547 // we push it on the stack to be able to find it again, but we never | 3540 // we never have to restore it, because it will not change. |
| 3548 // restore from it in case of changes, which makes it impossible to | |
| 3549 // support moving the C entry code stub. This should be fixed, but currently | |
| 3550 // this is OK because the CEntryStub gets generated so early in the V8 boot | |
| 3551 // sequence that it is not moving ever. | |
| 3552 | |
| 3553 { Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm); | 3541 { Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm); |
| 3554 // This branch-and-link sequence is needed to find the current PC on mips, | 3542 // This branch-and-link sequence is needed to find the current PC on mips, |
| 3555 // saved to the ra register. | 3543 // saved to the ra register. |
| 3556 // Use masm-> here instead of the double-underscore macro since extra | 3544 // Use masm-> here instead of the double-underscore macro since extra |
| 3557 // coverage code can interfere with the proper calculation of ra. | 3545 // coverage code can interfere with the proper calculation of ra. |
| 3558 Label find_ra; | 3546 Label find_ra; |
| 3559 masm->bal(&find_ra); // bal exposes branch delay slot. | 3547 masm->bal(&find_ra); // bal exposes branch delay slot. |
| 3560 masm->nop(); // Branch delay slot nop. | 3548 masm->nop(); // Branch delay slot nop. |
| 3561 masm->bind(&find_ra); | 3549 masm->bind(&find_ra); |
| 3562 | 3550 |
| (...skipping 504 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4067 __ Ret(); | 4055 __ Ret(); |
| 4068 | 4056 |
| 4069 // Slow-case: Handle non-smi or out-of-bounds access to arguments | 4057 // Slow-case: Handle non-smi or out-of-bounds access to arguments |
| 4070 // by calling the runtime system. | 4058 // by calling the runtime system. |
| 4071 __ bind(&slow); | 4059 __ bind(&slow); |
| 4072 __ push(a1); | 4060 __ push(a1); |
| 4073 __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1); | 4061 __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1); |
| 4074 } | 4062 } |
| 4075 | 4063 |
| 4076 | 4064 |
| 4077 void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) { | 4065 void ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) { |
| 4078 // sp[0] : number of parameters | 4066 // sp[0] : number of parameters |
| 4079 // sp[4] : receiver displacement | 4067 // sp[4] : receiver displacement |
| 4080 // sp[8] : function | 4068 // sp[8] : function |
| 4081 | 4069 // Check if the calling frame is an arguments adaptor frame. |
| 4070 Label runtime; |
| 4071 __ lw(a3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
| 4072 __ lw(a2, MemOperand(a3, StandardFrameConstants::kContextOffset)); |
| 4073 __ Branch(&runtime, ne, |
| 4074 a2, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 4075 |
| 4076 // Patch the arguments.length and the parameters pointer in the current frame. |
| 4077 __ lw(a2, MemOperand(a3, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 4078 __ sw(a2, MemOperand(sp, 0 * kPointerSize)); |
| 4079 __ sll(t3, a2, 1); |
| 4080 __ Addu(a3, a3, Operand(t3)); |
| 4081 __ addiu(a3, a3, StandardFrameConstants::kCallerSPOffset); |
| 4082 __ sw(a3, MemOperand(sp, 1 * kPointerSize)); |
| 4083 |
| 4084 __ bind(&runtime); |
| 4085 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); |
| 4086 } |
| 4087 |
| 4088 |
| 4089 void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) { |
| 4090 // Stack layout: |
| 4091 // sp[0] : number of parameters (tagged) |
| 4092 // sp[4] : address of receiver argument |
| 4093 // sp[8] : function |
| 4094 // Registers used over whole function: |
| 4095 // t2 : allocated object (tagged) |
| 4096 // t5 : mapped parameter count (tagged) |
| 4097 |
| 4098 __ lw(a1, MemOperand(sp, 0 * kPointerSize)); |
| 4099 // a1 = parameter count (tagged) |
| 4100 |
| 4101 // Check if the calling frame is an arguments adaptor frame. |
| 4102 Label runtime; |
| 4103 Label adaptor_frame, try_allocate; |
| 4104 __ lw(a3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
| 4105 __ lw(a2, MemOperand(a3, StandardFrameConstants::kContextOffset)); |
| 4106 __ Branch(&adaptor_frame, eq, a2, |
| 4107 Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 4108 |
| 4109 // No adaptor, parameter count = argument count. |
| 4110 __ mov(a2, a1); |
| 4111 __ b(&try_allocate); |
| 4112 __ nop(); // Branch delay slot nop. |
| 4113 |
| 4114 // We have an adaptor frame. Patch the parameters pointer. |
| 4115 __ bind(&adaptor_frame); |
| 4116 __ lw(a2, MemOperand(a3, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 4117 __ sll(t6, a2, 1); |
| 4118 __ Addu(a3, a3, Operand(t6)); |
| 4119 __ Addu(a3, a3, Operand(StandardFrameConstants::kCallerSPOffset)); |
| 4120 __ sw(a3, MemOperand(sp, 1 * kPointerSize)); |
| 4121 |
| 4122 // a1 = parameter count (tagged) |
| 4123 // a2 = argument count (tagged) |
| 4124 // Compute the mapped parameter count = min(a1, a2) in a1. |
| 4125 Label skip_min; |
| 4126 __ Branch(&skip_min, lt, a1, Operand(a2)); |
| 4127 __ mov(a1, a2); |
| 4128 __ bind(&skip_min); |
| 4129 |
| 4130 __ bind(&try_allocate); |
| 4131 |
| 4132 // Compute the sizes of backing store, parameter map, and arguments object. |
| 4133 // 1. Parameter map, has 2 extra words containing context and backing store. |
| 4134 const int kParameterMapHeaderSize = |
| 4135 FixedArray::kHeaderSize + 2 * kPointerSize; |
| 4136 // If there are no mapped parameters, we do not need the parameter_map. |
| 4137 Label param_map_size; |
| 4138 ASSERT_EQ(0, Smi::FromInt(0)); |
| 4139 __ Branch(USE_DELAY_SLOT, ¶m_map_size, eq, a1, Operand(zero_reg)); |
| 4140 __ mov(t5, zero_reg); // In delay slot: param map size = 0 when a1 == 0. |
| 4141 __ sll(t5, a1, 1); |
| 4142 __ addiu(t5, t5, kParameterMapHeaderSize); |
| 4143 __ bind(¶m_map_size); |
| 4144 |
| 4145 // 2. Backing store. |
| 4146 __ sll(t6, a2, 1); |
| 4147 __ Addu(t5, t5, Operand(t6)); |
| 4148 __ Addu(t5, t5, Operand(FixedArray::kHeaderSize)); |
| 4149 |
| 4150 // 3. Arguments object. |
| 4151 __ Addu(t5, t5, Operand(Heap::kArgumentsObjectSize)); |
| 4152 |
| 4153 // Do the allocation of all three objects in one go. |
| 4154 __ AllocateInNewSpace(t5, v0, a3, t0, &runtime, TAG_OBJECT); |
| 4155 |
| 4156 // v0 = address of new object(s) (tagged) |
| 4157 // a2 = argument count (tagged) |
| 4158 // Get the arguments boilerplate from the current (global) context into t0. |
| 4159 const int kNormalOffset = |
| 4160 Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX); |
| 4161 const int kAliasedOffset = |
| 4162 Context::SlotOffset(Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX); |
| 4163 |
| 4164 __ lw(t0, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 4165 __ lw(t0, FieldMemOperand(t0, GlobalObject::kGlobalContextOffset)); |
| 4166 Label skip2_ne, skip2_eq; |
| 4167 __ Branch(&skip2_ne, ne, a1, Operand(zero_reg)); |
| 4168 __ lw(t0, MemOperand(t0, kNormalOffset)); |
| 4169 __ bind(&skip2_ne); |
| 4170 |
| 4171 __ Branch(&skip2_eq, eq, a1, Operand(zero_reg)); |
| 4172 __ lw(t0, MemOperand(t0, kAliasedOffset)); |
| 4173 __ bind(&skip2_eq); |
| 4174 |
| 4175 // v0 = address of new object (tagged) |
| 4176 // a1 = mapped parameter count (tagged) |
| 4177 // a2 = argument count (tagged) |
| 4178 // t0 = address of boilerplate object (tagged) |
| 4179 // Copy the JS object part. |
| 4180 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { |
| 4181 __ lw(a3, FieldMemOperand(t0, i)); |
| 4182 __ sw(a3, FieldMemOperand(v0, i)); |
| 4183 } |
| 4184 |
| 4185 // Setup the callee in-object property. |
| 4186 STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1); |
| 4187 __ lw(a3, MemOperand(sp, 2 * kPointerSize)); |
| 4188 const int kCalleeOffset = JSObject::kHeaderSize + |
| 4189 Heap::kArgumentsCalleeIndex * kPointerSize; |
| 4190 __ sw(a3, FieldMemOperand(v0, kCalleeOffset)); |
| 4191 |
| 4192 // Use the length (smi tagged) and set that as an in-object property too. |
| 4193 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); |
| 4194 const int kLengthOffset = JSObject::kHeaderSize + |
| 4195 Heap::kArgumentsLengthIndex * kPointerSize; |
| 4196 __ sw(a2, FieldMemOperand(v0, kLengthOffset)); |
| 4197 |
| 4198 // Setup the elements pointer in the allocated arguments object. |
| 4199 // If we allocated a parameter map, t0 will point there, otherwise |
| 4200 // it will point to the backing store. |
| 4201 __ Addu(t0, v0, Operand(Heap::kArgumentsObjectSize)); |
| 4202 __ sw(t0, FieldMemOperand(v0, JSObject::kElementsOffset)); |
| 4203 |
| 4204 // v0 = address of new object (tagged) |
| 4205 // a1 = mapped parameter count (tagged) |
| 4206 // a2 = argument count (tagged) |
| 4207 // t0 = address of parameter map or backing store (tagged) |
| 4208 // Initialize parameter map. If there are no mapped arguments, we're done. |
| 4209 Label skip_parameter_map; |
| 4210 Label skip3; |
| 4211 __ Branch(&skip3, ne, a1, Operand(Smi::FromInt(0))); |
| 4212 // Move backing store address to a3, because it is |
| 4213 // expected there when filling in the unmapped arguments. |
| 4214 __ mov(a3, t0); |
| 4215 __ bind(&skip3); |
| 4216 |
| 4217 __ Branch(&skip_parameter_map, eq, a1, Operand(Smi::FromInt(0))); |
| 4218 |
| 4219 __ LoadRoot(t2, Heap::kNonStrictArgumentsElementsMapRootIndex); |
| 4220 __ sw(t2, FieldMemOperand(t0, FixedArray::kMapOffset)); |
| 4221 __ Addu(t2, a1, Operand(Smi::FromInt(2))); |
| 4222 __ sw(t2, FieldMemOperand(t0, FixedArray::kLengthOffset)); |
| 4223 __ sw(cp, FieldMemOperand(t0, FixedArray::kHeaderSize + 0 * kPointerSize)); |
| 4224 __ sll(t6, a1, 1); |
| 4225 __ Addu(t2, t0, Operand(t6)); |
| 4226 __ Addu(t2, t2, Operand(kParameterMapHeaderSize)); |
| 4227 __ sw(t2, FieldMemOperand(t0, FixedArray::kHeaderSize + 1 * kPointerSize)); |
| 4228 |
| 4229 // Copy the parameter slots and the holes in the arguments. |
| 4230 // We need to fill in mapped_parameter_count slots. They index the context, |
| 4231 // where parameters are stored in reverse order, at |
| 4232 // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1 |
| 4233 // The mapped parameter thus need to get indices |
| 4234 // MIN_CONTEXT_SLOTS+parameter_count-1 .. |
| 4235 // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count |
| 4236 // We loop from right to left. |
| 4237 Label parameters_loop, parameters_test; |
| 4238 __ mov(t2, a1); |
| 4239 __ lw(t5, MemOperand(sp, 0 * kPointerSize)); |
| 4240 __ Addu(t5, t5, Operand(Smi::FromInt(Context::MIN_CONTEXT_SLOTS))); |
| 4241 __ Subu(t5, t5, Operand(a1)); |
| 4242 __ LoadRoot(t3, Heap::kTheHoleValueRootIndex); |
| 4243 __ sll(t6, t2, 1); |
| 4244 __ Addu(a3, t0, Operand(t6)); |
| 4245 __ Addu(a3, a3, Operand(kParameterMapHeaderSize)); |
| 4246 |
| 4247 // t2 = loop variable (tagged) |
| 4248 // a1 = mapping index (tagged) |
| 4249 // a3 = address of backing store (tagged) |
| 4250 // t0 = address of parameter map (tagged) |
| 4251 // t1 = temporary scratch (a.o., for address calculation) |
| 4252 // t3 = the hole value |
| 4253 __ jmp(¶meters_test); |
| 4254 |
| 4255 __ bind(¶meters_loop); |
| 4256 __ Subu(t2, t2, Operand(Smi::FromInt(1))); |
| 4257 __ sll(t1, t2, 1); |
| 4258 __ Addu(t1, t1, Operand(kParameterMapHeaderSize - kHeapObjectTag)); |
| 4259 __ Addu(t6, t0, t1); |
| 4260 __ sw(t5, MemOperand(t6)); |
| 4261 __ Subu(t1, t1, Operand(kParameterMapHeaderSize - FixedArray::kHeaderSize)); |
| 4262 __ Addu(t6, a3, t1); |
| 4263 __ sw(t3, MemOperand(t6)); |
| 4264 __ Addu(t5, t5, Operand(Smi::FromInt(1))); |
| 4265 __ bind(¶meters_test); |
| 4266 __ Branch(¶meters_loop, ne, t2, Operand(Smi::FromInt(0))); |
| 4267 |
| 4268 __ bind(&skip_parameter_map); |
| 4269 // a2 = argument count (tagged) |
| 4270 // a3 = address of backing store (tagged) |
| 4271 // t1 = scratch |
| 4272 // Copy arguments header and remaining slots (if there are any). |
| 4273 __ LoadRoot(t1, Heap::kFixedArrayMapRootIndex); |
| 4274 __ sw(t1, FieldMemOperand(a3, FixedArray::kMapOffset)); |
| 4275 __ sw(a2, FieldMemOperand(a3, FixedArray::kLengthOffset)); |
| 4276 |
| 4277 Label arguments_loop, arguments_test; |
| 4278 __ mov(t5, a1); |
| 4279 __ lw(t0, MemOperand(sp, 1 * kPointerSize)); |
| 4280 __ sll(t6, t5, 1); |
| 4281 __ Subu(t0, t0, Operand(t6)); |
| 4282 __ jmp(&arguments_test); |
| 4283 |
| 4284 __ bind(&arguments_loop); |
| 4285 __ Subu(t0, t0, Operand(kPointerSize)); |
| 4286 __ lw(t2, MemOperand(t0, 0)); |
| 4287 __ sll(t6, t5, 1); |
| 4288 __ Addu(t1, a3, Operand(t6)); |
| 4289 __ sw(t2, FieldMemOperand(t1, FixedArray::kHeaderSize)); |
| 4290 __ Addu(t5, t5, Operand(Smi::FromInt(1))); |
| 4291 |
| 4292 __ bind(&arguments_test); |
| 4293 __ Branch(&arguments_loop, lt, t5, Operand(a2)); |
| 4294 |
| 4295 // Return and remove the on-stack parameters. |
| 4296 __ Addu(sp, sp, Operand(3 * kPointerSize)); |
| 4297 __ Ret(); |
| 4298 |
| 4299 // Do the runtime call to allocate the arguments object. |
| 4300 // a2 = argument count (taggged) |
| 4301 __ bind(&runtime); |
| 4302 __ sw(a2, MemOperand(sp, 0 * kPointerSize)); // Patch argument count. |
| 4303 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); |
| 4304 } |
| 4305 |
| 4306 |
| 4307 void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) { |
| 4308 // sp[0] : number of parameters |
| 4309 // sp[4] : receiver displacement |
| 4310 // sp[8] : function |
| 4082 // Check if the calling frame is an arguments adaptor frame. | 4311 // Check if the calling frame is an arguments adaptor frame. |
| 4083 Label adaptor_frame, try_allocate, runtime; | 4312 Label adaptor_frame, try_allocate, runtime; |
| 4084 __ lw(a2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); | 4313 __ lw(a2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
| 4085 __ lw(a3, MemOperand(a2, StandardFrameConstants::kContextOffset)); | 4314 __ lw(a3, MemOperand(a2, StandardFrameConstants::kContextOffset)); |
| 4086 __ Branch(&adaptor_frame, | 4315 __ Branch(&adaptor_frame, |
| 4087 eq, | 4316 eq, |
| 4088 a3, | 4317 a3, |
| 4089 Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 4318 Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 4090 | 4319 |
| 4091 // Get the length from the frame. | 4320 // Get the length from the frame. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 4104 | 4333 |
| 4105 // Try the new space allocation. Start out with computing the size | 4334 // Try the new space allocation. Start out with computing the size |
| 4106 // of the arguments object and the elements array in words. | 4335 // of the arguments object and the elements array in words. |
| 4107 Label add_arguments_object; | 4336 Label add_arguments_object; |
| 4108 __ bind(&try_allocate); | 4337 __ bind(&try_allocate); |
| 4109 __ Branch(&add_arguments_object, eq, a1, Operand(zero_reg)); | 4338 __ Branch(&add_arguments_object, eq, a1, Operand(zero_reg)); |
| 4110 __ srl(a1, a1, kSmiTagSize); | 4339 __ srl(a1, a1, kSmiTagSize); |
| 4111 | 4340 |
| 4112 __ Addu(a1, a1, Operand(FixedArray::kHeaderSize / kPointerSize)); | 4341 __ Addu(a1, a1, Operand(FixedArray::kHeaderSize / kPointerSize)); |
| 4113 __ bind(&add_arguments_object); | 4342 __ bind(&add_arguments_object); |
| 4114 __ Addu(a1, a1, Operand(GetArgumentsObjectSize() / kPointerSize)); | 4343 __ Addu(a1, a1, Operand(Heap::kArgumentsObjectSizeStrict / kPointerSize)); |
| 4115 | 4344 |
| 4116 // Do the allocation of both objects in one go. | 4345 // Do the allocation of both objects in one go. |
| 4117 __ AllocateInNewSpace( | 4346 __ AllocateInNewSpace(a1, |
| 4118 a1, | 4347 v0, |
| 4119 v0, | 4348 a2, |
| 4120 a2, | 4349 a3, |
| 4121 a3, | 4350 &runtime, |
| 4122 &runtime, | 4351 static_cast<AllocationFlags>(TAG_OBJECT | |
| 4123 static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS)); | 4352 SIZE_IN_WORDS)); |
| 4124 | 4353 |
| 4125 // Get the arguments boilerplate from the current (global) context. | 4354 // Get the arguments boilerplate from the current (global) context. |
| 4126 __ lw(t0, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); | 4355 __ lw(t0, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 4127 __ lw(t0, FieldMemOperand(t0, GlobalObject::kGlobalContextOffset)); | 4356 __ lw(t0, FieldMemOperand(t0, GlobalObject::kGlobalContextOffset)); |
| 4128 __ lw(t0, MemOperand(t0, | 4357 __ lw(t0, MemOperand(t0, Context::SlotOffset( |
| 4129 Context::SlotOffset(GetArgumentsBoilerplateIndex()))); | 4358 Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX))); |
| 4130 | 4359 |
| 4131 // Copy the JS object part. | 4360 // Copy the JS object part. |
| 4132 __ CopyFields(v0, t0, a3.bit(), JSObject::kHeaderSize / kPointerSize); | 4361 __ CopyFields(v0, t0, a3.bit(), JSObject::kHeaderSize / kPointerSize); |
| 4133 | 4362 |
| 4134 if (type_ == NEW_NON_STRICT) { | |
| 4135 // Setup the callee in-object property. | |
| 4136 STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1); | |
| 4137 __ lw(a3, MemOperand(sp, 2 * kPointerSize)); | |
| 4138 const int kCalleeOffset = JSObject::kHeaderSize + | |
| 4139 Heap::kArgumentsCalleeIndex * kPointerSize; | |
| 4140 __ sw(a3, FieldMemOperand(v0, kCalleeOffset)); | |
| 4141 } | |
| 4142 | |
| 4143 // Get the length (smi tagged) and set that as an in-object property too. | 4363 // Get the length (smi tagged) and set that as an in-object property too. |
| 4144 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); | 4364 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); |
| 4145 __ lw(a1, MemOperand(sp, 0 * kPointerSize)); | 4365 __ lw(a1, MemOperand(sp, 0 * kPointerSize)); |
| 4146 __ sw(a1, FieldMemOperand(v0, JSObject::kHeaderSize + | 4366 __ sw(a1, FieldMemOperand(v0, JSObject::kHeaderSize + |
| 4147 Heap::kArgumentsLengthIndex * kPointerSize)); | 4367 Heap::kArgumentsLengthIndex * kPointerSize)); |
| 4148 | 4368 |
| 4149 Label done; | 4369 Label done; |
| 4150 __ Branch(&done, eq, a1, Operand(zero_reg)); | 4370 __ Branch(&done, eq, a1, Operand(zero_reg)); |
| 4151 | 4371 |
| 4152 // Get the parameters pointer from the stack. | 4372 // Get the parameters pointer from the stack. |
| 4153 __ lw(a2, MemOperand(sp, 1 * kPointerSize)); | 4373 __ lw(a2, MemOperand(sp, 1 * kPointerSize)); |
| 4154 | 4374 |
| 4155 // Setup the elements pointer in the allocated arguments object and | 4375 // Setup the elements pointer in the allocated arguments object and |
| 4156 // initialize the header in the elements fixed array. | 4376 // initialize the header in the elements fixed array. |
| 4157 __ Addu(t0, v0, Operand(GetArgumentsObjectSize())); | 4377 __ Addu(t0, v0, Operand(Heap::kArgumentsObjectSizeStrict)); |
| 4158 __ sw(t0, FieldMemOperand(v0, JSObject::kElementsOffset)); | 4378 __ sw(t0, FieldMemOperand(v0, JSObject::kElementsOffset)); |
| 4159 __ LoadRoot(a3, Heap::kFixedArrayMapRootIndex); | 4379 __ LoadRoot(a3, Heap::kFixedArrayMapRootIndex); |
| 4160 __ sw(a3, FieldMemOperand(t0, FixedArray::kMapOffset)); | 4380 __ sw(a3, FieldMemOperand(t0, FixedArray::kMapOffset)); |
| 4161 __ sw(a1, FieldMemOperand(t0, FixedArray::kLengthOffset)); | 4381 __ sw(a1, FieldMemOperand(t0, FixedArray::kLengthOffset)); |
| 4162 __ srl(a1, a1, kSmiTagSize); // Untag the length for the loop. | 4382 // Untag the length for the loop. |
| 4383 __ srl(a1, a1, kSmiTagSize); |
| 4163 | 4384 |
| 4164 // Copy the fixed array slots. | 4385 // Copy the fixed array slots. |
| 4165 Label loop; | 4386 Label loop; |
| 4166 // Setup t0 to point to the first array slot. | 4387 // Setup t0 to point to the first array slot. |
| 4167 __ Addu(t0, t0, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 4388 __ Addu(t0, t0, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| 4168 __ bind(&loop); | 4389 __ bind(&loop); |
| 4169 // Pre-decrement a2 with kPointerSize on each iteration. | 4390 // Pre-decrement a2 with kPointerSize on each iteration. |
| 4170 // Pre-decrement in order to skip receiver. | 4391 // Pre-decrement in order to skip receiver. |
| 4171 __ Addu(a2, a2, Operand(-kPointerSize)); | 4392 __ Addu(a2, a2, Operand(-kPointerSize)); |
| 4172 __ lw(a3, MemOperand(a2)); | 4393 __ lw(a3, MemOperand(a2)); |
| 4173 // Post-increment t0 with kPointerSize on each iteration. | 4394 // Post-increment t0 with kPointerSize on each iteration. |
| 4174 __ sw(a3, MemOperand(t0)); | 4395 __ sw(a3, MemOperand(t0)); |
| 4175 __ Addu(t0, t0, Operand(kPointerSize)); | 4396 __ Addu(t0, t0, Operand(kPointerSize)); |
| 4176 __ Subu(a1, a1, Operand(1)); | 4397 __ Subu(a1, a1, Operand(1)); |
| 4177 __ Branch(&loop, ne, a1, Operand(zero_reg)); | 4398 __ Branch(&loop, ne, a1, Operand(zero_reg)); |
| 4178 | 4399 |
| 4179 // Return and remove the on-stack parameters. | 4400 // Return and remove the on-stack parameters. |
| 4180 __ bind(&done); | 4401 __ bind(&done); |
| 4181 __ Addu(sp, sp, Operand(3 * kPointerSize)); | 4402 __ Addu(sp, sp, Operand(3 * kPointerSize)); |
| 4182 __ Ret(); | 4403 __ Ret(); |
| 4183 | 4404 |
| 4184 // Do the runtime call to allocate the arguments object. | 4405 // Do the runtime call to allocate the arguments object. |
| 4185 __ bind(&runtime); | 4406 __ bind(&runtime); |
| 4186 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); | 4407 __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); |
| 4187 } | 4408 } |
| 4188 | 4409 |
| 4189 | 4410 |
| 4190 void RegExpExecStub::Generate(MacroAssembler* masm) { | 4411 void RegExpExecStub::Generate(MacroAssembler* masm) { |
| 4191 // Just jump directly to runtime if native RegExp is not selected at compile | 4412 // Just jump directly to runtime if native RegExp is not selected at compile |
| 4192 // time or if regexp entry in generated code is turned off runtime switch or | 4413 // time or if regexp entry in generated code is turned off runtime switch or |
| 4193 // at compilation. | 4414 // at compilation. |
| 4194 #ifdef V8_INTERPRETED_REGEXP | 4415 #ifdef V8_INTERPRETED_REGEXP |
| 4195 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); | 4416 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); |
| 4196 #else // V8_INTERPRETED_REGEXP | 4417 #else // V8_INTERPRETED_REGEXP |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4358 STATIC_ASSERT(kAsciiStringTag == 4); | 4579 STATIC_ASSERT(kAsciiStringTag == 4); |
| 4359 STATIC_ASSERT(kTwoByteStringTag == 0); | 4580 STATIC_ASSERT(kTwoByteStringTag == 0); |
| 4360 // Find the code object based on the assumptions above. | 4581 // Find the code object based on the assumptions above. |
| 4361 __ And(a0, a0, Operand(kStringEncodingMask)); // Non-zero for ascii. | 4582 __ And(a0, a0, Operand(kStringEncodingMask)); // Non-zero for ascii. |
| 4362 __ lw(t9, FieldMemOperand(regexp_data, JSRegExp::kDataAsciiCodeOffset)); | 4583 __ lw(t9, FieldMemOperand(regexp_data, JSRegExp::kDataAsciiCodeOffset)); |
| 4363 __ sra(a3, a0, 2); // a3 is 1 for ascii, 0 for UC16 (usyed below). | 4584 __ sra(a3, a0, 2); // a3 is 1 for ascii, 0 for UC16 (usyed below). |
| 4364 __ lw(t0, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset)); | 4585 __ lw(t0, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset)); |
| 4365 __ movz(t9, t0, a0); // If UC16 (a0 is 0), replace t9 w/kDataUC16CodeOffset. | 4586 __ movz(t9, t0, a0); // If UC16 (a0 is 0), replace t9 w/kDataUC16CodeOffset. |
| 4366 | 4587 |
| 4367 // Check that the irregexp code has been generated for the actual string | 4588 // Check that the irregexp code has been generated for the actual string |
| 4368 // encoding. If it has, the field contains a code object otherwise it | 4589 // encoding. If it has, the field contains a code object otherwise it contains |
| 4369 // contains the hole. | 4590 // a smi (code flushing support). |
| 4370 __ GetObjectType(t9, a0, a0); | 4591 __ JumpIfSmi(t9, &runtime); |
| 4371 __ Branch(&runtime, ne, a0, Operand(CODE_TYPE)); | |
| 4372 | 4592 |
| 4373 // a3: encoding of subject string (1 if ASCII, 0 if two_byte); | 4593 // a3: encoding of subject string (1 if ASCII, 0 if two_byte); |
| 4374 // t9: code | 4594 // t9: code |
| 4375 // subject: Subject string | 4595 // subject: Subject string |
| 4376 // regexp_data: RegExp data (FixedArray) | 4596 // regexp_data: RegExp data (FixedArray) |
| 4377 // Load used arguments before starting to push arguments for call to native | 4597 // Load used arguments before starting to push arguments for call to native |
| 4378 // RegExp code to avoid handling changing stack height. | 4598 // RegExp code to avoid handling changing stack height. |
| 4379 __ lw(a1, MemOperand(sp, kPreviousIndexOffset)); | 4599 __ lw(a1, MemOperand(sp, kPreviousIndexOffset)); |
| 4380 __ sra(a1, a1, kSmiTagSize); // Untag the Smi. | 4600 __ sra(a1, a1, kSmiTagSize); // Untag the Smi. |
| 4381 | 4601 |
| (...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4685 __ Branch(&slow, ne, a2, Operand(JS_FUNCTION_TYPE)); | 4905 __ Branch(&slow, ne, a2, Operand(JS_FUNCTION_TYPE)); |
| 4686 | 4906 |
| 4687 // Fast-case: Invoke the function now. | 4907 // Fast-case: Invoke the function now. |
| 4688 // a1: pushed function | 4908 // a1: pushed function |
| 4689 ParameterCount actual(argc_); | 4909 ParameterCount actual(argc_); |
| 4690 | 4910 |
| 4691 if (ReceiverMightBeImplicit()) { | 4911 if (ReceiverMightBeImplicit()) { |
| 4692 Label call_as_function; | 4912 Label call_as_function; |
| 4693 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 4913 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
| 4694 __ Branch(&call_as_function, eq, t0, Operand(at)); | 4914 __ Branch(&call_as_function, eq, t0, Operand(at)); |
| 4695 __ InvokeFunction(a1, actual, JUMP_FUNCTION); | 4915 __ InvokeFunction(a1, |
| 4916 actual, |
| 4917 JUMP_FUNCTION, |
| 4918 NullCallWrapper(), |
| 4919 CALL_AS_METHOD); |
| 4696 __ bind(&call_as_function); | 4920 __ bind(&call_as_function); |
| 4697 } | 4921 } |
| 4698 __ InvokeFunction(a1, | 4922 __ InvokeFunction(a1, |
| 4699 actual, | 4923 actual, |
| 4700 JUMP_FUNCTION, | 4924 JUMP_FUNCTION, |
| 4701 NullCallWrapper(), | 4925 NullCallWrapper(), |
| 4702 CALL_AS_FUNCTION); | 4926 CALL_AS_FUNCTION); |
| 4703 | 4927 |
| 4704 // Slow-case: Non-function called. | 4928 // Slow-case: Non-function called. |
| 4705 __ bind(&slow); | 4929 __ bind(&slow); |
| (...skipping 1639 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6345 __ LeaveInternalFrame(); | 6569 __ LeaveInternalFrame(); |
| 6346 // Compute the entry point of the rewritten stub. | 6570 // Compute the entry point of the rewritten stub. |
| 6347 __ Addu(a2, v0, Operand(Code::kHeaderSize - kHeapObjectTag)); | 6571 __ Addu(a2, v0, Operand(Code::kHeaderSize - kHeapObjectTag)); |
| 6348 // Restore registers. | 6572 // Restore registers. |
| 6349 __ pop(ra); | 6573 __ pop(ra); |
| 6350 __ pop(a0); | 6574 __ pop(a0); |
| 6351 __ pop(a1); | 6575 __ pop(a1); |
| 6352 __ Jump(a2); | 6576 __ Jump(a2); |
| 6353 } | 6577 } |
| 6354 | 6578 |
| 6579 |
| 6355 void DirectCEntryStub::Generate(MacroAssembler* masm) { | 6580 void DirectCEntryStub::Generate(MacroAssembler* masm) { |
| 6356 // No need to pop or drop anything, LeaveExitFrame will restore the old | 6581 // No need to pop or drop anything, LeaveExitFrame will restore the old |
| 6357 // stack, thus dropping the allocated space for the return value. | 6582 // stack, thus dropping the allocated space for the return value. |
| 6358 // The saved ra is after the reserved stack space for the 4 args. | 6583 // The saved ra is after the reserved stack space for the 4 args. |
| 6359 __ lw(t9, MemOperand(sp, kCArgsSlotsSize)); | 6584 __ lw(t9, MemOperand(sp, kCArgsSlotsSize)); |
| 6360 | 6585 |
| 6361 if (FLAG_debug_code && EnableSlowAsserts()) { | 6586 if (FLAG_debug_code && EnableSlowAsserts()) { |
| 6362 // In case of an error the return address may point to a memory area | 6587 // In case of an error the return address may point to a memory area |
| 6363 // filled with kZapValue by the GC. | 6588 // filled with kZapValue by the GC. |
| 6364 // Dereference the address and check for this. | 6589 // Dereference the address and check for this. |
| 6365 __ lw(t0, MemOperand(t9)); | 6590 __ lw(t0, MemOperand(t9)); |
| 6366 __ Assert(ne, "Received invalid return address.", t0, | 6591 __ Assert(ne, "Received invalid return address.", t0, |
| 6367 Operand(reinterpret_cast<uint32_t>(kZapValue))); | 6592 Operand(reinterpret_cast<uint32_t>(kZapValue))); |
| 6368 } | 6593 } |
| 6369 __ Jump(t9); | 6594 __ Jump(t9); |
| 6370 } | 6595 } |
| 6371 | 6596 |
| 6372 | 6597 |
| 6373 void DirectCEntryStub::GenerateCall(MacroAssembler* masm, | 6598 void DirectCEntryStub::GenerateCall(MacroAssembler* masm, |
| 6374 ExternalReference function) { | 6599 ExternalReference function) { |
| 6375 __ li(t9, Operand(function)); | 6600 __ li(t9, Operand(function)); |
| 6376 this->GenerateCall(masm, t9); | 6601 this->GenerateCall(masm, t9); |
| 6377 } | 6602 } |
| 6378 | 6603 |
| 6604 |
| 6379 void DirectCEntryStub::GenerateCall(MacroAssembler* masm, | 6605 void DirectCEntryStub::GenerateCall(MacroAssembler* masm, |
| 6380 Register target) { | 6606 Register target) { |
| 6381 __ Move(t9, target); | 6607 __ Move(t9, target); |
| 6382 __ AssertStackIsAligned(); | 6608 __ AssertStackIsAligned(); |
| 6383 // Allocate space for arg slots. | 6609 // Allocate space for arg slots. |
| 6384 __ Subu(sp, sp, kCArgsSlotsSize); | 6610 __ Subu(sp, sp, kCArgsSlotsSize); |
| 6385 | 6611 |
| 6386 // Block the trampoline pool through the whole function to make sure the | 6612 // Block the trampoline pool through the whole function to make sure the |
| 6387 // number of generated instructions is constant. | 6613 // number of generated instructions is constant. |
| 6388 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm); | 6614 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm); |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6647 __ mov(result, zero_reg); | 6873 __ mov(result, zero_reg); |
| 6648 __ Ret(); | 6874 __ Ret(); |
| 6649 } | 6875 } |
| 6650 | 6876 |
| 6651 | 6877 |
| 6652 #undef __ | 6878 #undef __ |
| 6653 | 6879 |
| 6654 } } // namespace v8::internal | 6880 } } // namespace v8::internal |
| 6655 | 6881 |
| 6656 #endif // V8_TARGET_ARCH_MIPS | 6882 #endif // V8_TARGET_ARCH_MIPS |
| OLD | NEW |