| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 Isolate* isolate, | 43 Isolate* isolate, |
| 44 CodeStubInterfaceDescriptor* descriptor) { | 44 CodeStubInterfaceDescriptor* descriptor) { |
| 45 static Register registers[] = { rbx }; | 45 static Register registers[] = { rbx }; |
| 46 descriptor->register_param_count_ = 1; | 46 descriptor->register_param_count_ = 1; |
| 47 descriptor->register_params_ = registers; | 47 descriptor->register_params_ = registers; |
| 48 descriptor->deoptimization_handler_ = | 48 descriptor->deoptimization_handler_ = |
| 49 Runtime::FunctionForId(Runtime::kNewClosureFromStubFailure)->entry; | 49 Runtime::FunctionForId(Runtime::kNewClosureFromStubFailure)->entry; |
| 50 } | 50 } |
| 51 | 51 |
| 52 | 52 |
| 53 void FastNewContextStub::InitializeInterfaceDescriptor( |
| 54 Isolate* isolate, |
| 55 CodeStubInterfaceDescriptor* descriptor) { |
| 56 static Register registers[] = { rdi }; |
| 57 descriptor->register_param_count_ = 1; |
| 58 descriptor->register_params_ = registers; |
| 59 descriptor->deoptimization_handler_ = NULL; |
| 60 } |
| 61 |
| 62 |
| 53 void ToNumberStub::InitializeInterfaceDescriptor( | 63 void ToNumberStub::InitializeInterfaceDescriptor( |
| 54 Isolate* isolate, | 64 Isolate* isolate, |
| 55 CodeStubInterfaceDescriptor* descriptor) { | 65 CodeStubInterfaceDescriptor* descriptor) { |
| 56 static Register registers[] = { rax }; | 66 static Register registers[] = { rax }; |
| 57 descriptor->register_param_count_ = 1; | 67 descriptor->register_param_count_ = 1; |
| 58 descriptor->register_params_ = registers; | 68 descriptor->register_params_ = registers; |
| 59 descriptor->deoptimization_handler_ = NULL; | 69 descriptor->deoptimization_handler_ = NULL; |
| 60 } | 70 } |
| 61 | 71 |
| 62 | 72 |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 180 } | 190 } |
| 181 | 191 |
| 182 | 192 |
| 183 static void InitializeArrayConstructorDescriptor( | 193 static void InitializeArrayConstructorDescriptor( |
| 184 Isolate* isolate, | 194 Isolate* isolate, |
| 185 CodeStubInterfaceDescriptor* descriptor, | 195 CodeStubInterfaceDescriptor* descriptor, |
| 186 int constant_stack_parameter_count) { | 196 int constant_stack_parameter_count) { |
| 187 // register state | 197 // register state |
| 188 // rax -- number of arguments | 198 // rax -- number of arguments |
| 189 // rdi -- function | 199 // rdi -- function |
| 190 // rbx -- type info cell with elements kind | 200 // rbx -- allocation site with elements kind |
| 191 static Register registers_variable_args[] = { rdi, rbx, rax }; | 201 static Register registers_variable_args[] = { rdi, rbx, rax }; |
| 192 static Register registers_no_args[] = { rdi, rbx }; | 202 static Register registers_no_args[] = { rdi, rbx }; |
| 193 | 203 |
| 194 if (constant_stack_parameter_count == 0) { | 204 if (constant_stack_parameter_count == 0) { |
| 195 descriptor->register_param_count_ = 2; | 205 descriptor->register_param_count_ = 2; |
| 196 descriptor->register_params_ = registers_no_args; | 206 descriptor->register_params_ = registers_no_args; |
| 197 } else { | 207 } else { |
| 198 // stack param count needs (constructor pointer, and single argument) | 208 // stack param count needs (constructor pointer, and single argument) |
| 199 descriptor->handler_arguments_mode_ = PASS_ARGUMENTS; | 209 descriptor->handler_arguments_mode_ = PASS_ARGUMENTS; |
| 200 descriptor->stack_parameter_count_ = rax; | 210 descriptor->stack_parameter_count_ = rax; |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 343 Isolate* isolate, | 353 Isolate* isolate, |
| 344 CodeStubInterfaceDescriptor* descriptor) { | 354 CodeStubInterfaceDescriptor* descriptor) { |
| 345 static Register registers[] = { rcx, rdx, rax }; | 355 static Register registers[] = { rcx, rdx, rax }; |
| 346 descriptor->register_param_count_ = 3; | 356 descriptor->register_param_count_ = 3; |
| 347 descriptor->register_params_ = registers; | 357 descriptor->register_params_ = registers; |
| 348 descriptor->deoptimization_handler_ = | 358 descriptor->deoptimization_handler_ = |
| 349 FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite); | 359 FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite); |
| 350 } | 360 } |
| 351 | 361 |
| 352 | 362 |
| 353 void NewStringAddStub::InitializeInterfaceDescriptor( | 363 void StringAddStub::InitializeInterfaceDescriptor( |
| 354 Isolate* isolate, | 364 Isolate* isolate, |
| 355 CodeStubInterfaceDescriptor* descriptor) { | 365 CodeStubInterfaceDescriptor* descriptor) { |
| 356 static Register registers[] = { rdx, rax }; | 366 static Register registers[] = { rdx, rax }; |
| 357 descriptor->register_param_count_ = 2; | 367 descriptor->register_param_count_ = 2; |
| 358 descriptor->register_params_ = registers; | 368 descriptor->register_params_ = registers; |
| 359 descriptor->deoptimization_handler_ = | 369 descriptor->deoptimization_handler_ = |
| 360 Runtime::FunctionForId(Runtime::kStringAdd)->entry; | 370 Runtime::FunctionForId(Runtime::kStringAdd)->entry; |
| 361 } | 371 } |
| 362 | 372 |
| 363 | 373 |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 431 __ push(descriptor->register_params_[i]); | 441 __ push(descriptor->register_params_[i]); |
| 432 } | 442 } |
| 433 ExternalReference miss = descriptor->miss_handler(); | 443 ExternalReference miss = descriptor->miss_handler(); |
| 434 __ CallExternalReference(miss, descriptor->register_param_count_); | 444 __ CallExternalReference(miss, descriptor->register_param_count_); |
| 435 } | 445 } |
| 436 | 446 |
| 437 __ Ret(); | 447 __ Ret(); |
| 438 } | 448 } |
| 439 | 449 |
| 440 | 450 |
| 441 void FastNewContextStub::Generate(MacroAssembler* masm) { | |
| 442 // Try to allocate the context in new space. | |
| 443 Label gc; | |
| 444 int length = slots_ + Context::MIN_CONTEXT_SLOTS; | |
| 445 __ Allocate((length * kPointerSize) + FixedArray::kHeaderSize, | |
| 446 rax, rbx, rcx, &gc, TAG_OBJECT); | |
| 447 | |
| 448 // Get the function from the stack. | |
| 449 StackArgumentsAccessor args(rsp, 1, ARGUMENTS_DONT_CONTAIN_RECEIVER); | |
| 450 __ movq(rcx, args.GetArgumentOperand(0)); | |
| 451 | |
| 452 // Set up the object header. | |
| 453 __ LoadRoot(kScratchRegister, Heap::kFunctionContextMapRootIndex); | |
| 454 __ movq(FieldOperand(rax, HeapObject::kMapOffset), kScratchRegister); | |
| 455 __ Move(FieldOperand(rax, FixedArray::kLengthOffset), Smi::FromInt(length)); | |
| 456 | |
| 457 // Set up the fixed slots. | |
| 458 __ Set(rbx, 0); // Set to NULL. | |
| 459 __ movq(Operand(rax, Context::SlotOffset(Context::CLOSURE_INDEX)), rcx); | |
| 460 __ movq(Operand(rax, Context::SlotOffset(Context::PREVIOUS_INDEX)), rsi); | |
| 461 __ movq(Operand(rax, Context::SlotOffset(Context::EXTENSION_INDEX)), rbx); | |
| 462 | |
| 463 // Copy the global object from the previous context. | |
| 464 __ movq(rbx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); | |
| 465 __ movq(Operand(rax, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)), rbx); | |
| 466 | |
| 467 // Initialize the rest of the slots to undefined. | |
| 468 __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex); | |
| 469 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { | |
| 470 __ movq(Operand(rax, Context::SlotOffset(i)), rbx); | |
| 471 } | |
| 472 | |
| 473 // Return and remove the on-stack parameter. | |
| 474 __ movq(rsi, rax); | |
| 475 __ ret(1 * kPointerSize); | |
| 476 | |
| 477 // Need to collect. Call into runtime system. | |
| 478 __ bind(&gc); | |
| 479 __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1); | |
| 480 } | |
| 481 | |
| 482 | |
| 483 void FastNewBlockContextStub::Generate(MacroAssembler* masm) { | 451 void FastNewBlockContextStub::Generate(MacroAssembler* masm) { |
| 484 // Stack layout on entry: | 452 // Stack layout on entry: |
| 485 // | 453 // |
| 486 // [rsp + (1 * kPointerSize)] : function | 454 // [rsp + (1 * kPointerSize)] : function |
| 487 // [rsp + (2 * kPointerSize)] : serialized scope info | 455 // [rsp + (2 * kPointerSize)] : serialized scope info |
| 488 | 456 |
| 489 // Try to allocate the context in new space. | 457 // Try to allocate the context in new space. |
| 490 Label gc; | 458 Label gc; |
| 491 int length = slots_ + Context::MIN_CONTEXT_SLOTS; | 459 int length = slots_ + Context::MIN_CONTEXT_SLOTS; |
| 492 __ Allocate(FixedArray::SizeFor(length), | 460 __ Allocate(FixedArray::SizeFor(length), |
| 493 rax, rbx, rcx, &gc, TAG_OBJECT); | 461 rax, rbx, rcx, &gc, TAG_OBJECT); |
| 494 | 462 |
| 495 // Get the function from the stack. | 463 // Get the function from the stack. |
| 496 StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER); | 464 StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 497 __ movq(rcx, args.GetArgumentOperand(1)); | 465 __ movp(rcx, args.GetArgumentOperand(1)); |
| 498 // Get the serialized scope info from the stack. | 466 // Get the serialized scope info from the stack. |
| 499 __ movq(rbx, args.GetArgumentOperand(0)); | 467 __ movp(rbx, args.GetArgumentOperand(0)); |
| 500 | 468 |
| 501 // Set up the object header. | 469 // Set up the object header. |
| 502 __ LoadRoot(kScratchRegister, Heap::kBlockContextMapRootIndex); | 470 __ LoadRoot(kScratchRegister, Heap::kBlockContextMapRootIndex); |
| 503 __ movq(FieldOperand(rax, HeapObject::kMapOffset), kScratchRegister); | 471 __ movp(FieldOperand(rax, HeapObject::kMapOffset), kScratchRegister); |
| 504 __ Move(FieldOperand(rax, FixedArray::kLengthOffset), Smi::FromInt(length)); | 472 __ Move(FieldOperand(rax, FixedArray::kLengthOffset), Smi::FromInt(length)); |
| 505 | 473 |
| 506 // If this block context is nested in the native context we get a smi | 474 // If this block context is nested in the native context we get a smi |
| 507 // sentinel instead of a function. The block context should get the | 475 // sentinel instead of a function. The block context should get the |
| 508 // canonical empty function of the native context as its closure which | 476 // canonical empty function of the native context as its closure which |
| 509 // we still have to look up. | 477 // we still have to look up. |
| 510 Label after_sentinel; | 478 Label after_sentinel; |
| 511 __ JumpIfNotSmi(rcx, &after_sentinel, Label::kNear); | 479 __ JumpIfNotSmi(rcx, &after_sentinel, Label::kNear); |
| 512 if (FLAG_debug_code) { | 480 if (FLAG_debug_code) { |
| 513 __ cmpq(rcx, Immediate(0)); | 481 __ cmpq(rcx, Immediate(0)); |
| 514 __ Assert(equal, kExpected0AsASmiSentinel); | 482 __ Assert(equal, kExpected0AsASmiSentinel); |
| 515 } | 483 } |
| 516 __ movq(rcx, GlobalObjectOperand()); | 484 __ movp(rcx, GlobalObjectOperand()); |
| 517 __ movq(rcx, FieldOperand(rcx, GlobalObject::kNativeContextOffset)); | 485 __ movp(rcx, FieldOperand(rcx, GlobalObject::kNativeContextOffset)); |
| 518 __ movq(rcx, ContextOperand(rcx, Context::CLOSURE_INDEX)); | 486 __ movp(rcx, ContextOperand(rcx, Context::CLOSURE_INDEX)); |
| 519 __ bind(&after_sentinel); | 487 __ bind(&after_sentinel); |
| 520 | 488 |
| 521 // Set up the fixed slots. | 489 // Set up the fixed slots. |
| 522 __ movq(ContextOperand(rax, Context::CLOSURE_INDEX), rcx); | 490 __ movp(ContextOperand(rax, Context::CLOSURE_INDEX), rcx); |
| 523 __ movq(ContextOperand(rax, Context::PREVIOUS_INDEX), rsi); | 491 __ movp(ContextOperand(rax, Context::PREVIOUS_INDEX), rsi); |
| 524 __ movq(ContextOperand(rax, Context::EXTENSION_INDEX), rbx); | 492 __ movp(ContextOperand(rax, Context::EXTENSION_INDEX), rbx); |
| 525 | 493 |
| 526 // Copy the global object from the previous context. | 494 // Copy the global object from the previous context. |
| 527 __ movq(rbx, ContextOperand(rsi, Context::GLOBAL_OBJECT_INDEX)); | 495 __ movp(rbx, ContextOperand(rsi, Context::GLOBAL_OBJECT_INDEX)); |
| 528 __ movq(ContextOperand(rax, Context::GLOBAL_OBJECT_INDEX), rbx); | 496 __ movp(ContextOperand(rax, Context::GLOBAL_OBJECT_INDEX), rbx); |
| 529 | 497 |
| 530 // Initialize the rest of the slots to the hole value. | 498 // Initialize the rest of the slots to the hole value. |
| 531 __ LoadRoot(rbx, Heap::kTheHoleValueRootIndex); | 499 __ LoadRoot(rbx, Heap::kTheHoleValueRootIndex); |
| 532 for (int i = 0; i < slots_; i++) { | 500 for (int i = 0; i < slots_; i++) { |
| 533 __ movq(ContextOperand(rax, i + Context::MIN_CONTEXT_SLOTS), rbx); | 501 __ movp(ContextOperand(rax, i + Context::MIN_CONTEXT_SLOTS), rbx); |
| 534 } | 502 } |
| 535 | 503 |
| 536 // Return and remove the on-stack parameter. | 504 // Return and remove the on-stack parameter. |
| 537 __ movq(rsi, rax); | 505 __ movp(rsi, rax); |
| 538 __ ret(2 * kPointerSize); | 506 __ ret(2 * kPointerSize); |
| 539 | 507 |
| 540 // Need to collect. Call into runtime system. | 508 // Need to collect. Call into runtime system. |
| 541 __ bind(&gc); | 509 __ bind(&gc); |
| 542 __ TailCallRuntime(Runtime::kPushBlockContext, 2, 1); | 510 __ TailCallRuntime(Runtime::kPushBlockContext, 2, 1); |
| 543 } | 511 } |
| 544 | 512 |
| 545 | 513 |
| 546 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { | 514 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { |
| 547 __ PushCallerSaved(save_doubles_); | 515 __ PushCallerSaved(save_doubles_); |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 693 const Register base = rax; | 661 const Register base = rax; |
| 694 const Register scratch = rcx; | 662 const Register scratch = rcx; |
| 695 const XMMRegister double_result = xmm3; | 663 const XMMRegister double_result = xmm3; |
| 696 const XMMRegister double_base = xmm2; | 664 const XMMRegister double_base = xmm2; |
| 697 const XMMRegister double_exponent = xmm1; | 665 const XMMRegister double_exponent = xmm1; |
| 698 const XMMRegister double_scratch = xmm4; | 666 const XMMRegister double_scratch = xmm4; |
| 699 | 667 |
| 700 Label call_runtime, done, exponent_not_smi, int_exponent; | 668 Label call_runtime, done, exponent_not_smi, int_exponent; |
| 701 | 669 |
| 702 // Save 1 in double_result - we need this several times later on. | 670 // Save 1 in double_result - we need this several times later on. |
| 703 __ movq(scratch, Immediate(1)); | 671 __ movp(scratch, Immediate(1)); |
| 704 __ Cvtlsi2sd(double_result, scratch); | 672 __ Cvtlsi2sd(double_result, scratch); |
| 705 | 673 |
| 706 if (exponent_type_ == ON_STACK) { | 674 if (exponent_type_ == ON_STACK) { |
| 707 Label base_is_smi, unpack_exponent; | 675 Label base_is_smi, unpack_exponent; |
| 708 // The exponent and base are supplied as arguments on the stack. | 676 // The exponent and base are supplied as arguments on the stack. |
| 709 // This can only happen if the stub is called from non-optimized code. | 677 // This can only happen if the stub is called from non-optimized code. |
| 710 // Load input parameters from stack. | 678 // Load input parameters from stack. |
| 711 StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER); | 679 StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 712 __ movq(base, args.GetArgumentOperand(0)); | 680 __ movp(base, args.GetArgumentOperand(0)); |
| 713 __ movq(exponent, args.GetArgumentOperand(1)); | 681 __ movp(exponent, args.GetArgumentOperand(1)); |
| 714 __ JumpIfSmi(base, &base_is_smi, Label::kNear); | 682 __ JumpIfSmi(base, &base_is_smi, Label::kNear); |
| 715 __ CompareRoot(FieldOperand(base, HeapObject::kMapOffset), | 683 __ CompareRoot(FieldOperand(base, HeapObject::kMapOffset), |
| 716 Heap::kHeapNumberMapRootIndex); | 684 Heap::kHeapNumberMapRootIndex); |
| 717 __ j(not_equal, &call_runtime); | 685 __ j(not_equal, &call_runtime); |
| 718 | 686 |
| 719 __ movsd(double_base, FieldOperand(base, HeapNumber::kValueOffset)); | 687 __ movsd(double_base, FieldOperand(base, HeapNumber::kValueOffset)); |
| 720 __ jmp(&unpack_exponent, Label::kNear); | 688 __ jmp(&unpack_exponent, Label::kNear); |
| 721 | 689 |
| 722 __ bind(&base_is_smi); | 690 __ bind(&base_is_smi); |
| 723 __ SmiToInteger32(base, base); | 691 __ SmiToInteger32(base, base); |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 863 __ bind(&fast_power_failed); | 831 __ bind(&fast_power_failed); |
| 864 __ fninit(); | 832 __ fninit(); |
| 865 __ addq(rsp, Immediate(kDoubleSize)); | 833 __ addq(rsp, Immediate(kDoubleSize)); |
| 866 __ jmp(&call_runtime); | 834 __ jmp(&call_runtime); |
| 867 } | 835 } |
| 868 | 836 |
| 869 // Calculate power with integer exponent. | 837 // Calculate power with integer exponent. |
| 870 __ bind(&int_exponent); | 838 __ bind(&int_exponent); |
| 871 const XMMRegister double_scratch2 = double_exponent; | 839 const XMMRegister double_scratch2 = double_exponent; |
| 872 // Back up exponent as we need to check if exponent is negative later. | 840 // Back up exponent as we need to check if exponent is negative later. |
| 873 __ movq(scratch, exponent); // Back up exponent. | 841 __ movp(scratch, exponent); // Back up exponent. |
| 874 __ movsd(double_scratch, double_base); // Back up base. | 842 __ movsd(double_scratch, double_base); // Back up base. |
| 875 __ movsd(double_scratch2, double_result); // Load double_exponent with 1. | 843 __ movsd(double_scratch2, double_result); // Load double_exponent with 1. |
| 876 | 844 |
| 877 // Get absolute value of exponent. | 845 // Get absolute value of exponent. |
| 878 Label no_neg, while_true, while_false; | 846 Label no_neg, while_true, while_false; |
| 879 __ testl(scratch, scratch); | 847 __ testl(scratch, scratch); |
| 880 __ j(positive, &no_neg, Label::kNear); | 848 __ j(positive, &no_neg, Label::kNear); |
| 881 __ negl(scratch); | 849 __ negl(scratch); |
| 882 __ bind(&no_neg); | 850 __ bind(&no_neg); |
| 883 | 851 |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1031 // Check that the receiver isn't a smi. | 999 // Check that the receiver isn't a smi. |
| 1032 __ JumpIfSmi(receiver, &miss); | 1000 __ JumpIfSmi(receiver, &miss); |
| 1033 | 1001 |
| 1034 // Check that the object is a JS array. | 1002 // Check that the object is a JS array. |
| 1035 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch); | 1003 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch); |
| 1036 __ j(not_equal, &miss); | 1004 __ j(not_equal, &miss); |
| 1037 | 1005 |
| 1038 // Check that elements are FixedArray. | 1006 // Check that elements are FixedArray. |
| 1039 // We rely on StoreIC_ArrayLength below to deal with all types of | 1007 // We rely on StoreIC_ArrayLength below to deal with all types of |
| 1040 // fast elements (including COW). | 1008 // fast elements (including COW). |
| 1041 __ movq(scratch, FieldOperand(receiver, JSArray::kElementsOffset)); | 1009 __ movp(scratch, FieldOperand(receiver, JSArray::kElementsOffset)); |
| 1042 __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch); | 1010 __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch); |
| 1043 __ j(not_equal, &miss); | 1011 __ j(not_equal, &miss); |
| 1044 | 1012 |
| 1045 // Check that the array has fast properties, otherwise the length | 1013 // Check that the array has fast properties, otherwise the length |
| 1046 // property might have been redefined. | 1014 // property might have been redefined. |
| 1047 __ movq(scratch, FieldOperand(receiver, JSArray::kPropertiesOffset)); | 1015 __ movp(scratch, FieldOperand(receiver, JSArray::kPropertiesOffset)); |
| 1048 __ CompareRoot(FieldOperand(scratch, FixedArray::kMapOffset), | 1016 __ CompareRoot(FieldOperand(scratch, FixedArray::kMapOffset), |
| 1049 Heap::kHashTableMapRootIndex); | 1017 Heap::kHashTableMapRootIndex); |
| 1050 __ j(equal, &miss); | 1018 __ j(equal, &miss); |
| 1051 | 1019 |
| 1052 // Check that value is a smi. | 1020 // Check that value is a smi. |
| 1053 __ JumpIfNotSmi(value, &miss); | 1021 __ JumpIfNotSmi(value, &miss); |
| 1054 | 1022 |
| 1055 // Prepare tail call to StoreIC_ArrayLength. | 1023 // Prepare tail call to StoreIC_ArrayLength. |
| 1056 __ PopReturnAddressTo(scratch); | 1024 __ PopReturnAddressTo(scratch); |
| 1057 __ push(receiver); | 1025 __ push(receiver); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1074 | 1042 |
| 1075 // Check that the key is a smi. | 1043 // Check that the key is a smi. |
| 1076 Label slow; | 1044 Label slow; |
| 1077 __ JumpIfNotSmi(rdx, &slow); | 1045 __ JumpIfNotSmi(rdx, &slow); |
| 1078 | 1046 |
| 1079 // Check if the calling frame is an arguments adaptor frame. We look at the | 1047 // Check if the calling frame is an arguments adaptor frame. We look at the |
| 1080 // context offset, and if the frame is not a regular one, then we find a | 1048 // context offset, and if the frame is not a regular one, then we find a |
| 1081 // Smi instead of the context. We can't use SmiCompare here, because that | 1049 // Smi instead of the context. We can't use SmiCompare here, because that |
| 1082 // only works for comparing two smis. | 1050 // only works for comparing two smis. |
| 1083 Label adaptor; | 1051 Label adaptor; |
| 1084 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 1052 __ movp(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 1085 __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset), | 1053 __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset), |
| 1086 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 1054 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 1087 __ j(equal, &adaptor); | 1055 __ j(equal, &adaptor); |
| 1088 | 1056 |
| 1089 // Check index against formal parameters count limit passed in | 1057 // Check index against formal parameters count limit passed in |
| 1090 // through register rax. Use unsigned comparison to get negative | 1058 // through register rax. Use unsigned comparison to get negative |
| 1091 // check for free. | 1059 // check for free. |
| 1092 __ cmpq(rdx, rax); | 1060 __ cmpq(rdx, rax); |
| 1093 __ j(above_equal, &slow); | 1061 __ j(above_equal, &slow); |
| 1094 | 1062 |
| 1095 // Read the argument from the stack and return it. | 1063 // Read the argument from the stack and return it. |
| 1096 __ SmiSub(rax, rax, rdx); | 1064 __ SmiSub(rax, rax, rdx); |
| 1097 __ SmiToInteger32(rax, rax); | 1065 __ SmiToInteger32(rax, rax); |
| 1098 StackArgumentsAccessor args(rbp, rax, ARGUMENTS_DONT_CONTAIN_RECEIVER); | 1066 StackArgumentsAccessor args(rbp, rax, ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 1099 __ movq(rax, args.GetArgumentOperand(0)); | 1067 __ movp(rax, args.GetArgumentOperand(0)); |
| 1100 __ Ret(); | 1068 __ Ret(); |
| 1101 | 1069 |
| 1102 // Arguments adaptor case: Check index against actual arguments | 1070 // Arguments adaptor case: Check index against actual arguments |
| 1103 // limit found in the arguments adaptor frame. Use unsigned | 1071 // limit found in the arguments adaptor frame. Use unsigned |
| 1104 // comparison to get negative check for free. | 1072 // comparison to get negative check for free. |
| 1105 __ bind(&adaptor); | 1073 __ bind(&adaptor); |
| 1106 __ movq(rcx, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 1074 __ movp(rcx, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 1107 __ cmpq(rdx, rcx); | 1075 __ cmpq(rdx, rcx); |
| 1108 __ j(above_equal, &slow); | 1076 __ j(above_equal, &slow); |
| 1109 | 1077 |
| 1110 // Read the argument from the stack and return it. | 1078 // Read the argument from the stack and return it. |
| 1111 __ SmiSub(rcx, rcx, rdx); | 1079 __ SmiSub(rcx, rcx, rdx); |
| 1112 __ SmiToInteger32(rcx, rcx); | 1080 __ SmiToInteger32(rcx, rcx); |
| 1113 StackArgumentsAccessor adaptor_args(rbx, rcx, | 1081 StackArgumentsAccessor adaptor_args(rbx, rcx, |
| 1114 ARGUMENTS_DONT_CONTAIN_RECEIVER); | 1082 ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 1115 __ movq(rax, adaptor_args.GetArgumentOperand(0)); | 1083 __ movp(rax, adaptor_args.GetArgumentOperand(0)); |
| 1116 __ Ret(); | 1084 __ Ret(); |
| 1117 | 1085 |
| 1118 // Slow-case: Handle non-smi or out-of-bounds access to arguments | 1086 // Slow-case: Handle non-smi or out-of-bounds access to arguments |
| 1119 // by calling the runtime system. | 1087 // by calling the runtime system. |
| 1120 __ bind(&slow); | 1088 __ bind(&slow); |
| 1121 __ PopReturnAddressTo(rbx); | 1089 __ PopReturnAddressTo(rbx); |
| 1122 __ push(rdx); | 1090 __ push(rdx); |
| 1123 __ PushReturnAddressFrom(rbx); | 1091 __ PushReturnAddressFrom(rbx); |
| 1124 __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1); | 1092 __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1); |
| 1125 } | 1093 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1137 | 1105 |
| 1138 Factory* factory = masm->isolate()->factory(); | 1106 Factory* factory = masm->isolate()->factory(); |
| 1139 | 1107 |
| 1140 StackArgumentsAccessor args(rsp, 3, ARGUMENTS_DONT_CONTAIN_RECEIVER); | 1108 StackArgumentsAccessor args(rsp, 3, ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 1141 __ SmiToInteger64(rbx, args.GetArgumentOperand(2)); | 1109 __ SmiToInteger64(rbx, args.GetArgumentOperand(2)); |
| 1142 // rbx = parameter count (untagged) | 1110 // rbx = parameter count (untagged) |
| 1143 | 1111 |
| 1144 // Check if the calling frame is an arguments adaptor frame. | 1112 // Check if the calling frame is an arguments adaptor frame. |
| 1145 Label runtime; | 1113 Label runtime; |
| 1146 Label adaptor_frame, try_allocate; | 1114 Label adaptor_frame, try_allocate; |
| 1147 __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 1115 __ movp(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 1148 __ movq(rcx, Operand(rdx, StandardFrameConstants::kContextOffset)); | 1116 __ movp(rcx, Operand(rdx, StandardFrameConstants::kContextOffset)); |
| 1149 __ Cmp(rcx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 1117 __ Cmp(rcx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 1150 __ j(equal, &adaptor_frame); | 1118 __ j(equal, &adaptor_frame); |
| 1151 | 1119 |
| 1152 // No adaptor, parameter count = argument count. | 1120 // No adaptor, parameter count = argument count. |
| 1153 __ movq(rcx, rbx); | 1121 __ movp(rcx, rbx); |
| 1154 __ jmp(&try_allocate, Label::kNear); | 1122 __ jmp(&try_allocate, Label::kNear); |
| 1155 | 1123 |
| 1156 // We have an adaptor frame. Patch the parameters pointer. | 1124 // We have an adaptor frame. Patch the parameters pointer. |
| 1157 __ bind(&adaptor_frame); | 1125 __ bind(&adaptor_frame); |
| 1158 __ SmiToInteger64(rcx, | 1126 __ SmiToInteger64(rcx, |
| 1159 Operand(rdx, | 1127 Operand(rdx, |
| 1160 ArgumentsAdaptorFrameConstants::kLengthOffset)); | 1128 ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 1161 __ lea(rdx, Operand(rdx, rcx, times_pointer_size, | 1129 __ lea(rdx, Operand(rdx, rcx, times_pointer_size, |
| 1162 StandardFrameConstants::kCallerSPOffset)); | 1130 StandardFrameConstants::kCallerSPOffset)); |
| 1163 __ movq(args.GetArgumentOperand(1), rdx); | 1131 __ movp(args.GetArgumentOperand(1), rdx); |
| 1164 | 1132 |
| 1165 // rbx = parameter count (untagged) | 1133 // rbx = parameter count (untagged) |
| 1166 // rcx = argument count (untagged) | 1134 // rcx = argument count (untagged) |
| 1167 // Compute the mapped parameter count = min(rbx, rcx) in rbx. | 1135 // Compute the mapped parameter count = min(rbx, rcx) in rbx. |
| 1168 __ cmpq(rbx, rcx); | 1136 __ cmpq(rbx, rcx); |
| 1169 __ j(less_equal, &try_allocate, Label::kNear); | 1137 __ j(less_equal, &try_allocate, Label::kNear); |
| 1170 __ movq(rbx, rcx); | 1138 __ movp(rbx, rcx); |
| 1171 | 1139 |
| 1172 __ bind(&try_allocate); | 1140 __ bind(&try_allocate); |
| 1173 | 1141 |
| 1174 // Compute the sizes of backing store, parameter map, and arguments object. | 1142 // Compute the sizes of backing store, parameter map, and arguments object. |
| 1175 // 1. Parameter map, has 2 extra words containing context and backing store. | 1143 // 1. Parameter map, has 2 extra words containing context and backing store. |
| 1176 const int kParameterMapHeaderSize = | 1144 const int kParameterMapHeaderSize = |
| 1177 FixedArray::kHeaderSize + 2 * kPointerSize; | 1145 FixedArray::kHeaderSize + 2 * kPointerSize; |
| 1178 Label no_parameter_map; | 1146 Label no_parameter_map; |
| 1179 __ xor_(r8, r8); | 1147 __ xor_(r8, r8); |
| 1180 __ testq(rbx, rbx); | 1148 __ testq(rbx, rbx); |
| 1181 __ j(zero, &no_parameter_map, Label::kNear); | 1149 __ j(zero, &no_parameter_map, Label::kNear); |
| 1182 __ lea(r8, Operand(rbx, times_pointer_size, kParameterMapHeaderSize)); | 1150 __ lea(r8, Operand(rbx, times_pointer_size, kParameterMapHeaderSize)); |
| 1183 __ bind(&no_parameter_map); | 1151 __ bind(&no_parameter_map); |
| 1184 | 1152 |
| 1185 // 2. Backing store. | 1153 // 2. Backing store. |
| 1186 __ lea(r8, Operand(r8, rcx, times_pointer_size, FixedArray::kHeaderSize)); | 1154 __ lea(r8, Operand(r8, rcx, times_pointer_size, FixedArray::kHeaderSize)); |
| 1187 | 1155 |
| 1188 // 3. Arguments object. | 1156 // 3. Arguments object. |
| 1189 __ addq(r8, Immediate(Heap::kArgumentsObjectSize)); | 1157 __ addq(r8, Immediate(Heap::kArgumentsObjectSize)); |
| 1190 | 1158 |
| 1191 // Do the allocation of all three objects in one go. | 1159 // Do the allocation of all three objects in one go. |
| 1192 __ Allocate(r8, rax, rdx, rdi, &runtime, TAG_OBJECT); | 1160 __ Allocate(r8, rax, rdx, rdi, &runtime, TAG_OBJECT); |
| 1193 | 1161 |
| 1194 // rax = address of new object(s) (tagged) | 1162 // rax = address of new object(s) (tagged) |
| 1195 // rcx = argument count (untagged) | 1163 // rcx = argument count (untagged) |
| 1196 // Get the arguments boilerplate from the current native context into rdi. | 1164 // Get the arguments boilerplate from the current native context into rdi. |
| 1197 Label has_mapped_parameters, copy; | 1165 Label has_mapped_parameters, copy; |
| 1198 __ movq(rdi, Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); | 1166 __ movp(rdi, Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); |
| 1199 __ movq(rdi, FieldOperand(rdi, GlobalObject::kNativeContextOffset)); | 1167 __ movp(rdi, FieldOperand(rdi, GlobalObject::kNativeContextOffset)); |
| 1200 __ testq(rbx, rbx); | 1168 __ testq(rbx, rbx); |
| 1201 __ j(not_zero, &has_mapped_parameters, Label::kNear); | 1169 __ j(not_zero, &has_mapped_parameters, Label::kNear); |
| 1202 | 1170 |
| 1203 const int kIndex = Context::ARGUMENTS_BOILERPLATE_INDEX; | 1171 const int kIndex = Context::ARGUMENTS_BOILERPLATE_INDEX; |
| 1204 __ movq(rdi, Operand(rdi, Context::SlotOffset(kIndex))); | 1172 __ movp(rdi, Operand(rdi, Context::SlotOffset(kIndex))); |
| 1205 __ jmp(©, Label::kNear); | 1173 __ jmp(©, Label::kNear); |
| 1206 | 1174 |
| 1207 const int kAliasedIndex = Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX; | 1175 const int kAliasedIndex = Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX; |
| 1208 __ bind(&has_mapped_parameters); | 1176 __ bind(&has_mapped_parameters); |
| 1209 __ movq(rdi, Operand(rdi, Context::SlotOffset(kAliasedIndex))); | 1177 __ movp(rdi, Operand(rdi, Context::SlotOffset(kAliasedIndex))); |
| 1210 __ bind(©); | 1178 __ bind(©); |
| 1211 | 1179 |
| 1212 // rax = address of new object (tagged) | 1180 // rax = address of new object (tagged) |
| 1213 // rbx = mapped parameter count (untagged) | 1181 // rbx = mapped parameter count (untagged) |
| 1214 // rcx = argument count (untagged) | 1182 // rcx = argument count (untagged) |
| 1215 // rdi = address of boilerplate object (tagged) | 1183 // rdi = address of boilerplate object (tagged) |
| 1216 // Copy the JS object part. | 1184 // Copy the JS object part. |
| 1217 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { | 1185 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { |
| 1218 __ movq(rdx, FieldOperand(rdi, i)); | 1186 __ movp(rdx, FieldOperand(rdi, i)); |
| 1219 __ movq(FieldOperand(rax, i), rdx); | 1187 __ movp(FieldOperand(rax, i), rdx); |
| 1220 } | 1188 } |
| 1221 | 1189 |
| 1222 // Set up the callee in-object property. | 1190 // Set up the callee in-object property. |
| 1223 STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1); | 1191 STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1); |
| 1224 __ movq(rdx, args.GetArgumentOperand(0)); | 1192 __ movp(rdx, args.GetArgumentOperand(0)); |
| 1225 __ movq(FieldOperand(rax, JSObject::kHeaderSize + | 1193 __ movp(FieldOperand(rax, JSObject::kHeaderSize + |
| 1226 Heap::kArgumentsCalleeIndex * kPointerSize), | 1194 Heap::kArgumentsCalleeIndex * kPointerSize), |
| 1227 rdx); | 1195 rdx); |
| 1228 | 1196 |
| 1229 // Use the length (smi tagged) and set that as an in-object property too. | 1197 // Use the length (smi tagged) and set that as an in-object property too. |
| 1230 // Note: rcx is tagged from here on. | 1198 // Note: rcx is tagged from here on. |
| 1231 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); | 1199 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); |
| 1232 __ Integer32ToSmi(rcx, rcx); | 1200 __ Integer32ToSmi(rcx, rcx); |
| 1233 __ movq(FieldOperand(rax, JSObject::kHeaderSize + | 1201 __ movp(FieldOperand(rax, JSObject::kHeaderSize + |
| 1234 Heap::kArgumentsLengthIndex * kPointerSize), | 1202 Heap::kArgumentsLengthIndex * kPointerSize), |
| 1235 rcx); | 1203 rcx); |
| 1236 | 1204 |
| 1237 // Set up the elements pointer in the allocated arguments object. | 1205 // Set up the elements pointer in the allocated arguments object. |
| 1238 // If we allocated a parameter map, edi will point there, otherwise to the | 1206 // If we allocated a parameter map, edi will point there, otherwise to the |
| 1239 // backing store. | 1207 // backing store. |
| 1240 __ lea(rdi, Operand(rax, Heap::kArgumentsObjectSize)); | 1208 __ lea(rdi, Operand(rax, Heap::kArgumentsObjectSize)); |
| 1241 __ movq(FieldOperand(rax, JSObject::kElementsOffset), rdi); | 1209 __ movp(FieldOperand(rax, JSObject::kElementsOffset), rdi); |
| 1242 | 1210 |
| 1243 // rax = address of new object (tagged) | 1211 // rax = address of new object (tagged) |
| 1244 // rbx = mapped parameter count (untagged) | 1212 // rbx = mapped parameter count (untagged) |
| 1245 // rcx = argument count (tagged) | 1213 // rcx = argument count (tagged) |
| 1246 // rdi = address of parameter map or backing store (tagged) | 1214 // rdi = address of parameter map or backing store (tagged) |
| 1247 | 1215 |
| 1248 // Initialize parameter map. If there are no mapped arguments, we're done. | 1216 // Initialize parameter map. If there are no mapped arguments, we're done. |
| 1249 Label skip_parameter_map; | 1217 Label skip_parameter_map; |
| 1250 __ testq(rbx, rbx); | 1218 __ testq(rbx, rbx); |
| 1251 __ j(zero, &skip_parameter_map); | 1219 __ j(zero, &skip_parameter_map); |
| 1252 | 1220 |
| 1253 __ LoadRoot(kScratchRegister, Heap::kNonStrictArgumentsElementsMapRootIndex); | 1221 __ LoadRoot(kScratchRegister, Heap::kNonStrictArgumentsElementsMapRootIndex); |
| 1254 // rbx contains the untagged argument count. Add 2 and tag to write. | 1222 // rbx contains the untagged argument count. Add 2 and tag to write. |
| 1255 __ movq(FieldOperand(rdi, FixedArray::kMapOffset), kScratchRegister); | 1223 __ movp(FieldOperand(rdi, FixedArray::kMapOffset), kScratchRegister); |
| 1256 __ Integer64PlusConstantToSmi(r9, rbx, 2); | 1224 __ Integer64PlusConstantToSmi(r9, rbx, 2); |
| 1257 __ movq(FieldOperand(rdi, FixedArray::kLengthOffset), r9); | 1225 __ movp(FieldOperand(rdi, FixedArray::kLengthOffset), r9); |
| 1258 __ movq(FieldOperand(rdi, FixedArray::kHeaderSize + 0 * kPointerSize), rsi); | 1226 __ movp(FieldOperand(rdi, FixedArray::kHeaderSize + 0 * kPointerSize), rsi); |
| 1259 __ lea(r9, Operand(rdi, rbx, times_pointer_size, kParameterMapHeaderSize)); | 1227 __ lea(r9, Operand(rdi, rbx, times_pointer_size, kParameterMapHeaderSize)); |
| 1260 __ movq(FieldOperand(rdi, FixedArray::kHeaderSize + 1 * kPointerSize), r9); | 1228 __ movp(FieldOperand(rdi, FixedArray::kHeaderSize + 1 * kPointerSize), r9); |
| 1261 | 1229 |
| 1262 // Copy the parameter slots and the holes in the arguments. | 1230 // Copy the parameter slots and the holes in the arguments. |
| 1263 // We need to fill in mapped_parameter_count slots. They index the context, | 1231 // We need to fill in mapped_parameter_count slots. They index the context, |
| 1264 // where parameters are stored in reverse order, at | 1232 // where parameters are stored in reverse order, at |
| 1265 // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1 | 1233 // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1 |
| 1266 // The mapped parameter thus need to get indices | 1234 // The mapped parameter thus need to get indices |
| 1267 // MIN_CONTEXT_SLOTS+parameter_count-1 .. | 1235 // MIN_CONTEXT_SLOTS+parameter_count-1 .. |
| 1268 // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count | 1236 // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count |
| 1269 // We loop from right to left. | 1237 // We loop from right to left. |
| 1270 Label parameters_loop, parameters_test; | 1238 Label parameters_loop, parameters_test; |
| 1271 | 1239 |
| 1272 // Load tagged parameter count into r9. | 1240 // Load tagged parameter count into r9. |
| 1273 __ Integer32ToSmi(r9, rbx); | 1241 __ Integer32ToSmi(r9, rbx); |
| 1274 __ Move(r8, Smi::FromInt(Context::MIN_CONTEXT_SLOTS)); | 1242 __ Move(r8, Smi::FromInt(Context::MIN_CONTEXT_SLOTS)); |
| 1275 __ addq(r8, args.GetArgumentOperand(2)); | 1243 __ addq(r8, args.GetArgumentOperand(2)); |
| 1276 __ subq(r8, r9); | 1244 __ subq(r8, r9); |
| 1277 __ Move(r11, factory->the_hole_value()); | 1245 __ Move(r11, factory->the_hole_value()); |
| 1278 __ movq(rdx, rdi); | 1246 __ movp(rdx, rdi); |
| 1279 __ lea(rdi, Operand(rdi, rbx, times_pointer_size, kParameterMapHeaderSize)); | 1247 __ lea(rdi, Operand(rdi, rbx, times_pointer_size, kParameterMapHeaderSize)); |
| 1280 // r9 = loop variable (tagged) | 1248 // r9 = loop variable (tagged) |
| 1281 // r8 = mapping index (tagged) | 1249 // r8 = mapping index (tagged) |
| 1282 // r11 = the hole value | 1250 // r11 = the hole value |
| 1283 // rdx = address of parameter map (tagged) | 1251 // rdx = address of parameter map (tagged) |
| 1284 // rdi = address of backing store (tagged) | 1252 // rdi = address of backing store (tagged) |
| 1285 __ jmp(¶meters_test, Label::kNear); | 1253 __ jmp(¶meters_test, Label::kNear); |
| 1286 | 1254 |
| 1287 __ bind(¶meters_loop); | 1255 __ bind(¶meters_loop); |
| 1288 __ SmiSubConstant(r9, r9, Smi::FromInt(1)); | 1256 __ SmiSubConstant(r9, r9, Smi::FromInt(1)); |
| 1289 __ SmiToInteger64(kScratchRegister, r9); | 1257 __ SmiToInteger64(kScratchRegister, r9); |
| 1290 __ movq(FieldOperand(rdx, kScratchRegister, | 1258 __ movp(FieldOperand(rdx, kScratchRegister, |
| 1291 times_pointer_size, | 1259 times_pointer_size, |
| 1292 kParameterMapHeaderSize), | 1260 kParameterMapHeaderSize), |
| 1293 r8); | 1261 r8); |
| 1294 __ movq(FieldOperand(rdi, kScratchRegister, | 1262 __ movp(FieldOperand(rdi, kScratchRegister, |
| 1295 times_pointer_size, | 1263 times_pointer_size, |
| 1296 FixedArray::kHeaderSize), | 1264 FixedArray::kHeaderSize), |
| 1297 r11); | 1265 r11); |
| 1298 __ SmiAddConstant(r8, r8, Smi::FromInt(1)); | 1266 __ SmiAddConstant(r8, r8, Smi::FromInt(1)); |
| 1299 __ bind(¶meters_test); | 1267 __ bind(¶meters_test); |
| 1300 __ SmiTest(r9); | 1268 __ SmiTest(r9); |
| 1301 __ j(not_zero, ¶meters_loop, Label::kNear); | 1269 __ j(not_zero, ¶meters_loop, Label::kNear); |
| 1302 | 1270 |
| 1303 __ bind(&skip_parameter_map); | 1271 __ bind(&skip_parameter_map); |
| 1304 | 1272 |
| 1305 // rcx = argument count (tagged) | 1273 // rcx = argument count (tagged) |
| 1306 // rdi = address of backing store (tagged) | 1274 // rdi = address of backing store (tagged) |
| 1307 // Copy arguments header and remaining slots (if there are any). | 1275 // Copy arguments header and remaining slots (if there are any). |
| 1308 __ Move(FieldOperand(rdi, FixedArray::kMapOffset), | 1276 __ Move(FieldOperand(rdi, FixedArray::kMapOffset), |
| 1309 factory->fixed_array_map()); | 1277 factory->fixed_array_map()); |
| 1310 __ movq(FieldOperand(rdi, FixedArray::kLengthOffset), rcx); | 1278 __ movp(FieldOperand(rdi, FixedArray::kLengthOffset), rcx); |
| 1311 | 1279 |
| 1312 Label arguments_loop, arguments_test; | 1280 Label arguments_loop, arguments_test; |
| 1313 __ movq(r8, rbx); | 1281 __ movp(r8, rbx); |
| 1314 __ movq(rdx, args.GetArgumentOperand(1)); | 1282 __ movp(rdx, args.GetArgumentOperand(1)); |
| 1315 // Untag rcx for the loop below. | 1283 // Untag rcx for the loop below. |
| 1316 __ SmiToInteger64(rcx, rcx); | 1284 __ SmiToInteger64(rcx, rcx); |
| 1317 __ lea(kScratchRegister, Operand(r8, times_pointer_size, 0)); | 1285 __ lea(kScratchRegister, Operand(r8, times_pointer_size, 0)); |
| 1318 __ subq(rdx, kScratchRegister); | 1286 __ subq(rdx, kScratchRegister); |
| 1319 __ jmp(&arguments_test, Label::kNear); | 1287 __ jmp(&arguments_test, Label::kNear); |
| 1320 | 1288 |
| 1321 __ bind(&arguments_loop); | 1289 __ bind(&arguments_loop); |
| 1322 __ subq(rdx, Immediate(kPointerSize)); | 1290 __ subq(rdx, Immediate(kPointerSize)); |
| 1323 __ movq(r9, Operand(rdx, 0)); | 1291 __ movp(r9, Operand(rdx, 0)); |
| 1324 __ movq(FieldOperand(rdi, r8, | 1292 __ movp(FieldOperand(rdi, r8, |
| 1325 times_pointer_size, | 1293 times_pointer_size, |
| 1326 FixedArray::kHeaderSize), | 1294 FixedArray::kHeaderSize), |
| 1327 r9); | 1295 r9); |
| 1328 __ addq(r8, Immediate(1)); | 1296 __ addq(r8, Immediate(1)); |
| 1329 | 1297 |
| 1330 __ bind(&arguments_test); | 1298 __ bind(&arguments_test); |
| 1331 __ cmpq(r8, rcx); | 1299 __ cmpq(r8, rcx); |
| 1332 __ j(less, &arguments_loop, Label::kNear); | 1300 __ j(less, &arguments_loop, Label::kNear); |
| 1333 | 1301 |
| 1334 // Return and remove the on-stack parameters. | 1302 // Return and remove the on-stack parameters. |
| 1335 __ ret(3 * kPointerSize); | 1303 __ ret(3 * kPointerSize); |
| 1336 | 1304 |
| 1337 // Do the runtime call to allocate the arguments object. | 1305 // Do the runtime call to allocate the arguments object. |
| 1338 // rcx = argument count (untagged) | 1306 // rcx = argument count (untagged) |
| 1339 __ bind(&runtime); | 1307 __ bind(&runtime); |
| 1340 __ Integer32ToSmi(rcx, rcx); | 1308 __ Integer32ToSmi(rcx, rcx); |
| 1341 __ movq(args.GetArgumentOperand(2), rcx); // Patch argument count. | 1309 __ movp(args.GetArgumentOperand(2), rcx); // Patch argument count. |
| 1342 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); | 1310 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); |
| 1343 } | 1311 } |
| 1344 | 1312 |
| 1345 | 1313 |
| 1346 void ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) { | 1314 void ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) { |
| 1347 // rsp[0] : return address | 1315 // rsp[0] : return address |
| 1348 // rsp[8] : number of parameters | 1316 // rsp[8] : number of parameters |
| 1349 // rsp[16] : receiver displacement | 1317 // rsp[16] : receiver displacement |
| 1350 // rsp[24] : function | 1318 // rsp[24] : function |
| 1351 | 1319 |
| 1352 // Check if the calling frame is an arguments adaptor frame. | 1320 // Check if the calling frame is an arguments adaptor frame. |
| 1353 Label runtime; | 1321 Label runtime; |
| 1354 __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 1322 __ movp(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 1355 __ movq(rcx, Operand(rdx, StandardFrameConstants::kContextOffset)); | 1323 __ movp(rcx, Operand(rdx, StandardFrameConstants::kContextOffset)); |
| 1356 __ Cmp(rcx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 1324 __ Cmp(rcx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 1357 __ j(not_equal, &runtime); | 1325 __ j(not_equal, &runtime); |
| 1358 | 1326 |
| 1359 // Patch the arguments.length and the parameters pointer. | 1327 // Patch the arguments.length and the parameters pointer. |
| 1360 StackArgumentsAccessor args(rsp, 3, ARGUMENTS_DONT_CONTAIN_RECEIVER); | 1328 StackArgumentsAccessor args(rsp, 3, ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 1361 __ movq(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 1329 __ movp(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 1362 __ movq(args.GetArgumentOperand(2), rcx); | 1330 __ movp(args.GetArgumentOperand(2), rcx); |
| 1363 __ SmiToInteger64(rcx, rcx); | 1331 __ SmiToInteger64(rcx, rcx); |
| 1364 __ lea(rdx, Operand(rdx, rcx, times_pointer_size, | 1332 __ lea(rdx, Operand(rdx, rcx, times_pointer_size, |
| 1365 StandardFrameConstants::kCallerSPOffset)); | 1333 StandardFrameConstants::kCallerSPOffset)); |
| 1366 __ movq(args.GetArgumentOperand(1), rdx); | 1334 __ movp(args.GetArgumentOperand(1), rdx); |
| 1367 | 1335 |
| 1368 __ bind(&runtime); | 1336 __ bind(&runtime); |
| 1369 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); | 1337 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); |
| 1370 } | 1338 } |
| 1371 | 1339 |
| 1372 | 1340 |
| 1373 void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) { | 1341 void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) { |
| 1374 // rsp[0] : return address | 1342 // rsp[0] : return address |
| 1375 // rsp[8] : number of parameters | 1343 // rsp[8] : number of parameters |
| 1376 // rsp[16] : receiver displacement | 1344 // rsp[16] : receiver displacement |
| 1377 // rsp[24] : function | 1345 // rsp[24] : function |
| 1378 | 1346 |
| 1379 // Check if the calling frame is an arguments adaptor frame. | 1347 // Check if the calling frame is an arguments adaptor frame. |
| 1380 Label adaptor_frame, try_allocate, runtime; | 1348 Label adaptor_frame, try_allocate, runtime; |
| 1381 __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 1349 __ movp(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 1382 __ movq(rcx, Operand(rdx, StandardFrameConstants::kContextOffset)); | 1350 __ movp(rcx, Operand(rdx, StandardFrameConstants::kContextOffset)); |
| 1383 __ Cmp(rcx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 1351 __ Cmp(rcx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 1384 __ j(equal, &adaptor_frame); | 1352 __ j(equal, &adaptor_frame); |
| 1385 | 1353 |
| 1386 // Get the length from the frame. | 1354 // Get the length from the frame. |
| 1387 StackArgumentsAccessor args(rsp, 3, ARGUMENTS_DONT_CONTAIN_RECEIVER); | 1355 StackArgumentsAccessor args(rsp, 3, ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 1388 __ movq(rcx, args.GetArgumentOperand(2)); | 1356 __ movp(rcx, args.GetArgumentOperand(2)); |
| 1389 __ SmiToInteger64(rcx, rcx); | 1357 __ SmiToInteger64(rcx, rcx); |
| 1390 __ jmp(&try_allocate); | 1358 __ jmp(&try_allocate); |
| 1391 | 1359 |
| 1392 // Patch the arguments.length and the parameters pointer. | 1360 // Patch the arguments.length and the parameters pointer. |
| 1393 __ bind(&adaptor_frame); | 1361 __ bind(&adaptor_frame); |
| 1394 __ movq(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 1362 __ movp(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 1395 __ movq(args.GetArgumentOperand(2), rcx); | 1363 __ movp(args.GetArgumentOperand(2), rcx); |
| 1396 __ SmiToInteger64(rcx, rcx); | 1364 __ SmiToInteger64(rcx, rcx); |
| 1397 __ lea(rdx, Operand(rdx, rcx, times_pointer_size, | 1365 __ lea(rdx, Operand(rdx, rcx, times_pointer_size, |
| 1398 StandardFrameConstants::kCallerSPOffset)); | 1366 StandardFrameConstants::kCallerSPOffset)); |
| 1399 __ movq(args.GetArgumentOperand(1), rdx); | 1367 __ movp(args.GetArgumentOperand(1), rdx); |
| 1400 | 1368 |
| 1401 // Try the new space allocation. Start out with computing the size of | 1369 // Try the new space allocation. Start out with computing the size of |
| 1402 // the arguments object and the elements array. | 1370 // the arguments object and the elements array. |
| 1403 Label add_arguments_object; | 1371 Label add_arguments_object; |
| 1404 __ bind(&try_allocate); | 1372 __ bind(&try_allocate); |
| 1405 __ testq(rcx, rcx); | 1373 __ testq(rcx, rcx); |
| 1406 __ j(zero, &add_arguments_object, Label::kNear); | 1374 __ j(zero, &add_arguments_object, Label::kNear); |
| 1407 __ lea(rcx, Operand(rcx, times_pointer_size, FixedArray::kHeaderSize)); | 1375 __ lea(rcx, Operand(rcx, times_pointer_size, FixedArray::kHeaderSize)); |
| 1408 __ bind(&add_arguments_object); | 1376 __ bind(&add_arguments_object); |
| 1409 __ addq(rcx, Immediate(Heap::kArgumentsObjectSizeStrict)); | 1377 __ addq(rcx, Immediate(Heap::kArgumentsObjectSizeStrict)); |
| 1410 | 1378 |
| 1411 // Do the allocation of both objects in one go. | 1379 // Do the allocation of both objects in one go. |
| 1412 __ Allocate(rcx, rax, rdx, rbx, &runtime, TAG_OBJECT); | 1380 __ Allocate(rcx, rax, rdx, rbx, &runtime, TAG_OBJECT); |
| 1413 | 1381 |
| 1414 // Get the arguments boilerplate from the current native context. | 1382 // Get the arguments boilerplate from the current native context. |
| 1415 __ movq(rdi, Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); | 1383 __ movp(rdi, Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); |
| 1416 __ movq(rdi, FieldOperand(rdi, GlobalObject::kNativeContextOffset)); | 1384 __ movp(rdi, FieldOperand(rdi, GlobalObject::kNativeContextOffset)); |
| 1417 const int offset = | 1385 const int offset = |
| 1418 Context::SlotOffset(Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX); | 1386 Context::SlotOffset(Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX); |
| 1419 __ movq(rdi, Operand(rdi, offset)); | 1387 __ movp(rdi, Operand(rdi, offset)); |
| 1420 | 1388 |
| 1421 // Copy the JS object part. | 1389 // Copy the JS object part. |
| 1422 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { | 1390 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { |
| 1423 __ movq(rbx, FieldOperand(rdi, i)); | 1391 __ movp(rbx, FieldOperand(rdi, i)); |
| 1424 __ movq(FieldOperand(rax, i), rbx); | 1392 __ movp(FieldOperand(rax, i), rbx); |
| 1425 } | 1393 } |
| 1426 | 1394 |
| 1427 // Get the length (smi tagged) and set that as an in-object property too. | 1395 // Get the length (smi tagged) and set that as an in-object property too. |
| 1428 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); | 1396 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); |
| 1429 __ movq(rcx, args.GetArgumentOperand(2)); | 1397 __ movp(rcx, args.GetArgumentOperand(2)); |
| 1430 __ movq(FieldOperand(rax, JSObject::kHeaderSize + | 1398 __ movp(FieldOperand(rax, JSObject::kHeaderSize + |
| 1431 Heap::kArgumentsLengthIndex * kPointerSize), | 1399 Heap::kArgumentsLengthIndex * kPointerSize), |
| 1432 rcx); | 1400 rcx); |
| 1433 | 1401 |
| 1434 // If there are no actual arguments, we're done. | 1402 // If there are no actual arguments, we're done. |
| 1435 Label done; | 1403 Label done; |
| 1436 __ testq(rcx, rcx); | 1404 __ testq(rcx, rcx); |
| 1437 __ j(zero, &done); | 1405 __ j(zero, &done); |
| 1438 | 1406 |
| 1439 // Get the parameters pointer from the stack. | 1407 // Get the parameters pointer from the stack. |
| 1440 __ movq(rdx, args.GetArgumentOperand(1)); | 1408 __ movp(rdx, args.GetArgumentOperand(1)); |
| 1441 | 1409 |
| 1442 // Set up the elements pointer in the allocated arguments object and | 1410 // Set up the elements pointer in the allocated arguments object and |
| 1443 // initialize the header in the elements fixed array. | 1411 // initialize the header in the elements fixed array. |
| 1444 __ lea(rdi, Operand(rax, Heap::kArgumentsObjectSizeStrict)); | 1412 __ lea(rdi, Operand(rax, Heap::kArgumentsObjectSizeStrict)); |
| 1445 __ movq(FieldOperand(rax, JSObject::kElementsOffset), rdi); | 1413 __ movp(FieldOperand(rax, JSObject::kElementsOffset), rdi); |
| 1446 __ LoadRoot(kScratchRegister, Heap::kFixedArrayMapRootIndex); | 1414 __ LoadRoot(kScratchRegister, Heap::kFixedArrayMapRootIndex); |
| 1447 __ movq(FieldOperand(rdi, FixedArray::kMapOffset), kScratchRegister); | 1415 __ movp(FieldOperand(rdi, FixedArray::kMapOffset), kScratchRegister); |
| 1448 | 1416 |
| 1449 | 1417 |
| 1450 __ movq(FieldOperand(rdi, FixedArray::kLengthOffset), rcx); | 1418 __ movp(FieldOperand(rdi, FixedArray::kLengthOffset), rcx); |
| 1451 // Untag the length for the loop below. | 1419 // Untag the length for the loop below. |
| 1452 __ SmiToInteger64(rcx, rcx); | 1420 __ SmiToInteger64(rcx, rcx); |
| 1453 | 1421 |
| 1454 // Copy the fixed array slots. | 1422 // Copy the fixed array slots. |
| 1455 Label loop; | 1423 Label loop; |
| 1456 __ bind(&loop); | 1424 __ bind(&loop); |
| 1457 __ movq(rbx, Operand(rdx, -1 * kPointerSize)); // Skip receiver. | 1425 __ movp(rbx, Operand(rdx, -1 * kPointerSize)); // Skip receiver. |
| 1458 __ movq(FieldOperand(rdi, FixedArray::kHeaderSize), rbx); | 1426 __ movp(FieldOperand(rdi, FixedArray::kHeaderSize), rbx); |
| 1459 __ addq(rdi, Immediate(kPointerSize)); | 1427 __ addq(rdi, Immediate(kPointerSize)); |
| 1460 __ subq(rdx, Immediate(kPointerSize)); | 1428 __ subq(rdx, Immediate(kPointerSize)); |
| 1461 __ decq(rcx); | 1429 __ decq(rcx); |
| 1462 __ j(not_zero, &loop); | 1430 __ j(not_zero, &loop); |
| 1463 | 1431 |
| 1464 // Return and remove the on-stack parameters. | 1432 // Return and remove the on-stack parameters. |
| 1465 __ bind(&done); | 1433 __ bind(&done); |
| 1466 __ ret(3 * kPointerSize); | 1434 __ ret(3 * kPointerSize); |
| 1467 | 1435 |
| 1468 // Do the runtime call to allocate the arguments object. | 1436 // Do the runtime call to allocate the arguments object. |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1501 Isolate* isolate = masm->isolate(); | 1469 Isolate* isolate = masm->isolate(); |
| 1502 ExternalReference address_of_regexp_stack_memory_address = | 1470 ExternalReference address_of_regexp_stack_memory_address = |
| 1503 ExternalReference::address_of_regexp_stack_memory_address(isolate); | 1471 ExternalReference::address_of_regexp_stack_memory_address(isolate); |
| 1504 ExternalReference address_of_regexp_stack_memory_size = | 1472 ExternalReference address_of_regexp_stack_memory_size = |
| 1505 ExternalReference::address_of_regexp_stack_memory_size(isolate); | 1473 ExternalReference::address_of_regexp_stack_memory_size(isolate); |
| 1506 __ Load(kScratchRegister, address_of_regexp_stack_memory_size); | 1474 __ Load(kScratchRegister, address_of_regexp_stack_memory_size); |
| 1507 __ testq(kScratchRegister, kScratchRegister); | 1475 __ testq(kScratchRegister, kScratchRegister); |
| 1508 __ j(zero, &runtime); | 1476 __ j(zero, &runtime); |
| 1509 | 1477 |
| 1510 // Check that the first argument is a JSRegExp object. | 1478 // Check that the first argument is a JSRegExp object. |
| 1511 __ movq(rax, args.GetArgumentOperand(JS_REG_EXP_OBJECT_ARGUMENT_INDEX)); | 1479 __ movp(rax, args.GetArgumentOperand(JS_REG_EXP_OBJECT_ARGUMENT_INDEX)); |
| 1512 __ JumpIfSmi(rax, &runtime); | 1480 __ JumpIfSmi(rax, &runtime); |
| 1513 __ CmpObjectType(rax, JS_REGEXP_TYPE, kScratchRegister); | 1481 __ CmpObjectType(rax, JS_REGEXP_TYPE, kScratchRegister); |
| 1514 __ j(not_equal, &runtime); | 1482 __ j(not_equal, &runtime); |
| 1515 | 1483 |
| 1516 // Check that the RegExp has been compiled (data contains a fixed array). | 1484 // Check that the RegExp has been compiled (data contains a fixed array). |
| 1517 __ movq(rax, FieldOperand(rax, JSRegExp::kDataOffset)); | 1485 __ movp(rax, FieldOperand(rax, JSRegExp::kDataOffset)); |
| 1518 if (FLAG_debug_code) { | 1486 if (FLAG_debug_code) { |
| 1519 Condition is_smi = masm->CheckSmi(rax); | 1487 Condition is_smi = masm->CheckSmi(rax); |
| 1520 __ Check(NegateCondition(is_smi), | 1488 __ Check(NegateCondition(is_smi), |
| 1521 kUnexpectedTypeForRegExpDataFixedArrayExpected); | 1489 kUnexpectedTypeForRegExpDataFixedArrayExpected); |
| 1522 __ CmpObjectType(rax, FIXED_ARRAY_TYPE, kScratchRegister); | 1490 __ CmpObjectType(rax, FIXED_ARRAY_TYPE, kScratchRegister); |
| 1523 __ Check(equal, kUnexpectedTypeForRegExpDataFixedArrayExpected); | 1491 __ Check(equal, kUnexpectedTypeForRegExpDataFixedArrayExpected); |
| 1524 } | 1492 } |
| 1525 | 1493 |
| 1526 // rax: RegExp data (FixedArray) | 1494 // rax: RegExp data (FixedArray) |
| 1527 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. | 1495 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. |
| 1528 __ SmiToInteger32(rbx, FieldOperand(rax, JSRegExp::kDataTagOffset)); | 1496 __ SmiToInteger32(rbx, FieldOperand(rax, JSRegExp::kDataTagOffset)); |
| 1529 __ cmpl(rbx, Immediate(JSRegExp::IRREGEXP)); | 1497 __ cmpl(rbx, Immediate(JSRegExp::IRREGEXP)); |
| 1530 __ j(not_equal, &runtime); | 1498 __ j(not_equal, &runtime); |
| 1531 | 1499 |
| 1532 // rax: RegExp data (FixedArray) | 1500 // rax: RegExp data (FixedArray) |
| 1533 // Check that the number of captures fit in the static offsets vector buffer. | 1501 // Check that the number of captures fit in the static offsets vector buffer. |
| 1534 __ SmiToInteger32(rdx, | 1502 __ SmiToInteger32(rdx, |
| 1535 FieldOperand(rax, JSRegExp::kIrregexpCaptureCountOffset)); | 1503 FieldOperand(rax, JSRegExp::kIrregexpCaptureCountOffset)); |
| 1536 // Check (number_of_captures + 1) * 2 <= offsets vector size | 1504 // Check (number_of_captures + 1) * 2 <= offsets vector size |
| 1537 // Or number_of_captures <= offsets vector size / 2 - 1 | 1505 // Or number_of_captures <= offsets vector size / 2 - 1 |
| 1538 STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2); | 1506 STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2); |
| 1539 __ cmpl(rdx, Immediate(Isolate::kJSRegexpStaticOffsetsVectorSize / 2 - 1)); | 1507 __ cmpl(rdx, Immediate(Isolate::kJSRegexpStaticOffsetsVectorSize / 2 - 1)); |
| 1540 __ j(above, &runtime); | 1508 __ j(above, &runtime); |
| 1541 | 1509 |
| 1542 // Reset offset for possibly sliced string. | 1510 // Reset offset for possibly sliced string. |
| 1543 __ Set(r14, 0); | 1511 __ Set(r14, 0); |
| 1544 __ movq(rdi, args.GetArgumentOperand(SUBJECT_STRING_ARGUMENT_INDEX)); | 1512 __ movp(rdi, args.GetArgumentOperand(SUBJECT_STRING_ARGUMENT_INDEX)); |
| 1545 __ JumpIfSmi(rdi, &runtime); | 1513 __ JumpIfSmi(rdi, &runtime); |
| 1546 __ movq(r15, rdi); // Make a copy of the original subject string. | 1514 __ movp(r15, rdi); // Make a copy of the original subject string. |
| 1547 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); | 1515 __ movp(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); |
| 1548 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | 1516 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
| 1549 // rax: RegExp data (FixedArray) | 1517 // rax: RegExp data (FixedArray) |
| 1550 // rdi: subject string | 1518 // rdi: subject string |
| 1551 // r15: subject string | 1519 // r15: subject string |
| 1552 // Handle subject string according to its encoding and representation: | 1520 // Handle subject string according to its encoding and representation: |
| 1553 // (1) Sequential two byte? If yes, go to (9). | 1521 // (1) Sequential two byte? If yes, go to (9). |
| 1554 // (2) Sequential one byte? If yes, go to (6). | 1522 // (2) Sequential one byte? If yes, go to (6). |
| 1555 // (3) Anything but sequential or cons? If yes, go to (7). | 1523 // (3) Anything but sequential or cons? If yes, go to (7). |
| 1556 // (4) Cons string. If the string is flat, replace subject with first string. | 1524 // (4) Cons string. If the string is flat, replace subject with first string. |
| 1557 // Otherwise bailout. | 1525 // Otherwise bailout. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1597 STATIC_ASSERT(kIsNotStringMask > kExternalStringTag); | 1565 STATIC_ASSERT(kIsNotStringMask > kExternalStringTag); |
| 1598 STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag); | 1566 STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag); |
| 1599 __ cmpq(rbx, Immediate(kExternalStringTag)); | 1567 __ cmpq(rbx, Immediate(kExternalStringTag)); |
| 1600 __ j(greater_equal, ¬_seq_nor_cons); // Go to (7). | 1568 __ j(greater_equal, ¬_seq_nor_cons); // Go to (7). |
| 1601 | 1569 |
| 1602 // (4) Cons string. Check that it's flat. | 1570 // (4) Cons string. Check that it's flat. |
| 1603 // Replace subject with first string and reload instance type. | 1571 // Replace subject with first string and reload instance type. |
| 1604 __ CompareRoot(FieldOperand(rdi, ConsString::kSecondOffset), | 1572 __ CompareRoot(FieldOperand(rdi, ConsString::kSecondOffset), |
| 1605 Heap::kempty_stringRootIndex); | 1573 Heap::kempty_stringRootIndex); |
| 1606 __ j(not_equal, &runtime); | 1574 __ j(not_equal, &runtime); |
| 1607 __ movq(rdi, FieldOperand(rdi, ConsString::kFirstOffset)); | 1575 __ movp(rdi, FieldOperand(rdi, ConsString::kFirstOffset)); |
| 1608 __ bind(&check_underlying); | 1576 __ bind(&check_underlying); |
| 1609 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); | 1577 __ movp(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); |
| 1610 __ movq(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | 1578 __ movp(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
| 1611 | 1579 |
| 1612 // (5a) Is subject sequential two byte? If yes, go to (9). | 1580 // (5a) Is subject sequential two byte? If yes, go to (9). |
| 1613 __ testb(rbx, Immediate(kStringRepresentationMask | kStringEncodingMask)); | 1581 __ testb(rbx, Immediate(kStringRepresentationMask | kStringEncodingMask)); |
| 1614 STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0); | 1582 STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0); |
| 1615 __ j(zero, &seq_two_byte_string); // Go to (9). | 1583 __ j(zero, &seq_two_byte_string); // Go to (9). |
| 1616 // (5b) Is subject external? If yes, go to (8). | 1584 // (5b) Is subject external? If yes, go to (8). |
| 1617 __ testb(rbx, Immediate(kStringRepresentationMask)); | 1585 __ testb(rbx, Immediate(kStringRepresentationMask)); |
| 1618 // The underlying external string is never a short external string. | 1586 // The underlying external string is never a short external string. |
| 1619 STATIC_CHECK(ExternalString::kMaxShortLength < ConsString::kMinLength); | 1587 STATIC_CHECK(ExternalString::kMaxShortLength < ConsString::kMinLength); |
| 1620 STATIC_CHECK(ExternalString::kMaxShortLength < SlicedString::kMinLength); | 1588 STATIC_CHECK(ExternalString::kMaxShortLength < SlicedString::kMinLength); |
| 1621 __ j(not_zero, &external_string); // Go to (8) | 1589 __ j(not_zero, &external_string); // Go to (8) |
| 1622 | 1590 |
| 1623 // (6) One byte sequential. Load regexp code for one byte. | 1591 // (6) One byte sequential. Load regexp code for one byte. |
| 1624 __ bind(&seq_one_byte_string); | 1592 __ bind(&seq_one_byte_string); |
| 1625 // rax: RegExp data (FixedArray) | 1593 // rax: RegExp data (FixedArray) |
| 1626 __ movq(r11, FieldOperand(rax, JSRegExp::kDataAsciiCodeOffset)); | 1594 __ movp(r11, FieldOperand(rax, JSRegExp::kDataAsciiCodeOffset)); |
| 1627 __ Set(rcx, 1); // Type is one byte. | 1595 __ Set(rcx, 1); // Type is one byte. |
| 1628 | 1596 |
| 1629 // (E) Carry on. String handling is done. | 1597 // (E) Carry on. String handling is done. |
| 1630 __ bind(&check_code); | 1598 __ bind(&check_code); |
| 1631 // r11: irregexp code | 1599 // r11: irregexp code |
| 1632 // Check that the irregexp code has been generated for the actual string | 1600 // Check that the irregexp code has been generated for the actual string |
| 1633 // encoding. If it has, the field contains a code object otherwise it contains | 1601 // encoding. If it has, the field contains a code object otherwise it contains |
| 1634 // smi (code flushing support) | 1602 // smi (code flushing support) |
| 1635 __ JumpIfSmi(r11, &runtime); | 1603 __ JumpIfSmi(r11, &runtime); |
| 1636 | 1604 |
| 1637 // rdi: sequential subject string (or look-alike, external string) | 1605 // rdi: sequential subject string (or look-alike, external string) |
| 1638 // r15: original subject string | 1606 // r15: original subject string |
| 1639 // rcx: encoding of subject string (1 if ASCII, 0 if two_byte); | 1607 // rcx: encoding of subject string (1 if ASCII, 0 if two_byte); |
| 1640 // r11: code | 1608 // r11: code |
| 1641 // Load used arguments before starting to push arguments for call to native | 1609 // Load used arguments before starting to push arguments for call to native |
| 1642 // RegExp code to avoid handling changing stack height. | 1610 // RegExp code to avoid handling changing stack height. |
| 1643 // We have to use r15 instead of rdi to load the length because rdi might | 1611 // We have to use r15 instead of rdi to load the length because rdi might |
| 1644 // have been only made to look like a sequential string when it actually | 1612 // have been only made to look like a sequential string when it actually |
| 1645 // is an external string. | 1613 // is an external string. |
| 1646 __ movq(rbx, args.GetArgumentOperand(PREVIOUS_INDEX_ARGUMENT_INDEX)); | 1614 __ movp(rbx, args.GetArgumentOperand(PREVIOUS_INDEX_ARGUMENT_INDEX)); |
| 1647 __ JumpIfNotSmi(rbx, &runtime); | 1615 __ JumpIfNotSmi(rbx, &runtime); |
| 1648 __ SmiCompare(rbx, FieldOperand(r15, String::kLengthOffset)); | 1616 __ SmiCompare(rbx, FieldOperand(r15, String::kLengthOffset)); |
| 1649 __ j(above_equal, &runtime); | 1617 __ j(above_equal, &runtime); |
| 1650 __ SmiToInteger64(rbx, rbx); | 1618 __ SmiToInteger64(rbx, rbx); |
| 1651 | 1619 |
| 1652 // rdi: subject string | 1620 // rdi: subject string |
| 1653 // rbx: previous index | 1621 // rbx: previous index |
| 1654 // rcx: encoding of subject string (1 if ASCII 0 if two_byte); | 1622 // rcx: encoding of subject string (1 if ASCII 0 if two_byte); |
| 1655 // r11: code | 1623 // r11: code |
| 1656 // All checks done. Now push arguments for native regexp code. | 1624 // All checks done. Now push arguments for native regexp code. |
| 1657 Counters* counters = masm->isolate()->counters(); | 1625 Counters* counters = masm->isolate()->counters(); |
| 1658 __ IncrementCounter(counters->regexp_entry_native(), 1); | 1626 __ IncrementCounter(counters->regexp_entry_native(), 1); |
| 1659 | 1627 |
| 1660 // Isolates: note we add an additional parameter here (isolate pointer). | 1628 // Isolates: note we add an additional parameter here (isolate pointer). |
| 1661 static const int kRegExpExecuteArguments = 9; | 1629 static const int kRegExpExecuteArguments = 9; |
| 1662 int argument_slots_on_stack = | 1630 int argument_slots_on_stack = |
| 1663 masm->ArgumentStackSlotsForCFunctionCall(kRegExpExecuteArguments); | 1631 masm->ArgumentStackSlotsForCFunctionCall(kRegExpExecuteArguments); |
| 1664 __ EnterApiExitFrame(argument_slots_on_stack); | 1632 __ EnterApiExitFrame(argument_slots_on_stack); |
| 1665 | 1633 |
| 1666 // Argument 9: Pass current isolate address. | 1634 // Argument 9: Pass current isolate address. |
| 1667 __ LoadAddress(kScratchRegister, | 1635 __ LoadAddress(kScratchRegister, |
| 1668 ExternalReference::isolate_address(masm->isolate())); | 1636 ExternalReference::isolate_address(masm->isolate())); |
| 1669 __ movq(Operand(rsp, (argument_slots_on_stack - 1) * kPointerSize), | 1637 __ movq(Operand(rsp, (argument_slots_on_stack - 1) * kRegisterSize), |
| 1670 kScratchRegister); | 1638 kScratchRegister); |
| 1671 | 1639 |
| 1672 // Argument 8: Indicate that this is a direct call from JavaScript. | 1640 // Argument 8: Indicate that this is a direct call from JavaScript. |
| 1673 __ movq(Operand(rsp, (argument_slots_on_stack - 2) * kPointerSize), | 1641 __ movq(Operand(rsp, (argument_slots_on_stack - 2) * kRegisterSize), |
| 1674 Immediate(1)); | 1642 Immediate(1)); |
| 1675 | 1643 |
| 1676 // Argument 7: Start (high end) of backtracking stack memory area. | 1644 // Argument 7: Start (high end) of backtracking stack memory area. |
| 1677 __ Move(kScratchRegister, address_of_regexp_stack_memory_address); | 1645 __ Move(kScratchRegister, address_of_regexp_stack_memory_address); |
| 1678 __ movq(r9, Operand(kScratchRegister, 0)); | 1646 __ movp(r9, Operand(kScratchRegister, 0)); |
| 1679 __ Move(kScratchRegister, address_of_regexp_stack_memory_size); | 1647 __ Move(kScratchRegister, address_of_regexp_stack_memory_size); |
| 1680 __ addq(r9, Operand(kScratchRegister, 0)); | 1648 __ addq(r9, Operand(kScratchRegister, 0)); |
| 1681 __ movq(Operand(rsp, (argument_slots_on_stack - 3) * kPointerSize), r9); | 1649 __ movq(Operand(rsp, (argument_slots_on_stack - 3) * kRegisterSize), r9); |
| 1682 | 1650 |
| 1683 // Argument 6: Set the number of capture registers to zero to force global | 1651 // Argument 6: Set the number of capture registers to zero to force global |
| 1684 // regexps to behave as non-global. This does not affect non-global regexps. | 1652 // regexps to behave as non-global. This does not affect non-global regexps. |
| 1685 // Argument 6 is passed in r9 on Linux and on the stack on Windows. | 1653 // Argument 6 is passed in r9 on Linux and on the stack on Windows. |
| 1686 #ifdef _WIN64 | 1654 #ifdef _WIN64 |
| 1687 __ movq(Operand(rsp, (argument_slots_on_stack - 4) * kPointerSize), | 1655 __ movq(Operand(rsp, (argument_slots_on_stack - 4) * kRegisterSize), |
| 1688 Immediate(0)); | 1656 Immediate(0)); |
| 1689 #else | 1657 #else |
| 1690 __ Set(r9, 0); | 1658 __ Set(r9, 0); |
| 1691 #endif | 1659 #endif |
| 1692 | 1660 |
| 1693 // Argument 5: static offsets vector buffer. | 1661 // Argument 5: static offsets vector buffer. |
| 1694 __ LoadAddress(r8, | 1662 __ LoadAddress(r8, |
| 1695 ExternalReference::address_of_static_offsets_vector(isolate)); | 1663 ExternalReference::address_of_static_offsets_vector(isolate)); |
| 1696 // Argument 5 passed in r8 on Linux and on the stack on Windows. | 1664 // Argument 5 passed in r8 on Linux and on the stack on Windows. |
| 1697 #ifdef _WIN64 | 1665 #ifdef _WIN64 |
| 1698 __ movq(Operand(rsp, (argument_slots_on_stack - 5) * kPointerSize), r8); | 1666 __ movq(Operand(rsp, (argument_slots_on_stack - 5) * kRegisterSize), r8); |
| 1699 #endif | 1667 #endif |
| 1700 | 1668 |
| 1701 // rdi: subject string | 1669 // rdi: subject string |
| 1702 // rbx: previous index | 1670 // rbx: previous index |
| 1703 // rcx: encoding of subject string (1 if ASCII 0 if two_byte); | 1671 // rcx: encoding of subject string (1 if ASCII 0 if two_byte); |
| 1704 // r11: code | 1672 // r11: code |
| 1705 // r14: slice offset | 1673 // r14: slice offset |
| 1706 // r15: original subject string | 1674 // r15: original subject string |
| 1707 | 1675 |
| 1708 // Argument 2: Previous index. | 1676 // Argument 2: Previous index. |
| 1709 __ movq(arg_reg_2, rbx); | 1677 __ movp(arg_reg_2, rbx); |
| 1710 | 1678 |
| 1711 // Argument 4: End of string data | 1679 // Argument 4: End of string data |
| 1712 // Argument 3: Start of string data | 1680 // Argument 3: Start of string data |
| 1713 Label setup_two_byte, setup_rest, got_length, length_not_from_slice; | 1681 Label setup_two_byte, setup_rest, got_length, length_not_from_slice; |
| 1714 // Prepare start and end index of the input. | 1682 // Prepare start and end index of the input. |
| 1715 // Load the length from the original sliced string if that is the case. | 1683 // Load the length from the original sliced string if that is the case. |
| 1716 __ addq(rbx, r14); | 1684 __ addq(rbx, r14); |
| 1717 __ SmiToInteger32(arg_reg_3, FieldOperand(r15, String::kLengthOffset)); | 1685 __ SmiToInteger32(arg_reg_3, FieldOperand(r15, String::kLengthOffset)); |
| 1718 __ addq(r14, arg_reg_3); // Using arg3 as scratch. | 1686 __ addq(r14, arg_reg_3); // Using arg3 as scratch. |
| 1719 | 1687 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1732 FieldOperand(rdi, r14, times_2, SeqTwoByteString::kHeaderSize)); | 1700 FieldOperand(rdi, r14, times_2, SeqTwoByteString::kHeaderSize)); |
| 1733 __ lea(arg_reg_3, | 1701 __ lea(arg_reg_3, |
| 1734 FieldOperand(rdi, rbx, times_2, SeqTwoByteString::kHeaderSize)); | 1702 FieldOperand(rdi, rbx, times_2, SeqTwoByteString::kHeaderSize)); |
| 1735 __ bind(&setup_rest); | 1703 __ bind(&setup_rest); |
| 1736 | 1704 |
| 1737 // Argument 1: Original subject string. | 1705 // Argument 1: Original subject string. |
| 1738 // The original subject is in the previous stack frame. Therefore we have to | 1706 // The original subject is in the previous stack frame. Therefore we have to |
| 1739 // use rbp, which points exactly to one pointer size below the previous rsp. | 1707 // use rbp, which points exactly to one pointer size below the previous rsp. |
| 1740 // (Because creating a new stack frame pushes the previous rbp onto the stack | 1708 // (Because creating a new stack frame pushes the previous rbp onto the stack |
| 1741 // and thereby moves up rsp by one kPointerSize.) | 1709 // and thereby moves up rsp by one kPointerSize.) |
| 1742 __ movq(arg_reg_1, r15); | 1710 __ movp(arg_reg_1, r15); |
| 1743 | 1711 |
| 1744 // Locate the code entry and call it. | 1712 // Locate the code entry and call it. |
| 1745 __ addq(r11, Immediate(Code::kHeaderSize - kHeapObjectTag)); | 1713 __ addq(r11, Immediate(Code::kHeaderSize - kHeapObjectTag)); |
| 1746 __ call(r11); | 1714 __ call(r11); |
| 1747 | 1715 |
| 1748 __ LeaveApiExitFrame(true); | 1716 __ LeaveApiExitFrame(true); |
| 1749 | 1717 |
| 1750 // Check the result. | 1718 // Check the result. |
| 1751 Label success; | 1719 Label success; |
| 1752 Label exception; | 1720 Label exception; |
| 1753 __ cmpl(rax, Immediate(1)); | 1721 __ cmpl(rax, Immediate(1)); |
| 1754 // We expect exactly one result since we force the called regexp to behave | 1722 // We expect exactly one result since we force the called regexp to behave |
| 1755 // as non-global. | 1723 // as non-global. |
| 1756 __ j(equal, &success, Label::kNear); | 1724 __ j(equal, &success, Label::kNear); |
| 1757 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::EXCEPTION)); | 1725 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::EXCEPTION)); |
| 1758 __ j(equal, &exception); | 1726 __ j(equal, &exception); |
| 1759 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::FAILURE)); | 1727 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::FAILURE)); |
| 1760 // If none of the above, it can only be retry. | 1728 // If none of the above, it can only be retry. |
| 1761 // Handle that in the runtime system. | 1729 // Handle that in the runtime system. |
| 1762 __ j(not_equal, &runtime); | 1730 __ j(not_equal, &runtime); |
| 1763 | 1731 |
| 1764 // For failure return null. | 1732 // For failure return null. |
| 1765 __ LoadRoot(rax, Heap::kNullValueRootIndex); | 1733 __ LoadRoot(rax, Heap::kNullValueRootIndex); |
| 1766 __ ret(REG_EXP_EXEC_ARGUMENT_COUNT * kPointerSize); | 1734 __ ret(REG_EXP_EXEC_ARGUMENT_COUNT * kPointerSize); |
| 1767 | 1735 |
| 1768 // Load RegExp data. | 1736 // Load RegExp data. |
| 1769 __ bind(&success); | 1737 __ bind(&success); |
| 1770 __ movq(rax, args.GetArgumentOperand(JS_REG_EXP_OBJECT_ARGUMENT_INDEX)); | 1738 __ movp(rax, args.GetArgumentOperand(JS_REG_EXP_OBJECT_ARGUMENT_INDEX)); |
| 1771 __ movq(rcx, FieldOperand(rax, JSRegExp::kDataOffset)); | 1739 __ movp(rcx, FieldOperand(rax, JSRegExp::kDataOffset)); |
| 1772 __ SmiToInteger32(rax, | 1740 __ SmiToInteger32(rax, |
| 1773 FieldOperand(rcx, JSRegExp::kIrregexpCaptureCountOffset)); | 1741 FieldOperand(rcx, JSRegExp::kIrregexpCaptureCountOffset)); |
| 1774 // Calculate number of capture registers (number_of_captures + 1) * 2. | 1742 // Calculate number of capture registers (number_of_captures + 1) * 2. |
| 1775 __ leal(rdx, Operand(rax, rax, times_1, 2)); | 1743 __ leal(rdx, Operand(rax, rax, times_1, 2)); |
| 1776 | 1744 |
| 1777 // rdx: Number of capture registers | 1745 // rdx: Number of capture registers |
| 1778 // Check that the fourth object is a JSArray object. | 1746 // Check that the fourth object is a JSArray object. |
| 1779 __ movq(r15, args.GetArgumentOperand(LAST_MATCH_INFO_ARGUMENT_INDEX)); | 1747 __ movp(r15, args.GetArgumentOperand(LAST_MATCH_INFO_ARGUMENT_INDEX)); |
| 1780 __ JumpIfSmi(r15, &runtime); | 1748 __ JumpIfSmi(r15, &runtime); |
| 1781 __ CmpObjectType(r15, JS_ARRAY_TYPE, kScratchRegister); | 1749 __ CmpObjectType(r15, JS_ARRAY_TYPE, kScratchRegister); |
| 1782 __ j(not_equal, &runtime); | 1750 __ j(not_equal, &runtime); |
| 1783 // Check that the JSArray is in fast case. | 1751 // Check that the JSArray is in fast case. |
| 1784 __ movq(rbx, FieldOperand(r15, JSArray::kElementsOffset)); | 1752 __ movp(rbx, FieldOperand(r15, JSArray::kElementsOffset)); |
| 1785 __ movq(rax, FieldOperand(rbx, HeapObject::kMapOffset)); | 1753 __ movp(rax, FieldOperand(rbx, HeapObject::kMapOffset)); |
| 1786 __ CompareRoot(rax, Heap::kFixedArrayMapRootIndex); | 1754 __ CompareRoot(rax, Heap::kFixedArrayMapRootIndex); |
| 1787 __ j(not_equal, &runtime); | 1755 __ j(not_equal, &runtime); |
| 1788 // Check that the last match info has space for the capture registers and the | 1756 // Check that the last match info has space for the capture registers and the |
| 1789 // additional information. Ensure no overflow in add. | 1757 // additional information. Ensure no overflow in add. |
| 1790 STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset); | 1758 STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset); |
| 1791 __ SmiToInteger32(rax, FieldOperand(rbx, FixedArray::kLengthOffset)); | 1759 __ SmiToInteger32(rax, FieldOperand(rbx, FixedArray::kLengthOffset)); |
| 1792 __ subl(rax, Immediate(RegExpImpl::kLastMatchOverhead)); | 1760 __ subl(rax, Immediate(RegExpImpl::kLastMatchOverhead)); |
| 1793 __ cmpl(rdx, rax); | 1761 __ cmpl(rdx, rax); |
| 1794 __ j(greater, &runtime); | 1762 __ j(greater, &runtime); |
| 1795 | 1763 |
| 1796 // rbx: last_match_info backing store (FixedArray) | 1764 // rbx: last_match_info backing store (FixedArray) |
| 1797 // rdx: number of capture registers | 1765 // rdx: number of capture registers |
| 1798 // Store the capture count. | 1766 // Store the capture count. |
| 1799 __ Integer32ToSmi(kScratchRegister, rdx); | 1767 __ Integer32ToSmi(kScratchRegister, rdx); |
| 1800 __ movq(FieldOperand(rbx, RegExpImpl::kLastCaptureCountOffset), | 1768 __ movp(FieldOperand(rbx, RegExpImpl::kLastCaptureCountOffset), |
| 1801 kScratchRegister); | 1769 kScratchRegister); |
| 1802 // Store last subject and last input. | 1770 // Store last subject and last input. |
| 1803 __ movq(rax, args.GetArgumentOperand(SUBJECT_STRING_ARGUMENT_INDEX)); | 1771 __ movp(rax, args.GetArgumentOperand(SUBJECT_STRING_ARGUMENT_INDEX)); |
| 1804 __ movq(FieldOperand(rbx, RegExpImpl::kLastSubjectOffset), rax); | 1772 __ movp(FieldOperand(rbx, RegExpImpl::kLastSubjectOffset), rax); |
| 1805 __ movq(rcx, rax); | 1773 __ movp(rcx, rax); |
| 1806 __ RecordWriteField(rbx, | 1774 __ RecordWriteField(rbx, |
| 1807 RegExpImpl::kLastSubjectOffset, | 1775 RegExpImpl::kLastSubjectOffset, |
| 1808 rax, | 1776 rax, |
| 1809 rdi, | 1777 rdi, |
| 1810 kDontSaveFPRegs); | 1778 kDontSaveFPRegs); |
| 1811 __ movq(rax, rcx); | 1779 __ movp(rax, rcx); |
| 1812 __ movq(FieldOperand(rbx, RegExpImpl::kLastInputOffset), rax); | 1780 __ movp(FieldOperand(rbx, RegExpImpl::kLastInputOffset), rax); |
| 1813 __ RecordWriteField(rbx, | 1781 __ RecordWriteField(rbx, |
| 1814 RegExpImpl::kLastInputOffset, | 1782 RegExpImpl::kLastInputOffset, |
| 1815 rax, | 1783 rax, |
| 1816 rdi, | 1784 rdi, |
| 1817 kDontSaveFPRegs); | 1785 kDontSaveFPRegs); |
| 1818 | 1786 |
| 1819 // Get the static offsets vector filled by the native regexp code. | 1787 // Get the static offsets vector filled by the native regexp code. |
| 1820 __ LoadAddress(rcx, | 1788 __ LoadAddress(rcx, |
| 1821 ExternalReference::address_of_static_offsets_vector(isolate)); | 1789 ExternalReference::address_of_static_offsets_vector(isolate)); |
| 1822 | 1790 |
| 1823 // rbx: last_match_info backing store (FixedArray) | 1791 // rbx: last_match_info backing store (FixedArray) |
| 1824 // rcx: offsets vector | 1792 // rcx: offsets vector |
| 1825 // rdx: number of capture registers | 1793 // rdx: number of capture registers |
| 1826 Label next_capture, done; | 1794 Label next_capture, done; |
| 1827 // Capture register counter starts from number of capture registers and | 1795 // Capture register counter starts from number of capture registers and |
| 1828 // counts down until wraping after zero. | 1796 // counts down until wraping after zero. |
| 1829 __ bind(&next_capture); | 1797 __ bind(&next_capture); |
| 1830 __ subq(rdx, Immediate(1)); | 1798 __ subq(rdx, Immediate(1)); |
| 1831 __ j(negative, &done, Label::kNear); | 1799 __ j(negative, &done, Label::kNear); |
| 1832 // Read the value from the static offsets vector buffer and make it a smi. | 1800 // Read the value from the static offsets vector buffer and make it a smi. |
| 1833 __ movl(rdi, Operand(rcx, rdx, times_int_size, 0)); | 1801 __ movl(rdi, Operand(rcx, rdx, times_int_size, 0)); |
| 1834 __ Integer32ToSmi(rdi, rdi); | 1802 __ Integer32ToSmi(rdi, rdi); |
| 1835 // Store the smi value in the last match info. | 1803 // Store the smi value in the last match info. |
| 1836 __ movq(FieldOperand(rbx, | 1804 __ movp(FieldOperand(rbx, |
| 1837 rdx, | 1805 rdx, |
| 1838 times_pointer_size, | 1806 times_pointer_size, |
| 1839 RegExpImpl::kFirstCaptureOffset), | 1807 RegExpImpl::kFirstCaptureOffset), |
| 1840 rdi); | 1808 rdi); |
| 1841 __ jmp(&next_capture); | 1809 __ jmp(&next_capture); |
| 1842 __ bind(&done); | 1810 __ bind(&done); |
| 1843 | 1811 |
| 1844 // Return last match info. | 1812 // Return last match info. |
| 1845 __ movq(rax, r15); | 1813 __ movp(rax, r15); |
| 1846 __ ret(REG_EXP_EXEC_ARGUMENT_COUNT * kPointerSize); | 1814 __ ret(REG_EXP_EXEC_ARGUMENT_COUNT * kPointerSize); |
| 1847 | 1815 |
| 1848 __ bind(&exception); | 1816 __ bind(&exception); |
| 1849 // Result must now be exception. If there is no pending exception already a | 1817 // Result must now be exception. If there is no pending exception already a |
| 1850 // stack overflow (on the backtrack stack) was detected in RegExp code but | 1818 // stack overflow (on the backtrack stack) was detected in RegExp code but |
| 1851 // haven't created the exception yet. Handle that in the runtime system. | 1819 // haven't created the exception yet. Handle that in the runtime system. |
| 1852 // TODO(592): Rerunning the RegExp to get the stack overflow exception. | 1820 // TODO(592): Rerunning the RegExp to get the stack overflow exception. |
| 1853 ExternalReference pending_exception_address( | 1821 ExternalReference pending_exception_address( |
| 1854 Isolate::kPendingExceptionAddress, isolate); | 1822 Isolate::kPendingExceptionAddress, isolate); |
| 1855 Operand pending_exception_operand = | 1823 Operand pending_exception_operand = |
| 1856 masm->ExternalOperand(pending_exception_address, rbx); | 1824 masm->ExternalOperand(pending_exception_address, rbx); |
| 1857 __ movq(rax, pending_exception_operand); | 1825 __ movp(rax, pending_exception_operand); |
| 1858 __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex); | 1826 __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex); |
| 1859 __ cmpq(rax, rdx); | 1827 __ cmpq(rax, rdx); |
| 1860 __ j(equal, &runtime); | 1828 __ j(equal, &runtime); |
| 1861 __ movq(pending_exception_operand, rdx); | 1829 __ movp(pending_exception_operand, rdx); |
| 1862 | 1830 |
| 1863 __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex); | 1831 __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex); |
| 1864 Label termination_exception; | 1832 Label termination_exception; |
| 1865 __ j(equal, &termination_exception, Label::kNear); | 1833 __ j(equal, &termination_exception, Label::kNear); |
| 1866 __ Throw(rax); | 1834 __ Throw(rax); |
| 1867 | 1835 |
| 1868 __ bind(&termination_exception); | 1836 __ bind(&termination_exception); |
| 1869 __ ThrowUncatchable(rax); | 1837 __ ThrowUncatchable(rax); |
| 1870 | 1838 |
| 1871 // Do the runtime call to execute the regexp. | 1839 // Do the runtime call to execute the regexp. |
| 1872 __ bind(&runtime); | 1840 __ bind(&runtime); |
| 1873 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); | 1841 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); |
| 1874 | 1842 |
| 1875 // Deferred code for string handling. | 1843 // Deferred code for string handling. |
| 1876 // (7) Not a long external string? If yes, go to (10). | 1844 // (7) Not a long external string? If yes, go to (10). |
| 1877 __ bind(¬_seq_nor_cons); | 1845 __ bind(¬_seq_nor_cons); |
| 1878 // Compare flags are still set from (3). | 1846 // Compare flags are still set from (3). |
| 1879 __ j(greater, ¬_long_external, Label::kNear); // Go to (10). | 1847 __ j(greater, ¬_long_external, Label::kNear); // Go to (10). |
| 1880 | 1848 |
| 1881 // (8) External string. Short external strings have been ruled out. | 1849 // (8) External string. Short external strings have been ruled out. |
| 1882 __ bind(&external_string); | 1850 __ bind(&external_string); |
| 1883 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); | 1851 __ movp(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); |
| 1884 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | 1852 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
| 1885 if (FLAG_debug_code) { | 1853 if (FLAG_debug_code) { |
| 1886 // Assert that we do not have a cons or slice (indirect strings) here. | 1854 // Assert that we do not have a cons or slice (indirect strings) here. |
| 1887 // Sequential strings have already been ruled out. | 1855 // Sequential strings have already been ruled out. |
| 1888 __ testb(rbx, Immediate(kIsIndirectStringMask)); | 1856 __ testb(rbx, Immediate(kIsIndirectStringMask)); |
| 1889 __ Assert(zero, kExternalStringExpectedButNotFound); | 1857 __ Assert(zero, kExternalStringExpectedButNotFound); |
| 1890 } | 1858 } |
| 1891 __ movq(rdi, FieldOperand(rdi, ExternalString::kResourceDataOffset)); | 1859 __ movp(rdi, FieldOperand(rdi, ExternalString::kResourceDataOffset)); |
| 1892 // Move the pointer so that offset-wise, it looks like a sequential string. | 1860 // Move the pointer so that offset-wise, it looks like a sequential string. |
| 1893 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); | 1861 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); |
| 1894 __ subq(rdi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 1862 __ subq(rdi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| 1895 STATIC_ASSERT(kTwoByteStringTag == 0); | 1863 STATIC_ASSERT(kTwoByteStringTag == 0); |
| 1896 // (8a) Is the external string one byte? If yes, go to (6). | 1864 // (8a) Is the external string one byte? If yes, go to (6). |
| 1897 __ testb(rbx, Immediate(kStringEncodingMask)); | 1865 __ testb(rbx, Immediate(kStringEncodingMask)); |
| 1898 __ j(not_zero, &seq_one_byte_string); // Goto (6). | 1866 __ j(not_zero, &seq_one_byte_string); // Goto (6). |
| 1899 | 1867 |
| 1900 // rdi: subject string (flat two-byte) | 1868 // rdi: subject string (flat two-byte) |
| 1901 // rax: RegExp data (FixedArray) | 1869 // rax: RegExp data (FixedArray) |
| 1902 // (9) Two byte sequential. Load regexp code for one byte. Go to (E). | 1870 // (9) Two byte sequential. Load regexp code for one byte. Go to (E). |
| 1903 __ bind(&seq_two_byte_string); | 1871 __ bind(&seq_two_byte_string); |
| 1904 __ movq(r11, FieldOperand(rax, JSRegExp::kDataUC16CodeOffset)); | 1872 __ movp(r11, FieldOperand(rax, JSRegExp::kDataUC16CodeOffset)); |
| 1905 __ Set(rcx, 0); // Type is two byte. | 1873 __ Set(rcx, 0); // Type is two byte. |
| 1906 __ jmp(&check_code); // Go to (E). | 1874 __ jmp(&check_code); // Go to (E). |
| 1907 | 1875 |
| 1908 // (10) Not a string or a short external string? If yes, bail out to runtime. | 1876 // (10) Not a string or a short external string? If yes, bail out to runtime. |
| 1909 __ bind(¬_long_external); | 1877 __ bind(¬_long_external); |
| 1910 // Catch non-string subject or short external string. | 1878 // Catch non-string subject or short external string. |
| 1911 STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0); | 1879 STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0); |
| 1912 __ testb(rbx, Immediate(kIsNotStringMask | kShortExternalStringMask)); | 1880 __ testb(rbx, Immediate(kIsNotStringMask | kShortExternalStringMask)); |
| 1913 __ j(not_zero, &runtime); | 1881 __ j(not_zero, &runtime); |
| 1914 | 1882 |
| 1915 // (11) Sliced string. Replace subject with parent. Go to (5a). | 1883 // (11) Sliced string. Replace subject with parent. Go to (5a). |
| 1916 // Load offset into r14 and replace subject string with parent. | 1884 // Load offset into r14 and replace subject string with parent. |
| 1917 __ SmiToInteger32(r14, FieldOperand(rdi, SlicedString::kOffsetOffset)); | 1885 __ SmiToInteger32(r14, FieldOperand(rdi, SlicedString::kOffsetOffset)); |
| 1918 __ movq(rdi, FieldOperand(rdi, SlicedString::kParentOffset)); | 1886 __ movp(rdi, FieldOperand(rdi, SlicedString::kParentOffset)); |
| 1919 __ jmp(&check_underlying); | 1887 __ jmp(&check_underlying); |
| 1920 #endif // V8_INTERPRETED_REGEXP | 1888 #endif // V8_INTERPRETED_REGEXP |
| 1921 } | 1889 } |
| 1922 | 1890 |
| 1923 | 1891 |
| 1924 void RegExpConstructResultStub::Generate(MacroAssembler* masm) { | 1892 void RegExpConstructResultStub::Generate(MacroAssembler* masm) { |
| 1925 const int kMaxInlineLength = 100; | 1893 const int kMaxInlineLength = 100; |
| 1926 Label slowcase; | 1894 Label slowcase; |
| 1927 Label done; | 1895 Label done; |
| 1928 StackArgumentsAccessor args(rsp, 3, ARGUMENTS_DONT_CONTAIN_RECEIVER); | 1896 StackArgumentsAccessor args(rsp, 3, ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 1929 __ movq(r8, args.GetArgumentOperand(0)); | 1897 __ movp(r8, args.GetArgumentOperand(0)); |
| 1930 __ JumpIfNotSmi(r8, &slowcase); | 1898 __ JumpIfNotSmi(r8, &slowcase); |
| 1931 __ SmiToInteger32(rbx, r8); | 1899 __ SmiToInteger32(rbx, r8); |
| 1932 __ cmpl(rbx, Immediate(kMaxInlineLength)); | 1900 __ cmpl(rbx, Immediate(kMaxInlineLength)); |
| 1933 __ j(above, &slowcase); | 1901 __ j(above, &slowcase); |
| 1934 // Smi-tagging is equivalent to multiplying by 2. | 1902 // Smi-tagging is equivalent to multiplying by 2. |
| 1935 STATIC_ASSERT(kSmiTag == 0); | 1903 STATIC_ASSERT(kSmiTag == 0); |
| 1936 STATIC_ASSERT(kSmiTagSize == 1); | 1904 STATIC_ASSERT(kSmiTagSize == 1); |
| 1937 // Allocate RegExpResult followed by FixedArray with size in rbx. | 1905 // Allocate RegExpResult followed by FixedArray with size in rbx. |
| 1938 // JSArray: [Map][empty properties][Elements][Length-smi][index][input] | 1906 // JSArray: [Map][empty properties][Elements][Length-smi][index][input] |
| 1939 // Elements: [Map][Length][..elements..] | 1907 // Elements: [Map][Length][..elements..] |
| 1940 __ Allocate(JSRegExpResult::kSize + FixedArray::kHeaderSize, | 1908 __ Allocate(JSRegExpResult::kSize + FixedArray::kHeaderSize, |
| 1941 times_pointer_size, | 1909 times_pointer_size, |
| 1942 rbx, // In: Number of elements. | 1910 rbx, // In: Number of elements. |
| 1943 rax, // Out: Start of allocation (tagged). | 1911 rax, // Out: Start of allocation (tagged). |
| 1944 rcx, // Out: End of allocation. | 1912 rcx, // Out: End of allocation. |
| 1945 rdx, // Scratch register | 1913 rdx, // Scratch register |
| 1946 &slowcase, | 1914 &slowcase, |
| 1947 TAG_OBJECT); | 1915 TAG_OBJECT); |
| 1948 // rax: Start of allocated area, object-tagged. | 1916 // rax: Start of allocated area, object-tagged. |
| 1949 // rbx: Number of array elements as int32. | 1917 // rbx: Number of array elements as int32. |
| 1950 // r8: Number of array elements as smi. | 1918 // r8: Number of array elements as smi. |
| 1951 | 1919 |
| 1952 // Set JSArray map to global.regexp_result_map(). | 1920 // Set JSArray map to global.regexp_result_map(). |
| 1953 __ movq(rdx, ContextOperand(rsi, Context::GLOBAL_OBJECT_INDEX)); | 1921 __ movp(rdx, ContextOperand(rsi, Context::GLOBAL_OBJECT_INDEX)); |
| 1954 __ movq(rdx, FieldOperand(rdx, GlobalObject::kNativeContextOffset)); | 1922 __ movp(rdx, FieldOperand(rdx, GlobalObject::kNativeContextOffset)); |
| 1955 __ movq(rdx, ContextOperand(rdx, Context::REGEXP_RESULT_MAP_INDEX)); | 1923 __ movp(rdx, ContextOperand(rdx, Context::REGEXP_RESULT_MAP_INDEX)); |
| 1956 __ movq(FieldOperand(rax, HeapObject::kMapOffset), rdx); | 1924 __ movp(FieldOperand(rax, HeapObject::kMapOffset), rdx); |
| 1957 | 1925 |
| 1958 // Set empty properties FixedArray. | 1926 // Set empty properties FixedArray. |
| 1959 __ LoadRoot(kScratchRegister, Heap::kEmptyFixedArrayRootIndex); | 1927 __ LoadRoot(kScratchRegister, Heap::kEmptyFixedArrayRootIndex); |
| 1960 __ movq(FieldOperand(rax, JSObject::kPropertiesOffset), kScratchRegister); | 1928 __ movp(FieldOperand(rax, JSObject::kPropertiesOffset), kScratchRegister); |
| 1961 | 1929 |
| 1962 // Set elements to point to FixedArray allocated right after the JSArray. | 1930 // Set elements to point to FixedArray allocated right after the JSArray. |
| 1963 __ lea(rcx, Operand(rax, JSRegExpResult::kSize)); | 1931 __ lea(rcx, Operand(rax, JSRegExpResult::kSize)); |
| 1964 __ movq(FieldOperand(rax, JSObject::kElementsOffset), rcx); | 1932 __ movp(FieldOperand(rax, JSObject::kElementsOffset), rcx); |
| 1965 | 1933 |
| 1966 // Set input, index and length fields from arguments. | 1934 // Set input, index and length fields from arguments. |
| 1967 __ movq(r8, args.GetArgumentOperand(2)); | 1935 __ movp(r8, args.GetArgumentOperand(2)); |
| 1968 __ movq(FieldOperand(rax, JSRegExpResult::kInputOffset), r8); | 1936 __ movp(FieldOperand(rax, JSRegExpResult::kInputOffset), r8); |
| 1969 __ movq(r8, args.GetArgumentOperand(1)); | 1937 __ movp(r8, args.GetArgumentOperand(1)); |
| 1970 __ movq(FieldOperand(rax, JSRegExpResult::kIndexOffset), r8); | 1938 __ movp(FieldOperand(rax, JSRegExpResult::kIndexOffset), r8); |
| 1971 __ movq(r8, args.GetArgumentOperand(0)); | 1939 __ movp(r8, args.GetArgumentOperand(0)); |
| 1972 __ movq(FieldOperand(rax, JSArray::kLengthOffset), r8); | 1940 __ movp(FieldOperand(rax, JSArray::kLengthOffset), r8); |
| 1973 | 1941 |
| 1974 // Fill out the elements FixedArray. | 1942 // Fill out the elements FixedArray. |
| 1975 // rax: JSArray. | 1943 // rax: JSArray. |
| 1976 // rcx: FixedArray. | 1944 // rcx: FixedArray. |
| 1977 // rbx: Number of elements in array as int32. | 1945 // rbx: Number of elements in array as int32. |
| 1978 | 1946 |
| 1979 // Set map. | 1947 // Set map. |
| 1980 __ LoadRoot(kScratchRegister, Heap::kFixedArrayMapRootIndex); | 1948 __ LoadRoot(kScratchRegister, Heap::kFixedArrayMapRootIndex); |
| 1981 __ movq(FieldOperand(rcx, HeapObject::kMapOffset), kScratchRegister); | 1949 __ movp(FieldOperand(rcx, HeapObject::kMapOffset), kScratchRegister); |
| 1982 // Set length. | 1950 // Set length. |
| 1983 __ Integer32ToSmi(rdx, rbx); | 1951 __ Integer32ToSmi(rdx, rbx); |
| 1984 __ movq(FieldOperand(rcx, FixedArray::kLengthOffset), rdx); | 1952 __ movp(FieldOperand(rcx, FixedArray::kLengthOffset), rdx); |
| 1985 // Fill contents of fixed-array with undefined. | 1953 // Fill contents of fixed-array with undefined. |
| 1986 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); | 1954 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); |
| 1987 __ lea(rcx, FieldOperand(rcx, FixedArray::kHeaderSize)); | 1955 __ lea(rcx, FieldOperand(rcx, FixedArray::kHeaderSize)); |
| 1988 // Fill fixed array elements with undefined. | 1956 // Fill fixed array elements with undefined. |
| 1989 // rax: JSArray. | 1957 // rax: JSArray. |
| 1990 // rbx: Number of elements in array that remains to be filled, as int32. | 1958 // rbx: Number of elements in array that remains to be filled, as int32. |
| 1991 // rcx: Start of elements in FixedArray. | 1959 // rcx: Start of elements in FixedArray. |
| 1992 // rdx: undefined. | 1960 // rdx: undefined. |
| 1993 Label loop; | 1961 Label loop; |
| 1994 __ testl(rbx, rbx); | 1962 __ testl(rbx, rbx); |
| 1995 __ bind(&loop); | 1963 __ bind(&loop); |
| 1996 __ j(less_equal, &done); // Jump if rcx is negative or zero. | 1964 __ j(less_equal, &done); // Jump if rcx is negative or zero. |
| 1997 __ subl(rbx, Immediate(1)); | 1965 __ subl(rbx, Immediate(1)); |
| 1998 __ movq(Operand(rcx, rbx, times_pointer_size, 0), rdx); | 1966 __ movp(Operand(rcx, rbx, times_pointer_size, 0), rdx); |
| 1999 __ jmp(&loop); | 1967 __ jmp(&loop); |
| 2000 | 1968 |
| 2001 __ bind(&done); | 1969 __ bind(&done); |
| 2002 __ ret(3 * kPointerSize); | 1970 __ ret(3 * kPointerSize); |
| 2003 | 1971 |
| 2004 __ bind(&slowcase); | 1972 __ bind(&slowcase); |
| 2005 __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1); | 1973 __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1); |
| 2006 } | 1974 } |
| 2007 | 1975 |
| 2008 | 1976 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 2030 // hydrogen doesn't care, the stub doesn't have to care either. | 1998 // hydrogen doesn't care, the stub doesn't have to care either. |
| 2031 __ bind(&ok); | 1999 __ bind(&ok); |
| 2032 } | 2000 } |
| 2033 | 2001 |
| 2034 | 2002 |
| 2035 static void BranchIfNotInternalizedString(MacroAssembler* masm, | 2003 static void BranchIfNotInternalizedString(MacroAssembler* masm, |
| 2036 Label* label, | 2004 Label* label, |
| 2037 Register object, | 2005 Register object, |
| 2038 Register scratch) { | 2006 Register scratch) { |
| 2039 __ JumpIfSmi(object, label); | 2007 __ JumpIfSmi(object, label); |
| 2040 __ movq(scratch, FieldOperand(object, HeapObject::kMapOffset)); | 2008 __ movp(scratch, FieldOperand(object, HeapObject::kMapOffset)); |
| 2041 __ movzxbq(scratch, | 2009 __ movzxbq(scratch, |
| 2042 FieldOperand(scratch, Map::kInstanceTypeOffset)); | 2010 FieldOperand(scratch, Map::kInstanceTypeOffset)); |
| 2043 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); | 2011 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); |
| 2044 __ testb(scratch, Immediate(kIsNotStringMask | kIsNotInternalizedMask)); | 2012 __ testb(scratch, Immediate(kIsNotStringMask | kIsNotInternalizedMask)); |
| 2045 __ j(not_zero, label); | 2013 __ j(not_zero, label); |
| 2046 } | 2014 } |
| 2047 | 2015 |
| 2048 | 2016 |
| 2049 void ICCompareStub::GenerateGeneric(MacroAssembler* masm) { | 2017 void ICCompareStub::GenerateGeneric(MacroAssembler* masm) { |
| 2050 Label check_unequal_objects, done; | 2018 Label check_unequal_objects, done; |
| 2051 Condition cc = GetCondition(); | 2019 Condition cc = GetCondition(); |
| 2052 Factory* factory = masm->isolate()->factory(); | 2020 Factory* factory = masm->isolate()->factory(); |
| 2053 | 2021 |
| 2054 Label miss; | 2022 Label miss; |
| 2055 CheckInputType(masm, rdx, left_, &miss); | 2023 CheckInputType(masm, rdx, left_, &miss); |
| 2056 CheckInputType(masm, rax, right_, &miss); | 2024 CheckInputType(masm, rax, right_, &miss); |
| 2057 | 2025 |
| 2058 // Compare two smis. | 2026 // Compare two smis. |
| 2059 Label non_smi, smi_done; | 2027 Label non_smi, smi_done; |
| 2060 __ JumpIfNotBothSmi(rax, rdx, &non_smi); | 2028 __ JumpIfNotBothSmi(rax, rdx, &non_smi); |
| 2061 __ subq(rdx, rax); | 2029 __ subq(rdx, rax); |
| 2062 __ j(no_overflow, &smi_done); | 2030 __ j(no_overflow, &smi_done); |
| 2063 __ not_(rdx); // Correct sign in case of overflow. rdx cannot be 0 here. | 2031 __ not_(rdx); // Correct sign in case of overflow. rdx cannot be 0 here. |
| 2064 __ bind(&smi_done); | 2032 __ bind(&smi_done); |
| 2065 __ movq(rax, rdx); | 2033 __ movp(rax, rdx); |
| 2066 __ ret(0); | 2034 __ ret(0); |
| 2067 __ bind(&non_smi); | 2035 __ bind(&non_smi); |
| 2068 | 2036 |
| 2069 // The compare stub returns a positive, negative, or zero 64-bit integer | 2037 // The compare stub returns a positive, negative, or zero 64-bit integer |
| 2070 // value in rax, corresponding to result of comparing the two inputs. | 2038 // value in rax, corresponding to result of comparing the two inputs. |
| 2071 // NOTICE! This code is only reached after a smi-fast-case check, so | 2039 // NOTICE! This code is only reached after a smi-fast-case check, so |
| 2072 // it is certain that at least one operand isn't a smi. | 2040 // it is certain that at least one operand isn't a smi. |
| 2073 | 2041 |
| 2074 // Two identical objects are equal unless they are both NaN or undefined. | 2042 // Two identical objects are equal unless they are both NaN or undefined. |
| 2075 { | 2043 { |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2134 { | 2102 { |
| 2135 Label not_smis; | 2103 Label not_smis; |
| 2136 __ SelectNonSmi(rbx, rax, rdx, ¬_smis); | 2104 __ SelectNonSmi(rbx, rax, rdx, ¬_smis); |
| 2137 | 2105 |
| 2138 // Check if the non-smi operand is a heap number. | 2106 // Check if the non-smi operand is a heap number. |
| 2139 __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset), | 2107 __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset), |
| 2140 factory->heap_number_map()); | 2108 factory->heap_number_map()); |
| 2141 // If heap number, handle it in the slow case. | 2109 // If heap number, handle it in the slow case. |
| 2142 __ j(equal, &slow); | 2110 __ j(equal, &slow); |
| 2143 // Return non-equal. ebx (the lower half of rbx) is not zero. | 2111 // Return non-equal. ebx (the lower half of rbx) is not zero. |
| 2144 __ movq(rax, rbx); | 2112 __ movp(rax, rbx); |
| 2145 __ ret(0); | 2113 __ ret(0); |
| 2146 | 2114 |
| 2147 __ bind(¬_smis); | 2115 __ bind(¬_smis); |
| 2148 } | 2116 } |
| 2149 | 2117 |
| 2150 // If either operand is a JSObject or an oddball value, then they are not | 2118 // If either operand is a JSObject or an oddball value, then they are not |
| 2151 // equal since their pointers are different | 2119 // equal since their pointers are different |
| 2152 // There is no test for undetectability in strict equality. | 2120 // There is no test for undetectability in strict equality. |
| 2153 | 2121 |
| 2154 // If the first object is a JS object, we have done pointer comparison. | 2122 // If the first object is a JS object, we have done pointer comparison. |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2312 // Cache the called function in a global property cell. Cache states | 2280 // Cache the called function in a global property cell. Cache states |
| 2313 // are uninitialized, monomorphic (indicated by a JSFunction), and | 2281 // are uninitialized, monomorphic (indicated by a JSFunction), and |
| 2314 // megamorphic. | 2282 // megamorphic. |
| 2315 // rax : number of arguments to the construct function | 2283 // rax : number of arguments to the construct function |
| 2316 // rbx : cache cell for call target | 2284 // rbx : cache cell for call target |
| 2317 // rdi : the function to call | 2285 // rdi : the function to call |
| 2318 Isolate* isolate = masm->isolate(); | 2286 Isolate* isolate = masm->isolate(); |
| 2319 Label initialize, done, miss, megamorphic, not_array_function; | 2287 Label initialize, done, miss, megamorphic, not_array_function; |
| 2320 | 2288 |
| 2321 // Load the cache state into rcx. | 2289 // Load the cache state into rcx. |
| 2322 __ movq(rcx, FieldOperand(rbx, Cell::kValueOffset)); | 2290 __ movp(rcx, FieldOperand(rbx, Cell::kValueOffset)); |
| 2323 | 2291 |
| 2324 // A monomorphic cache hit or an already megamorphic state: invoke the | 2292 // A monomorphic cache hit or an already megamorphic state: invoke the |
| 2325 // function without changing the state. | 2293 // function without changing the state. |
| 2326 __ cmpq(rcx, rdi); | 2294 __ cmpq(rcx, rdi); |
| 2327 __ j(equal, &done); | 2295 __ j(equal, &done); |
| 2328 __ Cmp(rcx, TypeFeedbackCells::MegamorphicSentinel(isolate)); | 2296 __ Cmp(rcx, TypeFeedbackCells::MegamorphicSentinel(isolate)); |
| 2329 __ j(equal, &done); | 2297 __ j(equal, &done); |
| 2330 | 2298 |
| 2331 // If we came here, we need to see if we are the array function. | 2299 // If we came here, we need to see if we are the array function. |
| 2332 // If we didn't have a matching function, and we didn't find the megamorph | 2300 // If we didn't have a matching function, and we didn't find the megamorph |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2379 __ CallStub(&create_stub); | 2347 __ CallStub(&create_stub); |
| 2380 | 2348 |
| 2381 __ pop(rbx); | 2349 __ pop(rbx); |
| 2382 __ pop(rdi); | 2350 __ pop(rdi); |
| 2383 __ pop(rax); | 2351 __ pop(rax); |
| 2384 __ SmiToInteger32(rax, rax); | 2352 __ SmiToInteger32(rax, rax); |
| 2385 } | 2353 } |
| 2386 __ jmp(&done); | 2354 __ jmp(&done); |
| 2387 | 2355 |
| 2388 __ bind(¬_array_function); | 2356 __ bind(¬_array_function); |
| 2389 __ movq(FieldOperand(rbx, Cell::kValueOffset), rdi); | 2357 __ movp(FieldOperand(rbx, Cell::kValueOffset), rdi); |
| 2390 // No need for a write barrier here - cells are rescanned. | 2358 // No need for a write barrier here - cells are rescanned. |
| 2391 | 2359 |
| 2392 __ bind(&done); | 2360 __ bind(&done); |
| 2393 } | 2361 } |
| 2394 | 2362 |
| 2395 | 2363 |
| 2396 void CallFunctionStub::Generate(MacroAssembler* masm) { | 2364 void CallFunctionStub::Generate(MacroAssembler* masm) { |
| 2397 // rbx : cache cell for call target | 2365 // rbx : cache cell for call target |
| 2398 // rdi : the function to call | 2366 // rdi : the function to call |
| 2399 Isolate* isolate = masm->isolate(); | 2367 Isolate* isolate = masm->isolate(); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2436 __ GetBuiltinEntry(rdx, Builtins::CALL_FUNCTION_PROXY); | 2404 __ GetBuiltinEntry(rdx, Builtins::CALL_FUNCTION_PROXY); |
| 2437 { | 2405 { |
| 2438 Handle<Code> adaptor = | 2406 Handle<Code> adaptor = |
| 2439 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(); | 2407 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(); |
| 2440 __ jmp(adaptor, RelocInfo::CODE_TARGET); | 2408 __ jmp(adaptor, RelocInfo::CODE_TARGET); |
| 2441 } | 2409 } |
| 2442 | 2410 |
| 2443 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead | 2411 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead |
| 2444 // of the original receiver from the call site). | 2412 // of the original receiver from the call site). |
| 2445 __ bind(&non_function); | 2413 __ bind(&non_function); |
| 2446 __ movq(args.GetReceiverOperand(), rdi); | 2414 __ movp(args.GetReceiverOperand(), rdi); |
| 2447 __ Set(rax, argc_); | 2415 __ Set(rax, argc_); |
| 2448 __ Set(rbx, 0); | 2416 __ Set(rbx, 0); |
| 2449 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION); | 2417 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION); |
| 2450 Handle<Code> adaptor = | 2418 Handle<Code> adaptor = |
| 2451 isolate->builtins()->ArgumentsAdaptorTrampoline(); | 2419 isolate->builtins()->ArgumentsAdaptorTrampoline(); |
| 2452 __ Jump(adaptor, RelocInfo::CODE_TARGET); | 2420 __ Jump(adaptor, RelocInfo::CODE_TARGET); |
| 2453 } | 2421 } |
| 2454 | 2422 |
| 2455 | 2423 |
| 2456 void CallConstructStub::Generate(MacroAssembler* masm) { | 2424 void CallConstructStub::Generate(MacroAssembler* masm) { |
| 2457 // rax : number of arguments | 2425 // rax : number of arguments |
| 2458 // rbx : cache cell for call target | 2426 // rbx : cache cell for call target |
| 2459 // rdi : constructor function | 2427 // rdi : constructor function |
| 2460 Label slow, non_function_call; | 2428 Label slow, non_function_call; |
| 2461 | 2429 |
| 2462 // Check that function is not a smi. | 2430 // Check that function is not a smi. |
| 2463 __ JumpIfSmi(rdi, &non_function_call); | 2431 __ JumpIfSmi(rdi, &non_function_call); |
| 2464 // Check that function is a JSFunction. | 2432 // Check that function is a JSFunction. |
| 2465 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); | 2433 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); |
| 2466 __ j(not_equal, &slow); | 2434 __ j(not_equal, &slow); |
| 2467 | 2435 |
| 2468 if (RecordCallTarget()) { | 2436 if (RecordCallTarget()) { |
| 2469 GenerateRecordCallTarget(masm); | 2437 GenerateRecordCallTarget(masm); |
| 2470 } | 2438 } |
| 2471 | 2439 |
| 2472 // Jump to the function-specific construct stub. | 2440 // Jump to the function-specific construct stub. |
| 2473 Register jmp_reg = rcx; | 2441 Register jmp_reg = rcx; |
| 2474 __ movq(jmp_reg, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); | 2442 __ movp(jmp_reg, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); |
| 2475 __ movq(jmp_reg, FieldOperand(jmp_reg, | 2443 __ movp(jmp_reg, FieldOperand(jmp_reg, |
| 2476 SharedFunctionInfo::kConstructStubOffset)); | 2444 SharedFunctionInfo::kConstructStubOffset)); |
| 2477 __ lea(jmp_reg, FieldOperand(jmp_reg, Code::kHeaderSize)); | 2445 __ lea(jmp_reg, FieldOperand(jmp_reg, Code::kHeaderSize)); |
| 2478 __ jmp(jmp_reg); | 2446 __ jmp(jmp_reg); |
| 2479 | 2447 |
| 2480 // rdi: called object | 2448 // rdi: called object |
| 2481 // rax: number of arguments | 2449 // rax: number of arguments |
| 2482 // rcx: object map | 2450 // rcx: object map |
| 2483 Label do_call; | 2451 Label do_call; |
| 2484 __ bind(&slow); | 2452 __ bind(&slow); |
| 2485 __ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE); | 2453 __ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2523 stub.GetCode(isolate); | 2491 stub.GetCode(isolate); |
| 2524 CEntryStub save_doubles(1, kSaveFPRegs); | 2492 CEntryStub save_doubles(1, kSaveFPRegs); |
| 2525 save_doubles.GetCode(isolate); | 2493 save_doubles.GetCode(isolate); |
| 2526 } | 2494 } |
| 2527 | 2495 |
| 2528 | 2496 |
| 2529 static void JumpIfOOM(MacroAssembler* masm, | 2497 static void JumpIfOOM(MacroAssembler* masm, |
| 2530 Register value, | 2498 Register value, |
| 2531 Register scratch, | 2499 Register scratch, |
| 2532 Label* oom_label) { | 2500 Label* oom_label) { |
| 2533 __ movq(scratch, value); | 2501 __ movp(scratch, value); |
| 2534 STATIC_ASSERT(Failure::OUT_OF_MEMORY_EXCEPTION == 3); | 2502 STATIC_ASSERT(Failure::OUT_OF_MEMORY_EXCEPTION == 3); |
| 2535 STATIC_ASSERT(kFailureTag == 3); | 2503 STATIC_ASSERT(kFailureTag == 3); |
| 2536 __ and_(scratch, Immediate(0xf)); | 2504 __ and_(scratch, Immediate(0xf)); |
| 2537 __ cmpq(scratch, Immediate(0xf)); | 2505 __ cmpq(scratch, Immediate(0xf)); |
| 2538 __ j(equal, oom_label); | 2506 __ j(equal, oom_label); |
| 2539 } | 2507 } |
| 2540 | 2508 |
| 2541 | 2509 |
| 2542 void CEntryStub::GenerateCore(MacroAssembler* masm, | 2510 void CEntryStub::GenerateCore(MacroAssembler* masm, |
| 2543 Label* throw_normal_exception, | 2511 Label* throw_normal_exception, |
| (...skipping 18 matching lines...) Expand all Loading... |
| 2562 if (FLAG_debug_code) { | 2530 if (FLAG_debug_code) { |
| 2563 __ CheckStackAlignment(); | 2531 __ CheckStackAlignment(); |
| 2564 } | 2532 } |
| 2565 | 2533 |
| 2566 if (do_gc) { | 2534 if (do_gc) { |
| 2567 // Pass failure code returned from last attempt as first argument to | 2535 // Pass failure code returned from last attempt as first argument to |
| 2568 // PerformGC. No need to use PrepareCallCFunction/CallCFunction here as the | 2536 // PerformGC. No need to use PrepareCallCFunction/CallCFunction here as the |
| 2569 // stack is known to be aligned. This function takes one argument which is | 2537 // stack is known to be aligned. This function takes one argument which is |
| 2570 // passed in register. | 2538 // passed in register. |
| 2571 __ Move(arg_reg_2, ExternalReference::isolate_address(masm->isolate())); | 2539 __ Move(arg_reg_2, ExternalReference::isolate_address(masm->isolate())); |
| 2572 __ movq(arg_reg_1, rax); | 2540 __ movp(arg_reg_1, rax); |
| 2573 __ Move(kScratchRegister, | 2541 __ Move(kScratchRegister, |
| 2574 ExternalReference::perform_gc_function(masm->isolate())); | 2542 ExternalReference::perform_gc_function(masm->isolate())); |
| 2575 __ call(kScratchRegister); | 2543 __ call(kScratchRegister); |
| 2576 } | 2544 } |
| 2577 | 2545 |
| 2578 ExternalReference scope_depth = | 2546 ExternalReference scope_depth = |
| 2579 ExternalReference::heap_always_allocate_scope_depth(masm->isolate()); | 2547 ExternalReference::heap_always_allocate_scope_depth(masm->isolate()); |
| 2580 if (always_allocate_scope) { | 2548 if (always_allocate_scope) { |
| 2581 Operand scope_depth_operand = masm->ExternalOperand(scope_depth); | 2549 Operand scope_depth_operand = masm->ExternalOperand(scope_depth); |
| 2582 __ incl(scope_depth_operand); | 2550 __ incl(scope_depth_operand); |
| 2583 } | 2551 } |
| 2584 | 2552 |
| 2585 // Call C function. | 2553 // Call C function. |
| 2586 #ifdef _WIN64 | 2554 #ifdef _WIN64 |
| 2587 // Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9. | 2555 // Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9. |
| 2588 // Pass argv and argc as two parameters. The arguments object will | 2556 // Pass argv and argc as two parameters. The arguments object will |
| 2589 // be created by stubs declared by DECLARE_RUNTIME_FUNCTION(). | 2557 // be created by stubs declared by DECLARE_RUNTIME_FUNCTION(). |
| 2590 if (result_size_ < 2) { | 2558 if (result_size_ < 2) { |
| 2591 // Pass a pointer to the Arguments object as the first argument. | 2559 // Pass a pointer to the Arguments object as the first argument. |
| 2592 // Return result in single register (rax). | 2560 // Return result in single register (rax). |
| 2593 __ movq(rcx, r14); // argc. | 2561 __ movp(rcx, r14); // argc. |
| 2594 __ movq(rdx, r15); // argv. | 2562 __ movp(rdx, r15); // argv. |
| 2595 __ Move(r8, ExternalReference::isolate_address(masm->isolate())); | 2563 __ Move(r8, ExternalReference::isolate_address(masm->isolate())); |
| 2596 } else { | 2564 } else { |
| 2597 ASSERT_EQ(2, result_size_); | 2565 ASSERT_EQ(2, result_size_); |
| 2598 // Pass a pointer to the result location as the first argument. | 2566 // Pass a pointer to the result location as the first argument. |
| 2599 __ lea(rcx, StackSpaceOperand(2)); | 2567 __ lea(rcx, StackSpaceOperand(2)); |
| 2600 // Pass a pointer to the Arguments object as the second argument. | 2568 // Pass a pointer to the Arguments object as the second argument. |
| 2601 __ movq(rdx, r14); // argc. | 2569 __ movp(rdx, r14); // argc. |
| 2602 __ movq(r8, r15); // argv. | 2570 __ movp(r8, r15); // argv. |
| 2603 __ Move(r9, ExternalReference::isolate_address(masm->isolate())); | 2571 __ Move(r9, ExternalReference::isolate_address(masm->isolate())); |
| 2604 } | 2572 } |
| 2605 | 2573 |
| 2606 #else // _WIN64 | 2574 #else // _WIN64 |
| 2607 // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9. | 2575 // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9. |
| 2608 __ movq(rdi, r14); // argc. | 2576 __ movp(rdi, r14); // argc. |
| 2609 __ movq(rsi, r15); // argv. | 2577 __ movp(rsi, r15); // argv. |
| 2610 __ Move(rdx, ExternalReference::isolate_address(masm->isolate())); | 2578 __ Move(rdx, ExternalReference::isolate_address(masm->isolate())); |
| 2611 #endif | 2579 #endif |
| 2612 __ call(rbx); | 2580 __ call(rbx); |
| 2613 // Result is in rax - do not destroy this register! | 2581 // Result is in rax - do not destroy this register! |
| 2614 | 2582 |
| 2615 if (always_allocate_scope) { | 2583 if (always_allocate_scope) { |
| 2616 Operand scope_depth_operand = masm->ExternalOperand(scope_depth); | 2584 Operand scope_depth_operand = masm->ExternalOperand(scope_depth); |
| 2617 __ decl(scope_depth_operand); | 2585 __ decl(scope_depth_operand); |
| 2618 } | 2586 } |
| 2619 | 2587 |
| 2620 // Check for failure result. | 2588 // Check for failure result. |
| 2621 Label failure_returned; | 2589 Label failure_returned; |
| 2622 STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0); | 2590 STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0); |
| 2623 #ifdef _WIN64 | 2591 #ifdef _WIN64 |
| 2624 // If return value is on the stack, pop it to registers. | 2592 // If return value is on the stack, pop it to registers. |
| 2625 if (result_size_ > 1) { | 2593 if (result_size_ > 1) { |
| 2626 ASSERT_EQ(2, result_size_); | 2594 ASSERT_EQ(2, result_size_); |
| 2627 // Read result values stored on stack. Result is stored | 2595 // Read result values stored on stack. Result is stored |
| 2628 // above the four argument mirror slots and the two | 2596 // above the four argument mirror slots and the two |
| 2629 // Arguments object slots. | 2597 // Arguments object slots. |
| 2630 __ movq(rax, Operand(rsp, 6 * kPointerSize)); | 2598 __ movq(rax, Operand(rsp, 6 * kRegisterSize)); |
| 2631 __ movq(rdx, Operand(rsp, 7 * kPointerSize)); | 2599 __ movq(rdx, Operand(rsp, 7 * kRegisterSize)); |
| 2632 } | 2600 } |
| 2633 #endif | 2601 #endif |
| 2634 __ lea(rcx, Operand(rax, 1)); | 2602 __ lea(rcx, Operand(rax, 1)); |
| 2635 // Lower 2 bits of rcx are 0 iff rax has failure tag. | 2603 // Lower 2 bits of rcx are 0 iff rax has failure tag. |
| 2636 __ testl(rcx, Immediate(kFailureTagMask)); | 2604 __ testl(rcx, Immediate(kFailureTagMask)); |
| 2637 __ j(zero, &failure_returned); | 2605 __ j(zero, &failure_returned); |
| 2638 | 2606 |
| 2639 // Exit the JavaScript to C++ exit frame. | 2607 // Exit the JavaScript to C++ exit frame. |
| 2640 __ LeaveExitFrame(save_doubles_); | 2608 __ LeaveExitFrame(save_doubles_); |
| 2641 __ ret(0); | 2609 __ ret(0); |
| 2642 | 2610 |
| 2643 // Handling of failure. | 2611 // Handling of failure. |
| 2644 __ bind(&failure_returned); | 2612 __ bind(&failure_returned); |
| 2645 | 2613 |
| 2646 Label retry; | 2614 Label retry; |
| 2647 // If the returned exception is RETRY_AFTER_GC continue at retry label | 2615 // If the returned exception is RETRY_AFTER_GC continue at retry label |
| 2648 STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0); | 2616 STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0); |
| 2649 __ testl(rax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); | 2617 __ testl(rax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); |
| 2650 __ j(zero, &retry, Label::kNear); | 2618 __ j(zero, &retry, Label::kNear); |
| 2651 | 2619 |
| 2652 // Special handling of out of memory exceptions. | 2620 // Special handling of out of memory exceptions. |
| 2653 JumpIfOOM(masm, rax, kScratchRegister, throw_out_of_memory_exception); | 2621 JumpIfOOM(masm, rax, kScratchRegister, throw_out_of_memory_exception); |
| 2654 | 2622 |
| 2655 // Retrieve the pending exception. | 2623 // Retrieve the pending exception. |
| 2656 ExternalReference pending_exception_address( | 2624 ExternalReference pending_exception_address( |
| 2657 Isolate::kPendingExceptionAddress, masm->isolate()); | 2625 Isolate::kPendingExceptionAddress, masm->isolate()); |
| 2658 Operand pending_exception_operand = | 2626 Operand pending_exception_operand = |
| 2659 masm->ExternalOperand(pending_exception_address); | 2627 masm->ExternalOperand(pending_exception_address); |
| 2660 __ movq(rax, pending_exception_operand); | 2628 __ movp(rax, pending_exception_operand); |
| 2661 | 2629 |
| 2662 // See if we just retrieved an OOM exception. | 2630 // See if we just retrieved an OOM exception. |
| 2663 JumpIfOOM(masm, rax, kScratchRegister, throw_out_of_memory_exception); | 2631 JumpIfOOM(masm, rax, kScratchRegister, throw_out_of_memory_exception); |
| 2664 | 2632 |
| 2665 // Clear the pending exception. | 2633 // Clear the pending exception. |
| 2666 pending_exception_operand = | 2634 pending_exception_operand = |
| 2667 masm->ExternalOperand(pending_exception_address); | 2635 masm->ExternalOperand(pending_exception_address); |
| 2668 __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex); | 2636 __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex); |
| 2669 __ movq(pending_exception_operand, rdx); | 2637 __ movp(pending_exception_operand, rdx); |
| 2670 | 2638 |
| 2671 // Special handling of termination exceptions which are uncatchable | 2639 // Special handling of termination exceptions which are uncatchable |
| 2672 // by javascript code. | 2640 // by javascript code. |
| 2673 __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex); | 2641 __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex); |
| 2674 __ j(equal, throw_termination_exception); | 2642 __ j(equal, throw_termination_exception); |
| 2675 | 2643 |
| 2676 // Handle normal exception. | 2644 // Handle normal exception. |
| 2677 __ jmp(throw_normal_exception); | 2645 __ jmp(throw_normal_exception); |
| 2678 | 2646 |
| 2679 // Retry. | 2647 // Retry. |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2774 void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { | 2742 void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { |
| 2775 Label invoke, handler_entry, exit; | 2743 Label invoke, handler_entry, exit; |
| 2776 Label not_outermost_js, not_outermost_js_2; | 2744 Label not_outermost_js, not_outermost_js_2; |
| 2777 | 2745 |
| 2778 ProfileEntryHookStub::MaybeCallEntryHook(masm); | 2746 ProfileEntryHookStub::MaybeCallEntryHook(masm); |
| 2779 | 2747 |
| 2780 { // NOLINT. Scope block confuses linter. | 2748 { // NOLINT. Scope block confuses linter. |
| 2781 MacroAssembler::NoRootArrayScope uninitialized_root_register(masm); | 2749 MacroAssembler::NoRootArrayScope uninitialized_root_register(masm); |
| 2782 // Set up frame. | 2750 // Set up frame. |
| 2783 __ push(rbp); | 2751 __ push(rbp); |
| 2784 __ movq(rbp, rsp); | 2752 __ movp(rbp, rsp); |
| 2785 | 2753 |
| 2786 // Push the stack frame type marker twice. | 2754 // Push the stack frame type marker twice. |
| 2787 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; | 2755 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; |
| 2788 // Scratch register is neither callee-save, nor an argument register on any | 2756 // Scratch register is neither callee-save, nor an argument register on any |
| 2789 // platform. It's free to use at this point. | 2757 // platform. It's free to use at this point. |
| 2790 // Cannot use smi-register for loading yet. | 2758 // Cannot use smi-register for loading yet. |
| 2791 __ Move(kScratchRegister, Smi::FromInt(marker), RelocInfo::NONE64); | 2759 __ Move(kScratchRegister, Smi::FromInt(marker), RelocInfo::NONE64); |
| 2792 __ push(kScratchRegister); // context slot | 2760 __ push(kScratchRegister); // context slot |
| 2793 __ push(kScratchRegister); // function slot | 2761 __ push(kScratchRegister); // function slot |
| 2794 // Save callee-saved registers (X64/Win64 calling conventions). | 2762 // Save callee-saved registers (X64/Win64 calling conventions). |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2831 Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp); | 2799 Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp); |
| 2832 __ push(c_entry_fp_operand); | 2800 __ push(c_entry_fp_operand); |
| 2833 } | 2801 } |
| 2834 | 2802 |
| 2835 // If this is the outermost JS call, set js_entry_sp value. | 2803 // If this is the outermost JS call, set js_entry_sp value. |
| 2836 ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, isolate); | 2804 ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, isolate); |
| 2837 __ Load(rax, js_entry_sp); | 2805 __ Load(rax, js_entry_sp); |
| 2838 __ testq(rax, rax); | 2806 __ testq(rax, rax); |
| 2839 __ j(not_zero, ¬_outermost_js); | 2807 __ j(not_zero, ¬_outermost_js); |
| 2840 __ Push(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)); | 2808 __ Push(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)); |
| 2841 __ movq(rax, rbp); | 2809 __ movp(rax, rbp); |
| 2842 __ Store(js_entry_sp, rax); | 2810 __ Store(js_entry_sp, rax); |
| 2843 Label cont; | 2811 Label cont; |
| 2844 __ jmp(&cont); | 2812 __ jmp(&cont); |
| 2845 __ bind(¬_outermost_js); | 2813 __ bind(¬_outermost_js); |
| 2846 __ Push(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME)); | 2814 __ Push(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME)); |
| 2847 __ bind(&cont); | 2815 __ bind(&cont); |
| 2848 | 2816 |
| 2849 // Jump to a faked try block that does the invoke, with a faked catch | 2817 // Jump to a faked try block that does the invoke, with a faked catch |
| 2850 // block that sets the pending exception. | 2818 // block that sets the pending exception. |
| 2851 __ jmp(&invoke); | 2819 __ jmp(&invoke); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2889 | 2857 |
| 2890 // Unlink this frame from the handler chain. | 2858 // Unlink this frame from the handler chain. |
| 2891 __ PopTryHandler(); | 2859 __ PopTryHandler(); |
| 2892 | 2860 |
| 2893 __ bind(&exit); | 2861 __ bind(&exit); |
| 2894 // Check if the current stack frame is marked as the outermost JS frame. | 2862 // Check if the current stack frame is marked as the outermost JS frame. |
| 2895 __ pop(rbx); | 2863 __ pop(rbx); |
| 2896 __ Cmp(rbx, Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)); | 2864 __ Cmp(rbx, Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)); |
| 2897 __ j(not_equal, ¬_outermost_js_2); | 2865 __ j(not_equal, ¬_outermost_js_2); |
| 2898 __ Move(kScratchRegister, js_entry_sp); | 2866 __ Move(kScratchRegister, js_entry_sp); |
| 2899 __ movq(Operand(kScratchRegister, 0), Immediate(0)); | 2867 __ movp(Operand(kScratchRegister, 0), Immediate(0)); |
| 2900 __ bind(¬_outermost_js_2); | 2868 __ bind(¬_outermost_js_2); |
| 2901 | 2869 |
| 2902 // Restore the top frame descriptor from the stack. | 2870 // Restore the top frame descriptor from the stack. |
| 2903 { Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp); | 2871 { Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp); |
| 2904 __ pop(c_entry_fp_operand); | 2872 __ pop(c_entry_fp_operand); |
| 2905 } | 2873 } |
| 2906 | 2874 |
| 2907 // Restore callee-saved registers (X64 conventions). | 2875 // Restore callee-saved registers (X64 conventions). |
| 2908 #ifdef _WIN64 | 2876 #ifdef _WIN64 |
| 2909 // On Win64 XMM6-XMM15 are callee-save | 2877 // On Win64 XMM6-XMM15 are callee-save |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2966 // before the offset of the hole value in the root array. | 2934 // before the offset of the hole value in the root array. |
| 2967 static const unsigned int kWordBeforeResultValue = 0x458B4906; | 2935 static const unsigned int kWordBeforeResultValue = 0x458B4906; |
| 2968 // Only the inline check flag is supported on X64. | 2936 // Only the inline check flag is supported on X64. |
| 2969 ASSERT(flags_ == kNoFlags || HasCallSiteInlineCheck()); | 2937 ASSERT(flags_ == kNoFlags || HasCallSiteInlineCheck()); |
| 2970 int extra_argument_offset = HasCallSiteInlineCheck() ? 1 : 0; | 2938 int extra_argument_offset = HasCallSiteInlineCheck() ? 1 : 0; |
| 2971 | 2939 |
| 2972 // Get the object - go slow case if it's a smi. | 2940 // Get the object - go slow case if it's a smi. |
| 2973 Label slow; | 2941 Label slow; |
| 2974 StackArgumentsAccessor args(rsp, 2 + extra_argument_offset, | 2942 StackArgumentsAccessor args(rsp, 2 + extra_argument_offset, |
| 2975 ARGUMENTS_DONT_CONTAIN_RECEIVER); | 2943 ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 2976 __ movq(rax, args.GetArgumentOperand(0)); | 2944 __ movp(rax, args.GetArgumentOperand(0)); |
| 2977 __ JumpIfSmi(rax, &slow); | 2945 __ JumpIfSmi(rax, &slow); |
| 2978 | 2946 |
| 2979 // Check that the left hand is a JS object. Leave its map in rax. | 2947 // Check that the left hand is a JS object. Leave its map in rax. |
| 2980 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rax); | 2948 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rax); |
| 2981 __ j(below, &slow); | 2949 __ j(below, &slow); |
| 2982 __ CmpInstanceType(rax, LAST_SPEC_OBJECT_TYPE); | 2950 __ CmpInstanceType(rax, LAST_SPEC_OBJECT_TYPE); |
| 2983 __ j(above, &slow); | 2951 __ j(above, &slow); |
| 2984 | 2952 |
| 2985 // Get the prototype of the function. | 2953 // Get the prototype of the function. |
| 2986 __ movq(rdx, args.GetArgumentOperand(1)); | 2954 __ movp(rdx, args.GetArgumentOperand(1)); |
| 2987 // rdx is function, rax is map. | 2955 // rdx is function, rax is map. |
| 2988 | 2956 |
| 2989 // If there is a call site cache don't look in the global cache, but do the | 2957 // If there is a call site cache don't look in the global cache, but do the |
| 2990 // real lookup and update the call site cache. | 2958 // real lookup and update the call site cache. |
| 2991 if (!HasCallSiteInlineCheck()) { | 2959 if (!HasCallSiteInlineCheck()) { |
| 2992 // Look up the function and the map in the instanceof cache. | 2960 // Look up the function and the map in the instanceof cache. |
| 2993 Label miss; | 2961 Label miss; |
| 2994 __ CompareRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); | 2962 __ CompareRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); |
| 2995 __ j(not_equal, &miss, Label::kNear); | 2963 __ j(not_equal, &miss, Label::kNear); |
| 2996 __ CompareRoot(rax, Heap::kInstanceofCacheMapRootIndex); | 2964 __ CompareRoot(rax, Heap::kInstanceofCacheMapRootIndex); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3011 | 2979 |
| 3012 // Register mapping: | 2980 // Register mapping: |
| 3013 // rax is object map. | 2981 // rax is object map. |
| 3014 // rdx is function. | 2982 // rdx is function. |
| 3015 // rbx is function prototype. | 2983 // rbx is function prototype. |
| 3016 if (!HasCallSiteInlineCheck()) { | 2984 if (!HasCallSiteInlineCheck()) { |
| 3017 __ StoreRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); | 2985 __ StoreRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); |
| 3018 __ StoreRoot(rax, Heap::kInstanceofCacheMapRootIndex); | 2986 __ StoreRoot(rax, Heap::kInstanceofCacheMapRootIndex); |
| 3019 } else { | 2987 } else { |
| 3020 // Get return address and delta to inlined map check. | 2988 // Get return address and delta to inlined map check. |
| 3021 __ movq(kScratchRegister, StackOperandForReturnAddress(0)); | 2989 __ movp(kScratchRegister, StackOperandForReturnAddress(0)); |
| 3022 __ subq(kScratchRegister, args.GetArgumentOperand(2)); | 2990 __ subq(kScratchRegister, args.GetArgumentOperand(2)); |
| 3023 if (FLAG_debug_code) { | 2991 if (FLAG_debug_code) { |
| 3024 __ movl(rdi, Immediate(kWordBeforeMapCheckValue)); | 2992 __ movl(rdi, Immediate(kWordBeforeMapCheckValue)); |
| 3025 __ cmpl(Operand(kScratchRegister, kOffsetToMapCheckValue - 4), rdi); | 2993 __ cmpl(Operand(kScratchRegister, kOffsetToMapCheckValue - 4), rdi); |
| 3026 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheCheck); | 2994 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheCheck); |
| 3027 } | 2995 } |
| 3028 __ movq(kScratchRegister, | 2996 __ movp(kScratchRegister, |
| 3029 Operand(kScratchRegister, kOffsetToMapCheckValue)); | 2997 Operand(kScratchRegister, kOffsetToMapCheckValue)); |
| 3030 __ movq(Operand(kScratchRegister, 0), rax); | 2998 __ movp(Operand(kScratchRegister, 0), rax); |
| 3031 } | 2999 } |
| 3032 | 3000 |
| 3033 __ movq(rcx, FieldOperand(rax, Map::kPrototypeOffset)); | 3001 __ movp(rcx, FieldOperand(rax, Map::kPrototypeOffset)); |
| 3034 | 3002 |
| 3035 // Loop through the prototype chain looking for the function prototype. | 3003 // Loop through the prototype chain looking for the function prototype. |
| 3036 Label loop, is_instance, is_not_instance; | 3004 Label loop, is_instance, is_not_instance; |
| 3037 __ LoadRoot(kScratchRegister, Heap::kNullValueRootIndex); | 3005 __ LoadRoot(kScratchRegister, Heap::kNullValueRootIndex); |
| 3038 __ bind(&loop); | 3006 __ bind(&loop); |
| 3039 __ cmpq(rcx, rbx); | 3007 __ cmpq(rcx, rbx); |
| 3040 __ j(equal, &is_instance, Label::kNear); | 3008 __ j(equal, &is_instance, Label::kNear); |
| 3041 __ cmpq(rcx, kScratchRegister); | 3009 __ cmpq(rcx, kScratchRegister); |
| 3042 // The code at is_not_instance assumes that kScratchRegister contains a | 3010 // The code at is_not_instance assumes that kScratchRegister contains a |
| 3043 // non-zero GCable value (the null object in this case). | 3011 // non-zero GCable value (the null object in this case). |
| 3044 __ j(equal, &is_not_instance, Label::kNear); | 3012 __ j(equal, &is_not_instance, Label::kNear); |
| 3045 __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset)); | 3013 __ movp(rcx, FieldOperand(rcx, HeapObject::kMapOffset)); |
| 3046 __ movq(rcx, FieldOperand(rcx, Map::kPrototypeOffset)); | 3014 __ movp(rcx, FieldOperand(rcx, Map::kPrototypeOffset)); |
| 3047 __ jmp(&loop); | 3015 __ jmp(&loop); |
| 3048 | 3016 |
| 3049 __ bind(&is_instance); | 3017 __ bind(&is_instance); |
| 3050 if (!HasCallSiteInlineCheck()) { | 3018 if (!HasCallSiteInlineCheck()) { |
| 3051 __ xorl(rax, rax); | 3019 __ xorl(rax, rax); |
| 3052 // Store bitwise zero in the cache. This is a Smi in GC terms. | 3020 // Store bitwise zero in the cache. This is a Smi in GC terms. |
| 3053 STATIC_ASSERT(kSmiTag == 0); | 3021 STATIC_ASSERT(kSmiTag == 0); |
| 3054 __ StoreRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); | 3022 __ StoreRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); |
| 3055 } else { | 3023 } else { |
| 3056 // Store offset of true in the root array at the inline check site. | 3024 // Store offset of true in the root array at the inline check site. |
| 3057 int true_offset = 0x100 + | 3025 int true_offset = 0x100 + |
| 3058 (Heap::kTrueValueRootIndex << kPointerSizeLog2) - kRootRegisterBias; | 3026 (Heap::kTrueValueRootIndex << kPointerSizeLog2) - kRootRegisterBias; |
| 3059 // Assert it is a 1-byte signed value. | 3027 // Assert it is a 1-byte signed value. |
| 3060 ASSERT(true_offset >= 0 && true_offset < 0x100); | 3028 ASSERT(true_offset >= 0 && true_offset < 0x100); |
| 3061 __ movl(rax, Immediate(true_offset)); | 3029 __ movl(rax, Immediate(true_offset)); |
| 3062 __ movq(kScratchRegister, StackOperandForReturnAddress(0)); | 3030 __ movp(kScratchRegister, StackOperandForReturnAddress(0)); |
| 3063 __ subq(kScratchRegister, args.GetArgumentOperand(2)); | 3031 __ subq(kScratchRegister, args.GetArgumentOperand(2)); |
| 3064 __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax); | 3032 __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax); |
| 3065 if (FLAG_debug_code) { | 3033 if (FLAG_debug_code) { |
| 3066 __ movl(rax, Immediate(kWordBeforeResultValue)); | 3034 __ movl(rax, Immediate(kWordBeforeResultValue)); |
| 3067 __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax); | 3035 __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax); |
| 3068 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheMov); | 3036 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheMov); |
| 3069 } | 3037 } |
| 3070 __ Set(rax, 0); | 3038 __ Set(rax, 0); |
| 3071 } | 3039 } |
| 3072 __ ret((2 + extra_argument_offset) * kPointerSize); | 3040 __ ret((2 + extra_argument_offset) * kPointerSize); |
| 3073 | 3041 |
| 3074 __ bind(&is_not_instance); | 3042 __ bind(&is_not_instance); |
| 3075 if (!HasCallSiteInlineCheck()) { | 3043 if (!HasCallSiteInlineCheck()) { |
| 3076 // We have to store a non-zero value in the cache. | 3044 // We have to store a non-zero value in the cache. |
| 3077 __ StoreRoot(kScratchRegister, Heap::kInstanceofCacheAnswerRootIndex); | 3045 __ StoreRoot(kScratchRegister, Heap::kInstanceofCacheAnswerRootIndex); |
| 3078 } else { | 3046 } else { |
| 3079 // Store offset of false in the root array at the inline check site. | 3047 // Store offset of false in the root array at the inline check site. |
| 3080 int false_offset = 0x100 + | 3048 int false_offset = 0x100 + |
| 3081 (Heap::kFalseValueRootIndex << kPointerSizeLog2) - kRootRegisterBias; | 3049 (Heap::kFalseValueRootIndex << kPointerSizeLog2) - kRootRegisterBias; |
| 3082 // Assert it is a 1-byte signed value. | 3050 // Assert it is a 1-byte signed value. |
| 3083 ASSERT(false_offset >= 0 && false_offset < 0x100); | 3051 ASSERT(false_offset >= 0 && false_offset < 0x100); |
| 3084 __ movl(rax, Immediate(false_offset)); | 3052 __ movl(rax, Immediate(false_offset)); |
| 3085 __ movq(kScratchRegister, StackOperandForReturnAddress(0)); | 3053 __ movp(kScratchRegister, StackOperandForReturnAddress(0)); |
| 3086 __ subq(kScratchRegister, args.GetArgumentOperand(2)); | 3054 __ subq(kScratchRegister, args.GetArgumentOperand(2)); |
| 3087 __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax); | 3055 __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax); |
| 3088 if (FLAG_debug_code) { | 3056 if (FLAG_debug_code) { |
| 3089 __ movl(rax, Immediate(kWordBeforeResultValue)); | 3057 __ movl(rax, Immediate(kWordBeforeResultValue)); |
| 3090 __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax); | 3058 __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax); |
| 3091 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheMov); | 3059 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheMov); |
| 3092 } | 3060 } |
| 3093 } | 3061 } |
| 3094 __ ret((2 + extra_argument_offset) * kPointerSize); | 3062 __ ret((2 + extra_argument_offset) * kPointerSize); |
| 3095 | 3063 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 3118 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { | 3086 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { |
| 3119 Label flat_string; | 3087 Label flat_string; |
| 3120 Label ascii_string; | 3088 Label ascii_string; |
| 3121 Label got_char_code; | 3089 Label got_char_code; |
| 3122 Label sliced_string; | 3090 Label sliced_string; |
| 3123 | 3091 |
| 3124 // If the receiver is a smi trigger the non-string case. | 3092 // If the receiver is a smi trigger the non-string case. |
| 3125 __ JumpIfSmi(object_, receiver_not_string_); | 3093 __ JumpIfSmi(object_, receiver_not_string_); |
| 3126 | 3094 |
| 3127 // Fetch the instance type of the receiver into result register. | 3095 // Fetch the instance type of the receiver into result register. |
| 3128 __ movq(result_, FieldOperand(object_, HeapObject::kMapOffset)); | 3096 __ movp(result_, FieldOperand(object_, HeapObject::kMapOffset)); |
| 3129 __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); | 3097 __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); |
| 3130 // If the receiver is not a string trigger the non-string case. | 3098 // If the receiver is not a string trigger the non-string case. |
| 3131 __ testb(result_, Immediate(kIsNotStringMask)); | 3099 __ testb(result_, Immediate(kIsNotStringMask)); |
| 3132 __ j(not_zero, receiver_not_string_); | 3100 __ j(not_zero, receiver_not_string_); |
| 3133 | 3101 |
| 3134 // If the index is non-smi trigger the non-smi case. | 3102 // If the index is non-smi trigger the non-smi case. |
| 3135 __ JumpIfNotSmi(index_, &index_not_smi_); | 3103 __ JumpIfNotSmi(index_, &index_not_smi_); |
| 3136 __ bind(&got_smi_index_); | 3104 __ bind(&got_smi_index_); |
| 3137 | 3105 |
| 3138 // Check for index out of range. | 3106 // Check for index out of range. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 3168 if (index_flags_ == STRING_INDEX_IS_NUMBER) { | 3136 if (index_flags_ == STRING_INDEX_IS_NUMBER) { |
| 3169 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1); | 3137 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1); |
| 3170 } else { | 3138 } else { |
| 3171 ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX); | 3139 ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX); |
| 3172 // NumberToSmi discards numbers that are not exact integers. | 3140 // NumberToSmi discards numbers that are not exact integers. |
| 3173 __ CallRuntime(Runtime::kNumberToSmi, 1); | 3141 __ CallRuntime(Runtime::kNumberToSmi, 1); |
| 3174 } | 3142 } |
| 3175 if (!index_.is(rax)) { | 3143 if (!index_.is(rax)) { |
| 3176 // Save the conversion result before the pop instructions below | 3144 // Save the conversion result before the pop instructions below |
| 3177 // have a chance to overwrite it. | 3145 // have a chance to overwrite it. |
| 3178 __ movq(index_, rax); | 3146 __ movp(index_, rax); |
| 3179 } | 3147 } |
| 3180 __ pop(object_); | 3148 __ pop(object_); |
| 3181 // Reload the instance type. | 3149 // Reload the instance type. |
| 3182 __ movq(result_, FieldOperand(object_, HeapObject::kMapOffset)); | 3150 __ movp(result_, FieldOperand(object_, HeapObject::kMapOffset)); |
| 3183 __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); | 3151 __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); |
| 3184 call_helper.AfterCall(masm); | 3152 call_helper.AfterCall(masm); |
| 3185 // If index is still not a smi, it must be out of range. | 3153 // If index is still not a smi, it must be out of range. |
| 3186 __ JumpIfNotSmi(index_, index_out_of_range_); | 3154 __ JumpIfNotSmi(index_, index_out_of_range_); |
| 3187 // Otherwise, return to the fast path. | 3155 // Otherwise, return to the fast path. |
| 3188 __ jmp(&got_smi_index_); | 3156 __ jmp(&got_smi_index_); |
| 3189 | 3157 |
| 3190 // Call runtime. We get here when the receiver is a string and the | 3158 // Call runtime. We get here when the receiver is a string and the |
| 3191 // index is a number, but the code of getting the actual character | 3159 // index is a number, but the code of getting the actual character |
| 3192 // is too complex (e.g., when the string needs to be flattened). | 3160 // is too complex (e.g., when the string needs to be flattened). |
| 3193 __ bind(&call_runtime_); | 3161 __ bind(&call_runtime_); |
| 3194 call_helper.BeforeCall(masm); | 3162 call_helper.BeforeCall(masm); |
| 3195 __ push(object_); | 3163 __ push(object_); |
| 3196 __ Integer32ToSmi(index_, index_); | 3164 __ Integer32ToSmi(index_, index_); |
| 3197 __ push(index_); | 3165 __ push(index_); |
| 3198 __ CallRuntime(Runtime::kStringCharCodeAt, 2); | 3166 __ CallRuntime(Runtime::kStringCharCodeAt, 2); |
| 3199 if (!result_.is(rax)) { | 3167 if (!result_.is(rax)) { |
| 3200 __ movq(result_, rax); | 3168 __ movp(result_, rax); |
| 3201 } | 3169 } |
| 3202 call_helper.AfterCall(masm); | 3170 call_helper.AfterCall(masm); |
| 3203 __ jmp(&exit_); | 3171 __ jmp(&exit_); |
| 3204 | 3172 |
| 3205 __ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase); | 3173 __ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase); |
| 3206 } | 3174 } |
| 3207 | 3175 |
| 3208 | 3176 |
| 3209 // ------------------------------------------------------------------------- | 3177 // ------------------------------------------------------------------------- |
| 3210 // StringCharFromCodeGenerator | 3178 // StringCharFromCodeGenerator |
| 3211 | 3179 |
| 3212 void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { | 3180 void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { |
| 3213 // Fast case of Heap::LookupSingleCharacterStringFromCode. | 3181 // Fast case of Heap::LookupSingleCharacterStringFromCode. |
| 3214 __ JumpIfNotSmi(code_, &slow_case_); | 3182 __ JumpIfNotSmi(code_, &slow_case_); |
| 3215 __ SmiCompare(code_, Smi::FromInt(String::kMaxOneByteCharCode)); | 3183 __ SmiCompare(code_, Smi::FromInt(String::kMaxOneByteCharCode)); |
| 3216 __ j(above, &slow_case_); | 3184 __ j(above, &slow_case_); |
| 3217 | 3185 |
| 3218 __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex); | 3186 __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex); |
| 3219 SmiIndex index = masm->SmiToIndex(kScratchRegister, code_, kPointerSizeLog2); | 3187 SmiIndex index = masm->SmiToIndex(kScratchRegister, code_, kPointerSizeLog2); |
| 3220 __ movq(result_, FieldOperand(result_, index.reg, index.scale, | 3188 __ movp(result_, FieldOperand(result_, index.reg, index.scale, |
| 3221 FixedArray::kHeaderSize)); | 3189 FixedArray::kHeaderSize)); |
| 3222 __ CompareRoot(result_, Heap::kUndefinedValueRootIndex); | 3190 __ CompareRoot(result_, Heap::kUndefinedValueRootIndex); |
| 3223 __ j(equal, &slow_case_); | 3191 __ j(equal, &slow_case_); |
| 3224 __ bind(&exit_); | 3192 __ bind(&exit_); |
| 3225 } | 3193 } |
| 3226 | 3194 |
| 3227 | 3195 |
| 3228 void StringCharFromCodeGenerator::GenerateSlow( | 3196 void StringCharFromCodeGenerator::GenerateSlow( |
| 3229 MacroAssembler* masm, | 3197 MacroAssembler* masm, |
| 3230 const RuntimeCallHelper& call_helper) { | 3198 const RuntimeCallHelper& call_helper) { |
| 3231 __ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase); | 3199 __ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase); |
| 3232 | 3200 |
| 3233 __ bind(&slow_case_); | 3201 __ bind(&slow_case_); |
| 3234 call_helper.BeforeCall(masm); | 3202 call_helper.BeforeCall(masm); |
| 3235 __ push(code_); | 3203 __ push(code_); |
| 3236 __ CallRuntime(Runtime::kCharFromCode, 1); | 3204 __ CallRuntime(Runtime::kCharFromCode, 1); |
| 3237 if (!result_.is(rax)) { | 3205 if (!result_.is(rax)) { |
| 3238 __ movq(result_, rax); | 3206 __ movp(result_, rax); |
| 3239 } | 3207 } |
| 3240 call_helper.AfterCall(masm); | 3208 call_helper.AfterCall(masm); |
| 3241 __ jmp(&exit_); | 3209 __ jmp(&exit_); |
| 3242 | 3210 |
| 3243 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); | 3211 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); |
| 3244 } | 3212 } |
| 3245 | 3213 |
| 3246 | 3214 |
| 3247 void StringAddStub::Generate(MacroAssembler* masm) { | |
| 3248 Label call_runtime, call_builtin; | |
| 3249 Builtins::JavaScript builtin_id = Builtins::ADD; | |
| 3250 | |
| 3251 // Load the two arguments. | |
| 3252 StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER); | |
| 3253 __ movq(rax, args.GetArgumentOperand(0)); // First argument (left). | |
| 3254 __ movq(rdx, args.GetArgumentOperand(1)); // Second argument (right). | |
| 3255 | |
| 3256 // Make sure that both arguments are strings if not known in advance. | |
| 3257 // Otherwise, at least one of the arguments is definitely a string, | |
| 3258 // and we convert the one that is not known to be a string. | |
| 3259 if ((flags_ & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) { | |
| 3260 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT); | |
| 3261 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT); | |
| 3262 __ JumpIfSmi(rax, &call_runtime); | |
| 3263 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8); | |
| 3264 __ j(above_equal, &call_runtime); | |
| 3265 | |
| 3266 // First argument is a a string, test second. | |
| 3267 __ JumpIfSmi(rdx, &call_runtime); | |
| 3268 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9); | |
| 3269 __ j(above_equal, &call_runtime); | |
| 3270 } else if ((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) { | |
| 3271 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == 0); | |
| 3272 GenerateConvertArgument(masm, 2 * kPointerSize, rax, rbx, rcx, rdi, | |
| 3273 &call_builtin); | |
| 3274 builtin_id = Builtins::STRING_ADD_RIGHT; | |
| 3275 } else if ((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) { | |
| 3276 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == 0); | |
| 3277 GenerateConvertArgument(masm, 1 * kPointerSize, rdx, rbx, rcx, rdi, | |
| 3278 &call_builtin); | |
| 3279 builtin_id = Builtins::STRING_ADD_LEFT; | |
| 3280 } | |
| 3281 | |
| 3282 // Both arguments are strings. | |
| 3283 // rax: first string | |
| 3284 // rdx: second string | |
| 3285 // Check if either of the strings are empty. In that case return the other. | |
| 3286 Label second_not_zero_length, both_not_zero_length; | |
| 3287 __ movq(rcx, FieldOperand(rdx, String::kLengthOffset)); | |
| 3288 __ SmiTest(rcx); | |
| 3289 __ j(not_zero, &second_not_zero_length, Label::kNear); | |
| 3290 // Second string is empty, result is first string which is already in rax. | |
| 3291 Counters* counters = masm->isolate()->counters(); | |
| 3292 __ IncrementCounter(counters->string_add_native(), 1); | |
| 3293 __ ret(2 * kPointerSize); | |
| 3294 __ bind(&second_not_zero_length); | |
| 3295 __ movq(rbx, FieldOperand(rax, String::kLengthOffset)); | |
| 3296 __ SmiTest(rbx); | |
| 3297 __ j(not_zero, &both_not_zero_length, Label::kNear); | |
| 3298 // First string is empty, result is second string which is in rdx. | |
| 3299 __ movq(rax, rdx); | |
| 3300 __ IncrementCounter(counters->string_add_native(), 1); | |
| 3301 __ ret(2 * kPointerSize); | |
| 3302 | |
| 3303 // Both strings are non-empty. | |
| 3304 // rax: first string | |
| 3305 // rbx: length of first string | |
| 3306 // rcx: length of second string | |
| 3307 // rdx: second string | |
| 3308 // r8: map of first string (if flags_ == NO_STRING_ADD_FLAGS) | |
| 3309 // r9: map of second string (if flags_ == NO_STRING_ADD_FLAGS) | |
| 3310 Label string_add_flat_result, longer_than_two; | |
| 3311 __ bind(&both_not_zero_length); | |
| 3312 | |
| 3313 // If arguments where known to be strings, maps are not loaded to r8 and r9 | |
| 3314 // by the code above. | |
| 3315 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) { | |
| 3316 __ movq(r8, FieldOperand(rax, HeapObject::kMapOffset)); | |
| 3317 __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset)); | |
| 3318 } | |
| 3319 // Get the instance types of the two strings as they will be needed soon. | |
| 3320 __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset)); | |
| 3321 __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset)); | |
| 3322 | |
| 3323 // Look at the length of the result of adding the two strings. | |
| 3324 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue / 2); | |
| 3325 __ SmiAdd(rbx, rbx, rcx); | |
| 3326 // Use the string table when adding two one character strings, as it | |
| 3327 // helps later optimizations to return an internalized string here. | |
| 3328 __ SmiCompare(rbx, Smi::FromInt(2)); | |
| 3329 __ j(not_equal, &longer_than_two); | |
| 3330 | |
| 3331 // Check that both strings are non-external ASCII strings. | |
| 3332 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r8, r9, rbx, rcx, | |
| 3333 &call_runtime); | |
| 3334 | |
| 3335 // Get the two characters forming the sub string. | |
| 3336 __ movzxbq(rbx, FieldOperand(rax, SeqOneByteString::kHeaderSize)); | |
| 3337 __ movzxbq(rcx, FieldOperand(rdx, SeqOneByteString::kHeaderSize)); | |
| 3338 | |
| 3339 // Try to lookup two character string in string table. If it is not found | |
| 3340 // just allocate a new one. | |
| 3341 Label make_two_character_string, make_flat_ascii_string; | |
| 3342 StringHelper::GenerateTwoCharacterStringTableProbe( | |
| 3343 masm, rbx, rcx, r14, r11, rdi, r15, &make_two_character_string); | |
| 3344 __ IncrementCounter(counters->string_add_native(), 1); | |
| 3345 __ ret(2 * kPointerSize); | |
| 3346 | |
| 3347 __ bind(&make_two_character_string); | |
| 3348 __ Set(rdi, 2); | |
| 3349 __ AllocateAsciiString(rax, rdi, r8, r9, r11, &call_runtime); | |
| 3350 // rbx - first byte: first character | |
| 3351 // rbx - second byte: *maybe* second character | |
| 3352 // Make sure that the second byte of rbx contains the second character. | |
| 3353 __ movzxbq(rcx, FieldOperand(rdx, SeqOneByteString::kHeaderSize)); | |
| 3354 __ shll(rcx, Immediate(kBitsPerByte)); | |
| 3355 __ orl(rbx, rcx); | |
| 3356 // Write both characters to the new string. | |
| 3357 __ movw(FieldOperand(rax, SeqOneByteString::kHeaderSize), rbx); | |
| 3358 __ IncrementCounter(counters->string_add_native(), 1); | |
| 3359 __ ret(2 * kPointerSize); | |
| 3360 | |
| 3361 __ bind(&longer_than_two); | |
| 3362 // Check if resulting string will be flat. | |
| 3363 __ SmiCompare(rbx, Smi::FromInt(ConsString::kMinLength)); | |
| 3364 __ j(below, &string_add_flat_result); | |
| 3365 // Handle exceptionally long strings in the runtime system. | |
| 3366 STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0); | |
| 3367 __ SmiCompare(rbx, Smi::FromInt(String::kMaxLength)); | |
| 3368 __ j(above, &call_runtime); | |
| 3369 | |
| 3370 // If result is not supposed to be flat, allocate a cons string object. If | |
| 3371 // both strings are ASCII the result is an ASCII cons string. | |
| 3372 // rax: first string | |
| 3373 // rbx: length of resulting flat string | |
| 3374 // rdx: second string | |
| 3375 // r8: instance type of first string | |
| 3376 // r9: instance type of second string | |
| 3377 Label non_ascii, allocated, ascii_data; | |
| 3378 __ movl(rcx, r8); | |
| 3379 __ and_(rcx, r9); | |
| 3380 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); | |
| 3381 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); | |
| 3382 __ testl(rcx, Immediate(kStringEncodingMask)); | |
| 3383 __ j(zero, &non_ascii); | |
| 3384 __ bind(&ascii_data); | |
| 3385 // Allocate an ASCII cons string. | |
| 3386 __ AllocateAsciiConsString(rcx, rdi, no_reg, &call_runtime); | |
| 3387 __ bind(&allocated); | |
| 3388 // Fill the fields of the cons string. | |
| 3389 __ movq(FieldOperand(rcx, ConsString::kLengthOffset), rbx); | |
| 3390 __ movq(FieldOperand(rcx, ConsString::kHashFieldOffset), | |
| 3391 Immediate(String::kEmptyHashField)); | |
| 3392 | |
| 3393 Label skip_write_barrier, after_writing; | |
| 3394 ExternalReference high_promotion_mode = ExternalReference:: | |
| 3395 new_space_high_promotion_mode_active_address(masm->isolate()); | |
| 3396 __ Load(rbx, high_promotion_mode); | |
| 3397 __ testb(rbx, Immediate(1)); | |
| 3398 __ j(zero, &skip_write_barrier); | |
| 3399 | |
| 3400 __ movq(FieldOperand(rcx, ConsString::kFirstOffset), rax); | |
| 3401 __ RecordWriteField(rcx, | |
| 3402 ConsString::kFirstOffset, | |
| 3403 rax, | |
| 3404 rbx, | |
| 3405 kDontSaveFPRegs); | |
| 3406 __ movq(FieldOperand(rcx, ConsString::kSecondOffset), rdx); | |
| 3407 __ RecordWriteField(rcx, | |
| 3408 ConsString::kSecondOffset, | |
| 3409 rdx, | |
| 3410 rbx, | |
| 3411 kDontSaveFPRegs); | |
| 3412 __ jmp(&after_writing); | |
| 3413 | |
| 3414 __ bind(&skip_write_barrier); | |
| 3415 __ movq(FieldOperand(rcx, ConsString::kFirstOffset), rax); | |
| 3416 __ movq(FieldOperand(rcx, ConsString::kSecondOffset), rdx); | |
| 3417 | |
| 3418 __ bind(&after_writing); | |
| 3419 | |
| 3420 __ movq(rax, rcx); | |
| 3421 __ IncrementCounter(counters->string_add_native(), 1); | |
| 3422 __ ret(2 * kPointerSize); | |
| 3423 __ bind(&non_ascii); | |
| 3424 // At least one of the strings is two-byte. Check whether it happens | |
| 3425 // to contain only one byte characters. | |
| 3426 // rcx: first instance type AND second instance type. | |
| 3427 // r8: first instance type. | |
| 3428 // r9: second instance type. | |
| 3429 __ testb(rcx, Immediate(kOneByteDataHintMask)); | |
| 3430 __ j(not_zero, &ascii_data); | |
| 3431 __ xor_(r8, r9); | |
| 3432 STATIC_ASSERT(kOneByteStringTag != 0 && kOneByteDataHintTag != 0); | |
| 3433 __ andb(r8, Immediate(kOneByteStringTag | kOneByteDataHintTag)); | |
| 3434 __ cmpb(r8, Immediate(kOneByteStringTag | kOneByteDataHintTag)); | |
| 3435 __ j(equal, &ascii_data); | |
| 3436 // Allocate a two byte cons string. | |
| 3437 __ AllocateTwoByteConsString(rcx, rdi, no_reg, &call_runtime); | |
| 3438 __ jmp(&allocated); | |
| 3439 | |
| 3440 // We cannot encounter sliced strings or cons strings here since: | |
| 3441 STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength); | |
| 3442 // Handle creating a flat result from either external or sequential strings. | |
| 3443 // Locate the first characters' locations. | |
| 3444 // rax: first string | |
| 3445 // rbx: length of resulting flat string as smi | |
| 3446 // rdx: second string | |
| 3447 // r8: instance type of first string | |
| 3448 // r9: instance type of first string | |
| 3449 Label first_prepared, second_prepared; | |
| 3450 Label first_is_sequential, second_is_sequential; | |
| 3451 __ bind(&string_add_flat_result); | |
| 3452 | |
| 3453 __ SmiToInteger32(r14, FieldOperand(rax, SeqString::kLengthOffset)); | |
| 3454 // r14: length of first string | |
| 3455 STATIC_ASSERT(kSeqStringTag == 0); | |
| 3456 __ testb(r8, Immediate(kStringRepresentationMask)); | |
| 3457 __ j(zero, &first_is_sequential, Label::kNear); | |
| 3458 // Rule out short external string and load string resource. | |
| 3459 STATIC_ASSERT(kShortExternalStringTag != 0); | |
| 3460 __ testb(r8, Immediate(kShortExternalStringMask)); | |
| 3461 __ j(not_zero, &call_runtime); | |
| 3462 __ movq(rcx, FieldOperand(rax, ExternalString::kResourceDataOffset)); | |
| 3463 __ jmp(&first_prepared, Label::kNear); | |
| 3464 __ bind(&first_is_sequential); | |
| 3465 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); | |
| 3466 __ lea(rcx, FieldOperand(rax, SeqOneByteString::kHeaderSize)); | |
| 3467 __ bind(&first_prepared); | |
| 3468 | |
| 3469 // Check whether both strings have same encoding. | |
| 3470 __ xorl(r8, r9); | |
| 3471 __ testb(r8, Immediate(kStringEncodingMask)); | |
| 3472 __ j(not_zero, &call_runtime); | |
| 3473 | |
| 3474 __ SmiToInteger32(r15, FieldOperand(rdx, SeqString::kLengthOffset)); | |
| 3475 // r15: length of second string | |
| 3476 STATIC_ASSERT(kSeqStringTag == 0); | |
| 3477 __ testb(r9, Immediate(kStringRepresentationMask)); | |
| 3478 __ j(zero, &second_is_sequential, Label::kNear); | |
| 3479 // Rule out short external string and load string resource. | |
| 3480 STATIC_ASSERT(kShortExternalStringTag != 0); | |
| 3481 __ testb(r9, Immediate(kShortExternalStringMask)); | |
| 3482 __ j(not_zero, &call_runtime); | |
| 3483 __ movq(rdx, FieldOperand(rdx, ExternalString::kResourceDataOffset)); | |
| 3484 __ jmp(&second_prepared, Label::kNear); | |
| 3485 __ bind(&second_is_sequential); | |
| 3486 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); | |
| 3487 __ lea(rdx, FieldOperand(rdx, SeqOneByteString::kHeaderSize)); | |
| 3488 __ bind(&second_prepared); | |
| 3489 | |
| 3490 Label non_ascii_string_add_flat_result; | |
| 3491 // r9: instance type of second string | |
| 3492 // First string and second string have the same encoding. | |
| 3493 STATIC_ASSERT(kTwoByteStringTag == 0); | |
| 3494 __ SmiToInteger32(rbx, rbx); | |
| 3495 __ testb(r9, Immediate(kStringEncodingMask)); | |
| 3496 __ j(zero, &non_ascii_string_add_flat_result); | |
| 3497 | |
| 3498 __ bind(&make_flat_ascii_string); | |
| 3499 // Both strings are ASCII strings. As they are short they are both flat. | |
| 3500 __ AllocateAsciiString(rax, rbx, rdi, r8, r9, &call_runtime); | |
| 3501 // rax: result string | |
| 3502 // Locate first character of result. | |
| 3503 __ lea(rbx, FieldOperand(rax, SeqOneByteString::kHeaderSize)); | |
| 3504 // rcx: first char of first string | |
| 3505 // rbx: first character of result | |
| 3506 // r14: length of first string | |
| 3507 StringHelper::GenerateCopyCharacters(masm, rbx, rcx, r14, true); | |
| 3508 // rbx: next character of result | |
| 3509 // rdx: first char of second string | |
| 3510 // r15: length of second string | |
| 3511 StringHelper::GenerateCopyCharacters(masm, rbx, rdx, r15, true); | |
| 3512 __ IncrementCounter(counters->string_add_native(), 1); | |
| 3513 __ ret(2 * kPointerSize); | |
| 3514 | |
| 3515 __ bind(&non_ascii_string_add_flat_result); | |
| 3516 // Both strings are ASCII strings. As they are short they are both flat. | |
| 3517 __ AllocateTwoByteString(rax, rbx, rdi, r8, r9, &call_runtime); | |
| 3518 // rax: result string | |
| 3519 // Locate first character of result. | |
| 3520 __ lea(rbx, FieldOperand(rax, SeqTwoByteString::kHeaderSize)); | |
| 3521 // rcx: first char of first string | |
| 3522 // rbx: first character of result | |
| 3523 // r14: length of first string | |
| 3524 StringHelper::GenerateCopyCharacters(masm, rbx, rcx, r14, false); | |
| 3525 // rbx: next character of result | |
| 3526 // rdx: first char of second string | |
| 3527 // r15: length of second string | |
| 3528 StringHelper::GenerateCopyCharacters(masm, rbx, rdx, r15, false); | |
| 3529 __ IncrementCounter(counters->string_add_native(), 1); | |
| 3530 __ ret(2 * kPointerSize); | |
| 3531 | |
| 3532 // Just jump to runtime to add the two strings. | |
| 3533 __ bind(&call_runtime); | |
| 3534 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | |
| 3535 | |
| 3536 if (call_builtin.is_linked()) { | |
| 3537 __ bind(&call_builtin); | |
| 3538 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); | |
| 3539 } | |
| 3540 } | |
| 3541 | |
| 3542 | |
| 3543 void StringAddStub::GenerateRegisterArgsPush(MacroAssembler* masm) { | |
| 3544 __ push(rax); | |
| 3545 __ push(rdx); | |
| 3546 } | |
| 3547 | |
| 3548 | |
| 3549 void StringAddStub::GenerateRegisterArgsPop(MacroAssembler* masm, | |
| 3550 Register temp) { | |
| 3551 __ PopReturnAddressTo(temp); | |
| 3552 __ pop(rdx); | |
| 3553 __ pop(rax); | |
| 3554 __ PushReturnAddressFrom(temp); | |
| 3555 } | |
| 3556 | |
| 3557 | |
| 3558 void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, | |
| 3559 int stack_offset, | |
| 3560 Register arg, | |
| 3561 Register scratch1, | |
| 3562 Register scratch2, | |
| 3563 Register scratch3, | |
| 3564 Label* slow) { | |
| 3565 // First check if the argument is already a string. | |
| 3566 Label not_string, done; | |
| 3567 __ JumpIfSmi(arg, ¬_string); | |
| 3568 __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1); | |
| 3569 __ j(below, &done); | |
| 3570 | |
| 3571 // Check the number to string cache. | |
| 3572 __ bind(¬_string); | |
| 3573 // Puts the cached result into scratch1. | |
| 3574 __ LookupNumberStringCache(arg, scratch1, scratch2, scratch3, slow); | |
| 3575 __ movq(arg, scratch1); | |
| 3576 __ movq(Operand(rsp, stack_offset), arg); | |
| 3577 __ bind(&done); | |
| 3578 } | |
| 3579 | |
| 3580 | |
| 3581 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, | |
| 3582 Register dest, | |
| 3583 Register src, | |
| 3584 Register count, | |
| 3585 bool ascii) { | |
| 3586 Label loop; | |
| 3587 __ bind(&loop); | |
| 3588 // This loop just copies one character at a time, as it is only used for very | |
| 3589 // short strings. | |
| 3590 if (ascii) { | |
| 3591 __ movb(kScratchRegister, Operand(src, 0)); | |
| 3592 __ movb(Operand(dest, 0), kScratchRegister); | |
| 3593 __ incq(src); | |
| 3594 __ incq(dest); | |
| 3595 } else { | |
| 3596 __ movzxwl(kScratchRegister, Operand(src, 0)); | |
| 3597 __ movw(Operand(dest, 0), kScratchRegister); | |
| 3598 __ addq(src, Immediate(2)); | |
| 3599 __ addq(dest, Immediate(2)); | |
| 3600 } | |
| 3601 __ decl(count); | |
| 3602 __ j(not_zero, &loop); | |
| 3603 } | |
| 3604 | |
| 3605 | |
| 3606 void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, | 3215 void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, |
| 3607 Register dest, | 3216 Register dest, |
| 3608 Register src, | 3217 Register src, |
| 3609 Register count, | 3218 Register count, |
| 3610 bool ascii) { | 3219 bool ascii) { |
| 3611 // Copy characters using rep movs of doublewords. Align destination on 4 byte | 3220 // Copy characters using rep movs of doublewords. Align destination on 4 byte |
| 3612 // boundary before starting rep movs. Copy remaining characters after running | 3221 // boundary before starting rep movs. Copy remaining characters after running |
| 3613 // rep movs. | 3222 // rep movs. |
| 3614 // Count is positive int32, dest and src are character pointers. | 3223 // Count is positive int32, dest and src are character pointers. |
| 3615 ASSERT(dest.is(rdi)); // rep movs destination | 3224 ASSERT(dest.is(rdi)); // rep movs destination |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3652 __ movb(kScratchRegister, Operand(src, 0)); | 3261 __ movb(kScratchRegister, Operand(src, 0)); |
| 3653 __ movb(Operand(dest, 0), kScratchRegister); | 3262 __ movb(Operand(dest, 0), kScratchRegister); |
| 3654 __ incq(src); | 3263 __ incq(src); |
| 3655 __ incq(dest); | 3264 __ incq(dest); |
| 3656 __ decl(count); | 3265 __ decl(count); |
| 3657 __ j(not_zero, &loop); | 3266 __ j(not_zero, &loop); |
| 3658 | 3267 |
| 3659 __ bind(&done); | 3268 __ bind(&done); |
| 3660 } | 3269 } |
| 3661 | 3270 |
| 3662 void StringHelper::GenerateTwoCharacterStringTableProbe(MacroAssembler* masm, | |
| 3663 Register c1, | |
| 3664 Register c2, | |
| 3665 Register scratch1, | |
| 3666 Register scratch2, | |
| 3667 Register scratch3, | |
| 3668 Register scratch4, | |
| 3669 Label* not_found) { | |
| 3670 // Register scratch3 is the general scratch register in this function. | |
| 3671 Register scratch = scratch3; | |
| 3672 | |
| 3673 // Make sure that both characters are not digits as such strings has a | |
| 3674 // different hash algorithm. Don't try to look for these in the string table. | |
| 3675 Label not_array_index; | |
| 3676 __ leal(scratch, Operand(c1, -'0')); | |
| 3677 __ cmpl(scratch, Immediate(static_cast<int>('9' - '0'))); | |
| 3678 __ j(above, ¬_array_index, Label::kNear); | |
| 3679 __ leal(scratch, Operand(c2, -'0')); | |
| 3680 __ cmpl(scratch, Immediate(static_cast<int>('9' - '0'))); | |
| 3681 __ j(below_equal, not_found); | |
| 3682 | |
| 3683 __ bind(¬_array_index); | |
| 3684 // Calculate the two character string hash. | |
| 3685 Register hash = scratch1; | |
| 3686 GenerateHashInit(masm, hash, c1, scratch); | |
| 3687 GenerateHashAddCharacter(masm, hash, c2, scratch); | |
| 3688 GenerateHashGetHash(masm, hash, scratch); | |
| 3689 | |
| 3690 // Collect the two characters in a register. | |
| 3691 Register chars = c1; | |
| 3692 __ shl(c2, Immediate(kBitsPerByte)); | |
| 3693 __ orl(chars, c2); | |
| 3694 | |
| 3695 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. | |
| 3696 // hash: hash of two character string. | |
| 3697 | |
| 3698 // Load the string table. | |
| 3699 Register string_table = c2; | |
| 3700 __ LoadRoot(string_table, Heap::kStringTableRootIndex); | |
| 3701 | |
| 3702 // Calculate capacity mask from the string table capacity. | |
| 3703 Register mask = scratch2; | |
| 3704 __ SmiToInteger32(mask, | |
| 3705 FieldOperand(string_table, StringTable::kCapacityOffset)); | |
| 3706 __ decl(mask); | |
| 3707 | |
| 3708 Register map = scratch4; | |
| 3709 | |
| 3710 // Registers | |
| 3711 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. | |
| 3712 // hash: hash of two character string (32-bit int) | |
| 3713 // string_table: string table | |
| 3714 // mask: capacity mask (32-bit int) | |
| 3715 // map: - | |
| 3716 // scratch: - | |
| 3717 | |
| 3718 // Perform a number of probes in the string table. | |
| 3719 static const int kProbes = 4; | |
| 3720 Label found_in_string_table; | |
| 3721 Label next_probe[kProbes]; | |
| 3722 Register candidate = scratch; // Scratch register contains candidate. | |
| 3723 for (int i = 0; i < kProbes; i++) { | |
| 3724 // Calculate entry in string table. | |
| 3725 __ movl(scratch, hash); | |
| 3726 if (i > 0) { | |
| 3727 __ addl(scratch, Immediate(StringTable::GetProbeOffset(i))); | |
| 3728 } | |
| 3729 __ andl(scratch, mask); | |
| 3730 | |
| 3731 // Load the entry from the string table. | |
| 3732 STATIC_ASSERT(StringTable::kEntrySize == 1); | |
| 3733 __ movq(candidate, | |
| 3734 FieldOperand(string_table, | |
| 3735 scratch, | |
| 3736 times_pointer_size, | |
| 3737 StringTable::kElementsStartOffset)); | |
| 3738 | |
| 3739 // If entry is undefined no string with this hash can be found. | |
| 3740 Label is_string; | |
| 3741 __ CmpObjectType(candidate, ODDBALL_TYPE, map); | |
| 3742 __ j(not_equal, &is_string, Label::kNear); | |
| 3743 | |
| 3744 __ CompareRoot(candidate, Heap::kUndefinedValueRootIndex); | |
| 3745 __ j(equal, not_found); | |
| 3746 // Must be the hole (deleted entry). | |
| 3747 if (FLAG_debug_code) { | |
| 3748 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | |
| 3749 __ cmpq(kScratchRegister, candidate); | |
| 3750 __ Assert(equal, kOddballInStringTableIsNotUndefinedOrTheHole); | |
| 3751 } | |
| 3752 __ jmp(&next_probe[i]); | |
| 3753 | |
| 3754 __ bind(&is_string); | |
| 3755 | |
| 3756 // If length is not 2 the string is not a candidate. | |
| 3757 __ SmiCompare(FieldOperand(candidate, String::kLengthOffset), | |
| 3758 Smi::FromInt(2)); | |
| 3759 __ j(not_equal, &next_probe[i]); | |
| 3760 | |
| 3761 // We use kScratchRegister as a temporary register in assumption that | |
| 3762 // JumpIfInstanceTypeIsNotSequentialAscii does not use it implicitly | |
| 3763 Register temp = kScratchRegister; | |
| 3764 | |
| 3765 // Check that the candidate is a non-external ASCII string. | |
| 3766 __ movzxbl(temp, FieldOperand(map, Map::kInstanceTypeOffset)); | |
| 3767 __ JumpIfInstanceTypeIsNotSequentialAscii( | |
| 3768 temp, temp, &next_probe[i]); | |
| 3769 | |
| 3770 // Check if the two characters match. | |
| 3771 __ movl(temp, FieldOperand(candidate, SeqOneByteString::kHeaderSize)); | |
| 3772 __ andl(temp, Immediate(0x0000ffff)); | |
| 3773 __ cmpl(chars, temp); | |
| 3774 __ j(equal, &found_in_string_table); | |
| 3775 __ bind(&next_probe[i]); | |
| 3776 } | |
| 3777 | |
| 3778 // No matching 2 character string found by probing. | |
| 3779 __ jmp(not_found); | |
| 3780 | |
| 3781 // Scratch register contains result when we fall through to here. | |
| 3782 Register result = candidate; | |
| 3783 __ bind(&found_in_string_table); | |
| 3784 if (!result.is(rax)) { | |
| 3785 __ movq(rax, result); | |
| 3786 } | |
| 3787 } | |
| 3788 | |
| 3789 | 3271 |
| 3790 void StringHelper::GenerateHashInit(MacroAssembler* masm, | 3272 void StringHelper::GenerateHashInit(MacroAssembler* masm, |
| 3791 Register hash, | 3273 Register hash, |
| 3792 Register character, | 3274 Register character, |
| 3793 Register scratch) { | 3275 Register scratch) { |
| 3794 // hash = (seed + character) + ((seed + character) << 10); | 3276 // hash = (seed + character) + ((seed + character) << 10); |
| 3795 __ LoadRoot(scratch, Heap::kHashSeedRootIndex); | 3277 __ LoadRoot(scratch, Heap::kHashSeedRootIndex); |
| 3796 __ SmiToInteger32(scratch, scratch); | 3278 __ SmiToInteger32(scratch, scratch); |
| 3797 __ addl(scratch, character); | 3279 __ addl(scratch, character); |
| 3798 __ movl(hash, scratch); | 3280 __ movl(hash, scratch); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3859 STRING_ARGUMENT_INDEX, | 3341 STRING_ARGUMENT_INDEX, |
| 3860 FROM_ARGUMENT_INDEX, | 3342 FROM_ARGUMENT_INDEX, |
| 3861 TO_ARGUMENT_INDEX, | 3343 TO_ARGUMENT_INDEX, |
| 3862 SUB_STRING_ARGUMENT_COUNT | 3344 SUB_STRING_ARGUMENT_COUNT |
| 3863 }; | 3345 }; |
| 3864 | 3346 |
| 3865 StackArgumentsAccessor args(rsp, SUB_STRING_ARGUMENT_COUNT, | 3347 StackArgumentsAccessor args(rsp, SUB_STRING_ARGUMENT_COUNT, |
| 3866 ARGUMENTS_DONT_CONTAIN_RECEIVER); | 3348 ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 3867 | 3349 |
| 3868 // Make sure first argument is a string. | 3350 // Make sure first argument is a string. |
| 3869 __ movq(rax, args.GetArgumentOperand(STRING_ARGUMENT_INDEX)); | 3351 __ movp(rax, args.GetArgumentOperand(STRING_ARGUMENT_INDEX)); |
| 3870 STATIC_ASSERT(kSmiTag == 0); | 3352 STATIC_ASSERT(kSmiTag == 0); |
| 3871 __ testl(rax, Immediate(kSmiTagMask)); | 3353 __ testl(rax, Immediate(kSmiTagMask)); |
| 3872 __ j(zero, &runtime); | 3354 __ j(zero, &runtime); |
| 3873 Condition is_string = masm->IsObjectStringType(rax, rbx, rbx); | 3355 Condition is_string = masm->IsObjectStringType(rax, rbx, rbx); |
| 3874 __ j(NegateCondition(is_string), &runtime); | 3356 __ j(NegateCondition(is_string), &runtime); |
| 3875 | 3357 |
| 3876 // rax: string | 3358 // rax: string |
| 3877 // rbx: instance type | 3359 // rbx: instance type |
| 3878 // Calculate length of sub string using the smi values. | 3360 // Calculate length of sub string using the smi values. |
| 3879 __ movq(rcx, args.GetArgumentOperand(TO_ARGUMENT_INDEX)); | 3361 __ movp(rcx, args.GetArgumentOperand(TO_ARGUMENT_INDEX)); |
| 3880 __ movq(rdx, args.GetArgumentOperand(FROM_ARGUMENT_INDEX)); | 3362 __ movp(rdx, args.GetArgumentOperand(FROM_ARGUMENT_INDEX)); |
| 3881 __ JumpUnlessBothNonNegativeSmi(rcx, rdx, &runtime); | 3363 __ JumpUnlessBothNonNegativeSmi(rcx, rdx, &runtime); |
| 3882 | 3364 |
| 3883 __ SmiSub(rcx, rcx, rdx); // Overflow doesn't happen. | 3365 __ SmiSub(rcx, rcx, rdx); // Overflow doesn't happen. |
| 3884 __ cmpq(rcx, FieldOperand(rax, String::kLengthOffset)); | 3366 __ cmpq(rcx, FieldOperand(rax, String::kLengthOffset)); |
| 3885 Label not_original_string; | 3367 Label not_original_string; |
| 3886 // Shorter than original string's length: an actual substring. | 3368 // Shorter than original string's length: an actual substring. |
| 3887 __ j(below, ¬_original_string, Label::kNear); | 3369 __ j(below, ¬_original_string, Label::kNear); |
| 3888 // Longer than original string's length or negative: unsafe arguments. | 3370 // Longer than original string's length or negative: unsafe arguments. |
| 3889 __ j(above, &runtime); | 3371 __ j(above, &runtime); |
| 3890 // Return original string. | 3372 // Return original string. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 3912 __ testb(rbx, Immediate(kIsIndirectStringMask)); | 3394 __ testb(rbx, Immediate(kIsIndirectStringMask)); |
| 3913 __ j(zero, &seq_or_external_string, Label::kNear); | 3395 __ j(zero, &seq_or_external_string, Label::kNear); |
| 3914 | 3396 |
| 3915 __ testb(rbx, Immediate(kSlicedNotConsMask)); | 3397 __ testb(rbx, Immediate(kSlicedNotConsMask)); |
| 3916 __ j(not_zero, &sliced_string, Label::kNear); | 3398 __ j(not_zero, &sliced_string, Label::kNear); |
| 3917 // Cons string. Check whether it is flat, then fetch first part. | 3399 // Cons string. Check whether it is flat, then fetch first part. |
| 3918 // Flat cons strings have an empty second part. | 3400 // Flat cons strings have an empty second part. |
| 3919 __ CompareRoot(FieldOperand(rax, ConsString::kSecondOffset), | 3401 __ CompareRoot(FieldOperand(rax, ConsString::kSecondOffset), |
| 3920 Heap::kempty_stringRootIndex); | 3402 Heap::kempty_stringRootIndex); |
| 3921 __ j(not_equal, &runtime); | 3403 __ j(not_equal, &runtime); |
| 3922 __ movq(rdi, FieldOperand(rax, ConsString::kFirstOffset)); | 3404 __ movp(rdi, FieldOperand(rax, ConsString::kFirstOffset)); |
| 3923 // Update instance type. | 3405 // Update instance type. |
| 3924 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); | 3406 __ movp(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); |
| 3925 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | 3407 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
| 3926 __ jmp(&underlying_unpacked, Label::kNear); | 3408 __ jmp(&underlying_unpacked, Label::kNear); |
| 3927 | 3409 |
| 3928 __ bind(&sliced_string); | 3410 __ bind(&sliced_string); |
| 3929 // Sliced string. Fetch parent and correct start index by offset. | 3411 // Sliced string. Fetch parent and correct start index by offset. |
| 3930 __ addq(rdx, FieldOperand(rax, SlicedString::kOffsetOffset)); | 3412 __ addq(rdx, FieldOperand(rax, SlicedString::kOffsetOffset)); |
| 3931 __ movq(rdi, FieldOperand(rax, SlicedString::kParentOffset)); | 3413 __ movp(rdi, FieldOperand(rax, SlicedString::kParentOffset)); |
| 3932 // Update instance type. | 3414 // Update instance type. |
| 3933 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); | 3415 __ movp(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); |
| 3934 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | 3416 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
| 3935 __ jmp(&underlying_unpacked, Label::kNear); | 3417 __ jmp(&underlying_unpacked, Label::kNear); |
| 3936 | 3418 |
| 3937 __ bind(&seq_or_external_string); | 3419 __ bind(&seq_or_external_string); |
| 3938 // Sequential or external string. Just move string to the correct register. | 3420 // Sequential or external string. Just move string to the correct register. |
| 3939 __ movq(rdi, rax); | 3421 __ movp(rdi, rax); |
| 3940 | 3422 |
| 3941 __ bind(&underlying_unpacked); | 3423 __ bind(&underlying_unpacked); |
| 3942 | 3424 |
| 3943 if (FLAG_string_slices) { | 3425 if (FLAG_string_slices) { |
| 3944 Label copy_routine; | 3426 Label copy_routine; |
| 3945 // rdi: underlying subject string | 3427 // rdi: underlying subject string |
| 3946 // rbx: instance type of underlying subject string | 3428 // rbx: instance type of underlying subject string |
| 3947 // rdx: adjusted start index (smi) | 3429 // rdx: adjusted start index (smi) |
| 3948 // rcx: length | 3430 // rcx: length |
| 3949 // If coming from the make_two_character_string path, the string | 3431 // If coming from the make_two_character_string path, the string |
| (...skipping 10 matching lines...) Expand all Loading... |
| 3960 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); | 3442 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); |
| 3961 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); | 3443 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); |
| 3962 __ testb(rbx, Immediate(kStringEncodingMask)); | 3444 __ testb(rbx, Immediate(kStringEncodingMask)); |
| 3963 __ j(zero, &two_byte_slice, Label::kNear); | 3445 __ j(zero, &two_byte_slice, Label::kNear); |
| 3964 __ AllocateAsciiSlicedString(rax, rbx, r14, &runtime); | 3446 __ AllocateAsciiSlicedString(rax, rbx, r14, &runtime); |
| 3965 __ jmp(&set_slice_header, Label::kNear); | 3447 __ jmp(&set_slice_header, Label::kNear); |
| 3966 __ bind(&two_byte_slice); | 3448 __ bind(&two_byte_slice); |
| 3967 __ AllocateTwoByteSlicedString(rax, rbx, r14, &runtime); | 3449 __ AllocateTwoByteSlicedString(rax, rbx, r14, &runtime); |
| 3968 __ bind(&set_slice_header); | 3450 __ bind(&set_slice_header); |
| 3969 __ Integer32ToSmi(rcx, rcx); | 3451 __ Integer32ToSmi(rcx, rcx); |
| 3970 __ movq(FieldOperand(rax, SlicedString::kLengthOffset), rcx); | 3452 __ movp(FieldOperand(rax, SlicedString::kLengthOffset), rcx); |
| 3971 __ movq(FieldOperand(rax, SlicedString::kHashFieldOffset), | 3453 __ movp(FieldOperand(rax, SlicedString::kHashFieldOffset), |
| 3972 Immediate(String::kEmptyHashField)); | 3454 Immediate(String::kEmptyHashField)); |
| 3973 __ movq(FieldOperand(rax, SlicedString::kParentOffset), rdi); | 3455 __ movp(FieldOperand(rax, SlicedString::kParentOffset), rdi); |
| 3974 __ movq(FieldOperand(rax, SlicedString::kOffsetOffset), rdx); | 3456 __ movp(FieldOperand(rax, SlicedString::kOffsetOffset), rdx); |
| 3975 __ IncrementCounter(counters->sub_string_native(), 1); | 3457 __ IncrementCounter(counters->sub_string_native(), 1); |
| 3976 __ ret(3 * kPointerSize); | 3458 __ ret(3 * kPointerSize); |
| 3977 | 3459 |
| 3978 __ bind(©_routine); | 3460 __ bind(©_routine); |
| 3979 } | 3461 } |
| 3980 | 3462 |
| 3981 // rdi: underlying subject string | 3463 // rdi: underlying subject string |
| 3982 // rbx: instance type of underlying subject string | 3464 // rbx: instance type of underlying subject string |
| 3983 // rdx: adjusted start index (smi) | 3465 // rdx: adjusted start index (smi) |
| 3984 // rcx: length | 3466 // rcx: length |
| 3985 // The subject string can only be external or sequential string of either | 3467 // The subject string can only be external or sequential string of either |
| 3986 // encoding at this point. | 3468 // encoding at this point. |
| 3987 Label two_byte_sequential, sequential_string; | 3469 Label two_byte_sequential, sequential_string; |
| 3988 STATIC_ASSERT(kExternalStringTag != 0); | 3470 STATIC_ASSERT(kExternalStringTag != 0); |
| 3989 STATIC_ASSERT(kSeqStringTag == 0); | 3471 STATIC_ASSERT(kSeqStringTag == 0); |
| 3990 __ testb(rbx, Immediate(kExternalStringTag)); | 3472 __ testb(rbx, Immediate(kExternalStringTag)); |
| 3991 __ j(zero, &sequential_string); | 3473 __ j(zero, &sequential_string); |
| 3992 | 3474 |
| 3993 // Handle external string. | 3475 // Handle external string. |
| 3994 // Rule out short external strings. | 3476 // Rule out short external strings. |
| 3995 STATIC_CHECK(kShortExternalStringTag != 0); | 3477 STATIC_CHECK(kShortExternalStringTag != 0); |
| 3996 __ testb(rbx, Immediate(kShortExternalStringMask)); | 3478 __ testb(rbx, Immediate(kShortExternalStringMask)); |
| 3997 __ j(not_zero, &runtime); | 3479 __ j(not_zero, &runtime); |
| 3998 __ movq(rdi, FieldOperand(rdi, ExternalString::kResourceDataOffset)); | 3480 __ movp(rdi, FieldOperand(rdi, ExternalString::kResourceDataOffset)); |
| 3999 // Move the pointer so that offset-wise, it looks like a sequential string. | 3481 // Move the pointer so that offset-wise, it looks like a sequential string. |
| 4000 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); | 3482 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); |
| 4001 __ subq(rdi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 3483 __ subq(rdi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| 4002 | 3484 |
| 4003 __ bind(&sequential_string); | 3485 __ bind(&sequential_string); |
| 4004 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); | 3486 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); |
| 4005 __ testb(rbx, Immediate(kStringEncodingMask)); | 3487 __ testb(rbx, Immediate(kStringEncodingMask)); |
| 4006 __ j(zero, &two_byte_sequential); | 3488 __ j(zero, &two_byte_sequential); |
| 4007 | 3489 |
| 4008 // Allocate the result. | 3490 // Allocate the result. |
| 4009 __ AllocateAsciiString(rax, rcx, r11, r14, r15, &runtime); | 3491 __ AllocateAsciiString(rax, rcx, r11, r14, r15, &runtime); |
| 4010 | 3492 |
| 4011 // rax: result string | 3493 // rax: result string |
| 4012 // rcx: result string length | 3494 // rcx: result string length |
| 4013 __ movq(r14, rsi); // esi used by following code. | 3495 __ movp(r14, rsi); // esi used by following code. |
| 4014 { // Locate character of sub string start. | 3496 { // Locate character of sub string start. |
| 4015 SmiIndex smi_as_index = masm->SmiToIndex(rdx, rdx, times_1); | 3497 SmiIndex smi_as_index = masm->SmiToIndex(rdx, rdx, times_1); |
| 4016 __ lea(rsi, Operand(rdi, smi_as_index.reg, smi_as_index.scale, | 3498 __ lea(rsi, Operand(rdi, smi_as_index.reg, smi_as_index.scale, |
| 4017 SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 3499 SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
| 4018 } | 3500 } |
| 4019 // Locate first character of result. | 3501 // Locate first character of result. |
| 4020 __ lea(rdi, FieldOperand(rax, SeqOneByteString::kHeaderSize)); | 3502 __ lea(rdi, FieldOperand(rax, SeqOneByteString::kHeaderSize)); |
| 4021 | 3503 |
| 4022 // rax: result string | 3504 // rax: result string |
| 4023 // rcx: result length | 3505 // rcx: result length |
| 4024 // rdi: first character of result | 3506 // rdi: first character of result |
| 4025 // rsi: character of sub string start | 3507 // rsi: character of sub string start |
| 4026 // r14: original value of rsi | 3508 // r14: original value of rsi |
| 4027 StringHelper::GenerateCopyCharactersREP(masm, rdi, rsi, rcx, true); | 3509 StringHelper::GenerateCopyCharactersREP(masm, rdi, rsi, rcx, true); |
| 4028 __ movq(rsi, r14); // Restore rsi. | 3510 __ movp(rsi, r14); // Restore rsi. |
| 4029 __ IncrementCounter(counters->sub_string_native(), 1); | 3511 __ IncrementCounter(counters->sub_string_native(), 1); |
| 4030 __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize); | 3512 __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize); |
| 4031 | 3513 |
| 4032 __ bind(&two_byte_sequential); | 3514 __ bind(&two_byte_sequential); |
| 4033 // Allocate the result. | 3515 // Allocate the result. |
| 4034 __ AllocateTwoByteString(rax, rcx, r11, r14, r15, &runtime); | 3516 __ AllocateTwoByteString(rax, rcx, r11, r14, r15, &runtime); |
| 4035 | 3517 |
| 4036 // rax: result string | 3518 // rax: result string |
| 4037 // rcx: result string length | 3519 // rcx: result string length |
| 4038 __ movq(r14, rsi); // esi used by following code. | 3520 __ movp(r14, rsi); // esi used by following code. |
| 4039 { // Locate character of sub string start. | 3521 { // Locate character of sub string start. |
| 4040 SmiIndex smi_as_index = masm->SmiToIndex(rdx, rdx, times_2); | 3522 SmiIndex smi_as_index = masm->SmiToIndex(rdx, rdx, times_2); |
| 4041 __ lea(rsi, Operand(rdi, smi_as_index.reg, smi_as_index.scale, | 3523 __ lea(rsi, Operand(rdi, smi_as_index.reg, smi_as_index.scale, |
| 4042 SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 3524 SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
| 4043 } | 3525 } |
| 4044 // Locate first character of result. | 3526 // Locate first character of result. |
| 4045 __ lea(rdi, FieldOperand(rax, SeqTwoByteString::kHeaderSize)); | 3527 __ lea(rdi, FieldOperand(rax, SeqTwoByteString::kHeaderSize)); |
| 4046 | 3528 |
| 4047 // rax: result string | 3529 // rax: result string |
| 4048 // rcx: result length | 3530 // rcx: result length |
| 4049 // rdi: first character of result | 3531 // rdi: first character of result |
| 4050 // rsi: character of sub string start | 3532 // rsi: character of sub string start |
| 4051 // r14: original value of rsi | 3533 // r14: original value of rsi |
| 4052 StringHelper::GenerateCopyCharactersREP(masm, rdi, rsi, rcx, false); | 3534 StringHelper::GenerateCopyCharactersREP(masm, rdi, rsi, rcx, false); |
| 4053 __ movq(rsi, r14); // Restore esi. | 3535 __ movp(rsi, r14); // Restore esi. |
| 4054 __ IncrementCounter(counters->sub_string_native(), 1); | 3536 __ IncrementCounter(counters->sub_string_native(), 1); |
| 4055 __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize); | 3537 __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize); |
| 4056 | 3538 |
| 4057 // Just jump to runtime to create the sub string. | 3539 // Just jump to runtime to create the sub string. |
| 4058 __ bind(&runtime); | 3540 __ bind(&runtime); |
| 4059 __ TailCallRuntime(Runtime::kSubString, 3, 1); | 3541 __ TailCallRuntime(Runtime::kSubString, 3, 1); |
| 4060 | 3542 |
| 4061 __ bind(&single_char); | 3543 __ bind(&single_char); |
| 4062 // rax: string | 3544 // rax: string |
| 4063 // rbx: instance type | 3545 // rbx: instance type |
| 4064 // rcx: sub string length (smi) | 3546 // rcx: sub string length (smi) |
| 4065 // rdx: from index (smi) | 3547 // rdx: from index (smi) |
| 4066 StringCharAtGenerator generator( | 3548 StringCharAtGenerator generator( |
| 4067 rax, rdx, rcx, rax, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER); | 3549 rax, rdx, rcx, rax, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER); |
| 4068 generator.GenerateFast(masm); | 3550 generator.GenerateFast(masm); |
| 4069 __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize); | 3551 __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize); |
| 4070 generator.SkipSlow(masm, &runtime); | 3552 generator.SkipSlow(masm, &runtime); |
| 4071 } | 3553 } |
| 4072 | 3554 |
| 4073 | 3555 |
| 4074 void StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm, | 3556 void StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm, |
| 4075 Register left, | 3557 Register left, |
| 4076 Register right, | 3558 Register right, |
| 4077 Register scratch1, | 3559 Register scratch1, |
| 4078 Register scratch2) { | 3560 Register scratch2) { |
| 4079 Register length = scratch1; | 3561 Register length = scratch1; |
| 4080 | 3562 |
| 4081 // Compare lengths. | 3563 // Compare lengths. |
| 4082 Label check_zero_length; | 3564 Label check_zero_length; |
| 4083 __ movq(length, FieldOperand(left, String::kLengthOffset)); | 3565 __ movp(length, FieldOperand(left, String::kLengthOffset)); |
| 4084 __ SmiCompare(length, FieldOperand(right, String::kLengthOffset)); | 3566 __ SmiCompare(length, FieldOperand(right, String::kLengthOffset)); |
| 4085 __ j(equal, &check_zero_length, Label::kNear); | 3567 __ j(equal, &check_zero_length, Label::kNear); |
| 4086 __ Move(rax, Smi::FromInt(NOT_EQUAL)); | 3568 __ Move(rax, Smi::FromInt(NOT_EQUAL)); |
| 4087 __ ret(0); | 3569 __ ret(0); |
| 4088 | 3570 |
| 4089 // Check if the length is zero. | 3571 // Check if the length is zero. |
| 4090 Label compare_chars; | 3572 Label compare_chars; |
| 4091 __ bind(&check_zero_length); | 3573 __ bind(&check_zero_length); |
| 4092 STATIC_ASSERT(kSmiTag == 0); | 3574 STATIC_ASSERT(kSmiTag == 0); |
| 4093 __ SmiTest(length); | 3575 __ SmiTest(length); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 4117 Register right, | 3599 Register right, |
| 4118 Register scratch1, | 3600 Register scratch1, |
| 4119 Register scratch2, | 3601 Register scratch2, |
| 4120 Register scratch3, | 3602 Register scratch3, |
| 4121 Register scratch4) { | 3603 Register scratch4) { |
| 4122 // Ensure that you can always subtract a string length from a non-negative | 3604 // Ensure that you can always subtract a string length from a non-negative |
| 4123 // number (e.g. another length). | 3605 // number (e.g. another length). |
| 4124 STATIC_ASSERT(String::kMaxLength < 0x7fffffff); | 3606 STATIC_ASSERT(String::kMaxLength < 0x7fffffff); |
| 4125 | 3607 |
| 4126 // Find minimum length and length difference. | 3608 // Find minimum length and length difference. |
| 4127 __ movq(scratch1, FieldOperand(left, String::kLengthOffset)); | 3609 __ movp(scratch1, FieldOperand(left, String::kLengthOffset)); |
| 4128 __ movq(scratch4, scratch1); | 3610 __ movp(scratch4, scratch1); |
| 4129 __ SmiSub(scratch4, | 3611 __ SmiSub(scratch4, |
| 4130 scratch4, | 3612 scratch4, |
| 4131 FieldOperand(right, String::kLengthOffset)); | 3613 FieldOperand(right, String::kLengthOffset)); |
| 4132 // Register scratch4 now holds left.length - right.length. | 3614 // Register scratch4 now holds left.length - right.length. |
| 4133 const Register length_difference = scratch4; | 3615 const Register length_difference = scratch4; |
| 4134 Label left_shorter; | 3616 Label left_shorter; |
| 4135 __ j(less, &left_shorter, Label::kNear); | 3617 __ j(less, &left_shorter, Label::kNear); |
| 4136 // The right string isn't longer that the left one. | 3618 // The right string isn't longer that the left one. |
| 4137 // Get the right string's length by subtracting the (non-negative) difference | 3619 // Get the right string's length by subtracting the (non-negative) difference |
| 4138 // from the left string's length. | 3620 // from the left string's length. |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4218 | 3700 |
| 4219 void StringCompareStub::Generate(MacroAssembler* masm) { | 3701 void StringCompareStub::Generate(MacroAssembler* masm) { |
| 4220 Label runtime; | 3702 Label runtime; |
| 4221 | 3703 |
| 4222 // Stack frame on entry. | 3704 // Stack frame on entry. |
| 4223 // rsp[0] : return address | 3705 // rsp[0] : return address |
| 4224 // rsp[8] : right string | 3706 // rsp[8] : right string |
| 4225 // rsp[16] : left string | 3707 // rsp[16] : left string |
| 4226 | 3708 |
| 4227 StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER); | 3709 StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 4228 __ movq(rdx, args.GetArgumentOperand(0)); // left | 3710 __ movp(rdx, args.GetArgumentOperand(0)); // left |
| 4229 __ movq(rax, args.GetArgumentOperand(1)); // right | 3711 __ movp(rax, args.GetArgumentOperand(1)); // right |
| 4230 | 3712 |
| 4231 // Check for identity. | 3713 // Check for identity. |
| 4232 Label not_same; | 3714 Label not_same; |
| 4233 __ cmpq(rdx, rax); | 3715 __ cmpq(rdx, rax); |
| 4234 __ j(not_equal, ¬_same, Label::kNear); | 3716 __ j(not_equal, ¬_same, Label::kNear); |
| 4235 __ Move(rax, Smi::FromInt(EQUAL)); | 3717 __ Move(rax, Smi::FromInt(EQUAL)); |
| 4236 Counters* counters = masm->isolate()->counters(); | 3718 Counters* counters = masm->isolate()->counters(); |
| 4237 __ IncrementCounter(counters->string_compare_native(), 1); | 3719 __ IncrementCounter(counters->string_compare_native(), 1); |
| 4238 __ ret(2 * kPointerSize); | 3720 __ ret(2 * kPointerSize); |
| 4239 | 3721 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 4250 __ PushReturnAddressFrom(rcx); | 3732 __ PushReturnAddressFrom(rcx); |
| 4251 GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, r8); | 3733 GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, r8); |
| 4252 | 3734 |
| 4253 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 3735 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
| 4254 // tagged as a small integer. | 3736 // tagged as a small integer. |
| 4255 __ bind(&runtime); | 3737 __ bind(&runtime); |
| 4256 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 3738 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
| 4257 } | 3739 } |
| 4258 | 3740 |
| 4259 | 3741 |
| 3742 void ArrayPushStub::Generate(MacroAssembler* masm) { |
| 3743 int argc = arguments_count(); |
| 3744 |
| 3745 StackArgumentsAccessor args(rsp, argc); |
| 3746 if (argc == 0) { |
| 3747 // Noop, return the length. |
| 3748 __ movp(rax, FieldOperand(rdx, JSArray::kLengthOffset)); |
| 3749 __ ret((argc + 1) * kPointerSize); |
| 3750 return; |
| 3751 } |
| 3752 |
| 3753 Isolate* isolate = masm->isolate(); |
| 3754 |
| 3755 if (argc != 1) { |
| 3756 __ TailCallExternalReference( |
| 3757 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1); |
| 3758 return; |
| 3759 } |
| 3760 |
| 3761 Label call_builtin, attempt_to_grow_elements, with_write_barrier; |
| 3762 |
| 3763 // Get the elements array of the object. |
| 3764 __ movp(rdi, FieldOperand(rdx, JSArray::kElementsOffset)); |
| 3765 |
| 3766 if (IsFastSmiOrObjectElementsKind(elements_kind())) { |
| 3767 // Check that the elements are in fast mode and writable. |
| 3768 __ Cmp(FieldOperand(rdi, HeapObject::kMapOffset), |
| 3769 isolate->factory()->fixed_array_map()); |
| 3770 __ j(not_equal, &call_builtin); |
| 3771 } |
| 3772 |
| 3773 // Get the array's length into rax and calculate new length. |
| 3774 __ SmiToInteger32(rax, FieldOperand(rdx, JSArray::kLengthOffset)); |
| 3775 STATIC_ASSERT(FixedArray::kMaxLength < Smi::kMaxValue); |
| 3776 __ addl(rax, Immediate(argc)); |
| 3777 |
| 3778 // Get the elements' length into rcx. |
| 3779 __ SmiToInteger32(rcx, FieldOperand(rdi, FixedArray::kLengthOffset)); |
| 3780 |
| 3781 // Check if we could survive without allocation. |
| 3782 __ cmpl(rax, rcx); |
| 3783 |
| 3784 if (IsFastSmiOrObjectElementsKind(elements_kind())) { |
| 3785 __ j(greater, &attempt_to_grow_elements); |
| 3786 |
| 3787 // Check if value is a smi. |
| 3788 __ movp(rcx, args.GetArgumentOperand(1)); |
| 3789 __ JumpIfNotSmi(rcx, &with_write_barrier); |
| 3790 |
| 3791 // Store the value. |
| 3792 __ movp(FieldOperand(rdi, |
| 3793 rax, |
| 3794 times_pointer_size, |
| 3795 FixedArray::kHeaderSize - argc * kPointerSize), |
| 3796 rcx); |
| 3797 } else { |
| 3798 __ j(greater, &call_builtin); |
| 3799 |
| 3800 __ movp(rcx, args.GetArgumentOperand(1)); |
| 3801 __ StoreNumberToDoubleElements( |
| 3802 rcx, rdi, rax, xmm0, &call_builtin, argc * kDoubleSize); |
| 3803 } |
| 3804 |
| 3805 // Save new length. |
| 3806 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax); |
| 3807 |
| 3808 __ Integer32ToSmi(rax, rax); // Return new length as smi. |
| 3809 __ ret((argc + 1) * kPointerSize); |
| 3810 |
| 3811 if (IsFastDoubleElementsKind(elements_kind())) { |
| 3812 __ bind(&call_builtin); |
| 3813 __ TailCallExternalReference( |
| 3814 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1); |
| 3815 return; |
| 3816 } |
| 3817 |
| 3818 __ bind(&with_write_barrier); |
| 3819 |
| 3820 if (IsFastSmiElementsKind(elements_kind())) { |
| 3821 if (FLAG_trace_elements_transitions) __ jmp(&call_builtin); |
| 3822 |
| 3823 __ Cmp(FieldOperand(rcx, HeapObject::kMapOffset), |
| 3824 isolate->factory()->heap_number_map()); |
| 3825 __ j(equal, &call_builtin); |
| 3826 |
| 3827 ElementsKind target_kind = IsHoleyElementsKind(elements_kind()) |
| 3828 ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS; |
| 3829 __ movp(rbx, ContextOperand(rsi, Context::GLOBAL_OBJECT_INDEX)); |
| 3830 __ movp(rbx, FieldOperand(rbx, GlobalObject::kNativeContextOffset)); |
| 3831 __ movp(rbx, ContextOperand(rbx, Context::JS_ARRAY_MAPS_INDEX)); |
| 3832 const int header_size = FixedArrayBase::kHeaderSize; |
| 3833 // Verify that the object can be transitioned in place. |
| 3834 const int origin_offset = header_size + elements_kind() * kPointerSize; |
| 3835 __ movp(rdi, FieldOperand(rbx, origin_offset)); |
| 3836 __ cmpq(rdi, FieldOperand(rdx, HeapObject::kMapOffset)); |
| 3837 __ j(not_equal, &call_builtin); |
| 3838 |
| 3839 const int target_offset = header_size + target_kind * kPointerSize; |
| 3840 __ movp(rbx, FieldOperand(rbx, target_offset)); |
| 3841 ElementsTransitionGenerator::GenerateMapChangeElementsTransition( |
| 3842 masm, DONT_TRACK_ALLOCATION_SITE, NULL); |
| 3843 __ movp(rdi, FieldOperand(rdx, JSArray::kElementsOffset)); |
| 3844 } |
| 3845 |
| 3846 // Save new length. |
| 3847 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax); |
| 3848 |
| 3849 // Store the value. |
| 3850 __ lea(rdx, FieldOperand(rdi, |
| 3851 rax, times_pointer_size, |
| 3852 FixedArray::kHeaderSize - argc * kPointerSize)); |
| 3853 __ movp(Operand(rdx, 0), rcx); |
| 3854 |
| 3855 __ RecordWrite(rdi, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, |
| 3856 OMIT_SMI_CHECK); |
| 3857 |
| 3858 __ Integer32ToSmi(rax, rax); // Return new length as smi. |
| 3859 __ ret((argc + 1) * kPointerSize); |
| 3860 |
| 3861 __ bind(&attempt_to_grow_elements); |
| 3862 if (!FLAG_inline_new) { |
| 3863 __ bind(&call_builtin); |
| 3864 __ TailCallExternalReference( |
| 3865 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1); |
| 3866 return; |
| 3867 } |
| 3868 |
| 3869 __ movp(rbx, args.GetArgumentOperand(1)); |
| 3870 // Growing elements that are SMI-only requires special handling in case the |
| 3871 // new element is non-Smi. For now, delegate to the builtin. |
| 3872 Label no_fast_elements_check; |
| 3873 __ JumpIfSmi(rbx, &no_fast_elements_check); |
| 3874 __ movp(rcx, FieldOperand(rdx, HeapObject::kMapOffset)); |
| 3875 __ CheckFastObjectElements(rcx, &call_builtin, Label::kFar); |
| 3876 __ bind(&no_fast_elements_check); |
| 3877 |
| 3878 ExternalReference new_space_allocation_top = |
| 3879 ExternalReference::new_space_allocation_top_address(isolate); |
| 3880 ExternalReference new_space_allocation_limit = |
| 3881 ExternalReference::new_space_allocation_limit_address(isolate); |
| 3882 |
| 3883 const int kAllocationDelta = 4; |
| 3884 ASSERT(kAllocationDelta >= argc); |
| 3885 // Load top. |
| 3886 __ Load(rcx, new_space_allocation_top); |
| 3887 |
| 3888 // Check if it's the end of elements. |
| 3889 __ lea(rdx, FieldOperand(rdi, |
| 3890 rax, times_pointer_size, |
| 3891 FixedArray::kHeaderSize - argc * kPointerSize)); |
| 3892 __ cmpq(rdx, rcx); |
| 3893 __ j(not_equal, &call_builtin); |
| 3894 __ addq(rcx, Immediate(kAllocationDelta * kPointerSize)); |
| 3895 Operand limit_operand = masm->ExternalOperand(new_space_allocation_limit); |
| 3896 __ cmpq(rcx, limit_operand); |
| 3897 __ j(above, &call_builtin); |
| 3898 |
| 3899 // We fit and could grow elements. |
| 3900 __ Store(new_space_allocation_top, rcx); |
| 3901 |
| 3902 // Push the argument... |
| 3903 __ movp(Operand(rdx, 0), rbx); |
| 3904 // ... and fill the rest with holes. |
| 3905 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
| 3906 for (int i = 1; i < kAllocationDelta; i++) { |
| 3907 __ movp(Operand(rdx, i * kPointerSize), kScratchRegister); |
| 3908 } |
| 3909 |
| 3910 if (IsFastObjectElementsKind(elements_kind())) { |
| 3911 // We know the elements array is in new space so we don't need the |
| 3912 // remembered set, but we just pushed a value onto it so we may have to tell |
| 3913 // the incremental marker to rescan the object that we just grew. We don't |
| 3914 // need to worry about the holes because they are in old space and already |
| 3915 // marked black. |
| 3916 __ RecordWrite(rdi, rdx, rbx, kDontSaveFPRegs, OMIT_REMEMBERED_SET); |
| 3917 } |
| 3918 |
| 3919 // Restore receiver to rdx as finish sequence assumes it's here. |
| 3920 __ movp(rdx, args.GetReceiverOperand()); |
| 3921 |
| 3922 // Increment element's and array's sizes. |
| 3923 __ SmiAddConstant(FieldOperand(rdi, FixedArray::kLengthOffset), |
| 3924 Smi::FromInt(kAllocationDelta)); |
| 3925 |
| 3926 // Make new length a smi before returning it. |
| 3927 __ Integer32ToSmi(rax, rax); |
| 3928 __ movp(FieldOperand(rdx, JSArray::kLengthOffset), rax); |
| 3929 |
| 3930 __ ret((argc + 1) * kPointerSize); |
| 3931 |
| 3932 __ bind(&call_builtin); |
| 3933 __ TailCallExternalReference( |
| 3934 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1); |
| 3935 } |
| 3936 |
| 3937 |
| 4260 void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) { | 3938 void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) { |
| 4261 // ----------- S t a t e ------------- | 3939 // ----------- S t a t e ------------- |
| 4262 // -- rdx : left | 3940 // -- rdx : left |
| 4263 // -- rax : right | 3941 // -- rax : right |
| 4264 // -- rsp[0] : return address | 3942 // -- rsp[0] : return address |
| 4265 // ----------------------------------- | 3943 // ----------------------------------- |
| 4266 Isolate* isolate = masm->isolate(); | 3944 Isolate* isolate = masm->isolate(); |
| 4267 | 3945 |
| 4268 // Load rcx with the allocation site. We stick an undefined dummy value here | 3946 // Load rcx with the allocation site. We stick an undefined dummy value here |
| 4269 // and replace it with the real allocation site later when we instantiate this | 3947 // and replace it with the real allocation site later when we instantiate this |
| (...skipping 24 matching lines...) Expand all Loading... |
| 4294 if (GetCondition() == equal) { | 3972 if (GetCondition() == equal) { |
| 4295 // For equality we do not care about the sign of the result. | 3973 // For equality we do not care about the sign of the result. |
| 4296 __ subq(rax, rdx); | 3974 __ subq(rax, rdx); |
| 4297 } else { | 3975 } else { |
| 4298 Label done; | 3976 Label done; |
| 4299 __ subq(rdx, rax); | 3977 __ subq(rdx, rax); |
| 4300 __ j(no_overflow, &done, Label::kNear); | 3978 __ j(no_overflow, &done, Label::kNear); |
| 4301 // Correct sign of result in case of overflow. | 3979 // Correct sign of result in case of overflow. |
| 4302 __ not_(rdx); | 3980 __ not_(rdx); |
| 4303 __ bind(&done); | 3981 __ bind(&done); |
| 4304 __ movq(rax, rdx); | 3982 __ movp(rax, rdx); |
| 4305 } | 3983 } |
| 4306 __ ret(0); | 3984 __ ret(0); |
| 4307 | 3985 |
| 4308 __ bind(&miss); | 3986 __ bind(&miss); |
| 4309 GenerateMiss(masm); | 3987 GenerateMiss(masm); |
| 4310 } | 3988 } |
| 4311 | 3989 |
| 4312 | 3990 |
| 4313 void ICCompareStub::GenerateNumbers(MacroAssembler* masm) { | 3991 void ICCompareStub::GenerateNumbers(MacroAssembler* masm) { |
| 4314 ASSERT(state_ == CompareIC::NUMBER); | 3992 ASSERT(state_ == CompareIC::NUMBER); |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4396 Register right = rax; | 4074 Register right = rax; |
| 4397 Register tmp1 = rcx; | 4075 Register tmp1 = rcx; |
| 4398 Register tmp2 = rbx; | 4076 Register tmp2 = rbx; |
| 4399 | 4077 |
| 4400 // Check that both operands are heap objects. | 4078 // Check that both operands are heap objects. |
| 4401 Label miss; | 4079 Label miss; |
| 4402 Condition cond = masm->CheckEitherSmi(left, right, tmp1); | 4080 Condition cond = masm->CheckEitherSmi(left, right, tmp1); |
| 4403 __ j(cond, &miss, Label::kNear); | 4081 __ j(cond, &miss, Label::kNear); |
| 4404 | 4082 |
| 4405 // Check that both operands are internalized strings. | 4083 // Check that both operands are internalized strings. |
| 4406 __ movq(tmp1, FieldOperand(left, HeapObject::kMapOffset)); | 4084 __ movp(tmp1, FieldOperand(left, HeapObject::kMapOffset)); |
| 4407 __ movq(tmp2, FieldOperand(right, HeapObject::kMapOffset)); | 4085 __ movp(tmp2, FieldOperand(right, HeapObject::kMapOffset)); |
| 4408 __ movzxbq(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); | 4086 __ movzxbq(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); |
| 4409 __ movzxbq(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); | 4087 __ movzxbq(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); |
| 4410 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); | 4088 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); |
| 4411 __ or_(tmp1, tmp2); | 4089 __ or_(tmp1, tmp2); |
| 4412 __ testb(tmp1, Immediate(kIsNotStringMask | kIsNotInternalizedMask)); | 4090 __ testb(tmp1, Immediate(kIsNotStringMask | kIsNotInternalizedMask)); |
| 4413 __ j(not_zero, &miss, Label::kNear); | 4091 __ j(not_zero, &miss, Label::kNear); |
| 4414 | 4092 |
| 4415 // Internalized strings are compared by identity. | 4093 // Internalized strings are compared by identity. |
| 4416 Label done; | 4094 Label done; |
| 4417 __ cmpq(left, right); | 4095 __ cmpq(left, right); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 4440 Register tmp1 = rcx; | 4118 Register tmp1 = rcx; |
| 4441 Register tmp2 = rbx; | 4119 Register tmp2 = rbx; |
| 4442 | 4120 |
| 4443 // Check that both operands are heap objects. | 4121 // Check that both operands are heap objects. |
| 4444 Label miss; | 4122 Label miss; |
| 4445 Condition cond = masm->CheckEitherSmi(left, right, tmp1); | 4123 Condition cond = masm->CheckEitherSmi(left, right, tmp1); |
| 4446 __ j(cond, &miss, Label::kNear); | 4124 __ j(cond, &miss, Label::kNear); |
| 4447 | 4125 |
| 4448 // Check that both operands are unique names. This leaves the instance | 4126 // Check that both operands are unique names. This leaves the instance |
| 4449 // types loaded in tmp1 and tmp2. | 4127 // types loaded in tmp1 and tmp2. |
| 4450 __ movq(tmp1, FieldOperand(left, HeapObject::kMapOffset)); | 4128 __ movp(tmp1, FieldOperand(left, HeapObject::kMapOffset)); |
| 4451 __ movq(tmp2, FieldOperand(right, HeapObject::kMapOffset)); | 4129 __ movp(tmp2, FieldOperand(right, HeapObject::kMapOffset)); |
| 4452 __ movzxbq(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); | 4130 __ movzxbq(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); |
| 4453 __ movzxbq(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); | 4131 __ movzxbq(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); |
| 4454 | 4132 |
| 4455 __ JumpIfNotUniqueName(tmp1, &miss, Label::kNear); | 4133 __ JumpIfNotUniqueName(tmp1, &miss, Label::kNear); |
| 4456 __ JumpIfNotUniqueName(tmp2, &miss, Label::kNear); | 4134 __ JumpIfNotUniqueName(tmp2, &miss, Label::kNear); |
| 4457 | 4135 |
| 4458 // Unique names are compared by identity. | 4136 // Unique names are compared by identity. |
| 4459 Label done; | 4137 Label done; |
| 4460 __ cmpq(left, right); | 4138 __ cmpq(left, right); |
| 4461 // Make sure rax is non-zero. At this point input operands are | 4139 // Make sure rax is non-zero. At this point input operands are |
| (...skipping 23 matching lines...) Expand all Loading... |
| 4485 Register tmp1 = rcx; | 4163 Register tmp1 = rcx; |
| 4486 Register tmp2 = rbx; | 4164 Register tmp2 = rbx; |
| 4487 Register tmp3 = rdi; | 4165 Register tmp3 = rdi; |
| 4488 | 4166 |
| 4489 // Check that both operands are heap objects. | 4167 // Check that both operands are heap objects. |
| 4490 Condition cond = masm->CheckEitherSmi(left, right, tmp1); | 4168 Condition cond = masm->CheckEitherSmi(left, right, tmp1); |
| 4491 __ j(cond, &miss); | 4169 __ j(cond, &miss); |
| 4492 | 4170 |
| 4493 // Check that both operands are strings. This leaves the instance | 4171 // Check that both operands are strings. This leaves the instance |
| 4494 // types loaded in tmp1 and tmp2. | 4172 // types loaded in tmp1 and tmp2. |
| 4495 __ movq(tmp1, FieldOperand(left, HeapObject::kMapOffset)); | 4173 __ movp(tmp1, FieldOperand(left, HeapObject::kMapOffset)); |
| 4496 __ movq(tmp2, FieldOperand(right, HeapObject::kMapOffset)); | 4174 __ movp(tmp2, FieldOperand(right, HeapObject::kMapOffset)); |
| 4497 __ movzxbq(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); | 4175 __ movzxbq(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); |
| 4498 __ movzxbq(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); | 4176 __ movzxbq(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); |
| 4499 __ movq(tmp3, tmp1); | 4177 __ movp(tmp3, tmp1); |
| 4500 STATIC_ASSERT(kNotStringTag != 0); | 4178 STATIC_ASSERT(kNotStringTag != 0); |
| 4501 __ or_(tmp3, tmp2); | 4179 __ or_(tmp3, tmp2); |
| 4502 __ testb(tmp3, Immediate(kIsNotStringMask)); | 4180 __ testb(tmp3, Immediate(kIsNotStringMask)); |
| 4503 __ j(not_zero, &miss); | 4181 __ j(not_zero, &miss); |
| 4504 | 4182 |
| 4505 // Fast check for identical strings. | 4183 // Fast check for identical strings. |
| 4506 Label not_same; | 4184 Label not_same; |
| 4507 __ cmpq(left, right); | 4185 __ cmpq(left, right); |
| 4508 __ j(not_equal, ¬_same, Label::kNear); | 4186 __ j(not_equal, ¬_same, Label::kNear); |
| 4509 STATIC_ASSERT(EQUAL == 0); | 4187 STATIC_ASSERT(EQUAL == 0); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4578 __ bind(&miss); | 4256 __ bind(&miss); |
| 4579 GenerateMiss(masm); | 4257 GenerateMiss(masm); |
| 4580 } | 4258 } |
| 4581 | 4259 |
| 4582 | 4260 |
| 4583 void ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) { | 4261 void ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) { |
| 4584 Label miss; | 4262 Label miss; |
| 4585 Condition either_smi = masm->CheckEitherSmi(rdx, rax); | 4263 Condition either_smi = masm->CheckEitherSmi(rdx, rax); |
| 4586 __ j(either_smi, &miss, Label::kNear); | 4264 __ j(either_smi, &miss, Label::kNear); |
| 4587 | 4265 |
| 4588 __ movq(rcx, FieldOperand(rax, HeapObject::kMapOffset)); | 4266 __ movp(rcx, FieldOperand(rax, HeapObject::kMapOffset)); |
| 4589 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); | 4267 __ movp(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); |
| 4590 __ Cmp(rcx, known_map_); | 4268 __ Cmp(rcx, known_map_); |
| 4591 __ j(not_equal, &miss, Label::kNear); | 4269 __ j(not_equal, &miss, Label::kNear); |
| 4592 __ Cmp(rbx, known_map_); | 4270 __ Cmp(rbx, known_map_); |
| 4593 __ j(not_equal, &miss, Label::kNear); | 4271 __ j(not_equal, &miss, Label::kNear); |
| 4594 | 4272 |
| 4595 __ subq(rax, rdx); | 4273 __ subq(rax, rdx); |
| 4596 __ ret(0); | 4274 __ ret(0); |
| 4597 | 4275 |
| 4598 __ bind(&miss); | 4276 __ bind(&miss); |
| 4599 GenerateMiss(masm); | 4277 GenerateMiss(masm); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4647 __ and_(index, | 4325 __ and_(index, |
| 4648 Immediate(name->Hash() + NameDictionary::GetProbeOffset(i))); | 4326 Immediate(name->Hash() + NameDictionary::GetProbeOffset(i))); |
| 4649 | 4327 |
| 4650 // Scale the index by multiplying by the entry size. | 4328 // Scale the index by multiplying by the entry size. |
| 4651 ASSERT(NameDictionary::kEntrySize == 3); | 4329 ASSERT(NameDictionary::kEntrySize == 3); |
| 4652 __ lea(index, Operand(index, index, times_2, 0)); // index *= 3. | 4330 __ lea(index, Operand(index, index, times_2, 0)); // index *= 3. |
| 4653 | 4331 |
| 4654 Register entity_name = r0; | 4332 Register entity_name = r0; |
| 4655 // Having undefined at this place means the name is not contained. | 4333 // Having undefined at this place means the name is not contained. |
| 4656 ASSERT_EQ(kSmiTagSize, 1); | 4334 ASSERT_EQ(kSmiTagSize, 1); |
| 4657 __ movq(entity_name, Operand(properties, | 4335 __ movp(entity_name, Operand(properties, |
| 4658 index, | 4336 index, |
| 4659 times_pointer_size, | 4337 times_pointer_size, |
| 4660 kElementsStartOffset - kHeapObjectTag)); | 4338 kElementsStartOffset - kHeapObjectTag)); |
| 4661 __ Cmp(entity_name, masm->isolate()->factory()->undefined_value()); | 4339 __ Cmp(entity_name, masm->isolate()->factory()->undefined_value()); |
| 4662 __ j(equal, done); | 4340 __ j(equal, done); |
| 4663 | 4341 |
| 4664 // Stop if found the property. | 4342 // Stop if found the property. |
| 4665 __ Cmp(entity_name, Handle<Name>(name)); | 4343 __ Cmp(entity_name, Handle<Name>(name)); |
| 4666 __ j(equal, miss); | 4344 __ j(equal, miss); |
| 4667 | 4345 |
| 4668 Label good; | 4346 Label good; |
| 4669 // Check for the hole and skip. | 4347 // Check for the hole and skip. |
| 4670 __ CompareRoot(entity_name, Heap::kTheHoleValueRootIndex); | 4348 __ CompareRoot(entity_name, Heap::kTheHoleValueRootIndex); |
| 4671 __ j(equal, &good, Label::kNear); | 4349 __ j(equal, &good, Label::kNear); |
| 4672 | 4350 |
| 4673 // Check if the entry name is not a unique name. | 4351 // Check if the entry name is not a unique name. |
| 4674 __ movq(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset)); | 4352 __ movp(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset)); |
| 4675 __ JumpIfNotUniqueName(FieldOperand(entity_name, Map::kInstanceTypeOffset), | 4353 __ JumpIfNotUniqueName(FieldOperand(entity_name, Map::kInstanceTypeOffset), |
| 4676 miss); | 4354 miss); |
| 4677 __ bind(&good); | 4355 __ bind(&good); |
| 4678 } | 4356 } |
| 4679 | 4357 |
| 4680 NameDictionaryLookupStub stub(properties, r0, r0, NEGATIVE_LOOKUP); | 4358 NameDictionaryLookupStub stub(properties, r0, r0, NEGATIVE_LOOKUP); |
| 4681 __ Push(Handle<Object>(name)); | 4359 __ Push(Handle<Object>(name)); |
| 4682 __ push(Immediate(name->Hash())); | 4360 __ push(Immediate(name->Hash())); |
| 4683 __ CallStub(&stub); | 4361 __ CallStub(&stub); |
| 4684 __ testq(r0, r0); | 4362 __ testq(r0, r0); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4765 | 4443 |
| 4766 // If names of slots in range from 1 to kProbes - 1 for the hash value are | 4444 // If names of slots in range from 1 to kProbes - 1 for the hash value are |
| 4767 // not equal to the name and kProbes-th slot is not used (its name is the | 4445 // not equal to the name and kProbes-th slot is not used (its name is the |
| 4768 // undefined value), it guarantees the hash table doesn't contain the | 4446 // undefined value), it guarantees the hash table doesn't contain the |
| 4769 // property. It's true even if some slots represent deleted properties | 4447 // property. It's true even if some slots represent deleted properties |
| 4770 // (their names are the null value). | 4448 // (their names are the null value). |
| 4771 StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER, | 4449 StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER, |
| 4772 kPointerSize); | 4450 kPointerSize); |
| 4773 for (int i = kInlinedProbes; i < kTotalProbes; i++) { | 4451 for (int i = kInlinedProbes; i < kTotalProbes; i++) { |
| 4774 // Compute the masked index: (hash + i + i * i) & mask. | 4452 // Compute the masked index: (hash + i + i * i) & mask. |
| 4775 __ movq(scratch, args.GetArgumentOperand(1)); | 4453 __ movp(scratch, args.GetArgumentOperand(1)); |
| 4776 if (i > 0) { | 4454 if (i > 0) { |
| 4777 __ addl(scratch, Immediate(NameDictionary::GetProbeOffset(i))); | 4455 __ addl(scratch, Immediate(NameDictionary::GetProbeOffset(i))); |
| 4778 } | 4456 } |
| 4779 __ and_(scratch, Operand(rsp, 0)); | 4457 __ and_(scratch, Operand(rsp, 0)); |
| 4780 | 4458 |
| 4781 // Scale the index by multiplying by the entry size. | 4459 // Scale the index by multiplying by the entry size. |
| 4782 ASSERT(NameDictionary::kEntrySize == 3); | 4460 ASSERT(NameDictionary::kEntrySize == 3); |
| 4783 __ lea(index_, Operand(scratch, scratch, times_2, 0)); // index *= 3. | 4461 __ lea(index_, Operand(scratch, scratch, times_2, 0)); // index *= 3. |
| 4784 | 4462 |
| 4785 // Having undefined at this place means the name is not contained. | 4463 // Having undefined at this place means the name is not contained. |
| 4786 __ movq(scratch, Operand(dictionary_, | 4464 __ movp(scratch, Operand(dictionary_, |
| 4787 index_, | 4465 index_, |
| 4788 times_pointer_size, | 4466 times_pointer_size, |
| 4789 kElementsStartOffset - kHeapObjectTag)); | 4467 kElementsStartOffset - kHeapObjectTag)); |
| 4790 | 4468 |
| 4791 __ Cmp(scratch, masm->isolate()->factory()->undefined_value()); | 4469 __ Cmp(scratch, masm->isolate()->factory()->undefined_value()); |
| 4792 __ j(equal, ¬_in_dictionary); | 4470 __ j(equal, ¬_in_dictionary); |
| 4793 | 4471 |
| 4794 // Stop if found the property. | 4472 // Stop if found the property. |
| 4795 __ cmpq(scratch, args.GetArgumentOperand(0)); | 4473 __ cmpq(scratch, args.GetArgumentOperand(0)); |
| 4796 __ j(equal, &in_dictionary); | 4474 __ j(equal, &in_dictionary); |
| 4797 | 4475 |
| 4798 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { | 4476 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { |
| 4799 // If we hit a key that is not a unique name during negative | 4477 // If we hit a key that is not a unique name during negative |
| 4800 // lookup we have to bailout as this key might be equal to the | 4478 // lookup we have to bailout as this key might be equal to the |
| 4801 // key we are looking for. | 4479 // key we are looking for. |
| 4802 | 4480 |
| 4803 // Check if the entry name is not a unique name. | 4481 // Check if the entry name is not a unique name. |
| 4804 __ movq(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); | 4482 __ movp(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); |
| 4805 __ JumpIfNotUniqueName(FieldOperand(scratch, Map::kInstanceTypeOffset), | 4483 __ JumpIfNotUniqueName(FieldOperand(scratch, Map::kInstanceTypeOffset), |
| 4806 &maybe_in_dictionary); | 4484 &maybe_in_dictionary); |
| 4807 } | 4485 } |
| 4808 } | 4486 } |
| 4809 | 4487 |
| 4810 __ bind(&maybe_in_dictionary); | 4488 __ bind(&maybe_in_dictionary); |
| 4811 // If we are doing negative lookup then probing failure should be | 4489 // If we are doing negative lookup then probing failure should be |
| 4812 // treated as a lookup success. For positive lookup probing failure | 4490 // treated as a lookup success. For positive lookup probing failure |
| 4813 // should be treated as lookup failure. | 4491 // should be treated as lookup failure. |
| 4814 if (mode_ == POSITIVE_LOOKUP) { | 4492 if (mode_ == POSITIVE_LOOKUP) { |
| 4815 __ movq(scratch, Immediate(0)); | 4493 __ movp(scratch, Immediate(0)); |
| 4816 __ Drop(1); | 4494 __ Drop(1); |
| 4817 __ ret(2 * kPointerSize); | 4495 __ ret(2 * kPointerSize); |
| 4818 } | 4496 } |
| 4819 | 4497 |
| 4820 __ bind(&in_dictionary); | 4498 __ bind(&in_dictionary); |
| 4821 __ movq(scratch, Immediate(1)); | 4499 __ movp(scratch, Immediate(1)); |
| 4822 __ Drop(1); | 4500 __ Drop(1); |
| 4823 __ ret(2 * kPointerSize); | 4501 __ ret(2 * kPointerSize); |
| 4824 | 4502 |
| 4825 __ bind(¬_in_dictionary); | 4503 __ bind(¬_in_dictionary); |
| 4826 __ movq(scratch, Immediate(0)); | 4504 __ movp(scratch, Immediate(0)); |
| 4827 __ Drop(1); | 4505 __ Drop(1); |
| 4828 __ ret(2 * kPointerSize); | 4506 __ ret(2 * kPointerSize); |
| 4829 } | 4507 } |
| 4830 | 4508 |
| 4831 | 4509 |
| 4832 void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime( | 4510 void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime( |
| 4833 Isolate* isolate) { | 4511 Isolate* isolate) { |
| 4834 StoreBufferOverflowStub stub1(kDontSaveFPRegs); | 4512 StoreBufferOverflowStub stub1(kDontSaveFPRegs); |
| 4835 stub1.GetCode(isolate); | 4513 stub1.GetCode(isolate); |
| 4836 StoreBufferOverflowStub stub2(kSaveFPRegs); | 4514 StoreBufferOverflowStub stub2(kSaveFPRegs); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4881 masm->set_byte_at(2, kFiveByteNopInstruction); | 4559 masm->set_byte_at(2, kFiveByteNopInstruction); |
| 4882 } | 4560 } |
| 4883 | 4561 |
| 4884 | 4562 |
| 4885 void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) { | 4563 void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) { |
| 4886 regs_.Save(masm); | 4564 regs_.Save(masm); |
| 4887 | 4565 |
| 4888 if (remembered_set_action_ == EMIT_REMEMBERED_SET) { | 4566 if (remembered_set_action_ == EMIT_REMEMBERED_SET) { |
| 4889 Label dont_need_remembered_set; | 4567 Label dont_need_remembered_set; |
| 4890 | 4568 |
| 4891 __ movq(regs_.scratch0(), Operand(regs_.address(), 0)); | 4569 __ movp(regs_.scratch0(), Operand(regs_.address(), 0)); |
| 4892 __ JumpIfNotInNewSpace(regs_.scratch0(), | 4570 __ JumpIfNotInNewSpace(regs_.scratch0(), |
| 4893 regs_.scratch0(), | 4571 regs_.scratch0(), |
| 4894 &dont_need_remembered_set); | 4572 &dont_need_remembered_set); |
| 4895 | 4573 |
| 4896 __ CheckPageFlag(regs_.object(), | 4574 __ CheckPageFlag(regs_.object(), |
| 4897 regs_.scratch0(), | 4575 regs_.scratch0(), |
| 4898 1 << MemoryChunk::SCAN_ON_SCAVENGE, | 4576 1 << MemoryChunk::SCAN_ON_SCAVENGE, |
| 4899 not_zero, | 4577 not_zero, |
| 4900 &dont_need_remembered_set); | 4578 &dont_need_remembered_set); |
| 4901 | 4579 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4955 | 4633 |
| 4956 | 4634 |
| 4957 void RecordWriteStub::CheckNeedsToInformIncrementalMarker( | 4635 void RecordWriteStub::CheckNeedsToInformIncrementalMarker( |
| 4958 MacroAssembler* masm, | 4636 MacroAssembler* masm, |
| 4959 OnNoNeedToInformIncrementalMarker on_no_need, | 4637 OnNoNeedToInformIncrementalMarker on_no_need, |
| 4960 Mode mode) { | 4638 Mode mode) { |
| 4961 Label on_black; | 4639 Label on_black; |
| 4962 Label need_incremental; | 4640 Label need_incremental; |
| 4963 Label need_incremental_pop_object; | 4641 Label need_incremental_pop_object; |
| 4964 | 4642 |
| 4965 __ movq(regs_.scratch0(), Immediate(~Page::kPageAlignmentMask)); | 4643 __ movp(regs_.scratch0(), Immediate(~Page::kPageAlignmentMask)); |
| 4966 __ and_(regs_.scratch0(), regs_.object()); | 4644 __ and_(regs_.scratch0(), regs_.object()); |
| 4967 __ movq(regs_.scratch1(), | 4645 __ movp(regs_.scratch1(), |
| 4968 Operand(regs_.scratch0(), | 4646 Operand(regs_.scratch0(), |
| 4969 MemoryChunk::kWriteBarrierCounterOffset)); | 4647 MemoryChunk::kWriteBarrierCounterOffset)); |
| 4970 __ subq(regs_.scratch1(), Immediate(1)); | 4648 __ subq(regs_.scratch1(), Immediate(1)); |
| 4971 __ movq(Operand(regs_.scratch0(), | 4649 __ movp(Operand(regs_.scratch0(), |
| 4972 MemoryChunk::kWriteBarrierCounterOffset), | 4650 MemoryChunk::kWriteBarrierCounterOffset), |
| 4973 regs_.scratch1()); | 4651 regs_.scratch1()); |
| 4974 __ j(negative, &need_incremental); | 4652 __ j(negative, &need_incremental); |
| 4975 | 4653 |
| 4976 // Let's look at the color of the object: If it is not black we don't have | 4654 // Let's look at the color of the object: If it is not black we don't have |
| 4977 // to inform the incremental marker. | 4655 // to inform the incremental marker. |
| 4978 __ JumpIfBlack(regs_.object(), | 4656 __ JumpIfBlack(regs_.object(), |
| 4979 regs_.scratch0(), | 4657 regs_.scratch0(), |
| 4980 regs_.scratch1(), | 4658 regs_.scratch1(), |
| 4981 &on_black, | 4659 &on_black, |
| 4982 Label::kNear); | 4660 Label::kNear); |
| 4983 | 4661 |
| 4984 regs_.Restore(masm); | 4662 regs_.Restore(masm); |
| 4985 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) { | 4663 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) { |
| 4986 __ RememberedSetHelper(object_, | 4664 __ RememberedSetHelper(object_, |
| 4987 address_, | 4665 address_, |
| 4988 value_, | 4666 value_, |
| 4989 save_fp_regs_mode_, | 4667 save_fp_regs_mode_, |
| 4990 MacroAssembler::kReturnAtEnd); | 4668 MacroAssembler::kReturnAtEnd); |
| 4991 } else { | 4669 } else { |
| 4992 __ ret(0); | 4670 __ ret(0); |
| 4993 } | 4671 } |
| 4994 | 4672 |
| 4995 __ bind(&on_black); | 4673 __ bind(&on_black); |
| 4996 | 4674 |
| 4997 // Get the value from the slot. | 4675 // Get the value from the slot. |
| 4998 __ movq(regs_.scratch0(), Operand(regs_.address(), 0)); | 4676 __ movp(regs_.scratch0(), Operand(regs_.address(), 0)); |
| 4999 | 4677 |
| 5000 if (mode == INCREMENTAL_COMPACTION) { | 4678 if (mode == INCREMENTAL_COMPACTION) { |
| 5001 Label ensure_not_white; | 4679 Label ensure_not_white; |
| 5002 | 4680 |
| 5003 __ CheckPageFlag(regs_.scratch0(), // Contains value. | 4681 __ CheckPageFlag(regs_.scratch0(), // Contains value. |
| 5004 regs_.scratch1(), // Scratch. | 4682 regs_.scratch1(), // Scratch. |
| 5005 MemoryChunk::kEvacuationCandidateMask, | 4683 MemoryChunk::kEvacuationCandidateMask, |
| 5006 zero, | 4684 zero, |
| 5007 &ensure_not_white, | 4685 &ensure_not_white, |
| 5008 Label::kNear); | 4686 Label::kNear); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5057 // ----------------------------------- | 4735 // ----------------------------------- |
| 5058 | 4736 |
| 5059 Label element_done; | 4737 Label element_done; |
| 5060 Label double_elements; | 4738 Label double_elements; |
| 5061 Label smi_element; | 4739 Label smi_element; |
| 5062 Label slow_elements; | 4740 Label slow_elements; |
| 5063 Label fast_elements; | 4741 Label fast_elements; |
| 5064 | 4742 |
| 5065 // Get array literal index, array literal and its map. | 4743 // Get array literal index, array literal and its map. |
| 5066 StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER); | 4744 StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 5067 __ movq(rdx, args.GetArgumentOperand(1)); | 4745 __ movp(rdx, args.GetArgumentOperand(1)); |
| 5068 __ movq(rbx, args.GetArgumentOperand(0)); | 4746 __ movp(rbx, args.GetArgumentOperand(0)); |
| 5069 __ movq(rdi, FieldOperand(rbx, JSObject::kMapOffset)); | 4747 __ movp(rdi, FieldOperand(rbx, JSObject::kMapOffset)); |
| 5070 | 4748 |
| 5071 __ CheckFastElements(rdi, &double_elements); | 4749 __ CheckFastElements(rdi, &double_elements); |
| 5072 | 4750 |
| 5073 // FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS | 4751 // FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS |
| 5074 __ JumpIfSmi(rax, &smi_element); | 4752 __ JumpIfSmi(rax, &smi_element); |
| 5075 __ CheckFastSmiElements(rdi, &fast_elements); | 4753 __ CheckFastSmiElements(rdi, &fast_elements); |
| 5076 | 4754 |
| 5077 // Store into the array literal requires a elements transition. Call into | 4755 // Store into the array literal requires a elements transition. Call into |
| 5078 // the runtime. | 4756 // the runtime. |
| 5079 | 4757 |
| 5080 __ bind(&slow_elements); | 4758 __ bind(&slow_elements); |
| 5081 __ PopReturnAddressTo(rdi); | 4759 __ PopReturnAddressTo(rdi); |
| 5082 __ push(rbx); | 4760 __ push(rbx); |
| 5083 __ push(rcx); | 4761 __ push(rcx); |
| 5084 __ push(rax); | 4762 __ push(rax); |
| 5085 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 4763 __ movp(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 5086 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset)); | 4764 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset)); |
| 5087 __ push(rdx); | 4765 __ push(rdx); |
| 5088 __ PushReturnAddressFrom(rdi); | 4766 __ PushReturnAddressFrom(rdi); |
| 5089 __ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1); | 4767 __ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1); |
| 5090 | 4768 |
| 5091 // Array literal has ElementsKind of FAST_*_ELEMENTS and value is an object. | 4769 // Array literal has ElementsKind of FAST_*_ELEMENTS and value is an object. |
| 5092 __ bind(&fast_elements); | 4770 __ bind(&fast_elements); |
| 5093 __ SmiToInteger32(kScratchRegister, rcx); | 4771 __ SmiToInteger32(kScratchRegister, rcx); |
| 5094 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); | 4772 __ movp(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); |
| 5095 __ lea(rcx, FieldOperand(rbx, kScratchRegister, times_pointer_size, | 4773 __ lea(rcx, FieldOperand(rbx, kScratchRegister, times_pointer_size, |
| 5096 FixedArrayBase::kHeaderSize)); | 4774 FixedArrayBase::kHeaderSize)); |
| 5097 __ movq(Operand(rcx, 0), rax); | 4775 __ movp(Operand(rcx, 0), rax); |
| 5098 // Update the write barrier for the array store. | 4776 // Update the write barrier for the array store. |
| 5099 __ RecordWrite(rbx, rcx, rax, | 4777 __ RecordWrite(rbx, rcx, rax, |
| 5100 kDontSaveFPRegs, | 4778 kDontSaveFPRegs, |
| 5101 EMIT_REMEMBERED_SET, | 4779 EMIT_REMEMBERED_SET, |
| 5102 OMIT_SMI_CHECK); | 4780 OMIT_SMI_CHECK); |
| 5103 __ ret(0); | 4781 __ ret(0); |
| 5104 | 4782 |
| 5105 // Array literal has ElementsKind of FAST_*_SMI_ELEMENTS or | 4783 // Array literal has ElementsKind of FAST_*_SMI_ELEMENTS or |
| 5106 // FAST_*_ELEMENTS, and value is Smi. | 4784 // FAST_*_ELEMENTS, and value is Smi. |
| 5107 __ bind(&smi_element); | 4785 __ bind(&smi_element); |
| 5108 __ SmiToInteger32(kScratchRegister, rcx); | 4786 __ SmiToInteger32(kScratchRegister, rcx); |
| 5109 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); | 4787 __ movp(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); |
| 5110 __ movq(FieldOperand(rbx, kScratchRegister, times_pointer_size, | 4788 __ movp(FieldOperand(rbx, kScratchRegister, times_pointer_size, |
| 5111 FixedArrayBase::kHeaderSize), rax); | 4789 FixedArrayBase::kHeaderSize), rax); |
| 5112 __ ret(0); | 4790 __ ret(0); |
| 5113 | 4791 |
| 5114 // Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS. | 4792 // Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS. |
| 5115 __ bind(&double_elements); | 4793 __ bind(&double_elements); |
| 5116 | 4794 |
| 5117 __ movq(r9, FieldOperand(rbx, JSObject::kElementsOffset)); | 4795 __ movp(r9, FieldOperand(rbx, JSObject::kElementsOffset)); |
| 5118 __ SmiToInteger32(r11, rcx); | 4796 __ SmiToInteger32(r11, rcx); |
| 5119 __ StoreNumberToDoubleElements(rax, | 4797 __ StoreNumberToDoubleElements(rax, |
| 5120 r9, | 4798 r9, |
| 5121 r11, | 4799 r11, |
| 5122 xmm0, | 4800 xmm0, |
| 5123 &slow_elements); | 4801 &slow_elements); |
| 5124 __ ret(0); | 4802 __ ret(0); |
| 5125 } | 4803 } |
| 5126 | 4804 |
| 5127 | 4805 |
| 5128 void StubFailureTrampolineStub::Generate(MacroAssembler* masm) { | 4806 void StubFailureTrampolineStub::Generate(MacroAssembler* masm) { |
| 5129 CEntryStub ces(1, fp_registers_ ? kSaveFPRegs : kDontSaveFPRegs); | 4807 CEntryStub ces(1, fp_registers_ ? kSaveFPRegs : kDontSaveFPRegs); |
| 5130 __ Call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET); | 4808 __ Call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET); |
| 5131 int parameter_count_offset = | 4809 int parameter_count_offset = |
| 5132 StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset; | 4810 StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset; |
| 5133 __ movq(rbx, MemOperand(rbp, parameter_count_offset)); | 4811 __ movp(rbx, MemOperand(rbp, parameter_count_offset)); |
| 5134 masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE); | 4812 masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE); |
| 5135 __ PopReturnAddressTo(rcx); | 4813 __ PopReturnAddressTo(rcx); |
| 5136 int additional_offset = function_mode_ == JS_FUNCTION_STUB_MODE | 4814 int additional_offset = function_mode_ == JS_FUNCTION_STUB_MODE |
| 5137 ? kPointerSize | 4815 ? kPointerSize |
| 5138 : 0; | 4816 : 0; |
| 5139 __ lea(rsp, MemOperand(rsp, rbx, times_pointer_size, additional_offset)); | 4817 __ lea(rsp, MemOperand(rsp, rbx, times_pointer_size, additional_offset)); |
| 5140 __ jmp(rcx); // Return to IC Miss stub, continuation still on stack. | 4818 __ jmp(rcx); // Return to IC Miss stub, continuation still on stack. |
| 5141 } | 4819 } |
| 5142 | 4820 |
| 5143 | 4821 |
| 5144 void StubFailureTailCallTrampolineStub::Generate(MacroAssembler* masm) { | 4822 void StubFailureTailCallTrampolineStub::Generate(MacroAssembler* masm) { |
| 5145 CEntryStub ces(1, fp_registers_ ? kSaveFPRegs : kDontSaveFPRegs); | 4823 CEntryStub ces(1, fp_registers_ ? kSaveFPRegs : kDontSaveFPRegs); |
| 5146 __ Call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET); | 4824 __ Call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET); |
| 5147 __ movq(rdi, rax); | 4825 __ movp(rdi, rax); |
| 5148 int parameter_count_offset = | 4826 int parameter_count_offset = |
| 5149 StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset; | 4827 StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset; |
| 5150 __ movq(rax, MemOperand(rbp, parameter_count_offset)); | 4828 __ movp(rax, MemOperand(rbp, parameter_count_offset)); |
| 5151 // The parameter count above includes the receiver for the arguments passed to | 4829 // The parameter count above includes the receiver for the arguments passed to |
| 5152 // the deoptimization handler. Subtract the receiver for the parameter count | 4830 // the deoptimization handler. Subtract the receiver for the parameter count |
| 5153 // for the call. | 4831 // for the call. |
| 5154 __ subl(rax, Immediate(1)); | 4832 __ subl(rax, Immediate(1)); |
| 5155 masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE); | 4833 masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE); |
| 5156 ParameterCount argument_count(rax); | 4834 ParameterCount argument_count(rax); |
| 5157 __ InvokeFunction(rdi, argument_count, JUMP_FUNCTION, NullCallWrapper()); | 4835 __ InvokeFunction(rdi, argument_count, JUMP_FUNCTION, NullCallWrapper()); |
| 5158 } | 4836 } |
| 5159 | 4837 |
| 5160 | 4838 |
| 5161 void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) { | 4839 void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) { |
| 5162 if (masm->isolate()->function_entry_hook() != NULL) { | 4840 if (masm->isolate()->function_entry_hook() != NULL) { |
| 5163 ProfileEntryHookStub stub; | 4841 ProfileEntryHookStub stub; |
| 5164 masm->CallStub(&stub); | 4842 masm->CallStub(&stub); |
| 5165 } | 4843 } |
| 5166 } | 4844 } |
| 5167 | 4845 |
| 5168 | 4846 |
| 5169 void ProfileEntryHookStub::Generate(MacroAssembler* masm) { | 4847 void ProfileEntryHookStub::Generate(MacroAssembler* masm) { |
| 5170 // This stub can be called from essentially anywhere, so it needs to save | 4848 // This stub can be called from essentially anywhere, so it needs to save |
| 5171 // all volatile and callee-save registers. | 4849 // all volatile and callee-save registers. |
| 5172 const size_t kNumSavedRegisters = 2; | 4850 const size_t kNumSavedRegisters = 2; |
| 5173 __ push(arg_reg_1); | 4851 __ push(arg_reg_1); |
| 5174 __ push(arg_reg_2); | 4852 __ push(arg_reg_2); |
| 5175 | 4853 |
| 5176 // Calculate the original stack pointer and store it in the second arg. | 4854 // Calculate the original stack pointer and store it in the second arg. |
| 5177 __ lea(arg_reg_2, Operand(rsp, (kNumSavedRegisters + 1) * kPointerSize)); | 4855 __ lea(arg_reg_2, |
| 4856 Operand(rsp, kNumSavedRegisters * kRegisterSize + kPCOnStackSize)); |
| 5178 | 4857 |
| 5179 // Calculate the function address to the first arg. | 4858 // Calculate the function address to the first arg. |
| 5180 __ movq(arg_reg_1, Operand(rsp, kNumSavedRegisters * kPointerSize)); | 4859 __ movp(arg_reg_1, Operand(rsp, kNumSavedRegisters * kRegisterSize)); |
| 5181 __ subq(arg_reg_1, Immediate(Assembler::kShortCallInstructionLength)); | 4860 __ subq(arg_reg_1, Immediate(Assembler::kShortCallInstructionLength)); |
| 5182 | 4861 |
| 5183 // Save the remainder of the volatile registers. | 4862 // Save the remainder of the volatile registers. |
| 5184 masm->PushCallerSaved(kSaveFPRegs, arg_reg_1, arg_reg_2); | 4863 masm->PushCallerSaved(kSaveFPRegs, arg_reg_1, arg_reg_2); |
| 5185 | 4864 |
| 5186 // Call the entry hook function. | 4865 // Call the entry hook function. |
| 5187 __ Move(rax, FUNCTION_ADDR(masm->isolate()->function_entry_hook()), | 4866 __ Move(rax, FUNCTION_ADDR(masm->isolate()->function_entry_hook()), |
| 5188 RelocInfo::NONE64); | 4867 RelocInfo::NONE64); |
| 5189 | 4868 |
| 5190 AllowExternalCallThatCantCauseGC scope(masm); | 4869 AllowExternalCallThatCantCauseGC scope(masm); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5224 // If we reached this point there is a problem. | 4903 // If we reached this point there is a problem. |
| 5225 __ Abort(kUnexpectedElementsKindInArrayConstructor); | 4904 __ Abort(kUnexpectedElementsKindInArrayConstructor); |
| 5226 } else { | 4905 } else { |
| 5227 UNREACHABLE(); | 4906 UNREACHABLE(); |
| 5228 } | 4907 } |
| 5229 } | 4908 } |
| 5230 | 4909 |
| 5231 | 4910 |
| 5232 static void CreateArrayDispatchOneArgument(MacroAssembler* masm, | 4911 static void CreateArrayDispatchOneArgument(MacroAssembler* masm, |
| 5233 AllocationSiteOverrideMode mode) { | 4912 AllocationSiteOverrideMode mode) { |
| 5234 // rbx - type info cell (if mode != DISABLE_ALLOCATION_SITES) | 4913 // rbx - allocation site (if mode != DISABLE_ALLOCATION_SITES) |
| 5235 // rdx - kind (if mode != DISABLE_ALLOCATION_SITES) | 4914 // rdx - kind (if mode != DISABLE_ALLOCATION_SITES) |
| 5236 // rax - number of arguments | 4915 // rax - number of arguments |
| 5237 // rdi - constructor? | 4916 // rdi - constructor? |
| 5238 // rsp[0] - return address | 4917 // rsp[0] - return address |
| 5239 // rsp[8] - last argument | 4918 // rsp[8] - last argument |
| 5240 Handle<Object> undefined_sentinel( | 4919 Handle<Object> undefined_sentinel( |
| 5241 masm->isolate()->heap()->undefined_value(), | 4920 masm->isolate()->heap()->undefined_value(), |
| 5242 masm->isolate()); | 4921 masm->isolate()); |
| 5243 | 4922 |
| 5244 Label normal_sequence; | 4923 Label normal_sequence; |
| 5245 if (mode == DONT_OVERRIDE) { | 4924 if (mode == DONT_OVERRIDE) { |
| 5246 ASSERT(FAST_SMI_ELEMENTS == 0); | 4925 ASSERT(FAST_SMI_ELEMENTS == 0); |
| 5247 ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); | 4926 ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); |
| 5248 ASSERT(FAST_ELEMENTS == 2); | 4927 ASSERT(FAST_ELEMENTS == 2); |
| 5249 ASSERT(FAST_HOLEY_ELEMENTS == 3); | 4928 ASSERT(FAST_HOLEY_ELEMENTS == 3); |
| 5250 ASSERT(FAST_DOUBLE_ELEMENTS == 4); | 4929 ASSERT(FAST_DOUBLE_ELEMENTS == 4); |
| 5251 ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5); | 4930 ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5); |
| 5252 | 4931 |
| 5253 // is the low bit set? If so, we are holey and that is good. | 4932 // is the low bit set? If so, we are holey and that is good. |
| 5254 __ testb(rdx, Immediate(1)); | 4933 __ testb(rdx, Immediate(1)); |
| 5255 __ j(not_zero, &normal_sequence); | 4934 __ j(not_zero, &normal_sequence); |
| 5256 } | 4935 } |
| 5257 | 4936 |
| 5258 // look at the first argument | 4937 // look at the first argument |
| 5259 StackArgumentsAccessor args(rsp, 1, ARGUMENTS_DONT_CONTAIN_RECEIVER); | 4938 StackArgumentsAccessor args(rsp, 1, ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 5260 __ movq(rcx, args.GetArgumentOperand(0)); | 4939 __ movp(rcx, args.GetArgumentOperand(0)); |
| 5261 __ testq(rcx, rcx); | 4940 __ testq(rcx, rcx); |
| 5262 __ j(zero, &normal_sequence); | 4941 __ j(zero, &normal_sequence); |
| 5263 | 4942 |
| 5264 if (mode == DISABLE_ALLOCATION_SITES) { | 4943 if (mode == DISABLE_ALLOCATION_SITES) { |
| 5265 ElementsKind initial = GetInitialFastElementsKind(); | 4944 ElementsKind initial = GetInitialFastElementsKind(); |
| 5266 ElementsKind holey_initial = GetHoleyElementsKind(initial); | 4945 ElementsKind holey_initial = GetHoleyElementsKind(initial); |
| 5267 | 4946 |
| 5268 ArraySingleArgumentConstructorStub stub_holey(holey_initial, | 4947 ArraySingleArgumentConstructorStub stub_holey(holey_initial, |
| 5269 DISABLE_ALLOCATION_SITES); | 4948 DISABLE_ALLOCATION_SITES); |
| 5270 __ TailCallStub(&stub_holey); | 4949 __ TailCallStub(&stub_holey); |
| 5271 | 4950 |
| 5272 __ bind(&normal_sequence); | 4951 __ bind(&normal_sequence); |
| 5273 ArraySingleArgumentConstructorStub stub(initial, | 4952 ArraySingleArgumentConstructorStub stub(initial, |
| 5274 DISABLE_ALLOCATION_SITES); | 4953 DISABLE_ALLOCATION_SITES); |
| 5275 __ TailCallStub(&stub); | 4954 __ TailCallStub(&stub); |
| 5276 } else if (mode == DONT_OVERRIDE) { | 4955 } else if (mode == DONT_OVERRIDE) { |
| 5277 // We are going to create a holey array, but our kind is non-holey. | 4956 // We are going to create a holey array, but our kind is non-holey. |
| 5278 // Fix kind and retry (only if we have an allocation site in the cell). | 4957 // Fix kind and retry (only if we have an allocation site in the cell). |
| 5279 __ incl(rdx); | 4958 __ incl(rdx); |
| 5280 __ movq(rcx, FieldOperand(rbx, Cell::kValueOffset)); | 4959 |
| 5281 if (FLAG_debug_code) { | 4960 if (FLAG_debug_code) { |
| 5282 Handle<Map> allocation_site_map = | 4961 Handle<Map> allocation_site_map = |
| 5283 masm->isolate()->factory()->allocation_site_map(); | 4962 masm->isolate()->factory()->allocation_site_map(); |
| 5284 __ Cmp(FieldOperand(rcx, 0), allocation_site_map); | 4963 __ Cmp(FieldOperand(rbx, 0), allocation_site_map); |
| 5285 __ Assert(equal, kExpectedAllocationSiteInCell); | 4964 __ Assert(equal, kExpectedAllocationSite); |
| 5286 } | 4965 } |
| 5287 | 4966 |
| 5288 // Save the resulting elements kind in type info. We can't just store r3 | 4967 // Save the resulting elements kind in type info. We can't just store r3 |
| 5289 // in the AllocationSite::transition_info field because elements kind is | 4968 // in the AllocationSite::transition_info field because elements kind is |
| 5290 // restricted to a portion of the field...upper bits need to be left alone. | 4969 // restricted to a portion of the field...upper bits need to be left alone. |
| 5291 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0); | 4970 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0); |
| 5292 __ SmiAddConstant(FieldOperand(rcx, AllocationSite::kTransitionInfoOffset), | 4971 __ SmiAddConstant(FieldOperand(rbx, AllocationSite::kTransitionInfoOffset), |
| 5293 Smi::FromInt(kFastElementsKindPackedToHoley)); | 4972 Smi::FromInt(kFastElementsKindPackedToHoley)); |
| 5294 | 4973 |
| 5295 __ bind(&normal_sequence); | 4974 __ bind(&normal_sequence); |
| 5296 int last_index = GetSequenceIndexFromFastElementsKind( | 4975 int last_index = GetSequenceIndexFromFastElementsKind( |
| 5297 TERMINAL_FAST_ELEMENTS_KIND); | 4976 TERMINAL_FAST_ELEMENTS_KIND); |
| 5298 for (int i = 0; i <= last_index; ++i) { | 4977 for (int i = 0; i <= last_index; ++i) { |
| 5299 Label next; | 4978 Label next; |
| 5300 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); | 4979 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); |
| 5301 __ cmpl(rdx, Immediate(kind)); | 4980 __ cmpl(rdx, Immediate(kind)); |
| 5302 __ j(not_equal, &next); | 4981 __ j(not_equal, &next); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5392 // ----------------------------------- | 5071 // ----------------------------------- |
| 5393 Handle<Object> undefined_sentinel( | 5072 Handle<Object> undefined_sentinel( |
| 5394 masm->isolate()->heap()->undefined_value(), | 5073 masm->isolate()->heap()->undefined_value(), |
| 5395 masm->isolate()); | 5074 masm->isolate()); |
| 5396 | 5075 |
| 5397 if (FLAG_debug_code) { | 5076 if (FLAG_debug_code) { |
| 5398 // The array construct code is only set for the global and natives | 5077 // The array construct code is only set for the global and natives |
| 5399 // builtin Array functions which always have maps. | 5078 // builtin Array functions which always have maps. |
| 5400 | 5079 |
| 5401 // Initial map for the builtin Array function should be a map. | 5080 // Initial map for the builtin Array function should be a map. |
| 5402 __ movq(rcx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); | 5081 __ movp(rcx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); |
| 5403 // Will both indicate a NULL and a Smi. | 5082 // Will both indicate a NULL and a Smi. |
| 5404 STATIC_ASSERT(kSmiTag == 0); | 5083 STATIC_ASSERT(kSmiTag == 0); |
| 5405 Condition not_smi = NegateCondition(masm->CheckSmi(rcx)); | 5084 Condition not_smi = NegateCondition(masm->CheckSmi(rcx)); |
| 5406 __ Check(not_smi, kUnexpectedInitialMapForArrayFunction); | 5085 __ Check(not_smi, kUnexpectedInitialMapForArrayFunction); |
| 5407 __ CmpObjectType(rcx, MAP_TYPE, rcx); | 5086 __ CmpObjectType(rcx, MAP_TYPE, rcx); |
| 5408 __ Check(equal, kUnexpectedInitialMapForArrayFunction); | 5087 __ Check(equal, kUnexpectedInitialMapForArrayFunction); |
| 5409 | 5088 |
| 5410 // We should either have undefined in rbx or a valid cell | 5089 // We should either have undefined in rbx or a valid cell |
| 5411 Label okay_here; | 5090 Label okay_here; |
| 5412 Handle<Map> cell_map = masm->isolate()->factory()->cell_map(); | 5091 Handle<Map> cell_map = masm->isolate()->factory()->cell_map(); |
| 5413 __ Cmp(rbx, undefined_sentinel); | 5092 __ Cmp(rbx, undefined_sentinel); |
| 5414 __ j(equal, &okay_here); | 5093 __ j(equal, &okay_here); |
| 5415 __ Cmp(FieldOperand(rbx, 0), cell_map); | 5094 __ Cmp(FieldOperand(rbx, 0), cell_map); |
| 5416 __ Assert(equal, kExpectedPropertyCellInRegisterRbx); | 5095 __ Assert(equal, kExpectedPropertyCellInRegisterRbx); |
| 5417 __ bind(&okay_here); | 5096 __ bind(&okay_here); |
| 5418 } | 5097 } |
| 5419 | 5098 |
| 5420 Label no_info; | 5099 Label no_info; |
| 5421 // If the type cell is undefined, or contains anything other than an | 5100 // If the type cell is undefined, or contains anything other than an |
| 5422 // AllocationSite, call an array constructor that doesn't use AllocationSites. | 5101 // AllocationSite, call an array constructor that doesn't use AllocationSites. |
| 5423 __ Cmp(rbx, undefined_sentinel); | 5102 __ Cmp(rbx, undefined_sentinel); |
| 5424 __ j(equal, &no_info); | 5103 __ j(equal, &no_info); |
| 5425 __ movq(rdx, FieldOperand(rbx, Cell::kValueOffset)); | 5104 __ movp(rbx, FieldOperand(rbx, Cell::kValueOffset)); |
| 5426 __ Cmp(FieldOperand(rdx, 0), | 5105 __ Cmp(FieldOperand(rbx, 0), |
| 5427 masm->isolate()->factory()->allocation_site_map()); | 5106 masm->isolate()->factory()->allocation_site_map()); |
| 5428 __ j(not_equal, &no_info); | 5107 __ j(not_equal, &no_info); |
| 5429 | 5108 |
| 5430 // Only look at the lower 16 bits of the transition info. | 5109 // Only look at the lower 16 bits of the transition info. |
| 5431 __ movq(rdx, FieldOperand(rdx, AllocationSite::kTransitionInfoOffset)); | 5110 __ movp(rdx, FieldOperand(rbx, AllocationSite::kTransitionInfoOffset)); |
| 5432 __ SmiToInteger32(rdx, rdx); | 5111 __ SmiToInteger32(rdx, rdx); |
| 5433 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0); | 5112 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0); |
| 5434 __ and_(rdx, Immediate(AllocationSite::ElementsKindBits::kMask)); | 5113 __ and_(rdx, Immediate(AllocationSite::ElementsKindBits::kMask)); |
| 5435 GenerateDispatchToArrayStub(masm, DONT_OVERRIDE); | 5114 GenerateDispatchToArrayStub(masm, DONT_OVERRIDE); |
| 5436 | 5115 |
| 5437 __ bind(&no_info); | 5116 __ bind(&no_info); |
| 5438 GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES); | 5117 GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES); |
| 5439 } | 5118 } |
| 5440 | 5119 |
| 5441 | 5120 |
| 5442 void InternalArrayConstructorStub::GenerateCase( | 5121 void InternalArrayConstructorStub::GenerateCase( |
| 5443 MacroAssembler* masm, ElementsKind kind) { | 5122 MacroAssembler* masm, ElementsKind kind) { |
| 5444 Label not_zero_case, not_one_case; | 5123 Label not_zero_case, not_one_case; |
| 5445 Label normal_sequence; | 5124 Label normal_sequence; |
| 5446 | 5125 |
| 5447 __ testq(rax, rax); | 5126 __ testq(rax, rax); |
| 5448 __ j(not_zero, ¬_zero_case); | 5127 __ j(not_zero, ¬_zero_case); |
| 5449 InternalArrayNoArgumentConstructorStub stub0(kind); | 5128 InternalArrayNoArgumentConstructorStub stub0(kind); |
| 5450 __ TailCallStub(&stub0); | 5129 __ TailCallStub(&stub0); |
| 5451 | 5130 |
| 5452 __ bind(¬_zero_case); | 5131 __ bind(¬_zero_case); |
| 5453 __ cmpl(rax, Immediate(1)); | 5132 __ cmpl(rax, Immediate(1)); |
| 5454 __ j(greater, ¬_one_case); | 5133 __ j(greater, ¬_one_case); |
| 5455 | 5134 |
| 5456 if (IsFastPackedElementsKind(kind)) { | 5135 if (IsFastPackedElementsKind(kind)) { |
| 5457 // We might need to create a holey array | 5136 // We might need to create a holey array |
| 5458 // look at the first argument | 5137 // look at the first argument |
| 5459 StackArgumentsAccessor args(rsp, 1, ARGUMENTS_DONT_CONTAIN_RECEIVER); | 5138 StackArgumentsAccessor args(rsp, 1, ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 5460 __ movq(rcx, args.GetArgumentOperand(0)); | 5139 __ movp(rcx, args.GetArgumentOperand(0)); |
| 5461 __ testq(rcx, rcx); | 5140 __ testq(rcx, rcx); |
| 5462 __ j(zero, &normal_sequence); | 5141 __ j(zero, &normal_sequence); |
| 5463 | 5142 |
| 5464 InternalArraySingleArgumentConstructorStub | 5143 InternalArraySingleArgumentConstructorStub |
| 5465 stub1_holey(GetHoleyElementsKind(kind)); | 5144 stub1_holey(GetHoleyElementsKind(kind)); |
| 5466 __ TailCallStub(&stub1_holey); | 5145 __ TailCallStub(&stub1_holey); |
| 5467 } | 5146 } |
| 5468 | 5147 |
| 5469 __ bind(&normal_sequence); | 5148 __ bind(&normal_sequence); |
| 5470 InternalArraySingleArgumentConstructorStub stub1(kind); | 5149 InternalArraySingleArgumentConstructorStub stub1(kind); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 5483 // -- rdi : constructor | 5162 // -- rdi : constructor |
| 5484 // -- rsp[0] : return address | 5163 // -- rsp[0] : return address |
| 5485 // -- rsp[8] : last argument | 5164 // -- rsp[8] : last argument |
| 5486 // ----------------------------------- | 5165 // ----------------------------------- |
| 5487 | 5166 |
| 5488 if (FLAG_debug_code) { | 5167 if (FLAG_debug_code) { |
| 5489 // The array construct code is only set for the global and natives | 5168 // The array construct code is only set for the global and natives |
| 5490 // builtin Array functions which always have maps. | 5169 // builtin Array functions which always have maps. |
| 5491 | 5170 |
| 5492 // Initial map for the builtin Array function should be a map. | 5171 // Initial map for the builtin Array function should be a map. |
| 5493 __ movq(rcx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); | 5172 __ movp(rcx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); |
| 5494 // Will both indicate a NULL and a Smi. | 5173 // Will both indicate a NULL and a Smi. |
| 5495 STATIC_ASSERT(kSmiTag == 0); | 5174 STATIC_ASSERT(kSmiTag == 0); |
| 5496 Condition not_smi = NegateCondition(masm->CheckSmi(rcx)); | 5175 Condition not_smi = NegateCondition(masm->CheckSmi(rcx)); |
| 5497 __ Check(not_smi, kUnexpectedInitialMapForArrayFunction); | 5176 __ Check(not_smi, kUnexpectedInitialMapForArrayFunction); |
| 5498 __ CmpObjectType(rcx, MAP_TYPE, rcx); | 5177 __ CmpObjectType(rcx, MAP_TYPE, rcx); |
| 5499 __ Check(equal, kUnexpectedInitialMapForArrayFunction); | 5178 __ Check(equal, kUnexpectedInitialMapForArrayFunction); |
| 5500 } | 5179 } |
| 5501 | 5180 |
| 5502 // Figure out the right elements kind | 5181 // Figure out the right elements kind |
| 5503 __ movq(rcx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); | 5182 __ movp(rcx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); |
| 5504 | 5183 |
| 5505 // Load the map's "bit field 2" into |result|. We only need the first byte, | 5184 // Load the map's "bit field 2" into |result|. We only need the first byte, |
| 5506 // but the following masking takes care of that anyway. | 5185 // but the following masking takes care of that anyway. |
| 5507 __ movzxbq(rcx, FieldOperand(rcx, Map::kBitField2Offset)); | 5186 __ movzxbq(rcx, FieldOperand(rcx, Map::kBitField2Offset)); |
| 5508 // Retrieve elements_kind from bit field 2. | 5187 // Retrieve elements_kind from bit field 2. |
| 5509 __ and_(rcx, Immediate(Map::kElementsKindMask)); | 5188 __ and_(rcx, Immediate(Map::kElementsKindMask)); |
| 5510 __ shr(rcx, Immediate(Map::kElementsKindShift)); | 5189 __ shr(rcx, Immediate(Map::kElementsKindShift)); |
| 5511 | 5190 |
| 5512 if (FLAG_debug_code) { | 5191 if (FLAG_debug_code) { |
| 5513 Label done; | 5192 Label done; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 5527 __ bind(&fast_elements_case); | 5206 __ bind(&fast_elements_case); |
| 5528 GenerateCase(masm, FAST_ELEMENTS); | 5207 GenerateCase(masm, FAST_ELEMENTS); |
| 5529 } | 5208 } |
| 5530 | 5209 |
| 5531 | 5210 |
| 5532 #undef __ | 5211 #undef __ |
| 5533 | 5212 |
| 5534 } } // namespace v8::internal | 5213 } } // namespace v8::internal |
| 5535 | 5214 |
| 5536 #endif // V8_TARGET_ARCH_X64 | 5215 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |