OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #if V8_TARGET_ARCH_ARM64 | 7 #if V8_TARGET_ARCH_ARM64 |
8 | 8 |
9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
(...skipping 465 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
476 Register left_bitfield = left_type; | 476 Register left_bitfield = left_type; |
477 __ Ldrb(right_bitfield, FieldMemOperand(right_map, Map::kBitFieldOffset)); | 477 __ Ldrb(right_bitfield, FieldMemOperand(right_map, Map::kBitFieldOffset)); |
478 __ Ldrb(left_bitfield, FieldMemOperand(left_map, Map::kBitFieldOffset)); | 478 __ Ldrb(left_bitfield, FieldMemOperand(left_map, Map::kBitFieldOffset)); |
479 __ And(result, right_bitfield, left_bitfield); | 479 __ And(result, right_bitfield, left_bitfield); |
480 __ And(result, result, 1 << Map::kIsUndetectable); | 480 __ And(result, result, 1 << Map::kIsUndetectable); |
481 __ Eor(result, result, 1 << Map::kIsUndetectable); | 481 __ Eor(result, result, 1 << Map::kIsUndetectable); |
482 __ Ret(); | 482 __ Ret(); |
483 } | 483 } |
484 | 484 |
485 | 485 |
486 static void ICCompareStub_CheckInputType(MacroAssembler* masm, | 486 static void CompareICStub_CheckInputType(MacroAssembler* masm, Register input, |
487 Register input, | |
488 Register scratch, | 487 Register scratch, |
489 CompareIC::State expected, | 488 CompareIC::State expected, |
490 Label* fail) { | 489 Label* fail) { |
491 Label ok; | 490 Label ok; |
492 if (expected == CompareIC::SMI) { | 491 if (expected == CompareIC::SMI) { |
493 __ JumpIfNotSmi(input, fail); | 492 __ JumpIfNotSmi(input, fail); |
494 } else if (expected == CompareIC::NUMBER) { | 493 } else if (expected == CompareIC::NUMBER) { |
495 __ JumpIfSmi(input, &ok); | 494 __ JumpIfSmi(input, &ok); |
496 __ CheckMap(input, scratch, Heap::kHeapNumberMapRootIndex, fail, | 495 __ CheckMap(input, scratch, Heap::kHeapNumberMapRootIndex, fail, |
497 DONT_DO_SMI_CHECK); | 496 DONT_DO_SMI_CHECK); |
498 } | 497 } |
499 // We could be strict about internalized/non-internalized here, but as long as | 498 // We could be strict about internalized/non-internalized here, but as long as |
500 // hydrogen doesn't care, the stub doesn't have to care either. | 499 // hydrogen doesn't care, the stub doesn't have to care either. |
501 __ Bind(&ok); | 500 __ Bind(&ok); |
502 } | 501 } |
503 | 502 |
504 | 503 |
505 void ICCompareStub::GenerateGeneric(MacroAssembler* masm) { | 504 void CompareICStub::GenerateGeneric(MacroAssembler* masm) { |
506 Register lhs = x1; | 505 Register lhs = x1; |
507 Register rhs = x0; | 506 Register rhs = x0; |
508 Register result = x0; | 507 Register result = x0; |
509 Condition cond = GetCondition(); | 508 Condition cond = GetCondition(); |
510 | 509 |
511 Label miss; | 510 Label miss; |
512 ICCompareStub_CheckInputType(masm, lhs, x2, left(), &miss); | 511 CompareICStub_CheckInputType(masm, lhs, x2, left(), &miss); |
513 ICCompareStub_CheckInputType(masm, rhs, x3, right(), &miss); | 512 CompareICStub_CheckInputType(masm, rhs, x3, right(), &miss); |
514 | 513 |
515 Label slow; // Call builtin. | 514 Label slow; // Call builtin. |
516 Label not_smis, both_loaded_as_doubles; | 515 Label not_smis, both_loaded_as_doubles; |
517 Label not_two_smis, smi_done; | 516 Label not_two_smis, smi_done; |
518 __ JumpIfEitherNotSmi(lhs, rhs, ¬_two_smis); | 517 __ JumpIfEitherNotSmi(lhs, rhs, ¬_two_smis); |
519 __ SmiUntag(lhs); | 518 __ SmiUntag(lhs); |
520 __ Sub(result, lhs, Operand::UntagSmi(rhs)); | 519 __ Sub(result, lhs, Operand::UntagSmi(rhs)); |
521 __ Ret(); | 520 __ Ret(); |
522 | 521 |
523 __ Bind(¬_two_smis); | 522 __ Bind(¬_two_smis); |
(...skipping 2666 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3190 __ Push(code_); | 3189 __ Push(code_); |
3191 __ CallRuntime(Runtime::kCharFromCode, 1); | 3190 __ CallRuntime(Runtime::kCharFromCode, 1); |
3192 __ Mov(result_, x0); | 3191 __ Mov(result_, x0); |
3193 call_helper.AfterCall(masm); | 3192 call_helper.AfterCall(masm); |
3194 __ B(&exit_); | 3193 __ B(&exit_); |
3195 | 3194 |
3196 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); | 3195 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); |
3197 } | 3196 } |
3198 | 3197 |
3199 | 3198 |
3200 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { | 3199 void CompareICStub::GenerateSmis(MacroAssembler* masm) { |
3201 // Inputs are in x0 (lhs) and x1 (rhs). | 3200 // Inputs are in x0 (lhs) and x1 (rhs). |
3202 DCHECK(state() == CompareIC::SMI); | 3201 DCHECK(state() == CompareIC::SMI); |
3203 ASM_LOCATION("ICCompareStub[Smis]"); | 3202 ASM_LOCATION("CompareICStub[Smis]"); |
3204 Label miss; | 3203 Label miss; |
3205 // Bail out (to 'miss') unless both x0 and x1 are smis. | 3204 // Bail out (to 'miss') unless both x0 and x1 are smis. |
3206 __ JumpIfEitherNotSmi(x0, x1, &miss); | 3205 __ JumpIfEitherNotSmi(x0, x1, &miss); |
3207 | 3206 |
3208 if (GetCondition() == eq) { | 3207 if (GetCondition() == eq) { |
3209 // For equality we do not care about the sign of the result. | 3208 // For equality we do not care about the sign of the result. |
3210 __ Sub(x0, x0, x1); | 3209 __ Sub(x0, x0, x1); |
3211 } else { | 3210 } else { |
3212 // Untag before subtracting to avoid handling overflow. | 3211 // Untag before subtracting to avoid handling overflow. |
3213 __ SmiUntag(x1); | 3212 __ SmiUntag(x1); |
3214 __ Sub(x0, x1, Operand::UntagSmi(x0)); | 3213 __ Sub(x0, x1, Operand::UntagSmi(x0)); |
3215 } | 3214 } |
3216 __ Ret(); | 3215 __ Ret(); |
3217 | 3216 |
3218 __ Bind(&miss); | 3217 __ Bind(&miss); |
3219 GenerateMiss(masm); | 3218 GenerateMiss(masm); |
3220 } | 3219 } |
3221 | 3220 |
3222 | 3221 |
3223 void ICCompareStub::GenerateNumbers(MacroAssembler* masm) { | 3222 void CompareICStub::GenerateNumbers(MacroAssembler* masm) { |
3224 DCHECK(state() == CompareIC::NUMBER); | 3223 DCHECK(state() == CompareIC::NUMBER); |
3225 ASM_LOCATION("ICCompareStub[HeapNumbers]"); | 3224 ASM_LOCATION("CompareICStub[HeapNumbers]"); |
3226 | 3225 |
3227 Label unordered, maybe_undefined1, maybe_undefined2; | 3226 Label unordered, maybe_undefined1, maybe_undefined2; |
3228 Label miss, handle_lhs, values_in_d_regs; | 3227 Label miss, handle_lhs, values_in_d_regs; |
3229 Label untag_rhs, untag_lhs; | 3228 Label untag_rhs, untag_lhs; |
3230 | 3229 |
3231 Register result = x0; | 3230 Register result = x0; |
3232 Register rhs = x0; | 3231 Register rhs = x0; |
3233 Register lhs = x1; | 3232 Register lhs = x1; |
3234 FPRegister rhs_d = d0; | 3233 FPRegister rhs_d = d0; |
3235 FPRegister lhs_d = d1; | 3234 FPRegister lhs_d = d1; |
(...skipping 23 matching lines...) Expand all Loading... |
3259 | 3258 |
3260 __ Bind(&values_in_d_regs); | 3259 __ Bind(&values_in_d_regs); |
3261 __ Fcmp(lhs_d, rhs_d); | 3260 __ Fcmp(lhs_d, rhs_d); |
3262 __ B(vs, &unordered); // Overflow flag set if either is NaN. | 3261 __ B(vs, &unordered); // Overflow flag set if either is NaN. |
3263 STATIC_ASSERT((LESS == -1) && (EQUAL == 0) && (GREATER == 1)); | 3262 STATIC_ASSERT((LESS == -1) && (EQUAL == 0) && (GREATER == 1)); |
3264 __ Cset(result, gt); // gt => 1, otherwise (lt, eq) => 0 (EQUAL). | 3263 __ Cset(result, gt); // gt => 1, otherwise (lt, eq) => 0 (EQUAL). |
3265 __ Csinv(result, result, xzr, ge); // lt => -1, gt => 1, eq => 0. | 3264 __ Csinv(result, result, xzr, ge); // lt => -1, gt => 1, eq => 0. |
3266 __ Ret(); | 3265 __ Ret(); |
3267 | 3266 |
3268 __ Bind(&unordered); | 3267 __ Bind(&unordered); |
3269 ICCompareStub stub(isolate(), op(), CompareIC::GENERIC, CompareIC::GENERIC, | 3268 CompareICStub stub(isolate(), op(), CompareIC::GENERIC, CompareIC::GENERIC, |
3270 CompareIC::GENERIC); | 3269 CompareIC::GENERIC); |
3271 __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); | 3270 __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); |
3272 | 3271 |
3273 __ Bind(&maybe_undefined1); | 3272 __ Bind(&maybe_undefined1); |
3274 if (Token::IsOrderedRelationalCompareOp(op())) { | 3273 if (Token::IsOrderedRelationalCompareOp(op())) { |
3275 __ JumpIfNotRoot(rhs, Heap::kUndefinedValueRootIndex, &miss); | 3274 __ JumpIfNotRoot(rhs, Heap::kUndefinedValueRootIndex, &miss); |
3276 __ JumpIfSmi(lhs, &unordered); | 3275 __ JumpIfSmi(lhs, &unordered); |
3277 __ JumpIfNotObjectType(lhs, x10, x10, HEAP_NUMBER_TYPE, &maybe_undefined2); | 3276 __ JumpIfNotObjectType(lhs, x10, x10, HEAP_NUMBER_TYPE, &maybe_undefined2); |
3278 __ B(&unordered); | 3277 __ B(&unordered); |
3279 } | 3278 } |
3280 | 3279 |
3281 __ Bind(&maybe_undefined2); | 3280 __ Bind(&maybe_undefined2); |
3282 if (Token::IsOrderedRelationalCompareOp(op())) { | 3281 if (Token::IsOrderedRelationalCompareOp(op())) { |
3283 __ JumpIfRoot(lhs, Heap::kUndefinedValueRootIndex, &unordered); | 3282 __ JumpIfRoot(lhs, Heap::kUndefinedValueRootIndex, &unordered); |
3284 } | 3283 } |
3285 | 3284 |
3286 __ Bind(&miss); | 3285 __ Bind(&miss); |
3287 GenerateMiss(masm); | 3286 GenerateMiss(masm); |
3288 } | 3287 } |
3289 | 3288 |
3290 | 3289 |
3291 void ICCompareStub::GenerateInternalizedStrings(MacroAssembler* masm) { | 3290 void CompareICStub::GenerateInternalizedStrings(MacroAssembler* masm) { |
3292 DCHECK(state() == CompareIC::INTERNALIZED_STRING); | 3291 DCHECK(state() == CompareIC::INTERNALIZED_STRING); |
3293 ASM_LOCATION("ICCompareStub[InternalizedStrings]"); | 3292 ASM_LOCATION("CompareICStub[InternalizedStrings]"); |
3294 Label miss; | 3293 Label miss; |
3295 | 3294 |
3296 Register result = x0; | 3295 Register result = x0; |
3297 Register rhs = x0; | 3296 Register rhs = x0; |
3298 Register lhs = x1; | 3297 Register lhs = x1; |
3299 | 3298 |
3300 // Check that both operands are heap objects. | 3299 // Check that both operands are heap objects. |
3301 __ JumpIfEitherSmi(lhs, rhs, &miss); | 3300 __ JumpIfEitherSmi(lhs, rhs, &miss); |
3302 | 3301 |
3303 // Check that both operands are internalized strings. | 3302 // Check that both operands are internalized strings. |
(...skipping 15 matching lines...) Expand all Loading... |
3319 STATIC_ASSERT(EQUAL == 0); | 3318 STATIC_ASSERT(EQUAL == 0); |
3320 __ Cmp(lhs, rhs); | 3319 __ Cmp(lhs, rhs); |
3321 __ Cset(result, ne); | 3320 __ Cset(result, ne); |
3322 __ Ret(); | 3321 __ Ret(); |
3323 | 3322 |
3324 __ Bind(&miss); | 3323 __ Bind(&miss); |
3325 GenerateMiss(masm); | 3324 GenerateMiss(masm); |
3326 } | 3325 } |
3327 | 3326 |
3328 | 3327 |
3329 void ICCompareStub::GenerateUniqueNames(MacroAssembler* masm) { | 3328 void CompareICStub::GenerateUniqueNames(MacroAssembler* masm) { |
3330 DCHECK(state() == CompareIC::UNIQUE_NAME); | 3329 DCHECK(state() == CompareIC::UNIQUE_NAME); |
3331 ASM_LOCATION("ICCompareStub[UniqueNames]"); | 3330 ASM_LOCATION("CompareICStub[UniqueNames]"); |
3332 DCHECK(GetCondition() == eq); | 3331 DCHECK(GetCondition() == eq); |
3333 Label miss; | 3332 Label miss; |
3334 | 3333 |
3335 Register result = x0; | 3334 Register result = x0; |
3336 Register rhs = x0; | 3335 Register rhs = x0; |
3337 Register lhs = x1; | 3336 Register lhs = x1; |
3338 | 3337 |
3339 Register lhs_instance_type = w2; | 3338 Register lhs_instance_type = w2; |
3340 Register rhs_instance_type = w3; | 3339 Register rhs_instance_type = w3; |
3341 | 3340 |
(...skipping 16 matching lines...) Expand all Loading... |
3358 STATIC_ASSERT(EQUAL == 0); | 3357 STATIC_ASSERT(EQUAL == 0); |
3359 __ Cmp(lhs, rhs); | 3358 __ Cmp(lhs, rhs); |
3360 __ Cset(result, ne); | 3359 __ Cset(result, ne); |
3361 __ Ret(); | 3360 __ Ret(); |
3362 | 3361 |
3363 __ Bind(&miss); | 3362 __ Bind(&miss); |
3364 GenerateMiss(masm); | 3363 GenerateMiss(masm); |
3365 } | 3364 } |
3366 | 3365 |
3367 | 3366 |
3368 void ICCompareStub::GenerateStrings(MacroAssembler* masm) { | 3367 void CompareICStub::GenerateStrings(MacroAssembler* masm) { |
3369 DCHECK(state() == CompareIC::STRING); | 3368 DCHECK(state() == CompareIC::STRING); |
3370 ASM_LOCATION("ICCompareStub[Strings]"); | 3369 ASM_LOCATION("CompareICStub[Strings]"); |
3371 | 3370 |
3372 Label miss; | 3371 Label miss; |
3373 | 3372 |
3374 bool equality = Token::IsEqualityOp(op()); | 3373 bool equality = Token::IsEqualityOp(op()); |
3375 | 3374 |
3376 Register result = x0; | 3375 Register result = x0; |
3377 Register rhs = x0; | 3376 Register rhs = x0; |
3378 Register lhs = x1; | 3377 Register lhs = x1; |
3379 | 3378 |
3380 // Check that both operands are heap objects. | 3379 // Check that both operands are heap objects. |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3438 __ TailCallRuntime(Runtime::kStringEquals, 2, 1); | 3437 __ TailCallRuntime(Runtime::kStringEquals, 2, 1); |
3439 } else { | 3438 } else { |
3440 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 3439 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
3441 } | 3440 } |
3442 | 3441 |
3443 __ Bind(&miss); | 3442 __ Bind(&miss); |
3444 GenerateMiss(masm); | 3443 GenerateMiss(masm); |
3445 } | 3444 } |
3446 | 3445 |
3447 | 3446 |
3448 void ICCompareStub::GenerateObjects(MacroAssembler* masm) { | 3447 void CompareICStub::GenerateObjects(MacroAssembler* masm) { |
3449 DCHECK(state() == CompareIC::OBJECT); | 3448 DCHECK(state() == CompareIC::OBJECT); |
3450 ASM_LOCATION("ICCompareStub[Objects]"); | 3449 ASM_LOCATION("CompareICStub[Objects]"); |
3451 | 3450 |
3452 Label miss; | 3451 Label miss; |
3453 | 3452 |
3454 Register result = x0; | 3453 Register result = x0; |
3455 Register rhs = x0; | 3454 Register rhs = x0; |
3456 Register lhs = x1; | 3455 Register lhs = x1; |
3457 | 3456 |
3458 __ JumpIfEitherSmi(rhs, lhs, &miss); | 3457 __ JumpIfEitherSmi(rhs, lhs, &miss); |
3459 | 3458 |
3460 __ JumpIfNotObjectType(rhs, x10, x10, JS_OBJECT_TYPE, &miss); | 3459 __ JumpIfNotObjectType(rhs, x10, x10, JS_OBJECT_TYPE, &miss); |
3461 __ JumpIfNotObjectType(lhs, x10, x10, JS_OBJECT_TYPE, &miss); | 3460 __ JumpIfNotObjectType(lhs, x10, x10, JS_OBJECT_TYPE, &miss); |
3462 | 3461 |
3463 DCHECK(GetCondition() == eq); | 3462 DCHECK(GetCondition() == eq); |
3464 __ Sub(result, rhs, lhs); | 3463 __ Sub(result, rhs, lhs); |
3465 __ Ret(); | 3464 __ Ret(); |
3466 | 3465 |
3467 __ Bind(&miss); | 3466 __ Bind(&miss); |
3468 GenerateMiss(masm); | 3467 GenerateMiss(masm); |
3469 } | 3468 } |
3470 | 3469 |
3471 | 3470 |
3472 void ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) { | 3471 void CompareICStub::GenerateKnownObjects(MacroAssembler* masm) { |
3473 ASM_LOCATION("ICCompareStub[KnownObjects]"); | 3472 ASM_LOCATION("CompareICStub[KnownObjects]"); |
3474 | 3473 |
3475 Label miss; | 3474 Label miss; |
3476 | 3475 |
3477 Register result = x0; | 3476 Register result = x0; |
3478 Register rhs = x0; | 3477 Register rhs = x0; |
3479 Register lhs = x1; | 3478 Register lhs = x1; |
3480 | 3479 |
3481 __ JumpIfEitherSmi(rhs, lhs, &miss); | 3480 __ JumpIfEitherSmi(rhs, lhs, &miss); |
3482 | 3481 |
3483 Register rhs_map = x10; | 3482 Register rhs_map = x10; |
3484 Register lhs_map = x11; | 3483 Register lhs_map = x11; |
3485 __ Ldr(rhs_map, FieldMemOperand(rhs, HeapObject::kMapOffset)); | 3484 __ Ldr(rhs_map, FieldMemOperand(rhs, HeapObject::kMapOffset)); |
3486 __ Ldr(lhs_map, FieldMemOperand(lhs, HeapObject::kMapOffset)); | 3485 __ Ldr(lhs_map, FieldMemOperand(lhs, HeapObject::kMapOffset)); |
3487 __ Cmp(rhs_map, Operand(known_map_)); | 3486 __ Cmp(rhs_map, Operand(known_map_)); |
3488 __ B(ne, &miss); | 3487 __ B(ne, &miss); |
3489 __ Cmp(lhs_map, Operand(known_map_)); | 3488 __ Cmp(lhs_map, Operand(known_map_)); |
3490 __ B(ne, &miss); | 3489 __ B(ne, &miss); |
3491 | 3490 |
3492 __ Sub(result, rhs, lhs); | 3491 __ Sub(result, rhs, lhs); |
3493 __ Ret(); | 3492 __ Ret(); |
3494 | 3493 |
3495 __ Bind(&miss); | 3494 __ Bind(&miss); |
3496 GenerateMiss(masm); | 3495 GenerateMiss(masm); |
3497 } | 3496 } |
3498 | 3497 |
3499 | 3498 |
3500 // This method handles the case where a compare stub had the wrong | 3499 // This method handles the case where a compare stub had the wrong |
3501 // implementation. It calls a miss handler, which re-writes the stub. All other | 3500 // implementation. It calls a miss handler, which re-writes the stub. All other |
3502 // ICCompareStub::Generate* methods should fall back into this one if their | 3501 // CompareICStub::Generate* methods should fall back into this one if their |
3503 // operands were not the expected types. | 3502 // operands were not the expected types. |
3504 void ICCompareStub::GenerateMiss(MacroAssembler* masm) { | 3503 void CompareICStub::GenerateMiss(MacroAssembler* masm) { |
3505 ASM_LOCATION("ICCompareStub[Miss]"); | 3504 ASM_LOCATION("CompareICStub[Miss]"); |
3506 | 3505 |
3507 Register stub_entry = x11; | 3506 Register stub_entry = x11; |
3508 { | 3507 { |
3509 ExternalReference miss = | 3508 ExternalReference miss = |
3510 ExternalReference(IC_Utility(IC::kCompareIC_Miss), isolate()); | 3509 ExternalReference(IC_Utility(IC::kCompareIC_Miss), isolate()); |
3511 | 3510 |
3512 FrameScope scope(masm, StackFrame::INTERNAL); | 3511 FrameScope scope(masm, StackFrame::INTERNAL); |
3513 Register op = x10; | 3512 Register op = x10; |
3514 Register left = x1; | 3513 Register left = x1; |
3515 Register right = x0; | 3514 Register right = x0; |
(...skipping 1599 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5115 MemOperand(fp, 6 * kPointerSize), | 5114 MemOperand(fp, 6 * kPointerSize), |
5116 NULL); | 5115 NULL); |
5117 } | 5116 } |
5118 | 5117 |
5119 | 5118 |
5120 #undef __ | 5119 #undef __ |
5121 | 5120 |
5122 } } // namespace v8::internal | 5121 } } // namespace v8::internal |
5123 | 5122 |
5124 #endif // V8_TARGET_ARCH_ARM64 | 5123 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |