Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(396)

Side by Side Diff: src/arm/codegen-arm.cc

Issue 119241: A bunch of changes to speed up math on ARM.... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 11 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | src/code-stubs.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. 1 // Copyright 2006-2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 657 matching lines...) Expand 10 before | Expand all | Expand 10 after
668 class OpBits: public BitField<Token::Value, 2, 14> {}; 668 class OpBits: public BitField<Token::Value, 2, 14> {};
669 669
670 Major MajorKey() { return GenericBinaryOp; } 670 Major MajorKey() { return GenericBinaryOp; }
671 int MinorKey() { 671 int MinorKey() {
672 // Encode the parameters in a unique 16 bit value. 672 // Encode the parameters in a unique 16 bit value.
673 return OpBits::encode(op_) 673 return OpBits::encode(op_)
674 | ModeBits::encode(mode_); 674 | ModeBits::encode(mode_);
675 } 675 }
676 676
677 void Generate(MacroAssembler* masm); 677 void Generate(MacroAssembler* masm);
678 void HandleNonSmiBitwiseOp(MacroAssembler* masm);
678 679
679 const char* GetName() { 680 const char* GetName() {
680 switch (op_) { 681 switch (op_) {
681 case Token::ADD: return "GenericBinaryOpStub_ADD"; 682 case Token::ADD: return "GenericBinaryOpStub_ADD";
682 case Token::SUB: return "GenericBinaryOpStub_SUB"; 683 case Token::SUB: return "GenericBinaryOpStub_SUB";
683 case Token::MUL: return "GenericBinaryOpStub_MUL"; 684 case Token::MUL: return "GenericBinaryOpStub_MUL";
684 case Token::DIV: return "GenericBinaryOpStub_DIV"; 685 case Token::DIV: return "GenericBinaryOpStub_DIV";
685 case Token::BIT_OR: return "GenericBinaryOpStub_BIT_OR"; 686 case Token::BIT_OR: return "GenericBinaryOpStub_BIT_OR";
686 case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND"; 687 case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND";
687 case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR"; 688 case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR";
(...skipping 2896 matching lines...) Expand 10 before | Expand all | Expand 10 after
3584 LoadAndSpill(node->expression()); 3585 LoadAndSpill(node->expression());
3585 frame_->EmitPop(r0); 3586 frame_->EmitPop(r0);
3586 switch (op) { 3587 switch (op) {
3587 case Token::NOT: 3588 case Token::NOT:
3588 case Token::DELETE: 3589 case Token::DELETE:
3589 case Token::TYPEOF: 3590 case Token::TYPEOF:
3590 UNREACHABLE(); // handled above 3591 UNREACHABLE(); // handled above
3591 break; 3592 break;
3592 3593
3593 case Token::SUB: { 3594 case Token::SUB: {
3594 UnarySubStub stub; 3595 bool overwrite =
3596 (node->AsBinaryOperation() != NULL &&
3597 node->AsBinaryOperation()->ResultOverwriteAllowed());
3598 UnarySubStub stub(overwrite);
3595 frame_->CallStub(&stub, 0); 3599 frame_->CallStub(&stub, 0);
3596 break; 3600 break;
3597 } 3601 }
3598 3602
3599 case Token::BIT_NOT: { 3603 case Token::BIT_NOT: {
3600 // smi check 3604 // smi check
3601 JumpTarget smi_label; 3605 JumpTarget smi_label;
3602 JumpTarget continue_label; 3606 JumpTarget continue_label;
3603 __ tst(r0, Operand(kSmiTagMask)); 3607 __ tst(r0, Operand(kSmiTagMask));
3604 smi_label.Branch(eq); 3608 smi_label.Branch(eq);
(...skipping 749 matching lines...) Expand 10 before | Expand all | Expand 10 after
4354 frame->EmitPush(result.reg()); 4358 frame->EmitPush(result.reg());
4355 break; 4359 break;
4356 } 4360 }
4357 4361
4358 default: 4362 default:
4359 UNREACHABLE(); 4363 UNREACHABLE();
4360 } 4364 }
4361 } 4365 }
4362 4366
4363 4367
4368 // Count leading zeros in a 32 bit word. On ARM5 and later it uses the clz
4369 // instruction. On pre-ARM5 hardware this routine gives the wrong answer for 0
4370 // (31 instead of 32).
4371 static void CountLeadingZeros(
4372 MacroAssembler* masm,
4373 Register source,
4374 Register scratch,
4375 Register zeros) {
4376 #ifdef __ARM_ARCH_5__
4377 __ clz(zeros, source); // This instruction is only supported after ARM5.
4378 #else
4379 __ mov(zeros, Operand(0));
4380 __ mov(scratch, source);
4381 // Top 16.
4382 __ tst(scratch, Operand(0xffff0000));
4383 __ add(zeros, zeros, Operand(16), LeaveCC, eq);
4384 __ mov(scratch, Operand(scratch, LSL, 16), LeaveCC, eq);
4385 // Top 8.
4386 __ tst(scratch, Operand(0xff000000));
4387 __ add(zeros, zeros, Operand(8), LeaveCC, eq);
4388 __ mov(scratch, Operand(scratch, LSL, 8), LeaveCC, eq);
4389 // Top 4.
4390 __ tst(scratch, Operand(0xf0000000));
4391 __ add(zeros, zeros, Operand(4), LeaveCC, eq);
4392 __ mov(scratch, Operand(scratch, LSL, 4), LeaveCC, eq);
4393 // Top 2.
4394 __ tst(scratch, Operand(0xc0000000));
4395 __ add(zeros, zeros, Operand(2), LeaveCC, eq);
4396 __ mov(scratch, Operand(scratch, LSL, 2), LeaveCC, eq);
4397 // Top bit.
4398 __ tst(scratch, Operand(0x80000000));
4399 __ add(zeros, zeros, Operand(1), LeaveCC, eq);
4400 #endif
4401 }
4402
4403
4404 // Takes a Smi and converts to an IEEE 64 bit floating point value in two
4405 // registers. The format is 1 sign bit, 11 exponent bits (biased 1023) and
4406 // 52 fraction bits (20 in the first word, 32 in the second). Zeros is a
4407 // scratch register. Destroys the source register. No GC occurs during this
4408 // stub so you don't have to set up the frame.
4409 class ConvertToDoubleStub : public CodeStub {
4410 public:
4411 ConvertToDoubleStub(Register result_reg_1,
4412 Register result_reg_2,
4413 Register source_reg,
4414 Register scratch_reg)
4415 : result1_(result_reg_1),
4416 result2_(result_reg_2),
4417 source_(source_reg),
4418 zeros_(scratch_reg) { }
4419
4420 private:
4421 Register result1_;
4422 Register result2_;
4423 Register source_;
4424 Register zeros_;
4425
4426 // Minor key encoding in 16 bits.
4427 class ModeBits: public BitField<OverwriteMode, 0, 2> {};
4428 class OpBits: public BitField<Token::Value, 2, 14> {};
4429
4430 Major MajorKey() { return ConvertToDouble; }
4431 int MinorKey() {
4432 // Encode the parameters in a unique 16 bit value.
4433 return result1_.code() +
4434 (result2_.code() << 4) +
4435 (source_.code() << 8) +
4436 (zeros_.code() << 12);
4437 }
4438
4439 void Generate(MacroAssembler* masm);
4440
4441 const char* GetName() { return "ConvertToDoubleStub"; }
4442
4443 #ifdef DEBUG
4444 void Print() { PrintF("ConvertToDoubleStub\n"); }
4445 #endif
4446 };
4447
4448
4449 void ConvertToDoubleStub::Generate(MacroAssembler* masm) {
4450 Label not_special, done;
4451 // Convert from Smi to integer.
4452 __ mov(source_, Operand(source_, ASR, kSmiTagSize));
4453 // Move sign bit from source to destination. This works because the sign bit
4454 // in the exponent word of the double has the same position and polarity as
4455 // the 2's complement sign bit in a Smi.
4456 ASSERT(HeapNumber::kSignMask == 0x80000000u);
4457 __ and_(result1_, source_, Operand(HeapNumber::kSignMask), SetCC);
4458 // Subtract from 0 if source was negative.
4459 __ rsb(source_, source_, Operand(0), LeaveCC, ne);
4460 __ cmp(source_, Operand(1));
4461 __ b(gt, &not_special);
4462
4463 // We have -1, 0 or 1, which we treat specially.
4464 __ cmp(source_, Operand(0));
4465 // For 1 or -1 we need to or in the 0 exponent (biased to 1023).
4466 static const uint32_t exponent_word_for_1 =
4467 HeapNumber::kExponentBias << HeapNumber::kExponentShift;
4468 __ orr(result1_, result1_, Operand(exponent_word_for_1), LeaveCC, ne);
4469 // 1, 0 and -1 all have 0 for the second word.
4470 __ mov(result2_, Operand(0));
4471 __ jmp(&done);
4472
4473 __ bind(&not_special);
4474 // Count leading zeros. Uses result2 for a scratch register on pre-ARM5.
4475 // Gets the wrong answer for 0, but we already checked for that case above.
4476 CountLeadingZeros(masm, source_, result2_, zeros_);
4477 // Compute exponent and or it into the exponent register.
4478 // We use result2 as a scratch register here.
4479 __ rsb(result2_, zeros_, Operand(31 + HeapNumber::kExponentBias));
4480 __ orr(result1_, result1_, Operand(result2_, LSL, 20));
iposva 2009/06/10 04:30:48 Please use kExponentShift, which you added to the
4481 // Shift up the source chopping the top bit off.
4482 __ add(zeros_, zeros_, Operand(1));
4483 // This wouldn't work for 1.0 or -1.0 as the shift would be 32 which means 0.
4484 __ mov(source_, Operand(source_, LSL, zeros_));
4485 // Compute lower part of fraction (last 12 bits).
4486 __ mov(result2_, Operand(source_, LSL, HeapNumber::kMantissaBitsInTopWord));
4487 // And the top (top 20 bits).
4488 __ orr(result1_,
4489 result1_,
4490 Operand(source_, LSR, 32 - HeapNumber::kMantissaBitsInTopWord));
4491 __ bind(&done);
4492 __ Ret();
4493 }
4494
4495
4496 // This stub can convert a signed int32 to a heap number (double). It does
4497 // not work for int32s that are in Smi range! No GC occurs during this stub
4498 // so you don't have to set up the frame.
4499 class WriteInt32ToHeapNumberStub : public CodeStub {
4500 public:
4501 WriteInt32ToHeapNumberStub(Register the_int,
4502 Register the_heap_number,
4503 Register scratch)
4504 : the_int_(the_int),
4505 the_heap_number_(the_heap_number),
4506 scratch_(scratch) { }
4507
4508 private:
4509 Register the_int_;
4510 Register the_heap_number_;
4511 Register scratch_;
4512
4513 // Minor key encoding in 16 bits.
4514 class ModeBits: public BitField<OverwriteMode, 0, 2> {};
4515 class OpBits: public BitField<Token::Value, 2, 14> {};
4516
4517 Major MajorKey() { return WriteInt32ToHeapNumber; }
4518 int MinorKey() {
4519 // Encode the parameters in a unique 16 bit value.
4520 return the_int_.code() +
4521 (the_heap_number_.code() << 4) +
4522 (scratch_.code() << 8);
4523 }
4524
4525 void Generate(MacroAssembler* masm);
4526
4527 const char* GetName() { return "WriteInt32ToHeapNumberStub"; }
4528
4529 #ifdef DEBUG
4530 void Print() { PrintF("WriteInt32ToHeapNumberStub\n"); }
4531 #endif
4532 };
4533
4534
4535 // See comment for class.
4536 void WriteInt32ToHeapNumberStub::Generate(MacroAssembler *masm) {
4537 Label max_negative_int;
4538 // the_int_ has the answer which is a signed int32 but not a Smi.
4539 // We test for the special value that has a different exponent. This test
4540 // has the neat side effect of setting the flags according to the sign.
4541 ASSERT(HeapNumber::kSignMask == 0x80000000u);
4542 __ cmp(the_int_, Operand(0x80000000));
4543 __ b(eq, &max_negative_int);
4544 // Set up the correct exponent in scratch_. All non-Smi int32s have the same.
4545 // A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased).
4546 uint32_t non_smi_exponent =
4547 (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift;
4548 __ mov(scratch_, Operand(non_smi_exponent));
4549 // Set the sign bit in scratch_ if the value was negative.
4550 __ orr(scratch_, scratch_, Operand(HeapNumber::kSignMask), LeaveCC, cs);
4551 // Subtract from 0 if the value was negative.
4552 __ rsb(the_int_, the_int_, Operand(0), LeaveCC, cs);
4553 // We should be masking the implict first digit of the mantissa away here,
4554 // but it just ends up combining harmlessly with the last digit of the
4555 // exponent that happens to be 1. The sign bit is 0 so we shift 10 to get
4556 // the most significant 1 to hit the last bit of the 12 bit sign and exponent.
4557 ASSERT(((1 << HeapNumber::kExponentShift) & non_smi_exponent) != 0);
4558 const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
4559 __ orr(scratch_, scratch_, Operand(the_int_, LSR, shift_distance));
4560 __ str(scratch_, FieldMemOperand(the_heap_number_,
4561 HeapNumber::kExponentOffset));
4562 __ mov(scratch_, Operand(the_int_, LSL, 32 - shift_distance));
4563 __ str(scratch_, FieldMemOperand(the_heap_number_,
4564 HeapNumber::kMantissaOffset));
4565 __ Ret();
4566
4567 __ bind(&max_negative_int);
4568 // The max negative int32 is stored as a positive number in the mantissa of
4569 // a double because it uses a sign bit instead of using two's complement.
4570 // The actual mantissa bits stored are all 0 because the implicit most
4571 // significant 1 bit is not stored.
4572 non_smi_exponent += 1 << HeapNumber::kExponentShift;
4573 __ mov(ip, Operand(HeapNumber::kSignMask | non_smi_exponent));
4574 __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kExponentOffset));
4575 __ mov(ip, Operand(0));
4576 __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kMantissaOffset));
4577 __ Ret();
4578 }
4579
4580
4581 // Allocates a heap number or jumps to the label if the young space is full and
4582 // a scavenge is needed.
4364 static void AllocateHeapNumber( 4583 static void AllocateHeapNumber(
4365 MacroAssembler* masm, 4584 MacroAssembler* masm,
4366 Label* need_gc, // Jump here if young space is full. 4585 Label* need_gc, // Jump here if young space is full.
4367 Register result_reg, // The tagged address of the new heap number. 4586 Register result_reg, // The tagged address of the new heap number.
4368 Register allocation_top_addr_reg, // A scratch register. 4587 Register allocation_top_addr_reg, // A scratch register.
4369 Register scratch2) { // Another scratch register. 4588 Register scratch2) { // Another scratch register.
4370 ExternalReference allocation_top = 4589 ExternalReference allocation_top =
4371 ExternalReference::new_space_allocation_top_address(); 4590 ExternalReference::new_space_allocation_top_address();
4372 ExternalReference allocation_limit = 4591 ExternalReference allocation_limit =
4373 ExternalReference::new_space_allocation_limit_address(); 4592 ExternalReference::new_space_allocation_limit_address();
(...skipping 16 matching lines...) Expand all
4390 __ str(result_reg, MemOperand(allocation_top_addr_reg)); // store new top 4609 __ str(result_reg, MemOperand(allocation_top_addr_reg)); // store new top
4391 // Tag and adjust back to start of new object. 4610 // Tag and adjust back to start of new object.
4392 __ sub(result_reg, result_reg, Operand(HeapNumber::kSize - kHeapObjectTag)); 4611 __ sub(result_reg, result_reg, Operand(HeapNumber::kSize - kHeapObjectTag));
4393 // Get heap number map into scratch2. 4612 // Get heap number map into scratch2.
4394 __ mov(scratch2, Operand(Factory::heap_number_map())); 4613 __ mov(scratch2, Operand(Factory::heap_number_map()));
4395 // Store heap number map in new object. 4614 // Store heap number map in new object.
4396 __ str(scratch2, FieldMemOperand(result_reg, HeapObject::kMapOffset)); 4615 __ str(scratch2, FieldMemOperand(result_reg, HeapObject::kMapOffset));
4397 } 4616 }
4398 4617
4399 4618
4619 // Checks that the object register (which is assumed not to be a Smi) points to
4620 // a heap number. Jumps to the label if it is not.
4621 void CheckForHeapNumber(MacroAssembler* masm,
4622 Register object,
4623 Register scratch,
4624 Label* slow) {
4625 // Get map of object into scratch.
4626 __ ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
4627 // Get type of object into scratch.
4628 __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
4629 __ cmp(scratch, Operand(HEAP_NUMBER_TYPE));
4630 __ b(ne, slow);
4631 }
4632
4633
4400 // We fall into this code if the operands were Smis, but the result was 4634 // We fall into this code if the operands were Smis, but the result was
4401 // not (eg. overflow). We branch into this code (to the not_smi label) if 4635 // not (eg. overflow). We branch into this code (to the not_smi label) if
4402 // the operands were not both Smi. 4636 // the operands were not both Smi. The operands are in r0 and r1. In order
4637 // to call the C-implemented binary fp operation routines we need to end up
4638 // with the double precision floating point operands in r0 and r1 (for the
4639 // value in r1) and r2 and r3 (for the value in r0).
4403 static void HandleBinaryOpSlowCases(MacroAssembler* masm, 4640 static void HandleBinaryOpSlowCases(MacroAssembler* masm,
4404 Label* not_smi, 4641 Label* not_smi,
4405 const Builtins::JavaScript& builtin, 4642 const Builtins::JavaScript& builtin,
4406 Token::Value operation, 4643 Token::Value operation,
4407 int swi_number, 4644 int swi_number,
4408 OverwriteMode mode) { 4645 OverwriteMode mode) {
4409 Label slow; 4646 Label slow, slow_pop_2_first, do_the_call;
4647 Label r0_is_smi, r1_is_smi, finished_loading_r0, finished_loading_r1;
4648 // Smi-smi case (overflow).
4649 // Since both are Smis there is no heap number to overwrite, so allocate.
4650 // The new heap number is in r5. r6 and r7 are scratch.
4651 AllocateHeapNumber(masm, &slow, r5, r6, r7);
4652 // Write Smi from r0 to r3 and r2 in double format. r6 is scratch.
4653 ConvertToDoubleStub stub1(r3, r2, r0, r6);
4654 __ push(lr);
4655 __ Call(stub1.GetCode(), RelocInfo::CODE_TARGET);
4656 // Write Smi from r1 to r1 and r0 in double format. r6 is scratch.
4657 __ mov(r7, Operand(r1));
4658 ConvertToDoubleStub stub2(r1, r0, r7, r6);
4659 __ Call(stub2.GetCode(), RelocInfo::CODE_TARGET);
4660 __ pop(lr);
4661 __ jmp(&do_the_call); // Tail call. No return.
4662
4663 // We jump to here if something goes wrong (one param is not a number of any
4664 // sort or new-space allocation fails).
4410 __ bind(&slow); 4665 __ bind(&slow);
4411 __ push(r1); 4666 __ push(r1);
4412 __ push(r0); 4667 __ push(r0);
4413 __ mov(r0, Operand(1)); // Set number of arguments. 4668 __ mov(r0, Operand(1)); // Set number of arguments.
4414 __ InvokeBuiltin(builtin, JUMP_JS); // Tail call. 4669 __ InvokeBuiltin(builtin, JUMP_JS); // Tail call. No return.
4415 4670
4671 // We branch here if at least one of r0 and r1 is not a Smi.
4416 __ bind(not_smi); 4672 __ bind(not_smi);
4673 if (mode == NO_OVERWRITE) {
4674 // In the case where there is no chance of an overwritable float we may as
4675 // well do the allocation immediately while r0 and r1 are untouched.
4676 AllocateHeapNumber(masm, &slow, r5, r6, r7);
4677 }
4678
4679 // Move r0 to a double in r2-r3.
4417 __ tst(r0, Operand(kSmiTagMask)); 4680 __ tst(r0, Operand(kSmiTagMask));
4418 __ b(eq, &slow); // We can't handle a Smi-double combination yet. 4681 __ b(eq, &r0_is_smi); // It's a Smi so don't check it's a heap number.
4682 CheckForHeapNumber(masm, r0, r4, &slow);
4683 if (mode == OVERWRITE_RIGHT) {
4684 __ mov(r5, Operand(r0)); // Overwrite this heap number.
4685 }
4686 // Calling convention says that second double is in r2 and r3.
4687 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
4688 __ ldr(r3, FieldMemOperand(r0, HeapNumber::kExponentOffset));
4689 __ jmp(&finished_loading_r0);
4690 __ bind(&r0_is_smi);
4691 if (mode == OVERWRITE_RIGHT) {
4692 // We can't overwrite a Smi so get address of new heap number into r5.
4693 AllocateHeapNumber(masm, &slow, r5, r6, r7);
4694 }
4695 // Write Smi from r0 to r3 and r2 in double format.
4696 __ mov(r7, Operand(r0));
4697 ConvertToDoubleStub stub3(r3, r2, r7, r6);
4698 __ push(lr);
4699 __ Call(stub3.GetCode(), RelocInfo::CODE_TARGET);
4700 __ pop(lr);
4701 __ bind(&finished_loading_r0);
4702
4703 // Move r1 to a double in r0-r1.
4419 __ tst(r1, Operand(kSmiTagMask)); 4704 __ tst(r1, Operand(kSmiTagMask));
4420 __ b(eq, &slow); // We can't handle a Smi-double combination yet. 4705 __ b(eq, &r1_is_smi); // It's a Smi so don't check it's a heap number.
4421 // Get map of r0 into r2. 4706 CheckForHeapNumber(masm, r1, r4, &slow);
4422 __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset)); 4707 if (mode == OVERWRITE_LEFT) {
4423 // Get type of r0 into r3. 4708 __ mov(r5, Operand(r1)); // Overwrite this heap number.
4424 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceTypeOffset));
4425 __ cmp(r3, Operand(HEAP_NUMBER_TYPE));
4426 __ b(ne, &slow);
4427 // Get type of r1 into r3.
4428 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
4429 // Check they are both the same map (heap number map).
4430 __ cmp(r2, r3);
4431 __ b(ne, &slow);
4432 // Both are doubles.
4433 // Calling convention says that second double is in r2 and r3.
4434 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kValueOffset));
4435 __ ldr(r3, FieldMemOperand(r0, HeapNumber::kValueOffset + kPointerSize));
4436
4437 if (mode == NO_OVERWRITE) {
4438 // Get address of new heap number into r5.
4439 AllocateHeapNumber(masm, &slow, r5, r6, r7);
4440 __ push(lr);
4441 __ push(r5);
4442 } else if (mode == OVERWRITE_LEFT) {
4443 __ push(lr);
4444 __ push(r1);
4445 } else {
4446 ASSERT(mode == OVERWRITE_RIGHT);
4447 __ push(lr);
4448 __ push(r0);
4449 } 4709 }
4450 // Calling convention says that first double is in r0 and r1. 4710 // Calling convention says that first double is in r0 and r1.
4451 __ ldr(r0, FieldMemOperand(r1, HeapNumber::kValueOffset)); 4711 __ ldr(r0, FieldMemOperand(r1, HeapNumber::kMantissaOffset));
4452 __ ldr(r1, FieldMemOperand(r1, HeapNumber::kValueOffset + kPointerSize)); 4712 __ ldr(r1, FieldMemOperand(r1, HeapNumber::kExponentOffset));
4713 __ jmp(&finished_loading_r1);
4714 __ bind(&r1_is_smi);
4715 if (mode == OVERWRITE_LEFT) {
4716 // We can't overwrite a Smi so get address of new heap number into r5.
4717 AllocateHeapNumber(masm, &slow, r5, r6, r7);
4718 }
4719 // Write Smi from r1 to r1 and r0 in double format.
4720 __ mov(r7, Operand(r1));
4721 ConvertToDoubleStub stub4(r1, r0, r7, r6);
4722 __ push(lr);
4723 __ Call(stub4.GetCode(), RelocInfo::CODE_TARGET);
4724 __ pop(lr);
4725 __ bind(&finished_loading_r1);
4726
4727 __ bind(&do_the_call);
4728 // r0: Left value (least significant part of mantissa).
4729 // r1: Left value (sign, exponent, top of mantissa).
4730 // r2: Right value (least significant part of mantissa).
4731 // r3: Right value (sign, exponent, top of mantissa).
4732 // r5: Address of heap number for result.
4733 __ push(lr); // For later.
4734 __ push(r5); // Address of heap number that is answer.
4453 // Call C routine that may not cause GC or other trouble. 4735 // Call C routine that may not cause GC or other trouble.
4454 __ mov(r5, Operand(ExternalReference::double_fp_operation(operation))); 4736 __ mov(r5, Operand(ExternalReference::double_fp_operation(operation)));
4455 #if !defined(__arm__) 4737 #if !defined(__arm__)
4456 // Notify the simulator that we are calling an add routine in C. 4738 // Notify the simulator that we are calling an add routine in C.
4457 __ swi(swi_number); 4739 __ swi(swi_number);
4458 #else 4740 #else
4459 // Actually call the add routine written in C. 4741 // Actually call the add routine written in C.
4460 __ Call(r5); 4742 __ Call(r5);
4461 #endif 4743 #endif
4462 // Store answer in the overwritable heap number. 4744 // Store answer in the overwritable heap number.
4463 __ pop(r4); 4745 __ pop(r4);
4464 #if !defined(__ARM_EABI__) && defined(__arm__) 4746 #if !defined(__ARM_EABI__) && defined(__arm__)
4465 // Double returned in fp coprocessor register 0 and 1, encoded as register 4747 // Double returned in fp coprocessor register 0 and 1, encoded as register
4466 // cr8. Offsets must be divisible by 4 for coprocessor so we need to 4748 // cr8. Offsets must be divisible by 4 for coprocessor so we need to
4467 // substract the tag from r4. 4749 // substract the tag from r4.
4468 __ sub(r5, r4, Operand(kHeapObjectTag)); 4750 __ sub(r5, r4, Operand(kHeapObjectTag));
4469 __ stc(p1, cr8, MemOperand(r5, HeapNumber::kValueOffset)); 4751 __ stc(p1, cr8, MemOperand(r5, HeapNumber::kValueOffset));
4470 #else 4752 #else
4471 // Double returned in fp coprocessor register 0 and 1. 4753 // Double returned in fp coprocessor register 0 and 1.
4472 __ str(r0, FieldMemOperand(r4, HeapNumber::kValueOffset)); 4754 __ str(r0, FieldMemOperand(r4, HeapNumber::kMantissaOffset));
4473 __ str(r1, FieldMemOperand(r4, HeapNumber::kValueOffset + kPointerSize)); 4755 __ str(r1, FieldMemOperand(r4, HeapNumber::kExponentOffset));
4474 #endif 4756 #endif
4475 __ mov(r0, Operand(r4)); 4757 __ mov(r0, Operand(r4));
4476 // And we are done. 4758 // And we are done.
4477 __ pop(pc); 4759 __ pop(pc);
4478 } 4760 }
4479 4761
4480 4762
4763 // Tries to get a signed int32 out of a double precision floating point heap
4764 // number. Rounds towards 0. Only succeeds for doubles that are in the ranges
4765 // -0x7fffffff to -0x40000000 or 0x40000000 to 0x7fffffff. This corresponds
4766 // almost to the range of signed int32 values that are not Smis. Jumps to the
4767 // label if the double isn't in the range it can cope with.
4768 static void GetInt32(MacroAssembler* masm,
4769 Register source,
4770 Register dest,
4771 Register scratch,
4772 Label* slow) {
4773 Register scratch2 = dest;
4774 // Get exponent word.
4775 __ ldr(scratch, FieldMemOperand(source, HeapNumber::kExponentOffset));
4776 // Get exponent alone in scratch2.
4777 __ and_(scratch2, scratch, Operand(HeapNumber::kExponentMask));
4778 // Check whether the exponent matches a 32 bit signed int that is not a Smi.
4779 // A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased).
4780 const uint32_t non_smi_exponent =
4781 (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift;
4782 __ cmp(scratch2, Operand(non_smi_exponent));
4783 // If not, then we go slow.
4784 __ b(ne, slow);
4785 // Get the top bits of the mantissa.
4786 __ and_(scratch2, scratch, Operand(HeapNumber::kMantissaMask));
4787 // Put back the implicit 1.
4788 __ orr(scratch2, scratch2, Operand(1 << HeapNumber::kExponentShift));
4789 // Shift up the mantissa bits to take up the space the exponent used to take.
4790 // We just orred in the implicit bit so that took care of one and we want to
4791 // leave the sign bit 0 so we subtract 2 bits from the shift distance.
4792 const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
4793 __ mov(scratch2, Operand(scratch2, LSL, shift_distance));
4794 // Put sign in zero flag.
4795 __ tst(scratch, Operand(HeapNumber::kSignMask));
4796 // Get the second half of the double.
4797 __ ldr(scratch, FieldMemOperand(source, HeapNumber::kMantissaOffset));
4798 // Shift down 22 bits to get the last 10 bits.
4799 __ orr(dest, scratch2, Operand(scratch, LSR, 32 - shift_distance));
4800 // Fix sign if sign bit was set.
4801 __ rsb(dest, dest, Operand(0), LeaveCC, ne);
4802 }
4803
4804
4805 // For bitwise ops where the inputs are not both Smis we here try to determine
4806 // whether both inputs are either Smis or at least heap numbers that can be
4807 // represented by a 32 bit signed value. We truncate towards zero as required
4808 // by the ES spec. If this is the case we do the bitwise op and see if the
4809 // result is a Smi. If so, great, otherwise we try to find a heap number to
4810 // write the answer into (either by allocating or by overwriting).
4811 // On entry the operands are in r0 and r1. On exit the answer is in r0.
4812 void GenericBinaryOpStub::HandleNonSmiBitwiseOp(MacroAssembler* masm) {
4813 Label slow, result_not_a_smi;
4814 Label r0_is_smi, r1_is_smi;
4815 Label done_checking_r0, done_checking_r1;
4816
4817 __ tst(r1, Operand(kSmiTagMask));
4818 __ b(eq, &r1_is_smi); // It's a Smi so don't check it's a heap number.
4819 CheckForHeapNumber(masm, r1, r4, &slow);
4820 GetInt32(masm, r1, r3, r4, &slow);
4821 __ jmp(&done_checking_r1);
4822 __ bind(&r1_is_smi);
4823 __ mov(r3, Operand(r1, ASR, 1));
4824 __ bind(&done_checking_r1);
4825
4826 __ tst(r0, Operand(kSmiTagMask));
4827 __ b(eq, &r0_is_smi); // It's a Smi so don't check it's a heap number.
4828 CheckForHeapNumber(masm, r0, r4, &slow);
4829 GetInt32(masm, r0, r2, r4, &slow);
4830 __ jmp(&done_checking_r0);
4831 __ bind(&r0_is_smi);
4832 __ mov(r2, Operand(r0, ASR, 1));
4833 __ bind(&done_checking_r0);
4834
4835 // r0 and r1: Original operands (Smi or heap numbers).
4836 // r2 and r3: Signed int32 operands.
4837 switch (op_) {
4838 case Token::BIT_OR: __ orr(r2, r2, Operand(r3)); break;
4839 case Token::BIT_XOR: __ eor(r2, r2, Operand(r3)); break;
4840 case Token::BIT_AND: __ and_(r2, r2, Operand(r3)); break;
4841 case Token::SAR:
4842 // Use only the 5 least significant bits of the shift count.
4843 __ and_(r2, r2, Operand(0x1f));
4844 __ mov(r2, Operand(r3, ASR, r2));
4845 break;
4846 case Token::SHR:
4847 // Use only the 5 least significant bits of the shift count.
4848 __ and_(r2, r2, Operand(0x1f));
4849 __ mov(r2, Operand(r3, LSR, r2), SetCC);
4850 // SHR is special because it is required to produce a positive answer.
4851 // The code below for writing into heap numbers isn't capable of writing
4852 // the register as an unsigned int so we go to slow case if we hit this
4853 // case.
4854 __ b(mi, &slow);
4855 break;
4856 case Token::SHL:
4857 // Use only the 5 least significant bits of the shift count.
4858 __ and_(r2, r2, Operand(0x1f));
4859 __ mov(r2, Operand(r3, LSL, r2));
4860 break;
4861 default: UNREACHABLE();
4862 }
4863 // check that the *signed* result fits in a smi
4864 __ add(r3, r2, Operand(0x40000000), SetCC);
4865 __ b(mi, &result_not_a_smi);
4866 __ mov(r0, Operand(r2, LSL, kSmiTagSize));
4867 __ Ret();
4868
4869 Label have_to_allocate, got_a_heap_number;
4870 __ bind(&result_not_a_smi);
4871 switch (mode_) {
4872 case OVERWRITE_RIGHT: {
4873 __ tst(r0, Operand(kSmiTagMask));
4874 __ b(eq, &have_to_allocate);
4875 __ mov(r5, Operand(r0));
4876 break;
4877 }
4878 case OVERWRITE_LEFT: {
4879 __ tst(r1, Operand(kSmiTagMask));
4880 __ b(eq, &have_to_allocate);
4881 __ mov(r5, Operand(r1));
4882 break;
4883 }
4884 case NO_OVERWRITE: {
4885 // Get a new heap number in r5. r6 and r7 are scratch.
4886 AllocateHeapNumber(masm, &slow, r5, r6, r7);
4887 }
4888 default: break;
4889 }
4890 __ bind(&got_a_heap_number);
4891 // r2: Answer as signed int32.
4892 // r5: Heap number to write answer into.
4893
4894 // Nothing can go wrong now, so move the heap number to r0, which is the
4895 // result.
4896 __ mov(r0, Operand(r5));
4897
4898 // Tail call that writes the int32 in r2 to the heap number in r0, using
4899 // r3 as scratch. r0 is preserved and returned.
4900 WriteInt32ToHeapNumberStub stub(r2, r0, r3);
4901 __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
4902
4903 if (mode_ != NO_OVERWRITE) {
4904 __ bind(&have_to_allocate);
4905 // Get a new heap number in r5. r6 and r7 are scratch.
4906 AllocateHeapNumber(masm, &slow, r5, r6, r7);
4907 __ jmp(&got_a_heap_number);
4908 }
4909
4910 // If all else failed then we go to the runtime system.
4911 __ bind(&slow);
4912 __ push(r1); // restore stack
4913 __ push(r0);
4914 __ mov(r0, Operand(1)); // 1 argument (not counting receiver).
4915 switch (op_) {
4916 case Token::BIT_OR:
4917 __ InvokeBuiltin(Builtins::BIT_OR, JUMP_JS);
4918 break;
4919 case Token::BIT_AND:
4920 __ InvokeBuiltin(Builtins::BIT_AND, JUMP_JS);
4921 break;
4922 case Token::BIT_XOR:
4923 __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_JS);
4924 break;
4925 case Token::SAR:
4926 __ InvokeBuiltin(Builtins::SAR, JUMP_JS);
4927 break;
4928 case Token::SHR:
4929 __ InvokeBuiltin(Builtins::SHR, JUMP_JS);
4930 break;
4931 case Token::SHL:
4932 __ InvokeBuiltin(Builtins::SHL, JUMP_JS);
4933 break;
4934 default:
4935 UNREACHABLE();
4936 }
4937 }
4938
4939
4481 void GenericBinaryOpStub::Generate(MacroAssembler* masm) { 4940 void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
4482 // r1 : x 4941 // r1 : x
4483 // r0 : y 4942 // r0 : y
4484 // result : r0 4943 // result : r0
4485 4944
4486 // All ops need to know whether we are dealing with two Smis. Set up r2 to 4945 // All ops need to know whether we are dealing with two Smis. Set up r2 to
4487 // tell us that. 4946 // tell us that.
4488 __ orr(r2, r1, Operand(r0)); // r2 = x | y; 4947 __ orr(r2, r1, Operand(r0)); // r2 = x | y;
4489 4948
4490 switch (op_) { 4949 switch (op_) {
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
4546 __ mov(r0, Operand(r3), LeaveCC, ne); 5005 __ mov(r0, Operand(r3), LeaveCC, ne);
4547 __ Ret(ne); 5006 __ Ret(ne);
4548 // Slow case. 5007 // Slow case.
4549 __ bind(&slow); 5008 __ bind(&slow);
4550 5009
4551 HandleBinaryOpSlowCases(masm, 5010 HandleBinaryOpSlowCases(masm,
4552 &not_smi, 5011 &not_smi,
4553 Builtins::MUL, 5012 Builtins::MUL,
4554 Token::MUL, 5013 Token::MUL,
4555 assembler::arm::simulator_fp_mul, 5014 assembler::arm::simulator_fp_mul,
4556 mode_); 5015 mode_);
4557 break; 5016 break;
4558 } 5017 }
4559 5018
4560 case Token::BIT_OR: 5019 case Token::BIT_OR:
4561 case Token::BIT_AND: 5020 case Token::BIT_AND:
4562 case Token::BIT_XOR: { 5021 case Token::BIT_XOR:
5022 case Token::SAR:
5023 case Token::SHR:
5024 case Token::SHL: {
4563 Label slow; 5025 Label slow;
4564 ASSERT(kSmiTag == 0); // adjust code below 5026 ASSERT(kSmiTag == 0); // adjust code below
4565 __ tst(r2, Operand(kSmiTagMask)); 5027 __ tst(r2, Operand(kSmiTagMask));
4566 __ b(ne, &slow); 5028 __ b(ne, &slow);
4567 switch (op_) { 5029 switch (op_) {
4568 case Token::BIT_OR: __ orr(r0, r0, Operand(r1)); break; 5030 case Token::BIT_OR: __ orr(r0, r0, Operand(r1)); break;
4569 case Token::BIT_AND: __ and_(r0, r0, Operand(r1)); break; 5031 case Token::BIT_AND: __ and_(r0, r0, Operand(r1)); break;
4570 case Token::BIT_XOR: __ eor(r0, r0, Operand(r1)); break; 5032 case Token::BIT_XOR: __ eor(r0, r0, Operand(r1)); break;
5033 case Token::SAR:
5034 // Remove tags from right operand.
5035 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // y
5036 // Use only the 5 least significant bits of the shift count.
5037 __ and_(r2, r2, Operand(0x1f));
5038 __ mov(r0, Operand(r1, ASR, r2));
5039 // Smi tag result.
5040 __ and_(r0, r0, Operand(~kSmiTagMask));
5041 break;
5042 case Token::SHR:
5043 // Remove tags from operands. We can't do this on a 31 bit number
5044 // because then the 0s get shifted into bit 30 instead of bit 31.
5045 __ mov(r3, Operand(r1, ASR, kSmiTagSize)); // x
5046 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // y
5047 // Use only the 5 least significant bits of the shift count.
5048 __ and_(r2, r2, Operand(0x1f));
5049 __ mov(r3, Operand(r3, LSR, r2));
5050 // Unsigned shift is not allowed to produce a negative number, so
5051 // check the sign bit and the sign bit after Smi tagging.
5052 __ tst(r3, Operand(0xc0000000));
5053 __ b(ne, &slow);
5054 // Smi tag result.
5055 __ mov(r0, Operand(r3, LSL, kSmiTagSize));
5056 break;
5057 case Token::SHL:
5058 // Remove tags from operands.
5059 __ mov(r3, Operand(r1, ASR, kSmiTagSize)); // x
5060 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // y
5061 // Use only the 5 least significant bits of the shift count.
5062 __ and_(r2, r2, Operand(0x1f));
5063 __ mov(r3, Operand(r3, LSL, r2));
5064 // Check that the signed result fits in a Smi.
5065 __ add(r2, r3, Operand(0x40000000), SetCC);
5066 __ b(mi, &slow);
5067 __ mov(r0, Operand(r3, LSL, kSmiTagSize));
5068 break;
4571 default: UNREACHABLE(); 5069 default: UNREACHABLE();
4572 } 5070 }
4573 __ Ret(); 5071 __ Ret();
4574 __ bind(&slow); 5072 __ bind(&slow);
4575 __ push(r1); // restore stack 5073 HandleNonSmiBitwiseOp(masm);
4576 __ push(r0);
4577 __ mov(r0, Operand(1)); // 1 argument (not counting receiver).
4578 switch (op_) {
4579 case Token::BIT_OR:
4580 __ InvokeBuiltin(Builtins::BIT_OR, JUMP_JS);
4581 break;
4582 case Token::BIT_AND:
4583 __ InvokeBuiltin(Builtins::BIT_AND, JUMP_JS);
4584 break;
4585 case Token::BIT_XOR:
4586 __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_JS);
4587 break;
4588 default:
4589 UNREACHABLE();
4590 }
4591 break; 5074 break;
4592 } 5075 }
4593 5076
4594 case Token::SHL:
4595 case Token::SHR:
4596 case Token::SAR: {
4597 Label slow;
4598 ASSERT(kSmiTag == 0); // adjust code below
4599 __ tst(r2, Operand(kSmiTagMask));
4600 __ b(ne, &slow);
4601 // remove tags from operands (but keep sign)
4602 __ mov(r3, Operand(r1, ASR, kSmiTagSize)); // x
4603 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // y
4604 // use only the 5 least significant bits of the shift count
4605 __ and_(r2, r2, Operand(0x1f));
4606 // perform operation
4607 switch (op_) {
4608 case Token::SAR:
4609 __ mov(r3, Operand(r3, ASR, r2));
4610 // no checks of result necessary
4611 break;
4612
4613 case Token::SHR:
4614 __ mov(r3, Operand(r3, LSR, r2));
4615 // check that the *unsigned* result fits in a smi
4616 // neither of the two high-order bits can be set:
4617 // - 0x80000000: high bit would be lost when smi tagging
4618 // - 0x40000000: this number would convert to negative when
4619 // smi tagging these two cases can only happen with shifts
4620 // by 0 or 1 when handed a valid smi
4621 __ and_(r2, r3, Operand(0xc0000000), SetCC);
4622 __ b(ne, &slow);
4623 break;
4624
4625 case Token::SHL:
4626 __ mov(r3, Operand(r3, LSL, r2));
4627 // check that the *signed* result fits in a smi
4628 __ add(r2, r3, Operand(0x40000000), SetCC);
4629 __ b(mi, &slow);
4630 break;
4631
4632 default: UNREACHABLE();
4633 }
4634 // tag result and store it in r0
4635 ASSERT(kSmiTag == 0); // adjust code below
4636 __ mov(r0, Operand(r3, LSL, kSmiTagSize));
4637 __ Ret();
4638 // slow case
4639 __ bind(&slow);
4640 __ push(r1); // restore stack
4641 __ push(r0);
4642 __ mov(r0, Operand(1)); // 1 argument (not counting receiver).
4643 switch (op_) {
4644 case Token::SAR: __ InvokeBuiltin(Builtins::SAR, JUMP_JS); break;
4645 case Token::SHR: __ InvokeBuiltin(Builtins::SHR, JUMP_JS); break;
4646 case Token::SHL: __ InvokeBuiltin(Builtins::SHL, JUMP_JS); break;
4647 default: UNREACHABLE();
4648 }
4649 break;
4650 }
4651
4652 default: UNREACHABLE(); 5077 default: UNREACHABLE();
4653 } 5078 }
4654 // This code should be unreachable. 5079 // This code should be unreachable.
4655 __ stop("Unreachable"); 5080 __ stop("Unreachable");
4656 } 5081 }
4657 5082
4658 5083
4659 void StackCheckStub::Generate(MacroAssembler* masm) { 5084 void StackCheckStub::Generate(MacroAssembler* masm) {
4660 Label within_limit; 5085 Label within_limit;
4661 __ mov(ip, Operand(ExternalReference::address_of_stack_guard_limit())); 5086 __ mov(ip, Operand(ExternalReference::address_of_stack_guard_limit()));
4662 __ ldr(ip, MemOperand(ip)); 5087 __ ldr(ip, MemOperand(ip));
4663 __ cmp(sp, Operand(ip)); 5088 __ cmp(sp, Operand(ip));
4664 __ b(hs, &within_limit); 5089 __ b(hs, &within_limit);
4665 // Do tail-call to runtime routine. Runtime routines expect at least one 5090 // Do tail-call to runtime routine. Runtime routines expect at least one
4666 // argument, so give it a Smi. 5091 // argument, so give it a Smi.
4667 __ mov(r0, Operand(Smi::FromInt(0))); 5092 __ mov(r0, Operand(Smi::FromInt(0)));
4668 __ push(r0); 5093 __ push(r0);
4669 __ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1); 5094 __ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1);
4670 __ bind(&within_limit); 5095 __ bind(&within_limit);
4671 5096
4672 __ StubReturn(1); 5097 __ StubReturn(1);
4673 } 5098 }
4674 5099
4675 5100
4676 void UnarySubStub::Generate(MacroAssembler* masm) { 5101 void UnarySubStub::Generate(MacroAssembler* masm) {
4677 Label undo; 5102 Label undo;
4678 Label slow; 5103 Label slow;
4679 Label done; 5104 Label done;
5105 Label not_smi;
4680 5106
4681 // Enter runtime system if the value is not a smi. 5107 // Enter runtime system if the value is not a smi.
4682 __ tst(r0, Operand(kSmiTagMask)); 5108 __ tst(r0, Operand(kSmiTagMask));
4683 __ b(ne, &slow); 5109 __ b(ne, &not_smi);
4684 5110
4685 // Enter runtime system if the value of the expression is zero 5111 // Enter runtime system if the value of the expression is zero
4686 // to make sure that we switch between 0 and -0. 5112 // to make sure that we switch between 0 and -0.
4687 __ cmp(r0, Operand(0)); 5113 __ cmp(r0, Operand(0));
4688 __ b(eq, &slow); 5114 __ b(eq, &slow);
4689 5115
4690 // The value of the expression is a smi that is not zero. Try 5116 // The value of the expression is a smi that is not zero. Try
4691 // optimistic subtraction '0 - value'. 5117 // optimistic subtraction '0 - value'.
4692 __ rsb(r1, r0, Operand(0), SetCC); 5118 __ rsb(r1, r0, Operand(0), SetCC);
4693 __ b(vs, &slow); 5119 __ b(vs, &slow);
4694 5120
4695 // If result is a smi we are done. 5121 __ mov(r0, Operand(r1)); // Set r0 to result.
4696 __ tst(r1, Operand(kSmiTagMask)); 5122 __ StubReturn(1);
4697 __ mov(r0, Operand(r1), LeaveCC, eq); // conditionally set r0 to result
4698 __ b(eq, &done);
4699 5123
4700 // Enter runtime system. 5124 // Enter runtime system.
4701 __ bind(&slow); 5125 __ bind(&slow);
4702 __ push(r0); 5126 __ push(r0);
4703 __ mov(r0, Operand(0)); // set number of arguments 5127 __ mov(r0, Operand(0)); // Set number of arguments.
4704 __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_JS); 5128 __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_JS);
4705 5129
4706 __ bind(&done); 5130 __ bind(&done);
4707 __ StubReturn(1); 5131 __ StubReturn(1);
5132
5133 __ bind(&not_smi);
5134 CheckForHeapNumber(masm, r0, r1, &slow);
5135 // r0 is a heap number. Get a new heap number in r1.
5136 if (overwrite_) {
5137 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
5138 __ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign.
5139 __ str(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
5140 } else {
5141 AllocateHeapNumber(masm, &slow, r1, r2, r3);
5142 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
5143 __ str(r2, FieldMemOperand(r1, HeapNumber::kMantissaOffset));
5144 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
5145 __ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign.
5146 __ str(r2, FieldMemOperand(r1, HeapNumber::kExponentOffset));
5147 __ mov(r0, Operand(r1));
5148 }
5149 __ StubReturn(1);
4708 } 5150 }
4709 5151
4710 5152
4711 void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { 5153 void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
4712 // r0 holds exception 5154 // r0 holds exception
4713 ASSERT(StackHandlerConstants::kSize == 6 * kPointerSize); // adjust this code 5155 ASSERT(StackHandlerConstants::kSize == 6 * kPointerSize); // adjust this code
4714 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); 5156 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
4715 __ ldr(sp, MemOperand(r3)); 5157 __ ldr(sp, MemOperand(r3));
4716 __ pop(r2); // pop next in chain 5158 __ pop(r2); // pop next in chain
4717 __ str(r2, MemOperand(r3)); 5159 __ str(r2, MemOperand(r3));
(...skipping 492 matching lines...) Expand 10 before | Expand all | Expand 10 after
5210 __ mov(r2, Operand(0)); 5652 __ mov(r2, Operand(0));
5211 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); 5653 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
5212 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)), 5654 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)),
5213 RelocInfo::CODE_TARGET); 5655 RelocInfo::CODE_TARGET);
5214 } 5656 }
5215 5657
5216 5658
5217 #undef __ 5659 #undef __
5218 5660
5219 } } // namespace v8::internal 5661 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « no previous file | src/code-stubs.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698