| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 543 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 554 } | 554 } |
| 555 | 555 |
| 556 | 556 |
| 557 MemOperand LCodeGen::ToHighMemOperand(LOperand* op) const { | 557 MemOperand LCodeGen::ToHighMemOperand(LOperand* op) const { |
| 558 ASSERT(op->IsDoubleStackSlot()); | 558 ASSERT(op->IsDoubleStackSlot()); |
| 559 return MemOperand(fp, StackSlotOffset(op->index()) + kPointerSize); | 559 return MemOperand(fp, StackSlotOffset(op->index()) + kPointerSize); |
| 560 } | 560 } |
| 561 | 561 |
| 562 | 562 |
| 563 void LCodeGen::WriteTranslation(LEnvironment* environment, | 563 void LCodeGen::WriteTranslation(LEnvironment* environment, |
| 564 Translation* translation, | 564 Translation* translation) { |
| 565 int* pushed_arguments_index, | |
| 566 int* pushed_arguments_count) { | |
| 567 if (environment == NULL) return; | 565 if (environment == NULL) return; |
| 568 | 566 |
| 569 // The translation includes one command per value in the environment. | 567 // The translation includes one command per value in the environment. |
| 570 int translation_size = environment->values()->length(); | 568 int translation_size = environment->translation_size(); |
| 571 // The output frame height does not include the parameters. | 569 // The output frame height does not include the parameters. |
| 572 int height = translation_size - environment->parameter_count(); | 570 int height = translation_size - environment->parameter_count(); |
| 573 | 571 |
| 574 // Function parameters are arguments to the outermost environment. The | 572 WriteTranslation(environment->outer(), translation); |
| 575 // arguments index points to the first element of a sequence of tagged | |
| 576 // values on the stack that represent the arguments. This needs to be | |
| 577 // kept in sync with the LArgumentsElements implementation. | |
| 578 *pushed_arguments_index = -environment->parameter_count(); | |
| 579 *pushed_arguments_count = environment->parameter_count(); | |
| 580 | |
| 581 WriteTranslation(environment->outer(), | |
| 582 translation, | |
| 583 pushed_arguments_index, | |
| 584 pushed_arguments_count); | |
| 585 bool has_closure_id = !info()->closure().is_null() && | 573 bool has_closure_id = !info()->closure().is_null() && |
| 586 !info()->closure().is_identical_to(environment->closure()); | 574 !info()->closure().is_identical_to(environment->closure()); |
| 587 int closure_id = has_closure_id | 575 int closure_id = has_closure_id |
| 588 ? DefineDeoptimizationLiteral(environment->closure()) | 576 ? DefineDeoptimizationLiteral(environment->closure()) |
| 589 : Translation::kSelfLiteralId; | 577 : Translation::kSelfLiteralId; |
| 590 | 578 |
| 591 switch (environment->frame_type()) { | 579 switch (environment->frame_type()) { |
| 592 case JS_FUNCTION: | 580 case JS_FUNCTION: |
| 593 translation->BeginJSFrame(environment->ast_id(), closure_id, height); | 581 translation->BeginJSFrame(environment->ast_id(), closure_id, height); |
| 594 break; | 582 break; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 606 translation->BeginSetterStubFrame(closure_id); | 594 translation->BeginSetterStubFrame(closure_id); |
| 607 break; | 595 break; |
| 608 case STUB: | 596 case STUB: |
| 609 translation->BeginCompiledStubFrame(); | 597 translation->BeginCompiledStubFrame(); |
| 610 break; | 598 break; |
| 611 case ARGUMENTS_ADAPTOR: | 599 case ARGUMENTS_ADAPTOR: |
| 612 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size); | 600 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size); |
| 613 break; | 601 break; |
| 614 } | 602 } |
| 615 | 603 |
| 616 // Inlined frames which push their arguments cause the index to be | |
| 617 // bumped and another stack area to be used for materialization, | |
| 618 // otherwise actual argument values are unknown for inlined frames. | |
| 619 bool arguments_known = true; | |
| 620 int arguments_index = *pushed_arguments_index; | |
| 621 int arguments_count = *pushed_arguments_count; | |
| 622 if (environment->entry() != NULL) { | |
| 623 arguments_known = environment->entry()->arguments_pushed(); | |
| 624 arguments_index = arguments_index < 0 | |
| 625 ? GetStackSlotCount() : arguments_index + arguments_count; | |
| 626 arguments_count = environment->entry()->arguments_count() + 1; | |
| 627 if (environment->entry()->arguments_pushed()) { | |
| 628 *pushed_arguments_index = arguments_index; | |
| 629 *pushed_arguments_count = arguments_count; | |
| 630 } | |
| 631 } | |
| 632 | |
| 633 for (int i = 0; i < translation_size; ++i) { | 604 for (int i = 0; i < translation_size; ++i) { |
| 634 LOperand* value = environment->values()->at(i); | 605 LOperand* value = environment->values()->at(i); |
| 635 // spilled_registers_ and spilled_double_registers_ are either | 606 // spilled_registers_ and spilled_double_registers_ are either |
| 636 // both NULL or both set. | 607 // both NULL or both set. |
| 637 if (environment->spilled_registers() != NULL && value != NULL) { | 608 if (environment->spilled_registers() != NULL && value != NULL) { |
| 638 if (value->IsRegister() && | 609 if (value->IsRegister() && |
| 639 environment->spilled_registers()[value->index()] != NULL) { | 610 environment->spilled_registers()[value->index()] != NULL) { |
| 640 translation->MarkDuplicate(); | 611 translation->MarkDuplicate(); |
| 641 AddToTranslation(translation, | 612 AddToTranslation(translation, |
| 642 environment->spilled_registers()[value->index()], | 613 environment->spilled_registers()[value->index()], |
| 643 environment->HasTaggedValueAt(i), | 614 environment->HasTaggedValueAt(i), |
| 644 environment->HasUint32ValueAt(i), | 615 environment->HasUint32ValueAt(i)); |
| 645 arguments_known, | |
| 646 arguments_index, | |
| 647 arguments_count); | |
| 648 } else if ( | 616 } else if ( |
| 649 value->IsDoubleRegister() && | 617 value->IsDoubleRegister() && |
| 650 environment->spilled_double_registers()[value->index()] != NULL) { | 618 environment->spilled_double_registers()[value->index()] != NULL) { |
| 651 translation->MarkDuplicate(); | 619 translation->MarkDuplicate(); |
| 652 AddToTranslation( | 620 AddToTranslation( |
| 653 translation, | 621 translation, |
| 654 environment->spilled_double_registers()[value->index()], | 622 environment->spilled_double_registers()[value->index()], |
| 655 false, | 623 false, |
| 656 false, | 624 false); |
| 657 arguments_known, | |
| 658 arguments_index, | |
| 659 arguments_count); | |
| 660 } | 625 } |
| 661 } | 626 } |
| 662 | 627 |
| 628 // TODO(mstarzinger): Introduce marker operands to indicate that this value |
| 629 // is not present and must be reconstructed from the deoptimizer. Currently |
| 630 // this is only used for the arguments object. |
| 631 if (value == NULL) { |
| 632 int arguments_count = environment->values()->length() - translation_size; |
| 633 translation->BeginArgumentsObject(arguments_count); |
| 634 for (int i = 0; i < arguments_count; ++i) { |
| 635 LOperand* value = environment->values()->at(translation_size + i); |
| 636 ASSERT(environment->spilled_registers() == NULL || |
| 637 !value->IsRegister() || |
| 638 environment->spilled_registers()[value->index()] == NULL); |
| 639 ASSERT(environment->spilled_registers() == NULL || |
| 640 !value->IsDoubleRegister() || |
| 641 environment->spilled_double_registers()[value->index()] == NULL); |
| 642 AddToTranslation(translation, |
| 643 value, |
| 644 environment->HasTaggedValueAt(translation_size + i), |
| 645 environment->HasUint32ValueAt(translation_size + i)); |
| 646 } |
| 647 continue; |
| 648 } |
| 649 |
| 663 AddToTranslation(translation, | 650 AddToTranslation(translation, |
| 664 value, | 651 value, |
| 665 environment->HasTaggedValueAt(i), | 652 environment->HasTaggedValueAt(i), |
| 666 environment->HasUint32ValueAt(i), | 653 environment->HasUint32ValueAt(i)); |
| 667 arguments_known, | |
| 668 arguments_index, | |
| 669 arguments_count); | |
| 670 } | 654 } |
| 671 } | 655 } |
| 672 | 656 |
| 673 | 657 |
| 674 void LCodeGen::AddToTranslation(Translation* translation, | 658 void LCodeGen::AddToTranslation(Translation* translation, |
| 675 LOperand* op, | 659 LOperand* op, |
| 676 bool is_tagged, | 660 bool is_tagged, |
| 677 bool is_uint32, | 661 bool is_uint32) { |
| 678 bool arguments_known, | 662 if (op->IsStackSlot()) { |
| 679 int arguments_index, | |
| 680 int arguments_count) { | |
| 681 if (op == NULL) { | |
| 682 // TODO(twuerthinger): Introduce marker operands to indicate that this value | |
| 683 // is not present and must be reconstructed from the deoptimizer. Currently | |
| 684 // this is only used for the arguments object. | |
| 685 translation->StoreArgumentsObject( | |
| 686 arguments_known, arguments_index, arguments_count); | |
| 687 } else if (op->IsStackSlot()) { | |
| 688 if (is_tagged) { | 663 if (is_tagged) { |
| 689 translation->StoreStackSlot(op->index()); | 664 translation->StoreStackSlot(op->index()); |
| 690 } else if (is_uint32) { | 665 } else if (is_uint32) { |
| 691 translation->StoreUint32StackSlot(op->index()); | 666 translation->StoreUint32StackSlot(op->index()); |
| 692 } else { | 667 } else { |
| 693 translation->StoreInt32StackSlot(op->index()); | 668 translation->StoreInt32StackSlot(op->index()); |
| 694 } | 669 } |
| 695 } else if (op->IsDoubleStackSlot()) { | 670 } else if (op->IsDoubleStackSlot()) { |
| 696 translation->StoreDoubleStackSlot(op->index()); | 671 translation->StoreDoubleStackSlot(op->index()); |
| 697 } else if (op->IsArgument()) { | 672 } else if (op->IsArgument()) { |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 772 // 0 ..................................................... size-1 | 747 // 0 ..................................................... size-1 |
| 773 // [parameters] [locals] [expression stack including arguments] | 748 // [parameters] [locals] [expression stack including arguments] |
| 774 | 749 |
| 775 // Layout of the translation: | 750 // Layout of the translation: |
| 776 // 0 ........................................................ size - 1 + 4 | 751 // 0 ........................................................ size - 1 + 4 |
| 777 // [expression stack including arguments] [locals] [4 words] [parameters] | 752 // [expression stack including arguments] [locals] [4 words] [parameters] |
| 778 // |>------------ translation_size ------------<| | 753 // |>------------ translation_size ------------<| |
| 779 | 754 |
| 780 int frame_count = 0; | 755 int frame_count = 0; |
| 781 int jsframe_count = 0; | 756 int jsframe_count = 0; |
| 782 int args_index = 0; | |
| 783 int args_count = 0; | |
| 784 for (LEnvironment* e = environment; e != NULL; e = e->outer()) { | 757 for (LEnvironment* e = environment; e != NULL; e = e->outer()) { |
| 785 ++frame_count; | 758 ++frame_count; |
| 786 if (e->frame_type() == JS_FUNCTION) { | 759 if (e->frame_type() == JS_FUNCTION) { |
| 787 ++jsframe_count; | 760 ++jsframe_count; |
| 788 } | 761 } |
| 789 } | 762 } |
| 790 Translation translation(&translations_, frame_count, jsframe_count, zone()); | 763 Translation translation(&translations_, frame_count, jsframe_count, zone()); |
| 791 WriteTranslation(environment, &translation, &args_index, &args_count); | 764 WriteTranslation(environment, &translation); |
| 792 int deoptimization_index = deoptimizations_.length(); | 765 int deoptimization_index = deoptimizations_.length(); |
| 793 int pc_offset = masm()->pc_offset(); | 766 int pc_offset = masm()->pc_offset(); |
| 794 environment->Register(deoptimization_index, | 767 environment->Register(deoptimization_index, |
| 795 translation.index(), | 768 translation.index(), |
| 796 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1); | 769 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1); |
| 797 deoptimizations_.Add(environment, zone()); | 770 deoptimizations_.Add(environment, zone()); |
| 798 } | 771 } |
| 799 } | 772 } |
| 800 | 773 |
| 801 | 774 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 816 } | 789 } |
| 817 | 790 |
| 818 ASSERT(FLAG_deopt_every_n_times < 2); // Other values not supported on MIPS. | 791 ASSERT(FLAG_deopt_every_n_times < 2); // Other values not supported on MIPS. |
| 819 if (FLAG_deopt_every_n_times == 1 && | 792 if (FLAG_deopt_every_n_times == 1 && |
| 820 !info()->IsStub() && | 793 !info()->IsStub() && |
| 821 info()->opt_count() == id) { | 794 info()->opt_count() == id) { |
| 822 __ Jump(entry, RelocInfo::RUNTIME_ENTRY); | 795 __ Jump(entry, RelocInfo::RUNTIME_ENTRY); |
| 823 return; | 796 return; |
| 824 } | 797 } |
| 825 | 798 |
| 826 if (FLAG_trap_on_deopt) { | 799 if (FLAG_trap_on_deopt && info()->IsOptimizing()) { |
| 827 Label skip; | 800 Label skip; |
| 828 if (cc != al) { | 801 if (cc != al) { |
| 829 __ Branch(&skip, NegateCondition(cc), src1, src2); | 802 __ Branch(&skip, NegateCondition(cc), src1, src2); |
| 830 } | 803 } |
| 831 __ stop("trap_on_deopt"); | 804 __ stop("trap_on_deopt"); |
| 832 __ bind(&skip); | 805 __ bind(&skip); |
| 833 } | 806 } |
| 834 | 807 |
| 835 ASSERT(info()->IsStub() || frame_is_built_); | 808 ASSERT(info()->IsStub() || frame_is_built_); |
| 836 bool needs_lazy_deopt = info()->IsStub(); | 809 bool needs_lazy_deopt = info()->IsStub(); |
| (...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1196 __ mfhi(result_reg); | 1169 __ mfhi(result_reg); |
| 1197 | 1170 |
| 1198 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1171 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1199 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg)); | 1172 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg)); |
| 1200 } | 1173 } |
| 1201 __ bind(&done); | 1174 __ bind(&done); |
| 1202 } | 1175 } |
| 1203 } | 1176 } |
| 1204 | 1177 |
| 1205 | 1178 |
| 1179 void LCodeGen::EmitSignedIntegerDivisionByConstant( |
| 1180 Register result, |
| 1181 Register dividend, |
| 1182 int32_t divisor, |
| 1183 Register remainder, |
| 1184 Register scratch, |
| 1185 LEnvironment* environment) { |
| 1186 ASSERT(!AreAliased(dividend, scratch, at, no_reg)); |
| 1187 ASSERT(LChunkBuilder::HasMagicNumberForDivisor(divisor)); |
| 1188 |
| 1189 uint32_t divisor_abs = abs(divisor); |
| 1190 |
| 1191 int32_t power_of_2_factor = |
| 1192 CompilerIntrinsics::CountTrailingZeros(divisor_abs); |
| 1193 |
| 1194 switch (divisor_abs) { |
| 1195 case 0: |
| 1196 DeoptimizeIf(al, environment); |
| 1197 return; |
| 1198 |
| 1199 case 1: |
| 1200 if (divisor > 0) { |
| 1201 __ Move(result, dividend); |
| 1202 } else { |
| 1203 __ SubuAndCheckForOverflow(result, zero_reg, dividend, scratch); |
| 1204 DeoptimizeIf(lt, environment, scratch, Operand(zero_reg)); |
| 1205 } |
| 1206 // Compute the remainder. |
| 1207 __ Move(remainder, zero_reg); |
| 1208 return; |
| 1209 |
| 1210 default: |
| 1211 if (IsPowerOf2(divisor_abs)) { |
| 1212 // Branch and condition free code for integer division by a power |
| 1213 // of two. |
| 1214 int32_t power = WhichPowerOf2(divisor_abs); |
| 1215 if (power > 1) { |
| 1216 __ sra(scratch, dividend, power - 1); |
| 1217 } |
| 1218 __ srl(scratch, scratch, 32 - power); |
| 1219 __ Addu(scratch, dividend, Operand(scratch)); |
| 1220 __ sra(result, scratch, power); |
| 1221 // Negate if necessary. |
| 1222 // We don't need to check for overflow because the case '-1' is |
| 1223 // handled separately. |
| 1224 if (divisor < 0) { |
| 1225 ASSERT(divisor != -1); |
| 1226 __ Subu(result, zero_reg, Operand(result)); |
| 1227 } |
| 1228 // Compute the remainder. |
| 1229 if (divisor > 0) { |
| 1230 __ sll(scratch, result, power); |
| 1231 __ Subu(remainder, dividend, Operand(scratch)); |
| 1232 } else { |
| 1233 __ sll(scratch, result, power); |
| 1234 __ Addu(remainder, dividend, Operand(scratch)); |
| 1235 } |
| 1236 return; |
| 1237 } else if (LChunkBuilder::HasMagicNumberForDivisor(divisor)) { |
| 1238 // Use magic numbers for a few specific divisors. |
| 1239 // Details and proofs can be found in: |
| 1240 // - Hacker's Delight, Henry S. Warren, Jr. |
| 1241 // - The PowerPC Compiler Writer's Guide |
| 1242 // and probably many others. |
| 1243 // |
| 1244 // We handle |
| 1245 // <divisor with magic numbers> * <power of 2> |
| 1246 // but not |
| 1247 // <divisor with magic numbers> * <other divisor with magic numbers> |
| 1248 DivMagicNumbers magic_numbers = |
| 1249 DivMagicNumberFor(divisor_abs >> power_of_2_factor); |
| 1250 // Branch and condition free code for integer division by a power |
| 1251 // of two. |
| 1252 const int32_t M = magic_numbers.M; |
| 1253 const int32_t s = magic_numbers.s + power_of_2_factor; |
| 1254 |
| 1255 __ li(scratch, Operand(M)); |
| 1256 __ mult(dividend, scratch); |
| 1257 __ mfhi(scratch); |
| 1258 if (M < 0) { |
| 1259 __ Addu(scratch, scratch, Operand(dividend)); |
| 1260 } |
| 1261 if (s > 0) { |
| 1262 __ sra(scratch, scratch, s); |
| 1263 __ mov(scratch, scratch); |
| 1264 } |
| 1265 __ srl(at, dividend, 31); |
| 1266 __ Addu(result, scratch, Operand(at)); |
| 1267 if (divisor < 0) __ Subu(result, zero_reg, Operand(result)); |
| 1268 // Compute the remainder. |
| 1269 __ li(scratch, Operand(divisor)); |
| 1270 __ Mul(scratch, result, Operand(scratch)); |
| 1271 __ Subu(remainder, dividend, Operand(scratch)); |
| 1272 } else { |
| 1273 __ li(scratch, Operand(divisor)); |
| 1274 __ div(dividend, scratch); |
| 1275 __ mfhi(remainder); |
| 1276 __ mflo(result); |
| 1277 } |
| 1278 } |
| 1279 } |
| 1280 |
| 1281 |
| 1206 void LCodeGen::DoDivI(LDivI* instr) { | 1282 void LCodeGen::DoDivI(LDivI* instr) { |
| 1207 const Register left = ToRegister(instr->left()); | 1283 const Register left = ToRegister(instr->left()); |
| 1208 const Register right = ToRegister(instr->right()); | 1284 const Register right = ToRegister(instr->right()); |
| 1209 const Register result = ToRegister(instr->result()); | 1285 const Register result = ToRegister(instr->result()); |
| 1210 | 1286 |
| 1211 // On MIPS div is asynchronous - it will run in the background while we | 1287 // On MIPS div is asynchronous - it will run in the background while we |
| 1212 // check for special cases. | 1288 // check for special cases. |
| 1213 __ div(left, right); | 1289 __ div(left, right); |
| 1214 | 1290 |
| 1215 // Check for x / 0. | 1291 // Check for x / 0. |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1246 DoubleRegister multiplier = ToDoubleRegister(instr->multiplier()); | 1322 DoubleRegister multiplier = ToDoubleRegister(instr->multiplier()); |
| 1247 DoubleRegister multiplicand = ToDoubleRegister(instr->multiplicand()); | 1323 DoubleRegister multiplicand = ToDoubleRegister(instr->multiplicand()); |
| 1248 | 1324 |
| 1249 // This is computed in-place. | 1325 // This is computed in-place. |
| 1250 ASSERT(addend.is(ToDoubleRegister(instr->result()))); | 1326 ASSERT(addend.is(ToDoubleRegister(instr->result()))); |
| 1251 | 1327 |
| 1252 __ madd_d(addend, addend, multiplier, multiplicand); | 1328 __ madd_d(addend, addend, multiplier, multiplicand); |
| 1253 } | 1329 } |
| 1254 | 1330 |
| 1255 | 1331 |
| 1332 void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) { |
| 1333 const Register result = ToRegister(instr->result()); |
| 1334 const Register left = ToRegister(instr->left()); |
| 1335 const Register remainder = ToRegister(instr->temp()); |
| 1336 const Register scratch = scratch0(); |
| 1337 |
| 1338 if (instr->right()->IsConstantOperand()) { |
| 1339 Label done; |
| 1340 int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right())); |
| 1341 if (divisor < 0) { |
| 1342 DeoptimizeIf(eq, instr->environment(), left, Operand(zero_reg)); |
| 1343 } |
| 1344 EmitSignedIntegerDivisionByConstant(result, |
| 1345 left, |
| 1346 divisor, |
| 1347 remainder, |
| 1348 scratch, |
| 1349 instr->environment()); |
| 1350 // We performed a truncating division. Correct the result if necessary. |
| 1351 __ Branch(&done, eq, remainder, Operand(zero_reg), USE_DELAY_SLOT); |
| 1352 __ Xor(scratch , remainder, Operand(divisor)); |
| 1353 __ Branch(&done, ge, scratch, Operand(zero_reg)); |
| 1354 __ Subu(result, result, Operand(1)); |
| 1355 __ bind(&done); |
| 1356 } else { |
| 1357 Label done; |
| 1358 const Register right = ToRegister(instr->right()); |
| 1359 |
| 1360 // On MIPS div is asynchronous - it will run in the background while we |
| 1361 // check for special cases. |
| 1362 __ div(left, right); |
| 1363 |
| 1364 // Check for x / 0. |
| 1365 DeoptimizeIf(eq, instr->environment(), right, Operand(zero_reg)); |
| 1366 |
| 1367 // Check for (0 / -x) that will produce negative zero. |
| 1368 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1369 Label left_not_zero; |
| 1370 __ Branch(&left_not_zero, ne, left, Operand(zero_reg)); |
| 1371 DeoptimizeIf(lt, instr->environment(), right, Operand(zero_reg)); |
| 1372 __ bind(&left_not_zero); |
| 1373 } |
| 1374 |
| 1375 // Check for (kMinInt / -1). |
| 1376 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { |
| 1377 Label left_not_min_int; |
| 1378 __ Branch(&left_not_min_int, ne, left, Operand(kMinInt)); |
| 1379 DeoptimizeIf(eq, instr->environment(), right, Operand(-1)); |
| 1380 __ bind(&left_not_min_int); |
| 1381 } |
| 1382 |
| 1383 __ mfhi(remainder); |
| 1384 __ mflo(result); |
| 1385 |
| 1386 // We performed a truncating division. Correct the result if necessary. |
| 1387 __ Branch(&done, eq, remainder, Operand(zero_reg), USE_DELAY_SLOT); |
| 1388 __ Xor(scratch , remainder, Operand(right)); |
| 1389 __ Branch(&done, ge, scratch, Operand(zero_reg)); |
| 1390 __ Subu(result, result, Operand(1)); |
| 1391 __ bind(&done); |
| 1392 } |
| 1393 } |
| 1394 |
| 1395 |
| 1256 void LCodeGen::DoMulI(LMulI* instr) { | 1396 void LCodeGen::DoMulI(LMulI* instr) { |
| 1257 Register scratch = scratch0(); | 1397 Register scratch = scratch0(); |
| 1258 Register result = ToRegister(instr->result()); | 1398 Register result = ToRegister(instr->result()); |
| 1259 // Note that result may alias left. | 1399 // Note that result may alias left. |
| 1260 Register left = ToRegister(instr->left()); | 1400 Register left = ToRegister(instr->left()); |
| 1261 LOperand* right_op = instr->right(); | 1401 LOperand* right_op = instr->right(); |
| 1262 | 1402 |
| 1263 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); | 1403 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); |
| 1264 bool bailout_on_minus_zero = | 1404 bool bailout_on_minus_zero = |
| 1265 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero); | 1405 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero); |
| (...skipping 1193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2459 // instanceof stub. | 2599 // instanceof stub. |
| 2460 Label cache_miss; | 2600 Label cache_miss; |
| 2461 Register map = temp; | 2601 Register map = temp; |
| 2462 __ lw(map, FieldMemOperand(object, HeapObject::kMapOffset)); | 2602 __ lw(map, FieldMemOperand(object, HeapObject::kMapOffset)); |
| 2463 | 2603 |
| 2464 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); | 2604 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); |
| 2465 __ bind(deferred->map_check()); // Label for calculating code patching. | 2605 __ bind(deferred->map_check()); // Label for calculating code patching. |
| 2466 // We use Factory::the_hole_value() on purpose instead of loading from the | 2606 // We use Factory::the_hole_value() on purpose instead of loading from the |
| 2467 // root array to force relocation to be able to later patch with | 2607 // root array to force relocation to be able to later patch with |
| 2468 // the cached map. | 2608 // the cached map. |
| 2469 Handle<JSGlobalPropertyCell> cell = | 2609 Handle<Cell> cell = factory()->NewCell(factory()->the_hole_value()); |
| 2470 factory()->NewJSGlobalPropertyCell(factory()->the_hole_value()); | |
| 2471 __ li(at, Operand(Handle<Object>(cell))); | 2610 __ li(at, Operand(Handle<Object>(cell))); |
| 2472 __ lw(at, FieldMemOperand(at, JSGlobalPropertyCell::kValueOffset)); | 2611 __ lw(at, FieldMemOperand(at, PropertyCell::kValueOffset)); |
| 2473 __ Branch(&cache_miss, ne, map, Operand(at)); | 2612 __ Branch(&cache_miss, ne, map, Operand(at)); |
| 2474 // We use Factory::the_hole_value() on purpose instead of loading from the | 2613 // We use Factory::the_hole_value() on purpose instead of loading from the |
| 2475 // root array to force relocation to be able to later patch | 2614 // root array to force relocation to be able to later patch |
| 2476 // with true or false. | 2615 // with true or false. |
| 2477 __ li(result, Operand(factory()->the_hole_value()), CONSTANT_SIZE); | 2616 __ li(result, Operand(factory()->the_hole_value()), CONSTANT_SIZE); |
| 2478 __ Branch(&done); | 2617 __ Branch(&done); |
| 2479 | 2618 |
| 2480 // The inlined call site cache did not match. Check null and string before | 2619 // The inlined call site cache did not match. Check null and string before |
| 2481 // calling the deferred code. | 2620 // calling the deferred code. |
| 2482 __ bind(&cache_miss); | 2621 __ bind(&cache_miss); |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2616 | 2755 |
| 2617 if (no_frame_start != -1) { | 2756 if (no_frame_start != -1) { |
| 2618 info_->AddNoFrameRange(no_frame_start, masm_->pc_offset()); | 2757 info_->AddNoFrameRange(no_frame_start, masm_->pc_offset()); |
| 2619 } | 2758 } |
| 2620 } | 2759 } |
| 2621 | 2760 |
| 2622 | 2761 |
| 2623 void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) { | 2762 void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) { |
| 2624 Register result = ToRegister(instr->result()); | 2763 Register result = ToRegister(instr->result()); |
| 2625 __ li(at, Operand(Handle<Object>(instr->hydrogen()->cell()))); | 2764 __ li(at, Operand(Handle<Object>(instr->hydrogen()->cell()))); |
| 2626 __ lw(result, FieldMemOperand(at, JSGlobalPropertyCell::kValueOffset)); | 2765 __ lw(result, FieldMemOperand(at, Cell::kValueOffset)); |
| 2627 if (instr->hydrogen()->RequiresHoleCheck()) { | 2766 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 2628 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 2767 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
| 2629 DeoptimizeIf(eq, instr->environment(), result, Operand(at)); | 2768 DeoptimizeIf(eq, instr->environment(), result, Operand(at)); |
| 2630 } | 2769 } |
| 2631 } | 2770 } |
| 2632 | 2771 |
| 2633 | 2772 |
| 2634 void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { | 2773 void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { |
| 2635 ASSERT(ToRegister(instr->global_object()).is(a0)); | 2774 ASSERT(ToRegister(instr->global_object()).is(a0)); |
| 2636 ASSERT(ToRegister(instr->result()).is(v0)); | 2775 ASSERT(ToRegister(instr->result()).is(v0)); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2650 // Load the cell. | 2789 // Load the cell. |
| 2651 __ li(cell, Operand(instr->hydrogen()->cell())); | 2790 __ li(cell, Operand(instr->hydrogen()->cell())); |
| 2652 | 2791 |
| 2653 // If the cell we are storing to contains the hole it could have | 2792 // If the cell we are storing to contains the hole it could have |
| 2654 // been deleted from the property dictionary. In that case, we need | 2793 // been deleted from the property dictionary. In that case, we need |
| 2655 // to update the property details in the property dictionary to mark | 2794 // to update the property details in the property dictionary to mark |
| 2656 // it as no longer deleted. | 2795 // it as no longer deleted. |
| 2657 if (instr->hydrogen()->RequiresHoleCheck()) { | 2796 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 2658 // We use a temp to check the payload. | 2797 // We use a temp to check the payload. |
| 2659 Register payload = ToRegister(instr->temp()); | 2798 Register payload = ToRegister(instr->temp()); |
| 2660 __ lw(payload, FieldMemOperand(cell, JSGlobalPropertyCell::kValueOffset)); | 2799 __ lw(payload, FieldMemOperand(cell, Cell::kValueOffset)); |
| 2661 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 2800 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
| 2662 DeoptimizeIf(eq, instr->environment(), payload, Operand(at)); | 2801 DeoptimizeIf(eq, instr->environment(), payload, Operand(at)); |
| 2663 } | 2802 } |
| 2664 | 2803 |
| 2665 // Store the value. | 2804 // Store the value. |
| 2666 __ sw(value, FieldMemOperand(cell, JSGlobalPropertyCell::kValueOffset)); | 2805 __ sw(value, FieldMemOperand(cell, Cell::kValueOffset)); |
| 2667 // Cells are always rescanned, so no write barrier here. | 2806 // Cells are always rescanned, so no write barrier here. |
| 2668 } | 2807 } |
| 2669 | 2808 |
| 2670 | 2809 |
| 2671 void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) { | 2810 void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) { |
| 2672 ASSERT(ToRegister(instr->global_object()).is(a1)); | 2811 ASSERT(ToRegister(instr->global_object()).is(a1)); |
| 2673 ASSERT(ToRegister(instr->value()).is(a0)); | 2812 ASSERT(ToRegister(instr->value()).is(a0)); |
| 2674 | 2813 |
| 2675 __ li(a2, Operand(instr->name())); | 2814 __ li(a2, Operand(instr->name())); |
| 2676 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode) | 2815 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode) |
| (...skipping 1247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3924 __ li(a0, Operand(instr->arity())); | 4063 __ li(a0, Operand(instr->arity())); |
| 3925 __ li(a2, Operand(instr->hydrogen()->property_cell())); | 4064 __ li(a2, Operand(instr->hydrogen()->property_cell())); |
| 3926 ElementsKind kind = instr->hydrogen()->elements_kind(); | 4065 ElementsKind kind = instr->hydrogen()->elements_kind(); |
| 3927 bool disable_allocation_sites = | 4066 bool disable_allocation_sites = |
| 3928 (AllocationSiteInfo::GetMode(kind) == TRACK_ALLOCATION_SITE); | 4067 (AllocationSiteInfo::GetMode(kind) == TRACK_ALLOCATION_SITE); |
| 3929 | 4068 |
| 3930 if (instr->arity() == 0) { | 4069 if (instr->arity() == 0) { |
| 3931 ArrayNoArgumentConstructorStub stub(kind, disable_allocation_sites); | 4070 ArrayNoArgumentConstructorStub stub(kind, disable_allocation_sites); |
| 3932 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); | 4071 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); |
| 3933 } else if (instr->arity() == 1) { | 4072 } else if (instr->arity() == 1) { |
| 4073 Label done; |
| 4074 if (IsFastPackedElementsKind(kind)) { |
| 4075 Label packed_case; |
| 4076 // We might need a change here, |
| 4077 // look at the first argument. |
| 4078 __ lw(t1, MemOperand(sp, 0)); |
| 4079 __ Branch(&packed_case, eq, t1, Operand(zero_reg)); |
| 4080 |
| 4081 ElementsKind holey_kind = GetHoleyElementsKind(kind); |
| 4082 ArraySingleArgumentConstructorStub stub(holey_kind, |
| 4083 disable_allocation_sites); |
| 4084 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); |
| 4085 __ jmp(&done); |
| 4086 __ bind(&packed_case); |
| 4087 } |
| 4088 |
| 3934 ArraySingleArgumentConstructorStub stub(kind, disable_allocation_sites); | 4089 ArraySingleArgumentConstructorStub stub(kind, disable_allocation_sites); |
| 3935 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); | 4090 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); |
| 4091 __ bind(&done); |
| 3936 } else { | 4092 } else { |
| 3937 ArrayNArgumentsConstructorStub stub(kind, disable_allocation_sites); | 4093 ArrayNArgumentsConstructorStub stub(kind, disable_allocation_sites); |
| 3938 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); | 4094 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); |
| 3939 } | 4095 } |
| 3940 } | 4096 } |
| 3941 | 4097 |
| 3942 | 4098 |
| 3943 void LCodeGen::DoCallRuntime(LCallRuntime* instr) { | 4099 void LCodeGen::DoCallRuntime(LCallRuntime* instr) { |
| 3944 CallRuntime(instr->function(), instr->arity(), instr); | 4100 CallRuntime(instr->function(), instr->arity(), instr); |
| 3945 } | 4101 } |
| (...skipping 1075 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5021 } | 5177 } |
| 5022 } | 5178 } |
| 5023 | 5179 |
| 5024 | 5180 |
| 5025 void LCodeGen::DoCheckFunction(LCheckFunction* instr) { | 5181 void LCodeGen::DoCheckFunction(LCheckFunction* instr) { |
| 5026 Register reg = ToRegister(instr->value()); | 5182 Register reg = ToRegister(instr->value()); |
| 5027 Handle<JSFunction> target = instr->hydrogen()->target(); | 5183 Handle<JSFunction> target = instr->hydrogen()->target(); |
| 5028 AllowDeferredHandleDereference smi_check; | 5184 AllowDeferredHandleDereference smi_check; |
| 5029 if (isolate()->heap()->InNewSpace(*target)) { | 5185 if (isolate()->heap()->InNewSpace(*target)) { |
| 5030 Register reg = ToRegister(instr->value()); | 5186 Register reg = ToRegister(instr->value()); |
| 5031 Handle<JSGlobalPropertyCell> cell = | 5187 Handle<Cell> cell = isolate()->factory()->NewPropertyCell(target); |
| 5032 isolate()->factory()->NewJSGlobalPropertyCell(target); | |
| 5033 __ li(at, Operand(Handle<Object>(cell))); | 5188 __ li(at, Operand(Handle<Object>(cell))); |
| 5034 __ lw(at, FieldMemOperand(at, JSGlobalPropertyCell::kValueOffset)); | 5189 __ lw(at, FieldMemOperand(at, Cell::kValueOffset)); |
| 5035 DeoptimizeIf(ne, instr->environment(), reg, | 5190 DeoptimizeIf(ne, instr->environment(), reg, |
| 5036 Operand(at)); | 5191 Operand(at)); |
| 5037 } else { | 5192 } else { |
| 5038 DeoptimizeIf(ne, instr->environment(), reg, | 5193 DeoptimizeIf(ne, instr->environment(), reg, |
| 5039 Operand(target)); | 5194 Operand(target)); |
| 5040 } | 5195 } |
| 5041 } | 5196 } |
| 5042 | 5197 |
| 5043 | 5198 |
| 5044 void LCodeGen::DoCheckMapCommon(Register map_reg, | 5199 void LCodeGen::DoCheckMapCommon(Register map_reg, |
| (...skipping 648 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5693 __ Subu(scratch, result, scratch); | 5848 __ Subu(scratch, result, scratch); |
| 5694 __ lw(result, FieldMemOperand(scratch, | 5849 __ lw(result, FieldMemOperand(scratch, |
| 5695 FixedArray::kHeaderSize - kPointerSize)); | 5850 FixedArray::kHeaderSize - kPointerSize)); |
| 5696 __ bind(&done); | 5851 __ bind(&done); |
| 5697 } | 5852 } |
| 5698 | 5853 |
| 5699 | 5854 |
| 5700 #undef __ | 5855 #undef __ |
| 5701 | 5856 |
| 5702 } } // namespace v8::internal | 5857 } } // namespace v8::internal |
| OLD | NEW |