| 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 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 62 __ ldr(scratch1, FieldMemOperand(operand, HeapObject::kMapOffset)); | 62 __ ldr(scratch1, FieldMemOperand(operand, HeapObject::kMapOffset)); |
| 63 __ LoadRoot(scratch2, Heap::kHeapNumberMapRootIndex); | 63 __ LoadRoot(scratch2, Heap::kHeapNumberMapRootIndex); |
| 64 __ cmp(scratch1, scratch2); | 64 __ cmp(scratch1, scratch2); |
| 65 __ b(ne, not_a_heap_number); | 65 __ b(ne, not_a_heap_number); |
| 66 } | 66 } |
| 67 | 67 |
| 68 | 68 |
| 69 void ToNumberStub::Generate(MacroAssembler* masm) { | 69 void ToNumberStub::Generate(MacroAssembler* masm) { |
| 70 // The ToNumber stub takes one argument in eax. | 70 // The ToNumber stub takes one argument in eax. |
| 71 Label check_heap_number, call_builtin; | 71 Label check_heap_number, call_builtin; |
| 72 __ tst(r0, Operand(kSmiTagMask)); | 72 __ JumpIfNotSmi(r0, &check_heap_number); |
| 73 __ b(ne, &check_heap_number); | |
| 74 __ Ret(); | 73 __ Ret(); |
| 75 | 74 |
| 76 __ bind(&check_heap_number); | 75 __ bind(&check_heap_number); |
| 77 EmitCheckForHeapNumber(masm, r0, r1, ip, &call_builtin); | 76 EmitCheckForHeapNumber(masm, r0, r1, ip, &call_builtin); |
| 78 __ Ret(); | 77 __ Ret(); |
| 79 | 78 |
| 80 __ bind(&call_builtin); | 79 __ bind(&call_builtin); |
| 81 __ push(r0); | 80 __ push(r0); |
| 82 __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION); | 81 __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION); |
| 83 } | 82 } |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 151 r0, | 150 r0, |
| 152 r1, | 151 r1, |
| 153 r2, | 152 r2, |
| 154 &gc, | 153 &gc, |
| 155 TAG_OBJECT); | 154 TAG_OBJECT); |
| 156 | 155 |
| 157 // Load the function from the stack. | 156 // Load the function from the stack. |
| 158 __ ldr(r3, MemOperand(sp, 0)); | 157 __ ldr(r3, MemOperand(sp, 0)); |
| 159 | 158 |
| 160 // Setup the object header. | 159 // Setup the object header. |
| 161 __ LoadRoot(r2, Heap::kContextMapRootIndex); | 160 __ LoadRoot(r2, Heap::kFunctionContextMapRootIndex); |
| 162 __ str(r2, FieldMemOperand(r0, HeapObject::kMapOffset)); | 161 __ str(r2, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 163 __ mov(r2, Operand(Smi::FromInt(length))); | 162 __ mov(r2, Operand(Smi::FromInt(length))); |
| 164 __ str(r2, FieldMemOperand(r0, FixedArray::kLengthOffset)); | 163 __ str(r2, FieldMemOperand(r0, FixedArray::kLengthOffset)); |
| 165 | 164 |
| 166 // Setup the fixed slots. | 165 // Setup the fixed slots. |
| 167 __ mov(r1, Operand(Smi::FromInt(0))); | 166 __ mov(r1, Operand(Smi::FromInt(0))); |
| 168 __ str(r3, MemOperand(r0, Context::SlotOffset(Context::CLOSURE_INDEX))); | 167 __ str(r3, MemOperand(r0, Context::SlotOffset(Context::CLOSURE_INDEX))); |
| 169 __ str(r0, MemOperand(r0, Context::SlotOffset(Context::FCONTEXT_INDEX))); | 168 __ str(cp, MemOperand(r0, Context::SlotOffset(Context::PREVIOUS_INDEX))); |
| 170 __ str(r1, MemOperand(r0, Context::SlotOffset(Context::PREVIOUS_INDEX))); | |
| 171 __ str(r1, MemOperand(r0, Context::SlotOffset(Context::EXTENSION_INDEX))); | 169 __ str(r1, MemOperand(r0, Context::SlotOffset(Context::EXTENSION_INDEX))); |
| 172 | 170 |
| 173 // Copy the global object from the surrounding context. | 171 // Copy the global object from the previous context. |
| 174 __ ldr(r1, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); | 172 __ ldr(r1, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 175 __ str(r1, MemOperand(r0, Context::SlotOffset(Context::GLOBAL_INDEX))); | 173 __ str(r1, MemOperand(r0, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 176 | 174 |
| 177 // Initialize the rest of the slots to undefined. | 175 // Initialize the rest of the slots to undefined. |
| 178 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex); | 176 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex); |
| 179 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { | 177 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { |
| 180 __ str(r1, MemOperand(r0, Context::SlotOffset(i))); | 178 __ str(r1, MemOperand(r0, Context::SlotOffset(i))); |
| 181 } | 179 } |
| 182 | 180 |
| 183 // Remove the on-stack argument and return. | 181 // Remove the on-stack argument and return. |
| 184 __ mov(cp, r0); | 182 __ mov(cp, r0); |
| 185 __ pop(); | 183 __ pop(); |
| 186 __ Ret(); | 184 __ Ret(); |
| 187 | 185 |
| 188 // Need to collect. Call into runtime system. | 186 // Need to collect. Call into runtime system. |
| 189 __ bind(&gc); | 187 __ bind(&gc); |
| 190 __ TailCallRuntime(Runtime::kNewContext, 1, 1); | 188 __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1); |
| 191 } | 189 } |
| 192 | 190 |
| 193 | 191 |
| 194 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { | 192 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { |
| 195 // Stack layout on entry: | 193 // Stack layout on entry: |
| 196 // | 194 // |
| 197 // [sp]: constant elements. | 195 // [sp]: constant elements. |
| 198 // [sp + kPointerSize]: literal index. | 196 // [sp + kPointerSize]: literal index. |
| 199 // [sp + (2 * kPointerSize)]: literals array. | 197 // [sp + (2 * kPointerSize)]: literals array. |
| 200 | 198 |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 Major MajorKey() { return ConvertToDouble; } | 297 Major MajorKey() { return ConvertToDouble; } |
| 300 int MinorKey() { | 298 int MinorKey() { |
| 301 // Encode the parameters in a unique 16 bit value. | 299 // Encode the parameters in a unique 16 bit value. |
| 302 return result1_.code() + | 300 return result1_.code() + |
| 303 (result2_.code() << 4) + | 301 (result2_.code() << 4) + |
| 304 (source_.code() << 8) + | 302 (source_.code() << 8) + |
| 305 (zeros_.code() << 12); | 303 (zeros_.code() << 12); |
| 306 } | 304 } |
| 307 | 305 |
| 308 void Generate(MacroAssembler* masm); | 306 void Generate(MacroAssembler* masm); |
| 309 | |
| 310 const char* GetName() { return "ConvertToDoubleStub"; } | |
| 311 | |
| 312 #ifdef DEBUG | |
| 313 void Print() { PrintF("ConvertToDoubleStub\n"); } | |
| 314 #endif | |
| 315 }; | 307 }; |
| 316 | 308 |
| 317 | 309 |
| 318 void ConvertToDoubleStub::Generate(MacroAssembler* masm) { | 310 void ConvertToDoubleStub::Generate(MacroAssembler* masm) { |
| 319 Register exponent = result1_; | 311 Register exponent = result1_; |
| 320 Register mantissa = result2_; | 312 Register mantissa = result2_; |
| 321 | 313 |
| 322 Label not_special; | 314 Label not_special; |
| 323 // Convert from Smi to integer. | 315 // Convert from Smi to integer. |
| 324 __ mov(source_, Operand(source_, ASR, kSmiTagSize)); | 316 __ mov(source_, Operand(source_, ASR, kSmiTagSize)); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 387 if (destination == kCoreRegisters) { | 379 if (destination == kCoreRegisters) { |
| 388 __ vmov(r2, r3, d7); | 380 __ vmov(r2, r3, d7); |
| 389 __ vmov(r0, r1, d6); | 381 __ vmov(r0, r1, d6); |
| 390 } | 382 } |
| 391 } else { | 383 } else { |
| 392 ASSERT(destination == kCoreRegisters); | 384 ASSERT(destination == kCoreRegisters); |
| 393 // Write Smi from r0 to r3 and r2 in double format. | 385 // Write Smi from r0 to r3 and r2 in double format. |
| 394 __ mov(scratch1, Operand(r0)); | 386 __ mov(scratch1, Operand(r0)); |
| 395 ConvertToDoubleStub stub1(r3, r2, scratch1, scratch2); | 387 ConvertToDoubleStub stub1(r3, r2, scratch1, scratch2); |
| 396 __ push(lr); | 388 __ push(lr); |
| 397 __ Call(stub1.GetCode(), RelocInfo::CODE_TARGET); | 389 __ Call(stub1.GetCode()); |
| 398 // Write Smi from r1 to r1 and r0 in double format. | 390 // Write Smi from r1 to r1 and r0 in double format. |
| 399 __ mov(scratch1, Operand(r1)); | 391 __ mov(scratch1, Operand(r1)); |
| 400 ConvertToDoubleStub stub2(r1, r0, scratch1, scratch2); | 392 ConvertToDoubleStub stub2(r1, r0, scratch1, scratch2); |
| 401 __ Call(stub2.GetCode(), RelocInfo::CODE_TARGET); | 393 __ Call(stub2.GetCode()); |
| 402 __ pop(lr); | 394 __ pop(lr); |
| 403 } | 395 } |
| 404 } | 396 } |
| 405 | 397 |
| 406 | 398 |
| 407 void FloatingPointHelper::LoadOperands( | 399 void FloatingPointHelper::LoadOperands( |
| 408 MacroAssembler* masm, | 400 MacroAssembler* masm, |
| 409 FloatingPointHelper::Destination destination, | 401 FloatingPointHelper::Destination destination, |
| 410 Register heap_number_map, | 402 Register heap_number_map, |
| 411 Register scratch1, | 403 Register scratch1, |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 468 if (destination == kCoreRegisters) { | 460 if (destination == kCoreRegisters) { |
| 469 // Load the converted smi to dst1 and dst2 in double format. | 461 // Load the converted smi to dst1 and dst2 in double format. |
| 470 __ vmov(dst1, dst2, dst); | 462 __ vmov(dst1, dst2, dst); |
| 471 } | 463 } |
| 472 } else { | 464 } else { |
| 473 ASSERT(destination == kCoreRegisters); | 465 ASSERT(destination == kCoreRegisters); |
| 474 // Write smi to dst1 and dst2 double format. | 466 // Write smi to dst1 and dst2 double format. |
| 475 __ mov(scratch1, Operand(object)); | 467 __ mov(scratch1, Operand(object)); |
| 476 ConvertToDoubleStub stub(dst2, dst1, scratch1, scratch2); | 468 ConvertToDoubleStub stub(dst2, dst1, scratch1, scratch2); |
| 477 __ push(lr); | 469 __ push(lr); |
| 478 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET); | 470 __ Call(stub.GetCode()); |
| 479 __ pop(lr); | 471 __ pop(lr); |
| 480 } | 472 } |
| 481 | 473 |
| 482 __ bind(&done); | 474 __ bind(&done); |
| 483 } | 475 } |
| 484 | 476 |
| 485 | 477 |
| 486 void FloatingPointHelper::ConvertNumberToInt32(MacroAssembler* masm, | 478 void FloatingPointHelper::ConvertNumberToInt32(MacroAssembler* masm, |
| 487 Register object, | 479 Register object, |
| 488 Register dst, | 480 Register dst, |
| (...skipping 435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 924 __ b(ne, ¬_identical); | 916 __ b(ne, ¬_identical); |
| 925 | 917 |
| 926 // The two objects are identical. If we know that one of them isn't NaN then | 918 // The two objects are identical. If we know that one of them isn't NaN then |
| 927 // we now know they test equal. | 919 // we now know they test equal. |
| 928 if (cond != eq || !never_nan_nan) { | 920 if (cond != eq || !never_nan_nan) { |
| 929 // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(), | 921 // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(), |
| 930 // so we do the second best thing - test it ourselves. | 922 // so we do the second best thing - test it ourselves. |
| 931 // They are both equal and they are not both Smis so both of them are not | 923 // They are both equal and they are not both Smis so both of them are not |
| 932 // Smis. If it's not a heap number, then return equal. | 924 // Smis. If it's not a heap number, then return equal. |
| 933 if (cond == lt || cond == gt) { | 925 if (cond == lt || cond == gt) { |
| 934 __ CompareObjectType(r0, r4, r4, FIRST_JS_OBJECT_TYPE); | 926 __ CompareObjectType(r0, r4, r4, FIRST_SPEC_OBJECT_TYPE); |
| 935 __ b(ge, slow); | 927 __ b(ge, slow); |
| 936 } else { | 928 } else { |
| 937 __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE); | 929 __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE); |
| 938 __ b(eq, &heap_number); | 930 __ b(eq, &heap_number); |
| 939 // Comparing JS objects with <=, >= is complicated. | 931 // Comparing JS objects with <=, >= is complicated. |
| 940 if (cond != eq) { | 932 if (cond != eq) { |
| 941 __ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE)); | 933 __ cmp(r4, Operand(FIRST_SPEC_OBJECT_TYPE)); |
| 942 __ b(ge, slow); | 934 __ b(ge, slow); |
| 943 // Normally here we fall through to return_equal, but undefined is | 935 // Normally here we fall through to return_equal, but undefined is |
| 944 // special: (undefined == undefined) == true, but | 936 // special: (undefined == undefined) == true, but |
| 945 // (undefined <= undefined) == false! See ECMAScript 11.8.5. | 937 // (undefined <= undefined) == false! See ECMAScript 11.8.5. |
| 946 if (cond == le || cond == ge) { | 938 if (cond == le || cond == ge) { |
| 947 __ cmp(r4, Operand(ODDBALL_TYPE)); | 939 __ cmp(r4, Operand(ODDBALL_TYPE)); |
| 948 __ b(ne, &return_equal); | 940 __ b(ne, &return_equal); |
| 949 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); | 941 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); |
| 950 __ cmp(r0, r2); | 942 __ cmp(r0, r2); |
| 951 __ b(ne, &return_equal); | 943 __ b(ne, &return_equal); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1022 static void EmitSmiNonsmiComparison(MacroAssembler* masm, | 1014 static void EmitSmiNonsmiComparison(MacroAssembler* masm, |
| 1023 Register lhs, | 1015 Register lhs, |
| 1024 Register rhs, | 1016 Register rhs, |
| 1025 Label* lhs_not_nan, | 1017 Label* lhs_not_nan, |
| 1026 Label* slow, | 1018 Label* slow, |
| 1027 bool strict) { | 1019 bool strict) { |
| 1028 ASSERT((lhs.is(r0) && rhs.is(r1)) || | 1020 ASSERT((lhs.is(r0) && rhs.is(r1)) || |
| 1029 (lhs.is(r1) && rhs.is(r0))); | 1021 (lhs.is(r1) && rhs.is(r0))); |
| 1030 | 1022 |
| 1031 Label rhs_is_smi; | 1023 Label rhs_is_smi; |
| 1032 __ tst(rhs, Operand(kSmiTagMask)); | 1024 __ JumpIfSmi(rhs, &rhs_is_smi); |
| 1033 __ b(eq, &rhs_is_smi); | |
| 1034 | 1025 |
| 1035 // Lhs is a Smi. Check whether the rhs is a heap number. | 1026 // Lhs is a Smi. Check whether the rhs is a heap number. |
| 1036 __ CompareObjectType(rhs, r4, r4, HEAP_NUMBER_TYPE); | 1027 __ CompareObjectType(rhs, r4, r4, HEAP_NUMBER_TYPE); |
| 1037 if (strict) { | 1028 if (strict) { |
| 1038 // If rhs is not a number and lhs is a Smi then strict equality cannot | 1029 // If rhs is not a number and lhs is a Smi then strict equality cannot |
| 1039 // succeed. Return non-equal | 1030 // succeed. Return non-equal |
| 1040 // If rhs is r0 then there is already a non zero value in it. | 1031 // If rhs is r0 then there is already a non zero value in it. |
| 1041 if (!rhs.is(r0)) { | 1032 if (!rhs.is(r0)) { |
| 1042 __ mov(r0, Operand(NOT_EQUAL), LeaveCC, ne); | 1033 __ mov(r0, Operand(NOT_EQUAL), LeaveCC, ne); |
| 1043 } | 1034 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1054 CpuFeatures::Scope scope(VFP3); | 1045 CpuFeatures::Scope scope(VFP3); |
| 1055 __ SmiToDoubleVFPRegister(lhs, d7, r7, s15); | 1046 __ SmiToDoubleVFPRegister(lhs, d7, r7, s15); |
| 1056 // Load the double from rhs, tagged HeapNumber r0, to d6. | 1047 // Load the double from rhs, tagged HeapNumber r0, to d6. |
| 1057 __ sub(r7, rhs, Operand(kHeapObjectTag)); | 1048 __ sub(r7, rhs, Operand(kHeapObjectTag)); |
| 1058 __ vldr(d6, r7, HeapNumber::kValueOffset); | 1049 __ vldr(d6, r7, HeapNumber::kValueOffset); |
| 1059 } else { | 1050 } else { |
| 1060 __ push(lr); | 1051 __ push(lr); |
| 1061 // Convert lhs to a double in r2, r3. | 1052 // Convert lhs to a double in r2, r3. |
| 1062 __ mov(r7, Operand(lhs)); | 1053 __ mov(r7, Operand(lhs)); |
| 1063 ConvertToDoubleStub stub1(r3, r2, r7, r6); | 1054 ConvertToDoubleStub stub1(r3, r2, r7, r6); |
| 1064 __ Call(stub1.GetCode(), RelocInfo::CODE_TARGET); | 1055 __ Call(stub1.GetCode()); |
| 1065 // Load rhs to a double in r0, r1. | 1056 // Load rhs to a double in r0, r1. |
| 1066 __ Ldrd(r0, r1, FieldMemOperand(rhs, HeapNumber::kValueOffset)); | 1057 __ Ldrd(r0, r1, FieldMemOperand(rhs, HeapNumber::kValueOffset)); |
| 1067 __ pop(lr); | 1058 __ pop(lr); |
| 1068 } | 1059 } |
| 1069 | 1060 |
| 1070 // We now have both loaded as doubles but we can skip the lhs nan check | 1061 // We now have both loaded as doubles but we can skip the lhs nan check |
| 1071 // since it's a smi. | 1062 // since it's a smi. |
| 1072 __ jmp(lhs_not_nan); | 1063 __ jmp(lhs_not_nan); |
| 1073 | 1064 |
| 1074 __ bind(&rhs_is_smi); | 1065 __ bind(&rhs_is_smi); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1096 __ vldr(d7, r7, HeapNumber::kValueOffset); | 1087 __ vldr(d7, r7, HeapNumber::kValueOffset); |
| 1097 // Convert rhs to a double in d6 . | 1088 // Convert rhs to a double in d6 . |
| 1098 __ SmiToDoubleVFPRegister(rhs, d6, r7, s13); | 1089 __ SmiToDoubleVFPRegister(rhs, d6, r7, s13); |
| 1099 } else { | 1090 } else { |
| 1100 __ push(lr); | 1091 __ push(lr); |
| 1101 // Load lhs to a double in r2, r3. | 1092 // Load lhs to a double in r2, r3. |
| 1102 __ Ldrd(r2, r3, FieldMemOperand(lhs, HeapNumber::kValueOffset)); | 1093 __ Ldrd(r2, r3, FieldMemOperand(lhs, HeapNumber::kValueOffset)); |
| 1103 // Convert rhs to a double in r0, r1. | 1094 // Convert rhs to a double in r0, r1. |
| 1104 __ mov(r7, Operand(rhs)); | 1095 __ mov(r7, Operand(rhs)); |
| 1105 ConvertToDoubleStub stub2(r1, r0, r7, r6); | 1096 ConvertToDoubleStub stub2(r1, r0, r7, r6); |
| 1106 __ Call(stub2.GetCode(), RelocInfo::CODE_TARGET); | 1097 __ Call(stub2.GetCode()); |
| 1107 __ pop(lr); | 1098 __ pop(lr); |
| 1108 } | 1099 } |
| 1109 // Fall through to both_loaded_as_doubles. | 1100 // Fall through to both_loaded_as_doubles. |
| 1110 } | 1101 } |
| 1111 | 1102 |
| 1112 | 1103 |
| 1113 void EmitNanCheck(MacroAssembler* masm, Label* lhs_not_nan, Condition cond) { | 1104 void EmitNanCheck(MacroAssembler* masm, Label* lhs_not_nan, Condition cond) { |
| 1114 bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset); | 1105 bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset); |
| 1115 Register rhs_exponent = exp_first ? r0 : r1; | 1106 Register rhs_exponent = exp_first ? r0 : r1; |
| 1116 Register lhs_exponent = exp_first ? r2 : r3; | 1107 Register lhs_exponent = exp_first ? r2 : r3; |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1213 } | 1204 } |
| 1214 | 1205 |
| 1215 | 1206 |
| 1216 // See comment at call site. | 1207 // See comment at call site. |
| 1217 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, | 1208 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, |
| 1218 Register lhs, | 1209 Register lhs, |
| 1219 Register rhs) { | 1210 Register rhs) { |
| 1220 ASSERT((lhs.is(r0) && rhs.is(r1)) || | 1211 ASSERT((lhs.is(r0) && rhs.is(r1)) || |
| 1221 (lhs.is(r1) && rhs.is(r0))); | 1212 (lhs.is(r1) && rhs.is(r0))); |
| 1222 | 1213 |
| 1223 // If either operand is a JSObject or an oddball value, then they are | 1214 // If either operand is a JS object or an oddball value, then they are |
| 1224 // not equal since their pointers are different. | 1215 // not equal since their pointers are different. |
| 1225 // There is no test for undetectability in strict equality. | 1216 // There is no test for undetectability in strict equality. |
| 1226 STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 1217 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE); |
| 1227 Label first_non_object; | 1218 Label first_non_object; |
| 1228 // Get the type of the first operand into r2 and compare it with | 1219 // Get the type of the first operand into r2 and compare it with |
| 1229 // FIRST_JS_OBJECT_TYPE. | 1220 // FIRST_SPEC_OBJECT_TYPE. |
| 1230 __ CompareObjectType(rhs, r2, r2, FIRST_JS_OBJECT_TYPE); | 1221 __ CompareObjectType(rhs, r2, r2, FIRST_SPEC_OBJECT_TYPE); |
| 1231 __ b(lt, &first_non_object); | 1222 __ b(lt, &first_non_object); |
| 1232 | 1223 |
| 1233 // Return non-zero (r0 is not zero) | 1224 // Return non-zero (r0 is not zero) |
| 1234 Label return_not_equal; | 1225 Label return_not_equal; |
| 1235 __ bind(&return_not_equal); | 1226 __ bind(&return_not_equal); |
| 1236 __ Ret(); | 1227 __ Ret(); |
| 1237 | 1228 |
| 1238 __ bind(&first_non_object); | 1229 __ bind(&first_non_object); |
| 1239 // Check for oddballs: true, false, null, undefined. | 1230 // Check for oddballs: true, false, null, undefined. |
| 1240 __ cmp(r2, Operand(ODDBALL_TYPE)); | 1231 __ cmp(r2, Operand(ODDBALL_TYPE)); |
| 1241 __ b(eq, &return_not_equal); | 1232 __ b(eq, &return_not_equal); |
| 1242 | 1233 |
| 1243 __ CompareObjectType(lhs, r3, r3, FIRST_JS_OBJECT_TYPE); | 1234 __ CompareObjectType(lhs, r3, r3, FIRST_SPEC_OBJECT_TYPE); |
| 1244 __ b(ge, &return_not_equal); | 1235 __ b(ge, &return_not_equal); |
| 1245 | 1236 |
| 1246 // Check for oddballs: true, false, null, undefined. | 1237 // Check for oddballs: true, false, null, undefined. |
| 1247 __ cmp(r3, Operand(ODDBALL_TYPE)); | 1238 __ cmp(r3, Operand(ODDBALL_TYPE)); |
| 1248 __ b(eq, &return_not_equal); | 1239 __ b(eq, &return_not_equal); |
| 1249 | 1240 |
| 1250 // Now that we have the types we might as well check for symbol-symbol. | 1241 // Now that we have the types we might as well check for symbol-symbol. |
| 1251 // Ensure that no non-strings have the symbol bit set. | 1242 // Ensure that no non-strings have the symbol bit set. |
| 1252 STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsSymbolMask); | 1243 STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsSymbolMask); |
| 1253 STATIC_ASSERT(kSymbolTag != 0); | 1244 STATIC_ASSERT(kSymbolTag != 0); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1310 __ b(ge, not_both_strings); | 1301 __ b(ge, not_both_strings); |
| 1311 __ tst(r3, Operand(kIsSymbolMask)); | 1302 __ tst(r3, Operand(kIsSymbolMask)); |
| 1312 __ b(eq, possible_strings); | 1303 __ b(eq, possible_strings); |
| 1313 | 1304 |
| 1314 // Both are symbols. We already checked they weren't the same pointer | 1305 // Both are symbols. We already checked they weren't the same pointer |
| 1315 // so they are not equal. | 1306 // so they are not equal. |
| 1316 __ mov(r0, Operand(NOT_EQUAL)); | 1307 __ mov(r0, Operand(NOT_EQUAL)); |
| 1317 __ Ret(); | 1308 __ Ret(); |
| 1318 | 1309 |
| 1319 __ bind(&object_test); | 1310 __ bind(&object_test); |
| 1320 __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE)); | 1311 __ cmp(r2, Operand(FIRST_SPEC_OBJECT_TYPE)); |
| 1321 __ b(lt, not_both_strings); | 1312 __ b(lt, not_both_strings); |
| 1322 __ CompareObjectType(lhs, r2, r3, FIRST_JS_OBJECT_TYPE); | 1313 __ CompareObjectType(lhs, r2, r3, FIRST_SPEC_OBJECT_TYPE); |
| 1323 __ b(lt, not_both_strings); | 1314 __ b(lt, not_both_strings); |
| 1324 // If both objects are undetectable, they are equal. Otherwise, they | 1315 // If both objects are undetectable, they are equal. Otherwise, they |
| 1325 // are not equal, since they are different objects and an object is not | 1316 // are not equal, since they are different objects and an object is not |
| 1326 // equal to undefined. | 1317 // equal to undefined. |
| 1327 __ ldr(r3, FieldMemOperand(rhs, HeapObject::kMapOffset)); | 1318 __ ldr(r3, FieldMemOperand(rhs, HeapObject::kMapOffset)); |
| 1328 __ ldrb(r2, FieldMemOperand(r2, Map::kBitFieldOffset)); | 1319 __ ldrb(r2, FieldMemOperand(r2, Map::kBitFieldOffset)); |
| 1329 __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset)); | 1320 __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset)); |
| 1330 __ and_(r0, r2, Operand(r3)); | 1321 __ and_(r0, r2, Operand(r3)); |
| 1331 __ and_(r0, r0, Operand(1 << Map::kIsUndetectable)); | 1322 __ and_(r0, r0, Operand(1 << Map::kIsUndetectable)); |
| 1332 __ eor(r0, r0, Operand(1 << Map::kIsUndetectable)); | 1323 __ eor(r0, r0, Operand(1 << Map::kIsUndetectable)); |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1451 void CompareStub::Generate(MacroAssembler* masm) { | 1442 void CompareStub::Generate(MacroAssembler* masm) { |
| 1452 ASSERT((lhs_.is(r0) && rhs_.is(r1)) || | 1443 ASSERT((lhs_.is(r0) && rhs_.is(r1)) || |
| 1453 (lhs_.is(r1) && rhs_.is(r0))); | 1444 (lhs_.is(r1) && rhs_.is(r0))); |
| 1454 | 1445 |
| 1455 Label slow; // Call builtin. | 1446 Label slow; // Call builtin. |
| 1456 Label not_smis, both_loaded_as_doubles, lhs_not_nan; | 1447 Label not_smis, both_loaded_as_doubles, lhs_not_nan; |
| 1457 | 1448 |
| 1458 if (include_smi_compare_) { | 1449 if (include_smi_compare_) { |
| 1459 Label not_two_smis, smi_done; | 1450 Label not_two_smis, smi_done; |
| 1460 __ orr(r2, r1, r0); | 1451 __ orr(r2, r1, r0); |
| 1461 __ tst(r2, Operand(kSmiTagMask)); | 1452 __ JumpIfNotSmi(r2, ¬_two_smis); |
| 1462 __ b(ne, ¬_two_smis); | |
| 1463 __ mov(r1, Operand(r1, ASR, 1)); | 1453 __ mov(r1, Operand(r1, ASR, 1)); |
| 1464 __ sub(r0, r1, Operand(r0, ASR, 1)); | 1454 __ sub(r0, r1, Operand(r0, ASR, 1)); |
| 1465 __ Ret(); | 1455 __ Ret(); |
| 1466 __ bind(¬_two_smis); | 1456 __ bind(¬_two_smis); |
| 1467 } else if (FLAG_debug_code) { | 1457 } else if (FLAG_debug_code) { |
| 1468 __ orr(r2, r1, r0); | 1458 __ orr(r2, r1, r0); |
| 1469 __ tst(r2, Operand(kSmiTagMask)); | 1459 __ tst(r2, Operand(kSmiTagMask)); |
| 1470 __ Assert(ne, "CompareStub: unexpected smi operands."); | 1460 __ Assert(ne, "CompareStub: unexpected smi operands."); |
| 1471 } | 1461 } |
| 1472 | 1462 |
| 1473 // NOTICE! This code is only reached after a smi-fast-case check, so | 1463 // NOTICE! This code is only reached after a smi-fast-case check, so |
| 1474 // it is certain that at least one operand isn't a smi. | 1464 // it is certain that at least one operand isn't a smi. |
| 1475 | 1465 |
| 1476 // Handle the case where the objects are identical. Either returns the answer | 1466 // Handle the case where the objects are identical. Either returns the answer |
| 1477 // or goes to slow. Only falls through if the objects were not identical. | 1467 // or goes to slow. Only falls through if the objects were not identical. |
| 1478 EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_); | 1468 EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_); |
| 1479 | 1469 |
| 1480 // If either is a Smi (we know that not both are), then they can only | 1470 // If either is a Smi (we know that not both are), then they can only |
| 1481 // be strictly equal if the other is a HeapNumber. | 1471 // be strictly equal if the other is a HeapNumber. |
| 1482 STATIC_ASSERT(kSmiTag == 0); | 1472 STATIC_ASSERT(kSmiTag == 0); |
| 1483 ASSERT_EQ(0, Smi::FromInt(0)); | 1473 ASSERT_EQ(0, Smi::FromInt(0)); |
| 1484 __ and_(r2, lhs_, Operand(rhs_)); | 1474 __ and_(r2, lhs_, Operand(rhs_)); |
| 1485 __ tst(r2, Operand(kSmiTagMask)); | 1475 __ JumpIfNotSmi(r2, ¬_smis); |
| 1486 __ b(ne, ¬_smis); | |
| 1487 // One operand is a smi. EmitSmiNonsmiComparison generates code that can: | 1476 // One operand is a smi. EmitSmiNonsmiComparison generates code that can: |
| 1488 // 1) Return the answer. | 1477 // 1) Return the answer. |
| 1489 // 2) Go to slow. | 1478 // 2) Go to slow. |
| 1490 // 3) Fall through to both_loaded_as_doubles. | 1479 // 3) Fall through to both_loaded_as_doubles. |
| 1491 // 4) Jump to lhs_not_nan. | 1480 // 4) Jump to lhs_not_nan. |
| 1492 // In cases 3 and 4 we have found out we were dealing with a number-number | 1481 // In cases 3 and 4 we have found out we were dealing with a number-number |
| 1493 // comparison. If VFP3 is supported the double values of the numbers have | 1482 // comparison. If VFP3 is supported the double values of the numbers have |
| 1494 // been loaded into d7 and d6. Otherwise, the double values have been loaded | 1483 // been loaded into d7 and d6. Otherwise, the double values have been loaded |
| 1495 // into r0, r1, r2, and r3. | 1484 // into r0, r1, r2, and r3. |
| 1496 EmitSmiNonsmiComparison(masm, lhs_, rhs_, &lhs_not_nan, &slow, strict_); | 1485 EmitSmiNonsmiComparison(masm, lhs_, rhs_, &lhs_not_nan, &slow, strict_); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1607 __ mov(r0, Operand(Smi::FromInt(ncr))); | 1596 __ mov(r0, Operand(Smi::FromInt(ncr))); |
| 1608 __ push(r0); | 1597 __ push(r0); |
| 1609 } | 1598 } |
| 1610 | 1599 |
| 1611 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) | 1600 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) |
| 1612 // tagged as a small integer. | 1601 // tagged as a small integer. |
| 1613 __ InvokeBuiltin(native, JUMP_FUNCTION); | 1602 __ InvokeBuiltin(native, JUMP_FUNCTION); |
| 1614 } | 1603 } |
| 1615 | 1604 |
| 1616 | 1605 |
| 1617 // This stub does not handle the inlined cases (Smis, Booleans, undefined). | |
| 1618 // The stub returns zero for false, and a non-zero value for true. | 1606 // The stub returns zero for false, and a non-zero value for true. |
| 1619 void ToBooleanStub::Generate(MacroAssembler* masm) { | 1607 void ToBooleanStub::Generate(MacroAssembler* masm) { |
| 1620 // This stub uses VFP3 instructions. | 1608 // This stub uses VFP3 instructions. |
| 1621 CpuFeatures::Scope scope(VFP3); | 1609 CpuFeatures::Scope scope(VFP3); |
| 1622 | 1610 |
| 1623 Label false_result; | 1611 Label false_result, true_result, not_string; |
| 1624 Label not_heap_number; | 1612 const Register map = r9.is(tos_) ? r7 : r9; |
| 1625 Register scratch = r9.is(tos_) ? r7 : r9; | |
| 1626 | 1613 |
| 1627 // undefined -> false | 1614 // undefined -> false |
| 1628 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | 1615 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); |
| 1629 __ cmp(tos_, ip); | 1616 __ cmp(tos_, ip); |
| 1630 __ b(eq, &false_result); | 1617 __ b(eq, &false_result); |
| 1631 | 1618 |
| 1632 // Boolean -> its value | 1619 // Boolean -> its value |
| 1633 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | 1620 __ LoadRoot(ip, Heap::kFalseValueRootIndex); |
| 1634 __ cmp(tos_, ip); | 1621 __ cmp(tos_, ip); |
| 1635 __ b(eq, &false_result); | 1622 __ b(eq, &false_result); |
| 1636 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 1623 __ LoadRoot(ip, Heap::kTrueValueRootIndex); |
| 1637 __ cmp(tos_, ip); | 1624 __ cmp(tos_, ip); |
| 1638 // "tos_" is a register and contains a non-zero value. Hence we implicitly | 1625 // "tos_" is a register and contains a non-zero value. Hence we implicitly |
| 1639 // return true if the equal condition is satisfied. | 1626 // return true if the equal condition is satisfied. |
| 1640 __ Ret(eq); | 1627 __ Ret(eq); |
| 1641 | 1628 |
| 1642 // Smis: 0 -> false, all other -> true | 1629 // Smis: 0 -> false, all other -> true |
| 1643 __ tst(tos_, tos_); | 1630 __ tst(tos_, tos_); |
| 1644 __ b(eq, &false_result); | 1631 __ b(eq, &false_result); |
| 1645 __ tst(tos_, Operand(kSmiTagMask)); | 1632 __ tst(tos_, Operand(kSmiTagMask)); |
| 1646 // "tos_" is a register and contains a non-zero value. Hence we implicitly | 1633 // "tos_" is a register and contains a non-zero value. Hence we implicitly |
| 1647 // return true if the not equal condition is satisfied. | 1634 // return true if the not equal condition is satisfied. |
| 1648 __ Ret(eq); | 1635 __ Ret(eq); |
| 1649 | 1636 |
| 1650 // 'null' -> false | 1637 // 'null' -> false |
| 1651 __ LoadRoot(ip, Heap::kNullValueRootIndex); | 1638 __ LoadRoot(ip, Heap::kNullValueRootIndex); |
| 1652 __ cmp(tos_, ip); | 1639 __ cmp(tos_, ip); |
| 1653 __ b(eq, &false_result); | 1640 __ b(eq, &false_result); |
| 1654 | 1641 |
| 1655 // HeapNumber => false iff +0, -0, or NaN. | 1642 // Get the map of the heap object. |
| 1656 __ ldr(scratch, FieldMemOperand(tos_, HeapObject::kMapOffset)); | 1643 __ ldr(map, FieldMemOperand(tos_, HeapObject::kMapOffset)); |
| 1657 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); | 1644 |
| 1658 __ cmp(scratch, ip); | 1645 // Undetectable -> false. |
| 1659 __ b(¬_heap_number, ne); | 1646 __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset)); |
| 1647 __ tst(ip, Operand(1 << Map::kIsUndetectable)); |
| 1648 __ b(&false_result, ne); |
| 1649 |
| 1650 // JavaScript object -> true. |
| 1651 __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE); |
| 1652 // "tos_" is a register and contains a non-zero value. Hence we implicitly |
| 1653 // return true if the greater than condition is satisfied. |
| 1654 __ Ret(ge); |
| 1655 |
| 1656 // String value -> false iff empty. |
| 1657 __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE); |
| 1658 __ b(¬_string, ge); |
| 1659 __ ldr(tos_, FieldMemOperand(tos_, String::kLengthOffset)); |
| 1660 // Return string length as boolean value, i.e. return false iff length is 0. |
| 1661 __ Ret(); |
| 1662 |
| 1663 __ bind(¬_string); |
| 1664 // HeapNumber -> false iff +0, -0, or NaN. |
| 1665 __ CompareRoot(map, Heap::kHeapNumberMapRootIndex); |
| 1666 __ b(&true_result, ne); |
| 1660 __ vldr(d1, FieldMemOperand(tos_, HeapNumber::kValueOffset)); | 1667 __ vldr(d1, FieldMemOperand(tos_, HeapNumber::kValueOffset)); |
| 1661 __ VFPCompareAndSetFlags(d1, 0.0); | 1668 __ VFPCompareAndSetFlags(d1, 0.0); |
| 1662 // "tos_" is a register, and contains a non zero value by default. | 1669 // "tos_" is a register, and contains a non zero value by default. |
| 1663 // Hence we only need to overwrite "tos_" with zero to return false for | 1670 // Hence we only need to overwrite "tos_" with zero to return false for |
| 1664 // FP_ZERO or FP_NAN cases. Otherwise, by default it returns true. | 1671 // FP_ZERO or FP_NAN cases. Otherwise, by default it returns true. |
| 1665 __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, eq); // for FP_ZERO | 1672 __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, eq); // for FP_ZERO |
| 1666 __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, vs); // for FP_NAN | 1673 __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, vs); // for FP_NAN |
| 1667 __ Ret(); | 1674 __ Ret(); |
| 1668 | 1675 |
| 1669 __ bind(¬_heap_number); | 1676 // Return 1/0 for true/false in tos_. |
| 1670 | 1677 __ bind(&true_result); |
| 1671 // It can be an undetectable object. | 1678 __ mov(tos_, Operand(1, RelocInfo::NONE)); |
| 1672 // Undetectable => false. | |
| 1673 __ ldr(ip, FieldMemOperand(tos_, HeapObject::kMapOffset)); | |
| 1674 __ ldrb(scratch, FieldMemOperand(ip, Map::kBitFieldOffset)); | |
| 1675 __ and_(scratch, scratch, Operand(1 << Map::kIsUndetectable)); | |
| 1676 __ cmp(scratch, Operand(1 << Map::kIsUndetectable)); | |
| 1677 __ b(&false_result, eq); | |
| 1678 | |
| 1679 // JavaScript object => true. | |
| 1680 __ ldr(scratch, FieldMemOperand(tos_, HeapObject::kMapOffset)); | |
| 1681 __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); | |
| 1682 __ cmp(scratch, Operand(FIRST_JS_OBJECT_TYPE)); | |
| 1683 // "tos_" is a register and contains a non-zero value. | |
| 1684 // Hence we implicitly return true if the greater than | |
| 1685 // condition is satisfied. | |
| 1686 __ Ret(gt); | |
| 1687 | |
| 1688 // Check for string | |
| 1689 __ ldr(scratch, FieldMemOperand(tos_, HeapObject::kMapOffset)); | |
| 1690 __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); | |
| 1691 __ cmp(scratch, Operand(FIRST_NONSTRING_TYPE)); | |
| 1692 // "tos_" is a register and contains a non-zero value. | |
| 1693 // Hence we implicitly return true if the greater than | |
| 1694 // condition is satisfied. | |
| 1695 __ Ret(gt); | |
| 1696 | |
| 1697 // String value => false iff empty, i.e., length is zero | |
| 1698 __ ldr(tos_, FieldMemOperand(tos_, String::kLengthOffset)); | |
| 1699 // If length is zero, "tos_" contains zero ==> false. | |
| 1700 // If length is not zero, "tos_" contains a non-zero value ==> true. | |
| 1701 __ Ret(); | 1679 __ Ret(); |
| 1702 | |
| 1703 // Return 0 in "tos_" for false . | |
| 1704 __ bind(&false_result); | 1680 __ bind(&false_result); |
| 1705 __ mov(tos_, Operand(0, RelocInfo::NONE)); | 1681 __ mov(tos_, Operand(0, RelocInfo::NONE)); |
| 1706 __ Ret(); | 1682 __ Ret(); |
| 1707 } | 1683 } |
| 1708 | 1684 |
| 1709 | 1685 |
| 1710 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { | 1686 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { |
| 1711 // We don't allow a GC during a store buffer overflow so there is no need to | 1687 // We don't allow a GC during a store buffer overflow so there is no need to |
| 1712 // store the registers in any particular way, but we do have to store and | 1688 // store the registers in any particular way, but we do have to store and |
| 1713 // restore them. | 1689 // restore them. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1733 for (int i = 0; i < DwVfpRegister::kNumRegisters; i++) { | 1709 for (int i = 0; i < DwVfpRegister::kNumRegisters; i++) { |
| 1734 DwVfpRegister reg = DwVfpRegister::from_code(i); | 1710 DwVfpRegister reg = DwVfpRegister::from_code(i); |
| 1735 __ vldr(reg, MemOperand(sp, i * kDoubleSize)); | 1711 __ vldr(reg, MemOperand(sp, i * kDoubleSize)); |
| 1736 } | 1712 } |
| 1737 __ add(sp, sp, Operand(kDoubleSize * DwVfpRegister::kNumRegisters)); | 1713 __ add(sp, sp, Operand(kDoubleSize * DwVfpRegister::kNumRegisters)); |
| 1738 } | 1714 } |
| 1739 __ ldm(ia_w, sp, kCallerSaved | pc.bit()); // Also pop pc to get Ret(0). | 1715 __ ldm(ia_w, sp, kCallerSaved | pc.bit()); // Also pop pc to get Ret(0). |
| 1740 } | 1716 } |
| 1741 | 1717 |
| 1742 | 1718 |
| 1743 Handle<Code> GetUnaryOpStub(int key, UnaryOpIC::TypeInfo type_info) { | |
| 1744 UnaryOpStub stub(key, type_info); | |
| 1745 return stub.GetCode(); | |
| 1746 } | |
| 1747 | |
| 1748 | |
| 1749 const char* UnaryOpStub::GetName() { | 1719 const char* UnaryOpStub::GetName() { |
| 1750 if (name_ != NULL) return name_; | 1720 if (name_ != NULL) return name_; |
| 1751 const int kMaxNameLength = 100; | 1721 const int kMaxNameLength = 100; |
| 1752 name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray( | 1722 name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray( |
| 1753 kMaxNameLength); | 1723 kMaxNameLength); |
| 1754 if (name_ == NULL) return "OOM"; | 1724 if (name_ == NULL) return "OOM"; |
| 1755 const char* op_name = Token::Name(op_); | 1725 const char* op_name = Token::Name(op_); |
| 1756 const char* overwrite_name = NULL; // Make g++ happy. | 1726 const char* overwrite_name = NULL; // Make g++ happy. |
| 1757 switch (mode_) { | 1727 switch (mode_) { |
| 1758 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; | 1728 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1781 GenerateHeapNumberStub(masm); | 1751 GenerateHeapNumberStub(masm); |
| 1782 break; | 1752 break; |
| 1783 case UnaryOpIC::GENERIC: | 1753 case UnaryOpIC::GENERIC: |
| 1784 GenerateGenericStub(masm); | 1754 GenerateGenericStub(masm); |
| 1785 break; | 1755 break; |
| 1786 } | 1756 } |
| 1787 } | 1757 } |
| 1788 | 1758 |
| 1789 | 1759 |
| 1790 void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { | 1760 void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { |
| 1791 // Prepare to push argument. | 1761 __ mov(r3, Operand(r0)); // the operand |
| 1792 __ mov(r3, Operand(r0)); | 1762 __ mov(r2, Operand(Smi::FromInt(op_))); |
| 1793 | 1763 __ mov(r1, Operand(Smi::FromInt(mode_))); |
| 1794 // Push this stub's key. Although the operation and the type info are | |
| 1795 // encoded into the key, the encoding is opaque, so push them too. | |
| 1796 __ mov(r2, Operand(Smi::FromInt(MinorKey()))); | |
| 1797 __ mov(r1, Operand(Smi::FromInt(op_))); | |
| 1798 __ mov(r0, Operand(Smi::FromInt(operand_type_))); | 1764 __ mov(r0, Operand(Smi::FromInt(operand_type_))); |
| 1799 | |
| 1800 __ Push(r3, r2, r1, r0); | 1765 __ Push(r3, r2, r1, r0); |
| 1801 | 1766 |
| 1802 __ TailCallExternalReference( | 1767 __ TailCallExternalReference( |
| 1803 ExternalReference(IC_Utility(IC::kUnaryOp_Patch), | 1768 ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1); |
| 1804 masm->isolate()), | |
| 1805 4, | |
| 1806 1); | |
| 1807 } | 1769 } |
| 1808 | 1770 |
| 1809 | 1771 |
| 1810 // TODO(svenpanne): Use virtual functions instead of switch. | 1772 // TODO(svenpanne): Use virtual functions instead of switch. |
| 1811 void UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) { | 1773 void UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) { |
| 1812 switch (op_) { | 1774 switch (op_) { |
| 1813 case Token::SUB: | 1775 case Token::SUB: |
| 1814 GenerateSmiStubSub(masm); | 1776 GenerateSmiStubSub(masm); |
| 1815 break; | 1777 break; |
| 1816 case Token::BIT_NOT: | 1778 case Token::BIT_NOT: |
| (...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2045 break; | 2007 break; |
| 2046 case Token::BIT_NOT: | 2008 case Token::BIT_NOT: |
| 2047 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); | 2009 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); |
| 2048 break; | 2010 break; |
| 2049 default: | 2011 default: |
| 2050 UNREACHABLE(); | 2012 UNREACHABLE(); |
| 2051 } | 2013 } |
| 2052 } | 2014 } |
| 2053 | 2015 |
| 2054 | 2016 |
| 2055 Handle<Code> GetBinaryOpStub(int key, | |
| 2056 BinaryOpIC::TypeInfo type_info, | |
| 2057 BinaryOpIC::TypeInfo result_type_info) { | |
| 2058 BinaryOpStub stub(key, type_info, result_type_info); | |
| 2059 return stub.GetCode(); | |
| 2060 } | |
| 2061 | |
| 2062 | |
| 2063 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { | 2017 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { |
| 2064 Label get_result; | 2018 Label get_result; |
| 2065 | 2019 |
| 2066 __ Push(r1, r0); | 2020 __ Push(r1, r0); |
| 2067 | 2021 |
| 2068 __ mov(r2, Operand(Smi::FromInt(MinorKey()))); | 2022 __ mov(r2, Operand(Smi::FromInt(MinorKey()))); |
| 2069 __ mov(r1, Operand(Smi::FromInt(op_))); | 2023 __ mov(r1, Operand(Smi::FromInt(op_))); |
| 2070 __ mov(r0, Operand(Smi::FromInt(operands_type_))); | 2024 __ mov(r0, Operand(Smi::FromInt(operands_type_))); |
| 2071 __ Push(r2, r1, r0); | 2025 __ Push(r2, r1, r0); |
| 2072 | 2026 |
| (...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2487 Label not_smis; | 2441 Label not_smis; |
| 2488 | 2442 |
| 2489 Register left = r1; | 2443 Register left = r1; |
| 2490 Register right = r0; | 2444 Register right = r0; |
| 2491 Register scratch1 = r7; | 2445 Register scratch1 = r7; |
| 2492 Register scratch2 = r9; | 2446 Register scratch2 = r9; |
| 2493 | 2447 |
| 2494 // Perform combined smi check on both operands. | 2448 // Perform combined smi check on both operands. |
| 2495 __ orr(scratch1, left, Operand(right)); | 2449 __ orr(scratch1, left, Operand(right)); |
| 2496 STATIC_ASSERT(kSmiTag == 0); | 2450 STATIC_ASSERT(kSmiTag == 0); |
| 2497 __ tst(scratch1, Operand(kSmiTagMask)); | 2451 __ JumpIfNotSmi(scratch1, ¬_smis); |
| 2498 __ b(ne, ¬_smis); | |
| 2499 | 2452 |
| 2500 // If the smi-smi operation results in a smi return is generated. | 2453 // If the smi-smi operation results in a smi return is generated. |
| 2501 GenerateSmiSmiOperation(masm); | 2454 GenerateSmiSmiOperation(masm); |
| 2502 | 2455 |
| 2503 // If heap number results are possible generate the result in an allocated | 2456 // If heap number results are possible generate the result in an allocated |
| 2504 // heap number. | 2457 // heap number. |
| 2505 if (allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS) { | 2458 if (allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS) { |
| 2506 GenerateFPOperation(masm, true, use_runtime, gc_required); | 2459 GenerateFPOperation(masm, true, use_runtime, gc_required); |
| 2507 } | 2460 } |
| 2508 __ bind(¬_smis); | 2461 __ bind(¬_smis); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2601 GenerateSmiSmiOperation(masm); | 2554 GenerateSmiSmiOperation(masm); |
| 2602 // Fall through if the result is not a smi. | 2555 // Fall through if the result is not a smi. |
| 2603 __ bind(&skip); | 2556 __ bind(&skip); |
| 2604 | 2557 |
| 2605 switch (op_) { | 2558 switch (op_) { |
| 2606 case Token::ADD: | 2559 case Token::ADD: |
| 2607 case Token::SUB: | 2560 case Token::SUB: |
| 2608 case Token::MUL: | 2561 case Token::MUL: |
| 2609 case Token::DIV: | 2562 case Token::DIV: |
| 2610 case Token::MOD: { | 2563 case Token::MOD: { |
| 2611 // Load both operands and check that they are 32-bit integer. | 2564 // Load both operands and check that they are 32-bit integer. |
| 2612 // Jump to type transition if they are not. The registers r0 and r1 (right | 2565 // Jump to type transition if they are not. The registers r0 and r1 (right |
| 2613 // and left) are preserved for the runtime call. | 2566 // and left) are preserved for the runtime call. |
| 2614 FloatingPointHelper::Destination destination = | 2567 FloatingPointHelper::Destination destination = |
| 2615 CpuFeatures::IsSupported(VFP3) && | 2568 (CpuFeatures::IsSupported(VFP3) && op_ != Token::MOD) |
| 2616 op_ != Token::MOD ? | 2569 ? FloatingPointHelper::kVFPRegisters |
| 2617 FloatingPointHelper::kVFPRegisters : | 2570 : FloatingPointHelper::kCoreRegisters; |
| 2618 FloatingPointHelper::kCoreRegisters; | |
| 2619 | 2571 |
| 2620 FloatingPointHelper::LoadNumberAsInt32Double(masm, | 2572 FloatingPointHelper::LoadNumberAsInt32Double(masm, |
| 2621 right, | 2573 right, |
| 2622 destination, | 2574 destination, |
| 2623 d7, | 2575 d7, |
| 2624 r2, | 2576 r2, |
| 2625 r3, | 2577 r3, |
| 2626 heap_number_map, | 2578 heap_number_map, |
| 2627 scratch1, | 2579 scratch1, |
| 2628 scratch2, | 2580 scratch2, |
| 2629 s0, | 2581 s0, |
| 2630 &transition); | 2582 &transition); |
| 2631 FloatingPointHelper::LoadNumberAsInt32Double(masm, | 2583 FloatingPointHelper::LoadNumberAsInt32Double(masm, |
| 2632 left, | 2584 left, |
| 2633 destination, | 2585 destination, |
| 2634 d6, | 2586 d6, |
| 2635 r4, | 2587 r4, |
| 2636 r5, | 2588 r5, |
| 2637 heap_number_map, | 2589 heap_number_map, |
| 2638 scratch1, | 2590 scratch1, |
| 2639 scratch2, | 2591 scratch2, |
| 2640 s0, | 2592 s0, |
| 2641 &transition); | 2593 &transition); |
| 2642 | 2594 |
| 2643 if (destination == FloatingPointHelper::kVFPRegisters) { | 2595 if (destination == FloatingPointHelper::kVFPRegisters) { |
| 2644 CpuFeatures::Scope scope(VFP3); | 2596 CpuFeatures::Scope scope(VFP3); |
| 2645 Label return_heap_number; | 2597 Label return_heap_number; |
| 2646 switch (op_) { | 2598 switch (op_) { |
| 2647 case Token::ADD: | 2599 case Token::ADD: |
| 2648 __ vadd(d5, d6, d7); | 2600 __ vadd(d5, d6, d7); |
| 2649 break; | 2601 break; |
| 2650 case Token::SUB: | 2602 case Token::SUB: |
| 2651 __ vsub(d5, d6, d7); | 2603 __ vsub(d5, d6, d7); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2692 __ b(ne, &return_heap_number); | 2644 __ b(ne, &return_heap_number); |
| 2693 __ bind(¬_zero); | 2645 __ bind(¬_zero); |
| 2694 | 2646 |
| 2695 // Tag the result and return. | 2647 // Tag the result and return. |
| 2696 __ SmiTag(r0, scratch1); | 2648 __ SmiTag(r0, scratch1); |
| 2697 __ Ret(); | 2649 __ Ret(); |
| 2698 } else { | 2650 } else { |
| 2699 // DIV just falls through to allocating a heap number. | 2651 // DIV just falls through to allocating a heap number. |
| 2700 } | 2652 } |
| 2701 | 2653 |
| 2702 if (result_type_ >= (op_ == Token::DIV) ? BinaryOpIC::HEAP_NUMBER | 2654 __ bind(&return_heap_number); |
| 2703 : BinaryOpIC::INT32) { | 2655 // Return a heap number, or fall through to type transition or runtime |
| 2704 __ bind(&return_heap_number); | 2656 // call if we can't. |
| 2657 if (result_type_ >= ((op_ == Token::DIV) ? BinaryOpIC::HEAP_NUMBER |
| 2658 : BinaryOpIC::INT32)) { |
| 2705 // We are using vfp registers so r5 is available. | 2659 // We are using vfp registers so r5 is available. |
| 2706 heap_number_result = r5; | 2660 heap_number_result = r5; |
| 2707 GenerateHeapResultAllocation(masm, | 2661 GenerateHeapResultAllocation(masm, |
| 2708 heap_number_result, | 2662 heap_number_result, |
| 2709 heap_number_map, | 2663 heap_number_map, |
| 2710 scratch1, | 2664 scratch1, |
| 2711 scratch2, | 2665 scratch2, |
| 2712 &call_runtime); | 2666 &call_runtime); |
| 2713 __ sub(r0, heap_number_result, Operand(kHeapObjectTag)); | 2667 __ sub(r0, heap_number_result, Operand(kHeapObjectTag)); |
| 2714 __ vstr(d5, r0, HeapNumber::kValueOffset); | 2668 __ vstr(d5, r0, HeapNumber::kValueOffset); |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2868 __ TailCallStub(&stub); | 2822 __ TailCallStub(&stub); |
| 2869 } | 2823 } |
| 2870 | 2824 |
| 2871 break; | 2825 break; |
| 2872 } | 2826 } |
| 2873 | 2827 |
| 2874 default: | 2828 default: |
| 2875 UNREACHABLE(); | 2829 UNREACHABLE(); |
| 2876 } | 2830 } |
| 2877 | 2831 |
| 2878 if (transition.is_linked()) { | 2832 // We never expect DIV to yield an integer result, so we always generate |
| 2833 // type transition code for DIV operations expecting an integer result: the |
| 2834 // code will fall through to this type transition. |
| 2835 if (transition.is_linked() || |
| 2836 ((op_ == Token::DIV) && (result_type_ <= BinaryOpIC::INT32))) { |
| 2879 __ bind(&transition); | 2837 __ bind(&transition); |
| 2880 GenerateTypeTransition(masm); | 2838 GenerateTypeTransition(masm); |
| 2881 } | 2839 } |
| 2882 | 2840 |
| 2883 __ bind(&call_runtime); | 2841 __ bind(&call_runtime); |
| 2884 GenerateCallRuntime(masm); | 2842 GenerateCallRuntime(masm); |
| 2885 } | 2843 } |
| 2886 | 2844 |
| 2887 | 2845 |
| 2888 void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { | 2846 void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { |
| (...skipping 548 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3437 __ b(eq, &alignment_as_expected); | 3395 __ b(eq, &alignment_as_expected); |
| 3438 // Don't use Check here, as it will call Runtime_Abort re-entering here. | 3396 // Don't use Check here, as it will call Runtime_Abort re-entering here. |
| 3439 __ stop("Unexpected alignment"); | 3397 __ stop("Unexpected alignment"); |
| 3440 __ bind(&alignment_as_expected); | 3398 __ bind(&alignment_as_expected); |
| 3441 } | 3399 } |
| 3442 } | 3400 } |
| 3443 #endif | 3401 #endif |
| 3444 | 3402 |
| 3445 __ mov(r2, Operand(ExternalReference::isolate_address())); | 3403 __ mov(r2, Operand(ExternalReference::isolate_address())); |
| 3446 | 3404 |
| 3447 | 3405 // To let the GC traverse the return address of the exit frames, we need to |
| 3448 // TODO(1242173): To let the GC traverse the return address of the exit | 3406 // know where the return address is. The CEntryStub is unmovable, so |
| 3449 // frames, we need to know where the return address is. Right now, | 3407 // we can store the address on the stack to be able to find it again and |
| 3450 // we store it on the stack to be able to find it again, but we never | 3408 // we never have to restore it, because it will not change. |
| 3451 // restore from it in case of changes, which makes it impossible to | |
| 3452 // support moving the C entry code stub. This should be fixed, but currently | |
| 3453 // this is OK because the CEntryStub gets generated so early in the V8 boot | |
| 3454 // sequence that it is not moving ever. | |
| 3455 | |
| 3456 // Compute the return address in lr to return to after the jump below. Pc is | 3409 // Compute the return address in lr to return to after the jump below. Pc is |
| 3457 // already at '+ 8' from the current instruction but return is after three | 3410 // already at '+ 8' from the current instruction but return is after three |
| 3458 // instructions so add another 4 to pc to get the return address. | 3411 // instructions so add another 4 to pc to get the return address. |
| 3459 masm->add(lr, pc, Operand(4)); | 3412 masm->add(lr, pc, Operand(4)); |
| 3460 __ str(lr, MemOperand(sp, 0)); | 3413 __ str(lr, MemOperand(sp, 0)); |
| 3461 masm->Jump(r5); | 3414 masm->Jump(r5); |
| 3462 | 3415 |
| 3463 if (always_allocate) { | 3416 if (always_allocate) { |
| 3464 // It's okay to clobber r2 and r3 here. Don't mess with r0 and r1 | 3417 // It's okay to clobber r2 and r3 here. Don't mess with r0 and r1 |
| 3465 // though (contain the result). | 3418 // though (contain the result). |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3595 // r3: argc | 3548 // r3: argc |
| 3596 // [sp+0]: argv | 3549 // [sp+0]: argv |
| 3597 | 3550 |
| 3598 Label invoke, exit; | 3551 Label invoke, exit; |
| 3599 | 3552 |
| 3600 // Called from C, so do not pop argc and args on exit (preserve sp) | 3553 // Called from C, so do not pop argc and args on exit (preserve sp) |
| 3601 // No need to save register-passed args | 3554 // No need to save register-passed args |
| 3602 // Save callee-saved registers (incl. cp and fp), sp, and lr | 3555 // Save callee-saved registers (incl. cp and fp), sp, and lr |
| 3603 __ stm(db_w, sp, kCalleeSaved | lr.bit()); | 3556 __ stm(db_w, sp, kCalleeSaved | lr.bit()); |
| 3604 | 3557 |
| 3558 if (CpuFeatures::IsSupported(VFP3)) { |
| 3559 CpuFeatures::Scope scope(VFP3); |
| 3560 // Save callee-saved vfp registers. |
| 3561 __ vstm(db_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg); |
| 3562 // Set up the reserved register for 0.0. |
| 3563 __ vmov(kDoubleRegZero, 0.0); |
| 3564 } |
| 3565 |
| 3605 // Get address of argv, see stm above. | 3566 // Get address of argv, see stm above. |
| 3606 // r0: code entry | 3567 // r0: code entry |
| 3607 // r1: function | 3568 // r1: function |
| 3608 // r2: receiver | 3569 // r2: receiver |
| 3609 // r3: argc | 3570 // r3: argc |
| 3610 __ ldr(r4, MemOperand(sp, (kNumCalleeSaved + 1) * kPointerSize)); // argv | 3571 |
| 3572 // Setup argv in r4. |
| 3573 int offset_to_argv = (kNumCalleeSaved + 1) * kPointerSize; |
| 3574 if (CpuFeatures::IsSupported(VFP3)) { |
| 3575 offset_to_argv += kNumDoubleCalleeSaved * kDoubleSize; |
| 3576 } |
| 3577 __ ldr(r4, MemOperand(sp, offset_to_argv)); |
| 3611 | 3578 |
| 3612 // Push a frame with special values setup to mark it as an entry frame. | 3579 // Push a frame with special values setup to mark it as an entry frame. |
| 3613 // r0: code entry | 3580 // r0: code entry |
| 3614 // r1: function | 3581 // r1: function |
| 3615 // r2: receiver | 3582 // r2: receiver |
| 3616 // r3: argc | 3583 // r3: argc |
| 3617 // r4: argv | 3584 // r4: argv |
| 3618 Isolate* isolate = masm->isolate(); | 3585 Isolate* isolate = masm->isolate(); |
| 3619 __ mov(r8, Operand(-1)); // Push a bad frame pointer to fail if it is used. | 3586 __ mov(r8, Operand(-1)); // Push a bad frame pointer to fail if it is used. |
| 3620 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; | 3587 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3725 | 3692 |
| 3726 // Reset the stack to the callee saved registers. | 3693 // Reset the stack to the callee saved registers. |
| 3727 __ add(sp, sp, Operand(-EntryFrameConstants::kCallerFPOffset)); | 3694 __ add(sp, sp, Operand(-EntryFrameConstants::kCallerFPOffset)); |
| 3728 | 3695 |
| 3729 // Restore callee-saved registers and return. | 3696 // Restore callee-saved registers and return. |
| 3730 #ifdef DEBUG | 3697 #ifdef DEBUG |
| 3731 if (FLAG_debug_code) { | 3698 if (FLAG_debug_code) { |
| 3732 __ mov(lr, Operand(pc)); | 3699 __ mov(lr, Operand(pc)); |
| 3733 } | 3700 } |
| 3734 #endif | 3701 #endif |
| 3702 |
| 3703 if (CpuFeatures::IsSupported(VFP3)) { |
| 3704 CpuFeatures::Scope scope(VFP3); |
| 3705 // Restore callee-saved vfp registers. |
| 3706 __ vldm(ia_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg); |
| 3707 } |
| 3708 |
| 3735 __ ldm(ia_w, sp, kCalleeSaved | pc.bit()); | 3709 __ ldm(ia_w, sp, kCalleeSaved | pc.bit()); |
| 3736 } | 3710 } |
| 3737 | 3711 |
| 3738 | 3712 |
| 3739 // Uses registers r0 to r4. | 3713 // Uses registers r0 to r4. |
| 3740 // Expected input (depending on whether args are in registers or on the stack): | 3714 // Expected input (depending on whether args are in registers or on the stack): |
| 3741 // * object: r0 or at sp + 1 * kPointerSize. | 3715 // * object: r0 or at sp + 1 * kPointerSize. |
| 3742 // * function: r1 or at sp. | 3716 // * function: r1 or at sp. |
| 3743 // | 3717 // |
| 3744 // An inlined call site may have been generated before calling this stub. | 3718 // An inlined call site may have been generated before calling this stub. |
| (...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3964 __ Jump(lr); | 3938 __ Jump(lr); |
| 3965 | 3939 |
| 3966 // Slow-case: Handle non-smi or out-of-bounds access to arguments | 3940 // Slow-case: Handle non-smi or out-of-bounds access to arguments |
| 3967 // by calling the runtime system. | 3941 // by calling the runtime system. |
| 3968 __ bind(&slow); | 3942 __ bind(&slow); |
| 3969 __ push(r1); | 3943 __ push(r1); |
| 3970 __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1); | 3944 __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1); |
| 3971 } | 3945 } |
| 3972 | 3946 |
| 3973 | 3947 |
| 3974 void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) { | 3948 void ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) { |
| 3975 // sp[0] : number of parameters | 3949 // sp[0] : number of parameters |
| 3976 // sp[4] : receiver displacement | 3950 // sp[4] : receiver displacement |
| 3977 // sp[8] : function | 3951 // sp[8] : function |
| 3978 | 3952 |
| 3979 // Check if the calling frame is an arguments adaptor frame. | 3953 // Check if the calling frame is an arguments adaptor frame. |
| 3954 Label runtime; |
| 3955 __ ldr(r3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
| 3956 __ ldr(r2, MemOperand(r3, StandardFrameConstants::kContextOffset)); |
| 3957 __ cmp(r2, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 3958 __ b(ne, &runtime); |
| 3959 |
| 3960 // Patch the arguments.length and the parameters pointer in the current frame. |
| 3961 __ ldr(r2, MemOperand(r3, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 3962 __ str(r2, MemOperand(sp, 0 * kPointerSize)); |
| 3963 __ add(r3, r3, Operand(r2, LSL, 1)); |
| 3964 __ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset)); |
| 3965 __ str(r3, MemOperand(sp, 1 * kPointerSize)); |
| 3966 |
| 3967 __ bind(&runtime); |
| 3968 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); |
| 3969 } |
| 3970 |
| 3971 |
| 3972 void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) { |
| 3973 // Stack layout: |
| 3974 // sp[0] : number of parameters (tagged) |
| 3975 // sp[4] : address of receiver argument |
| 3976 // sp[8] : function |
| 3977 // Registers used over whole function: |
| 3978 // r6 : allocated object (tagged) |
| 3979 // r9 : mapped parameter count (tagged) |
| 3980 |
| 3981 __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); |
| 3982 // r1 = parameter count (tagged) |
| 3983 |
| 3984 // Check if the calling frame is an arguments adaptor frame. |
| 3985 Label runtime; |
| 3986 Label adaptor_frame, try_allocate; |
| 3987 __ ldr(r3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
| 3988 __ ldr(r2, MemOperand(r3, StandardFrameConstants::kContextOffset)); |
| 3989 __ cmp(r2, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 3990 __ b(eq, &adaptor_frame); |
| 3991 |
| 3992 // No adaptor, parameter count = argument count. |
| 3993 __ mov(r2, r1); |
| 3994 __ b(&try_allocate); |
| 3995 |
| 3996 // We have an adaptor frame. Patch the parameters pointer. |
| 3997 __ bind(&adaptor_frame); |
| 3998 __ ldr(r2, MemOperand(r3, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 3999 __ add(r3, r3, Operand(r2, LSL, 1)); |
| 4000 __ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset)); |
| 4001 __ str(r3, MemOperand(sp, 1 * kPointerSize)); |
| 4002 |
| 4003 // r1 = parameter count (tagged) |
| 4004 // r2 = argument count (tagged) |
| 4005 // Compute the mapped parameter count = min(r1, r2) in r1. |
| 4006 __ cmp(r1, Operand(r2)); |
| 4007 __ mov(r1, Operand(r2), LeaveCC, gt); |
| 4008 |
| 4009 __ bind(&try_allocate); |
| 4010 |
| 4011 // Compute the sizes of backing store, parameter map, and arguments object. |
| 4012 // 1. Parameter map, has 2 extra words containing context and backing store. |
| 4013 const int kParameterMapHeaderSize = |
| 4014 FixedArray::kHeaderSize + 2 * kPointerSize; |
| 4015 // If there are no mapped parameters, we do not need the parameter_map. |
| 4016 __ cmp(r1, Operand(Smi::FromInt(0))); |
| 4017 __ mov(r9, Operand(0), LeaveCC, eq); |
| 4018 __ mov(r9, Operand(r1, LSL, 1), LeaveCC, ne); |
| 4019 __ add(r9, r9, Operand(kParameterMapHeaderSize), LeaveCC, ne); |
| 4020 |
| 4021 // 2. Backing store. |
| 4022 __ add(r9, r9, Operand(r2, LSL, 1)); |
| 4023 __ add(r9, r9, Operand(FixedArray::kHeaderSize)); |
| 4024 |
| 4025 // 3. Arguments object. |
| 4026 __ add(r9, r9, Operand(Heap::kArgumentsObjectSize)); |
| 4027 |
| 4028 // Do the allocation of all three objects in one go. |
| 4029 __ AllocateInNewSpace(r9, r0, r3, r4, &runtime, TAG_OBJECT); |
| 4030 |
| 4031 // r0 = address of new object(s) (tagged) |
| 4032 // r2 = argument count (tagged) |
| 4033 // Get the arguments boilerplate from the current (global) context into r4. |
| 4034 const int kNormalOffset = |
| 4035 Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX); |
| 4036 const int kAliasedOffset = |
| 4037 Context::SlotOffset(Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX); |
| 4038 |
| 4039 __ ldr(r4, MemOperand(r8, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 4040 __ ldr(r4, FieldMemOperand(r4, GlobalObject::kGlobalContextOffset)); |
| 4041 __ cmp(r1, Operand(0)); |
| 4042 __ ldr(r4, MemOperand(r4, kNormalOffset), eq); |
| 4043 __ ldr(r4, MemOperand(r4, kAliasedOffset), ne); |
| 4044 |
| 4045 // r0 = address of new object (tagged) |
| 4046 // r1 = mapped parameter count (tagged) |
| 4047 // r2 = argument count (tagged) |
| 4048 // r4 = address of boilerplate object (tagged) |
| 4049 // Copy the JS object part. |
| 4050 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { |
| 4051 __ ldr(r3, FieldMemOperand(r4, i)); |
| 4052 __ str(r3, FieldMemOperand(r0, i)); |
| 4053 } |
| 4054 |
| 4055 // Setup the callee in-object property. |
| 4056 STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1); |
| 4057 __ ldr(r3, MemOperand(sp, 2 * kPointerSize)); |
| 4058 const int kCalleeOffset = JSObject::kHeaderSize + |
| 4059 Heap::kArgumentsCalleeIndex * kPointerSize; |
| 4060 __ str(r3, FieldMemOperand(r0, kCalleeOffset)); |
| 4061 |
| 4062 // Use the length (smi tagged) and set that as an in-object property too. |
| 4063 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); |
| 4064 const int kLengthOffset = JSObject::kHeaderSize + |
| 4065 Heap::kArgumentsLengthIndex * kPointerSize; |
| 4066 __ str(r2, FieldMemOperand(r0, kLengthOffset)); |
| 4067 |
| 4068 // Setup the elements pointer in the allocated arguments object. |
| 4069 // If we allocated a parameter map, r4 will point there, otherwise |
| 4070 // it will point to the backing store. |
| 4071 __ add(r4, r0, Operand(Heap::kArgumentsObjectSize)); |
| 4072 __ str(r4, FieldMemOperand(r0, JSObject::kElementsOffset)); |
| 4073 |
| 4074 // r0 = address of new object (tagged) |
| 4075 // r1 = mapped parameter count (tagged) |
| 4076 // r2 = argument count (tagged) |
| 4077 // r4 = address of parameter map or backing store (tagged) |
| 4078 // Initialize parameter map. If there are no mapped arguments, we're done. |
| 4079 Label skip_parameter_map; |
| 4080 __ cmp(r1, Operand(Smi::FromInt(0))); |
| 4081 // Move backing store address to r3, because it is |
| 4082 // expected there when filling in the unmapped arguments. |
| 4083 __ mov(r3, r4, LeaveCC, eq); |
| 4084 __ b(eq, &skip_parameter_map); |
| 4085 |
| 4086 __ LoadRoot(r6, Heap::kNonStrictArgumentsElementsMapRootIndex); |
| 4087 __ str(r6, FieldMemOperand(r4, FixedArray::kMapOffset)); |
| 4088 __ add(r6, r1, Operand(Smi::FromInt(2))); |
| 4089 __ str(r6, FieldMemOperand(r4, FixedArray::kLengthOffset)); |
| 4090 __ str(r8, FieldMemOperand(r4, FixedArray::kHeaderSize + 0 * kPointerSize)); |
| 4091 __ add(r6, r4, Operand(r1, LSL, 1)); |
| 4092 __ add(r6, r6, Operand(kParameterMapHeaderSize)); |
| 4093 __ str(r6, FieldMemOperand(r4, FixedArray::kHeaderSize + 1 * kPointerSize)); |
| 4094 |
| 4095 // Copy the parameter slots and the holes in the arguments. |
| 4096 // We need to fill in mapped_parameter_count slots. They index the context, |
| 4097 // where parameters are stored in reverse order, at |
| 4098 // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1 |
| 4099 // The mapped parameter thus need to get indices |
| 4100 // MIN_CONTEXT_SLOTS+parameter_count-1 .. |
| 4101 // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count |
| 4102 // We loop from right to left. |
| 4103 Label parameters_loop, parameters_test; |
| 4104 __ mov(r6, r1); |
| 4105 __ ldr(r9, MemOperand(sp, 0 * kPointerSize)); |
| 4106 __ add(r9, r9, Operand(Smi::FromInt(Context::MIN_CONTEXT_SLOTS))); |
| 4107 __ sub(r9, r9, Operand(r1)); |
| 4108 __ LoadRoot(r7, Heap::kTheHoleValueRootIndex); |
| 4109 __ add(r3, r4, Operand(r6, LSL, 1)); |
| 4110 __ add(r3, r3, Operand(kParameterMapHeaderSize)); |
| 4111 |
| 4112 // r6 = loop variable (tagged) |
| 4113 // r1 = mapping index (tagged) |
| 4114 // r3 = address of backing store (tagged) |
| 4115 // r4 = address of parameter map (tagged) |
| 4116 // r5 = temporary scratch (a.o., for address calculation) |
| 4117 // r7 = the hole value |
| 4118 __ jmp(¶meters_test); |
| 4119 |
| 4120 __ bind(¶meters_loop); |
| 4121 __ sub(r6, r6, Operand(Smi::FromInt(1))); |
| 4122 __ mov(r5, Operand(r6, LSL, 1)); |
| 4123 __ add(r5, r5, Operand(kParameterMapHeaderSize - kHeapObjectTag)); |
| 4124 __ str(r9, MemOperand(r4, r5)); |
| 4125 __ sub(r5, r5, Operand(kParameterMapHeaderSize - FixedArray::kHeaderSize)); |
| 4126 __ str(r7, MemOperand(r3, r5)); |
| 4127 __ add(r9, r9, Operand(Smi::FromInt(1))); |
| 4128 __ bind(¶meters_test); |
| 4129 __ cmp(r6, Operand(Smi::FromInt(0))); |
| 4130 __ b(ne, ¶meters_loop); |
| 4131 |
| 4132 __ bind(&skip_parameter_map); |
| 4133 // r2 = argument count (tagged) |
| 4134 // r3 = address of backing store (tagged) |
| 4135 // r5 = scratch |
| 4136 // Copy arguments header and remaining slots (if there are any). |
| 4137 __ LoadRoot(r5, Heap::kFixedArrayMapRootIndex); |
| 4138 __ str(r5, FieldMemOperand(r3, FixedArray::kMapOffset)); |
| 4139 __ str(r2, FieldMemOperand(r3, FixedArray::kLengthOffset)); |
| 4140 |
| 4141 Label arguments_loop, arguments_test; |
| 4142 __ mov(r9, r1); |
| 4143 __ ldr(r4, MemOperand(sp, 1 * kPointerSize)); |
| 4144 __ sub(r4, r4, Operand(r9, LSL, 1)); |
| 4145 __ jmp(&arguments_test); |
| 4146 |
| 4147 __ bind(&arguments_loop); |
| 4148 __ sub(r4, r4, Operand(kPointerSize)); |
| 4149 __ ldr(r6, MemOperand(r4, 0)); |
| 4150 __ add(r5, r3, Operand(r9, LSL, 1)); |
| 4151 __ str(r6, FieldMemOperand(r5, FixedArray::kHeaderSize)); |
| 4152 __ add(r9, r9, Operand(Smi::FromInt(1))); |
| 4153 |
| 4154 __ bind(&arguments_test); |
| 4155 __ cmp(r9, Operand(r2)); |
| 4156 __ b(lt, &arguments_loop); |
| 4157 |
| 4158 // Return and remove the on-stack parameters. |
| 4159 __ add(sp, sp, Operand(3 * kPointerSize)); |
| 4160 __ Ret(); |
| 4161 |
| 4162 // Do the runtime call to allocate the arguments object. |
| 4163 // r2 = argument count (taggged) |
| 4164 __ bind(&runtime); |
| 4165 __ str(r2, MemOperand(sp, 0 * kPointerSize)); // Patch argument count. |
| 4166 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); |
| 4167 } |
| 4168 |
| 4169 |
| 4170 void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) { |
| 4171 // sp[0] : number of parameters |
| 4172 // sp[4] : receiver displacement |
| 4173 // sp[8] : function |
| 4174 // Check if the calling frame is an arguments adaptor frame. |
| 3980 Label adaptor_frame, try_allocate, runtime; | 4175 Label adaptor_frame, try_allocate, runtime; |
| 3981 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); | 4176 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
| 3982 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset)); | 4177 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset)); |
| 3983 __ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 4178 __ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 3984 __ b(eq, &adaptor_frame); | 4179 __ b(eq, &adaptor_frame); |
| 3985 | 4180 |
| 3986 // Get the length from the frame. | 4181 // Get the length from the frame. |
| 3987 __ ldr(r1, MemOperand(sp, 0)); | 4182 __ ldr(r1, MemOperand(sp, 0)); |
| 3988 __ b(&try_allocate); | 4183 __ b(&try_allocate); |
| 3989 | 4184 |
| 3990 // Patch the arguments.length and the parameters pointer. | 4185 // Patch the arguments.length and the parameters pointer. |
| 3991 __ bind(&adaptor_frame); | 4186 __ bind(&adaptor_frame); |
| 3992 __ ldr(r1, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 4187 __ ldr(r1, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 3993 __ str(r1, MemOperand(sp, 0)); | 4188 __ str(r1, MemOperand(sp, 0)); |
| 3994 __ add(r3, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize)); | 4189 __ add(r3, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize)); |
| 3995 __ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset)); | 4190 __ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset)); |
| 3996 __ str(r3, MemOperand(sp, 1 * kPointerSize)); | 4191 __ str(r3, MemOperand(sp, 1 * kPointerSize)); |
| 3997 | 4192 |
| 3998 // Try the new space allocation. Start out with computing the size | 4193 // Try the new space allocation. Start out with computing the size |
| 3999 // of the arguments object and the elements array in words. | 4194 // of the arguments object and the elements array in words. |
| 4000 Label add_arguments_object; | 4195 Label add_arguments_object; |
| 4001 __ bind(&try_allocate); | 4196 __ bind(&try_allocate); |
| 4002 __ cmp(r1, Operand(0, RelocInfo::NONE)); | 4197 __ cmp(r1, Operand(0, RelocInfo::NONE)); |
| 4003 __ b(eq, &add_arguments_object); | 4198 __ b(eq, &add_arguments_object); |
| 4004 __ mov(r1, Operand(r1, LSR, kSmiTagSize)); | 4199 __ mov(r1, Operand(r1, LSR, kSmiTagSize)); |
| 4005 __ add(r1, r1, Operand(FixedArray::kHeaderSize / kPointerSize)); | 4200 __ add(r1, r1, Operand(FixedArray::kHeaderSize / kPointerSize)); |
| 4006 __ bind(&add_arguments_object); | 4201 __ bind(&add_arguments_object); |
| 4007 __ add(r1, r1, Operand(GetArgumentsObjectSize() / kPointerSize)); | 4202 __ add(r1, r1, Operand(Heap::kArgumentsObjectSizeStrict / kPointerSize)); |
| 4008 | 4203 |
| 4009 // Do the allocation of both objects in one go. | 4204 // Do the allocation of both objects in one go. |
| 4010 __ AllocateInNewSpace( | 4205 __ AllocateInNewSpace(r1, |
| 4011 r1, | 4206 r0, |
| 4012 r0, | 4207 r2, |
| 4013 r2, | 4208 r3, |
| 4014 r3, | 4209 &runtime, |
| 4015 &runtime, | 4210 static_cast<AllocationFlags>(TAG_OBJECT | |
| 4016 static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS)); | 4211 SIZE_IN_WORDS)); |
| 4017 | 4212 |
| 4018 // Get the arguments boilerplate from the current (global) context. | 4213 // Get the arguments boilerplate from the current (global) context. |
| 4019 __ ldr(r4, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); | 4214 __ ldr(r4, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 4020 __ ldr(r4, FieldMemOperand(r4, GlobalObject::kGlobalContextOffset)); | 4215 __ ldr(r4, FieldMemOperand(r4, GlobalObject::kGlobalContextOffset)); |
| 4021 __ ldr(r4, MemOperand(r4, | 4216 __ ldr(r4, MemOperand(r4, Context::SlotOffset( |
| 4022 Context::SlotOffset(GetArgumentsBoilerplateIndex()))); | 4217 Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX))); |
| 4023 | 4218 |
| 4024 // Copy the JS object part. | 4219 // Copy the JS object part. |
| 4025 __ CopyFields(r0, r4, r3.bit(), JSObject::kHeaderSize / kPointerSize); | 4220 __ CopyFields(r0, r4, r3.bit(), JSObject::kHeaderSize / kPointerSize); |
| 4026 | 4221 |
| 4027 if (type_ == NEW_NON_STRICT) { | |
| 4028 // Setup the callee in-object property. | |
| 4029 STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1); | |
| 4030 __ ldr(r3, MemOperand(sp, 2 * kPointerSize)); | |
| 4031 const int kCalleeOffset = JSObject::kHeaderSize + | |
| 4032 Heap::kArgumentsCalleeIndex * kPointerSize; | |
| 4033 __ str(r3, FieldMemOperand(r0, kCalleeOffset)); | |
| 4034 } | |
| 4035 | |
| 4036 // Get the length (smi tagged) and set that as an in-object property too. | 4222 // Get the length (smi tagged) and set that as an in-object property too. |
| 4037 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); | 4223 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); |
| 4038 __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); | 4224 __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); |
| 4039 __ str(r1, FieldMemOperand(r0, JSObject::kHeaderSize + | 4225 __ str(r1, FieldMemOperand(r0, JSObject::kHeaderSize + |
| 4040 Heap::kArgumentsLengthIndex * kPointerSize)); | 4226 Heap::kArgumentsLengthIndex * kPointerSize)); |
| 4041 | 4227 |
| 4042 // If there are no actual arguments, we're done. | 4228 // If there are no actual arguments, we're done. |
| 4043 Label done; | 4229 Label done; |
| 4044 __ cmp(r1, Operand(0, RelocInfo::NONE)); | 4230 __ cmp(r1, Operand(0, RelocInfo::NONE)); |
| 4045 __ b(eq, &done); | 4231 __ b(eq, &done); |
| 4046 | 4232 |
| 4047 // Get the parameters pointer from the stack. | 4233 // Get the parameters pointer from the stack. |
| 4048 __ ldr(r2, MemOperand(sp, 1 * kPointerSize)); | 4234 __ ldr(r2, MemOperand(sp, 1 * kPointerSize)); |
| 4049 | 4235 |
| 4050 // Setup the elements pointer in the allocated arguments object and | 4236 // Setup the elements pointer in the allocated arguments object and |
| 4051 // initialize the header in the elements fixed array. | 4237 // initialize the header in the elements fixed array. |
| 4052 __ add(r4, r0, Operand(GetArgumentsObjectSize())); | 4238 __ add(r4, r0, Operand(Heap::kArgumentsObjectSizeStrict)); |
| 4053 __ str(r4, FieldMemOperand(r0, JSObject::kElementsOffset)); | 4239 __ str(r4, FieldMemOperand(r0, JSObject::kElementsOffset)); |
| 4054 __ LoadRoot(r3, Heap::kFixedArrayMapRootIndex); | 4240 __ LoadRoot(r3, Heap::kFixedArrayMapRootIndex); |
| 4055 __ str(r3, FieldMemOperand(r4, FixedArray::kMapOffset)); | 4241 __ str(r3, FieldMemOperand(r4, FixedArray::kMapOffset)); |
| 4056 __ str(r1, FieldMemOperand(r4, FixedArray::kLengthOffset)); | 4242 __ str(r1, FieldMemOperand(r4, FixedArray::kLengthOffset)); |
| 4057 __ mov(r1, Operand(r1, LSR, kSmiTagSize)); // Untag the length for the loop. | 4243 // Untag the length for the loop. |
| 4244 __ mov(r1, Operand(r1, LSR, kSmiTagSize)); |
| 4058 | 4245 |
| 4059 // Copy the fixed array slots. | 4246 // Copy the fixed array slots. |
| 4060 Label loop; | 4247 Label loop; |
| 4061 // Setup r4 to point to the first array slot. | 4248 // Setup r4 to point to the first array slot. |
| 4062 __ add(r4, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 4249 __ add(r4, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| 4063 __ bind(&loop); | 4250 __ bind(&loop); |
| 4064 // Pre-decrement r2 with kPointerSize on each iteration. | 4251 // Pre-decrement r2 with kPointerSize on each iteration. |
| 4065 // Pre-decrement in order to skip receiver. | 4252 // Pre-decrement in order to skip receiver. |
| 4066 __ ldr(r3, MemOperand(r2, kPointerSize, NegPreIndex)); | 4253 __ ldr(r3, MemOperand(r2, kPointerSize, NegPreIndex)); |
| 4067 // Post-increment r4 with kPointerSize on each iteration. | 4254 // Post-increment r4 with kPointerSize on each iteration. |
| 4068 __ str(r3, MemOperand(r4, kPointerSize, PostIndex)); | 4255 __ str(r3, MemOperand(r4, kPointerSize, PostIndex)); |
| 4069 __ sub(r1, r1, Operand(1)); | 4256 __ sub(r1, r1, Operand(1)); |
| 4070 __ cmp(r1, Operand(0, RelocInfo::NONE)); | 4257 __ cmp(r1, Operand(0, RelocInfo::NONE)); |
| 4071 __ b(ne, &loop); | 4258 __ b(ne, &loop); |
| 4072 | 4259 |
| 4073 // Return and remove the on-stack parameters. | 4260 // Return and remove the on-stack parameters. |
| 4074 __ bind(&done); | 4261 __ bind(&done); |
| 4075 __ add(sp, sp, Operand(3 * kPointerSize)); | 4262 __ add(sp, sp, Operand(3 * kPointerSize)); |
| 4076 __ Ret(); | 4263 __ Ret(); |
| 4077 | 4264 |
| 4078 // Do the runtime call to allocate the arguments object. | 4265 // Do the runtime call to allocate the arguments object. |
| 4079 __ bind(&runtime); | 4266 __ bind(&runtime); |
| 4080 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); | 4267 __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); |
| 4081 } | 4268 } |
| 4082 | 4269 |
| 4083 | 4270 |
| 4084 void RegExpExecStub::Generate(MacroAssembler* masm) { | 4271 void RegExpExecStub::Generate(MacroAssembler* masm) { |
| 4085 // Just jump directly to runtime if native RegExp is not selected at compile | 4272 // Just jump directly to runtime if native RegExp is not selected at compile |
| 4086 // time or if regexp entry in generated code is turned off runtime switch or | 4273 // time or if regexp entry in generated code is turned off runtime switch or |
| 4087 // at compilation. | 4274 // at compilation. |
| 4088 #ifdef V8_INTERPRETED_REGEXP | 4275 #ifdef V8_INTERPRETED_REGEXP |
| 4089 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); | 4276 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); |
| 4090 #else // V8_INTERPRETED_REGEXP | 4277 #else // V8_INTERPRETED_REGEXP |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4122 ExternalReference address_of_regexp_stack_memory_size = | 4309 ExternalReference address_of_regexp_stack_memory_size = |
| 4123 ExternalReference::address_of_regexp_stack_memory_size(isolate); | 4310 ExternalReference::address_of_regexp_stack_memory_size(isolate); |
| 4124 __ mov(r0, Operand(address_of_regexp_stack_memory_size)); | 4311 __ mov(r0, Operand(address_of_regexp_stack_memory_size)); |
| 4125 __ ldr(r0, MemOperand(r0, 0)); | 4312 __ ldr(r0, MemOperand(r0, 0)); |
| 4126 __ tst(r0, Operand(r0)); | 4313 __ tst(r0, Operand(r0)); |
| 4127 __ b(eq, &runtime); | 4314 __ b(eq, &runtime); |
| 4128 | 4315 |
| 4129 // Check that the first argument is a JSRegExp object. | 4316 // Check that the first argument is a JSRegExp object. |
| 4130 __ ldr(r0, MemOperand(sp, kJSRegExpOffset)); | 4317 __ ldr(r0, MemOperand(sp, kJSRegExpOffset)); |
| 4131 STATIC_ASSERT(kSmiTag == 0); | 4318 STATIC_ASSERT(kSmiTag == 0); |
| 4132 __ tst(r0, Operand(kSmiTagMask)); | 4319 __ JumpIfSmi(r0, &runtime); |
| 4133 __ b(eq, &runtime); | |
| 4134 __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE); | 4320 __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE); |
| 4135 __ b(ne, &runtime); | 4321 __ b(ne, &runtime); |
| 4136 | 4322 |
| 4137 // Check that the RegExp has been compiled (data contains a fixed array). | 4323 // Check that the RegExp has been compiled (data contains a fixed array). |
| 4138 __ ldr(regexp_data, FieldMemOperand(r0, JSRegExp::kDataOffset)); | 4324 __ ldr(regexp_data, FieldMemOperand(r0, JSRegExp::kDataOffset)); |
| 4139 if (FLAG_debug_code) { | 4325 if (FLAG_debug_code) { |
| 4140 __ tst(regexp_data, Operand(kSmiTagMask)); | 4326 __ tst(regexp_data, Operand(kSmiTagMask)); |
| 4141 __ Check(ne, "Unexpected type for RegExp data, FixedArray expected"); | 4327 __ Check(ne, "Unexpected type for RegExp data, FixedArray expected"); |
| 4142 __ CompareObjectType(regexp_data, r0, r0, FIXED_ARRAY_TYPE); | 4328 __ CompareObjectType(regexp_data, r0, r0, FIXED_ARRAY_TYPE); |
| 4143 __ Check(eq, "Unexpected type for RegExp data, FixedArray expected"); | 4329 __ Check(eq, "Unexpected type for RegExp data, FixedArray expected"); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 4159 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); | 4345 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); |
| 4160 __ add(r2, r2, Operand(2)); // r2 was a smi. | 4346 __ add(r2, r2, Operand(2)); // r2 was a smi. |
| 4161 // Check that the static offsets vector buffer is large enough. | 4347 // Check that the static offsets vector buffer is large enough. |
| 4162 __ cmp(r2, Operand(OffsetsVector::kStaticOffsetsVectorSize)); | 4348 __ cmp(r2, Operand(OffsetsVector::kStaticOffsetsVectorSize)); |
| 4163 __ b(hi, &runtime); | 4349 __ b(hi, &runtime); |
| 4164 | 4350 |
| 4165 // r2: Number of capture registers | 4351 // r2: Number of capture registers |
| 4166 // regexp_data: RegExp data (FixedArray) | 4352 // regexp_data: RegExp data (FixedArray) |
| 4167 // Check that the second argument is a string. | 4353 // Check that the second argument is a string. |
| 4168 __ ldr(subject, MemOperand(sp, kSubjectOffset)); | 4354 __ ldr(subject, MemOperand(sp, kSubjectOffset)); |
| 4169 __ tst(subject, Operand(kSmiTagMask)); | 4355 __ JumpIfSmi(subject, &runtime); |
| 4170 __ b(eq, &runtime); | |
| 4171 Condition is_string = masm->IsObjectStringType(subject, r0); | 4356 Condition is_string = masm->IsObjectStringType(subject, r0); |
| 4172 __ b(NegateCondition(is_string), &runtime); | 4357 __ b(NegateCondition(is_string), &runtime); |
| 4173 // Get the length of the string to r3. | 4358 // Get the length of the string to r3. |
| 4174 __ ldr(r3, FieldMemOperand(subject, String::kLengthOffset)); | 4359 __ ldr(r3, FieldMemOperand(subject, String::kLengthOffset)); |
| 4175 | 4360 |
| 4176 // r2: Number of capture registers | 4361 // r2: Number of capture registers |
| 4177 // r3: Length of subject string as a smi | 4362 // r3: Length of subject string as a smi |
| 4178 // subject: Subject string | 4363 // subject: Subject string |
| 4179 // regexp_data: RegExp data (FixedArray) | 4364 // regexp_data: RegExp data (FixedArray) |
| 4180 // Check that the third argument is a positive smi less than the subject | 4365 // Check that the third argument is a positive smi less than the subject |
| 4181 // string length. A negative value will be greater (unsigned comparison). | 4366 // string length. A negative value will be greater (unsigned comparison). |
| 4182 __ ldr(r0, MemOperand(sp, kPreviousIndexOffset)); | 4367 __ ldr(r0, MemOperand(sp, kPreviousIndexOffset)); |
| 4183 __ tst(r0, Operand(kSmiTagMask)); | 4368 __ JumpIfNotSmi(r0, &runtime); |
| 4184 __ b(ne, &runtime); | |
| 4185 __ cmp(r3, Operand(r0)); | 4369 __ cmp(r3, Operand(r0)); |
| 4186 __ b(ls, &runtime); | 4370 __ b(ls, &runtime); |
| 4187 | 4371 |
| 4188 // r2: Number of capture registers | 4372 // r2: Number of capture registers |
| 4189 // subject: Subject string | 4373 // subject: Subject string |
| 4190 // regexp_data: RegExp data (FixedArray) | 4374 // regexp_data: RegExp data (FixedArray) |
| 4191 // Check that the fourth object is a JSArray object. | 4375 // Check that the fourth object is a JSArray object. |
| 4192 __ ldr(r0, MemOperand(sp, kLastMatchInfoOffset)); | 4376 __ ldr(r0, MemOperand(sp, kLastMatchInfoOffset)); |
| 4193 __ tst(r0, Operand(kSmiTagMask)); | 4377 __ JumpIfSmi(r0, &runtime); |
| 4194 __ b(eq, &runtime); | |
| 4195 __ CompareObjectType(r0, r1, r1, JS_ARRAY_TYPE); | 4378 __ CompareObjectType(r0, r1, r1, JS_ARRAY_TYPE); |
| 4196 __ b(ne, &runtime); | 4379 __ b(ne, &runtime); |
| 4197 // Check that the JSArray is in fast case. | 4380 // Check that the JSArray is in fast case. |
| 4198 __ ldr(last_match_info_elements, | 4381 __ ldr(last_match_info_elements, |
| 4199 FieldMemOperand(r0, JSArray::kElementsOffset)); | 4382 FieldMemOperand(r0, JSArray::kElementsOffset)); |
| 4200 __ ldr(r0, FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset)); | 4383 __ ldr(r0, FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset)); |
| 4201 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); | 4384 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); |
| 4202 __ cmp(r0, ip); | 4385 __ cmp(r0, ip); |
| 4203 __ b(ne, &runtime); | 4386 __ b(ne, &runtime); |
| 4204 // Check that the last match info has space for the capture registers and the | 4387 // Check that the last match info has space for the capture registers and the |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4250 STATIC_ASSERT(4 == kAsciiStringTag); | 4433 STATIC_ASSERT(4 == kAsciiStringTag); |
| 4251 STATIC_ASSERT(kTwoByteStringTag == 0); | 4434 STATIC_ASSERT(kTwoByteStringTag == 0); |
| 4252 // Find the code object based on the assumptions above. | 4435 // Find the code object based on the assumptions above. |
| 4253 __ and_(r0, r0, Operand(kStringEncodingMask)); | 4436 __ and_(r0, r0, Operand(kStringEncodingMask)); |
| 4254 __ mov(r3, Operand(r0, ASR, 2), SetCC); | 4437 __ mov(r3, Operand(r0, ASR, 2), SetCC); |
| 4255 __ ldr(r7, FieldMemOperand(regexp_data, JSRegExp::kDataAsciiCodeOffset), ne); | 4438 __ ldr(r7, FieldMemOperand(regexp_data, JSRegExp::kDataAsciiCodeOffset), ne); |
| 4256 __ ldr(r7, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset), eq); | 4439 __ ldr(r7, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset), eq); |
| 4257 | 4440 |
| 4258 // Check that the irregexp code has been generated for the actual string | 4441 // Check that the irregexp code has been generated for the actual string |
| 4259 // encoding. If it has, the field contains a code object otherwise it contains | 4442 // encoding. If it has, the field contains a code object otherwise it contains |
| 4260 // the hole. | 4443 // a smi (code flushing support). |
| 4261 __ CompareObjectType(r7, r0, r0, CODE_TYPE); | 4444 __ JumpIfSmi(r7, &runtime); |
| 4262 __ b(ne, &runtime); | |
| 4263 | 4445 |
| 4264 // r3: encoding of subject string (1 if ASCII, 0 if two_byte); | 4446 // r3: encoding of subject string (1 if ASCII, 0 if two_byte); |
| 4265 // r7: code | 4447 // r7: code |
| 4266 // subject: Subject string | 4448 // subject: Subject string |
| 4267 // regexp_data: RegExp data (FixedArray) | 4449 // regexp_data: RegExp data (FixedArray) |
| 4268 // Load used arguments before starting to push arguments for call to native | 4450 // Load used arguments before starting to push arguments for call to native |
| 4269 // RegExp code to avoid handling changing stack height. | 4451 // RegExp code to avoid handling changing stack height. |
| 4270 __ ldr(r1, MemOperand(sp, kPreviousIndexOffset)); | 4452 __ ldr(r1, MemOperand(sp, kPreviousIndexOffset)); |
| 4271 __ mov(r1, Operand(r1, ASR, kSmiTagSize)); | 4453 __ mov(r1, Operand(r1, ASR, kSmiTagSize)); |
| 4272 | 4454 |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4453 | 4635 |
| 4454 void RegExpConstructResultStub::Generate(MacroAssembler* masm) { | 4636 void RegExpConstructResultStub::Generate(MacroAssembler* masm) { |
| 4455 const int kMaxInlineLength = 100; | 4637 const int kMaxInlineLength = 100; |
| 4456 Label slowcase; | 4638 Label slowcase; |
| 4457 Label done; | 4639 Label done; |
| 4458 Factory* factory = masm->isolate()->factory(); | 4640 Factory* factory = masm->isolate()->factory(); |
| 4459 | 4641 |
| 4460 __ ldr(r1, MemOperand(sp, kPointerSize * 2)); | 4642 __ ldr(r1, MemOperand(sp, kPointerSize * 2)); |
| 4461 STATIC_ASSERT(kSmiTag == 0); | 4643 STATIC_ASSERT(kSmiTag == 0); |
| 4462 STATIC_ASSERT(kSmiTagSize == 1); | 4644 STATIC_ASSERT(kSmiTagSize == 1); |
| 4463 __ tst(r1, Operand(kSmiTagMask)); | 4645 __ JumpIfNotSmi(r1, &slowcase); |
| 4464 __ b(ne, &slowcase); | |
| 4465 __ cmp(r1, Operand(Smi::FromInt(kMaxInlineLength))); | 4646 __ cmp(r1, Operand(Smi::FromInt(kMaxInlineLength))); |
| 4466 __ b(hi, &slowcase); | 4647 __ b(hi, &slowcase); |
| 4467 // Smi-tagging is equivalent to multiplying by 2. | 4648 // Smi-tagging is equivalent to multiplying by 2. |
| 4468 // Allocate RegExpResult followed by FixedArray with size in ebx. | 4649 // Allocate RegExpResult followed by FixedArray with size in ebx. |
| 4469 // JSArray: [Map][empty properties][Elements][Length-smi][index][input] | 4650 // JSArray: [Map][empty properties][Elements][Length-smi][index][input] |
| 4470 // Elements: [Map][Length][..elements..] | 4651 // Elements: [Map][Length][..elements..] |
| 4471 // Size of JSArray with two in-object properties and the header of a | 4652 // Size of JSArray with two in-object properties and the header of a |
| 4472 // FixedArray. | 4653 // FixedArray. |
| 4473 int objects_size = | 4654 int objects_size = |
| 4474 (JSRegExpResult::kSize + FixedArray::kHeaderSize) / kPointerSize; | 4655 (JSRegExpResult::kSize + FixedArray::kHeaderSize) / kPointerSize; |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4575 __ b(ne, &slow); | 4756 __ b(ne, &slow); |
| 4576 | 4757 |
| 4577 // Fast-case: Invoke the function now. | 4758 // Fast-case: Invoke the function now. |
| 4578 // r1: pushed function | 4759 // r1: pushed function |
| 4579 ParameterCount actual(argc_); | 4760 ParameterCount actual(argc_); |
| 4580 | 4761 |
| 4581 if (ReceiverMightBeImplicit()) { | 4762 if (ReceiverMightBeImplicit()) { |
| 4582 Label call_as_function; | 4763 Label call_as_function; |
| 4583 __ CompareRoot(r4, Heap::kTheHoleValueRootIndex); | 4764 __ CompareRoot(r4, Heap::kTheHoleValueRootIndex); |
| 4584 __ b(eq, &call_as_function); | 4765 __ b(eq, &call_as_function); |
| 4585 __ InvokeFunction(r1, actual, JUMP_FUNCTION); | 4766 __ InvokeFunction(r1, |
| 4767 actual, |
| 4768 JUMP_FUNCTION, |
| 4769 NullCallWrapper(), |
| 4770 CALL_AS_METHOD); |
| 4586 __ bind(&call_as_function); | 4771 __ bind(&call_as_function); |
| 4587 } | 4772 } |
| 4588 __ InvokeFunction(r1, | 4773 __ InvokeFunction(r1, |
| 4589 actual, | 4774 actual, |
| 4590 JUMP_FUNCTION, | 4775 JUMP_FUNCTION, |
| 4591 NullCallWrapper(), | 4776 NullCallWrapper(), |
| 4592 CALL_AS_FUNCTION); | 4777 CALL_AS_FUNCTION); |
| 4593 | 4778 |
| 4594 // Slow-case: Non-function called. | 4779 // Slow-case: Non-function called. |
| 4595 __ bind(&slow); | 4780 __ bind(&slow); |
| (...skipping 735 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5331 __ b(lt, &runtime); | 5516 __ b(lt, &runtime); |
| 5332 | 5517 |
| 5333 // r2: length | 5518 // r2: length |
| 5334 // r3: from index (untaged smi) | 5519 // r3: from index (untaged smi) |
| 5335 // r6 (a.k.a. to): to (smi) | 5520 // r6 (a.k.a. to): to (smi) |
| 5336 // r7 (a.k.a. from): from offset (smi) | 5521 // r7 (a.k.a. from): from offset (smi) |
| 5337 | 5522 |
| 5338 // Make sure first argument is a sequential (or flat) string. | 5523 // Make sure first argument is a sequential (or flat) string. |
| 5339 __ ldr(r5, MemOperand(sp, kStringOffset)); | 5524 __ ldr(r5, MemOperand(sp, kStringOffset)); |
| 5340 STATIC_ASSERT(kSmiTag == 0); | 5525 STATIC_ASSERT(kSmiTag == 0); |
| 5341 __ tst(r5, Operand(kSmiTagMask)); | 5526 __ JumpIfSmi(r5, &runtime); |
| 5342 __ b(eq, &runtime); | |
| 5343 Condition is_string = masm->IsObjectStringType(r5, r1); | 5527 Condition is_string = masm->IsObjectStringType(r5, r1); |
| 5344 __ b(NegateCondition(is_string), &runtime); | 5528 __ b(NegateCondition(is_string), &runtime); |
| 5345 | 5529 |
| 5346 // r1: instance type | 5530 // r1: instance type |
| 5347 // r2: length | 5531 // r2: length |
| 5348 // r3: from index (untagged smi) | 5532 // r3: from index (untagged smi) |
| 5349 // r5: string | 5533 // r5: string |
| 5350 // r6 (a.k.a. to): to (smi) | 5534 // r6 (a.k.a. to): to (smi) |
| 5351 // r7 (a.k.a. from): from offset (smi) | 5535 // r7 (a.k.a. from): from offset (smi) |
| 5352 Label seq_string; | 5536 Label seq_string; |
| (...skipping 616 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5969 __ str(arg, MemOperand(sp, stack_offset)); | 6153 __ str(arg, MemOperand(sp, stack_offset)); |
| 5970 | 6154 |
| 5971 __ bind(&done); | 6155 __ bind(&done); |
| 5972 } | 6156 } |
| 5973 | 6157 |
| 5974 | 6158 |
| 5975 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { | 6159 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { |
| 5976 ASSERT(state_ == CompareIC::SMIS); | 6160 ASSERT(state_ == CompareIC::SMIS); |
| 5977 Label miss; | 6161 Label miss; |
| 5978 __ orr(r2, r1, r0); | 6162 __ orr(r2, r1, r0); |
| 5979 __ tst(r2, Operand(kSmiTagMask)); | 6163 __ JumpIfNotSmi(r2, &miss); |
| 5980 __ b(ne, &miss); | |
| 5981 | 6164 |
| 5982 if (GetCondition() == eq) { | 6165 if (GetCondition() == eq) { |
| 5983 // For equality we do not care about the sign of the result. | 6166 // For equality we do not care about the sign of the result. |
| 5984 __ sub(r0, r0, r1, SetCC); | 6167 __ sub(r0, r0, r1, SetCC); |
| 5985 } else { | 6168 } else { |
| 5986 // Untag before subtracting to avoid handling overflow. | 6169 // Untag before subtracting to avoid handling overflow. |
| 5987 __ SmiUntag(r1); | 6170 __ SmiUntag(r1); |
| 5988 __ sub(r0, r1, SmiUntagOperand(r0)); | 6171 __ sub(r0, r1, SmiUntagOperand(r0)); |
| 5989 } | 6172 } |
| 5990 __ Ret(); | 6173 __ Ret(); |
| 5991 | 6174 |
| 5992 __ bind(&miss); | 6175 __ bind(&miss); |
| 5993 GenerateMiss(masm); | 6176 GenerateMiss(masm); |
| 5994 } | 6177 } |
| 5995 | 6178 |
| 5996 | 6179 |
| 5997 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { | 6180 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { |
| 5998 ASSERT(state_ == CompareIC::HEAP_NUMBERS); | 6181 ASSERT(state_ == CompareIC::HEAP_NUMBERS); |
| 5999 | 6182 |
| 6000 Label generic_stub; | 6183 Label generic_stub; |
| 6001 Label unordered; | 6184 Label unordered; |
| 6002 Label miss; | 6185 Label miss; |
| 6003 __ and_(r2, r1, Operand(r0)); | 6186 __ and_(r2, r1, Operand(r0)); |
| 6004 __ tst(r2, Operand(kSmiTagMask)); | 6187 __ JumpIfSmi(r2, &generic_stub); |
| 6005 __ b(eq, &generic_stub); | |
| 6006 | 6188 |
| 6007 __ CompareObjectType(r0, r2, r2, HEAP_NUMBER_TYPE); | 6189 __ CompareObjectType(r0, r2, r2, HEAP_NUMBER_TYPE); |
| 6008 __ b(ne, &miss); | 6190 __ b(ne, &miss); |
| 6009 __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE); | 6191 __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE); |
| 6010 __ b(ne, &miss); | 6192 __ b(ne, &miss); |
| 6011 | 6193 |
| 6012 // Inlining the double comparison and falling back to the general compare | 6194 // Inlining the double comparison and falling back to the general compare |
| 6013 // stub if NaN is involved or VFP3 is unsupported. | 6195 // stub if NaN is involved or VFP3 is unsupported. |
| 6014 if (CpuFeatures::IsSupported(VFP3)) { | 6196 if (CpuFeatures::IsSupported(VFP3)) { |
| 6015 CpuFeatures::Scope scope(VFP3); | 6197 CpuFeatures::Scope scope(VFP3); |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6144 | 6326 |
| 6145 __ bind(&miss); | 6327 __ bind(&miss); |
| 6146 GenerateMiss(masm); | 6328 GenerateMiss(masm); |
| 6147 } | 6329 } |
| 6148 | 6330 |
| 6149 | 6331 |
| 6150 void ICCompareStub::GenerateObjects(MacroAssembler* masm) { | 6332 void ICCompareStub::GenerateObjects(MacroAssembler* masm) { |
| 6151 ASSERT(state_ == CompareIC::OBJECTS); | 6333 ASSERT(state_ == CompareIC::OBJECTS); |
| 6152 Label miss; | 6334 Label miss; |
| 6153 __ and_(r2, r1, Operand(r0)); | 6335 __ and_(r2, r1, Operand(r0)); |
| 6154 __ tst(r2, Operand(kSmiTagMask)); | 6336 __ JumpIfSmi(r2, &miss); |
| 6155 __ b(eq, &miss); | |
| 6156 | 6337 |
| 6157 __ CompareObjectType(r0, r2, r2, JS_OBJECT_TYPE); | 6338 __ CompareObjectType(r0, r2, r2, JS_OBJECT_TYPE); |
| 6158 __ b(ne, &miss); | 6339 __ b(ne, &miss); |
| 6159 __ CompareObjectType(r1, r2, r2, JS_OBJECT_TYPE); | 6340 __ CompareObjectType(r1, r2, r2, JS_OBJECT_TYPE); |
| 6160 __ b(ne, &miss); | 6341 __ b(ne, &miss); |
| 6161 | 6342 |
| 6162 ASSERT(GetCondition() == eq); | 6343 ASSERT(GetCondition() == eq); |
| 6163 __ sub(r0, r0, Operand(r1)); | 6344 __ sub(r0, r0, Operand(r1)); |
| 6164 __ Ret(); | 6345 __ Ret(); |
| 6165 | 6346 |
| (...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6461 } | 6642 } |
| 6462 __ Ret(); | 6643 __ Ret(); |
| 6463 } | 6644 } |
| 6464 | 6645 |
| 6465 | 6646 |
| 6466 #undef __ | 6647 #undef __ |
| 6467 | 6648 |
| 6468 } } // namespace v8::internal | 6649 } } // namespace v8::internal |
| 6469 | 6650 |
| 6470 #endif // V8_TARGET_ARCH_ARM | 6651 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |