| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 69 // receiver: holds the receiver on entry and is unchanged. | 69 // receiver: holds the receiver on entry and is unchanged. |
| 70 // r0: used to hold receiver instance type. | 70 // r0: used to hold receiver instance type. |
| 71 // Holds the property dictionary on fall through. | 71 // Holds the property dictionary on fall through. |
| 72 // r1: used to hold receivers map. | 72 // r1: used to hold receivers map. |
| 73 | 73 |
| 74 __ JumpIfSmi(receiver, miss); | 74 __ JumpIfSmi(receiver, miss); |
| 75 | 75 |
| 76 // Check that the receiver is a valid JS object. | 76 // Check that the receiver is a valid JS object. |
| 77 __ movq(r1, FieldOperand(receiver, HeapObject::kMapOffset)); | 77 __ movq(r1, FieldOperand(receiver, HeapObject::kMapOffset)); |
| 78 __ movb(r0, FieldOperand(r1, Map::kInstanceTypeOffset)); | 78 __ movb(r0, FieldOperand(r1, Map::kInstanceTypeOffset)); |
| 79 __ cmpb(r0, Immediate(FIRST_JS_OBJECT_TYPE)); | 79 __ cmpb(r0, Immediate(FIRST_SPEC_OBJECT_TYPE)); |
| 80 __ j(below, miss); | 80 __ j(below, miss); |
| 81 | 81 |
| 82 // If this assert fails, we have to check upper bound too. | 82 // If this assert fails, we have to check upper bound too. |
| 83 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 83 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE); |
| 84 | 84 |
| 85 GenerateGlobalInstanceTypeCheck(masm, r0, miss); | 85 GenerateGlobalInstanceTypeCheck(masm, r0, miss); |
| 86 | 86 |
| 87 // Check for non-global object that requires access check. | 87 // Check for non-global object that requires access check. |
| 88 __ testb(FieldOperand(r1, Map::kBitFieldOffset), | 88 __ testb(FieldOperand(r1, Map::kBitFieldOffset), |
| 89 Immediate((1 << Map::kIsAccessCheckNeeded) | | 89 Immediate((1 << Map::kIsAccessCheckNeeded) | |
| 90 (1 << Map::kHasNamedInterceptor))); | 90 (1 << Map::kHasNamedInterceptor))); |
| 91 __ j(not_zero, miss); | 91 __ j(not_zero, miss); |
| 92 | 92 |
| 93 __ movq(r0, FieldOperand(receiver, JSObject::kPropertiesOffset)); | 93 __ movq(r0, FieldOperand(receiver, JSObject::kPropertiesOffset)); |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 218 times_pointer_size, | 218 times_pointer_size, |
| 219 kValueOffset - kHeapObjectTag)); | 219 kValueOffset - kHeapObjectTag)); |
| 220 __ movq(Operand(scratch1, 0), value); | 220 __ movq(Operand(scratch1, 0), value); |
| 221 | 221 |
| 222 // Update write barrier. Make sure not to clobber the value. | 222 // Update write barrier. Make sure not to clobber the value. |
| 223 __ movq(scratch0, value); | 223 __ movq(scratch0, value); |
| 224 __ RecordWrite(elements, scratch1, scratch0, kDontSaveFPRegs); | 224 __ RecordWrite(elements, scratch1, scratch0, kDontSaveFPRegs); |
| 225 } | 225 } |
| 226 | 226 |
| 227 | 227 |
| 228 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, | |
| 229 Label* miss, | |
| 230 Register elements, | |
| 231 Register key, | |
| 232 Register r0, | |
| 233 Register r1, | |
| 234 Register r2, | |
| 235 Register result) { | |
| 236 // Register use: | |
| 237 // | |
| 238 // elements - holds the slow-case elements of the receiver on entry. | |
| 239 // Unchanged unless 'result' is the same register. | |
| 240 // | |
| 241 // key - holds the smi key on entry. | |
| 242 // Unchanged unless 'result' is the same register. | |
| 243 // | |
| 244 // Scratch registers: | |
| 245 // | |
| 246 // r0 - holds the untagged key on entry and holds the hash once computed. | |
| 247 // | |
| 248 // r1 - used to hold the capacity mask of the dictionary | |
| 249 // | |
| 250 // r2 - used for the index into the dictionary. | |
| 251 // | |
| 252 // result - holds the result on exit if the load succeeded. | |
| 253 // Allowed to be the same as 'key' or 'result'. | |
| 254 // Unchanged on bailout so 'key' or 'result' can be used | |
| 255 // in further computation. | |
| 256 | |
| 257 Label done; | |
| 258 | |
| 259 // Compute the hash code from the untagged key. This must be kept in sync | |
| 260 // with ComputeIntegerHash in utils.h. | |
| 261 // | |
| 262 // hash = ~hash + (hash << 15); | |
| 263 __ movl(r1, r0); | |
| 264 __ notl(r0); | |
| 265 __ shll(r1, Immediate(15)); | |
| 266 __ addl(r0, r1); | |
| 267 // hash = hash ^ (hash >> 12); | |
| 268 __ movl(r1, r0); | |
| 269 __ shrl(r1, Immediate(12)); | |
| 270 __ xorl(r0, r1); | |
| 271 // hash = hash + (hash << 2); | |
| 272 __ leal(r0, Operand(r0, r0, times_4, 0)); | |
| 273 // hash = hash ^ (hash >> 4); | |
| 274 __ movl(r1, r0); | |
| 275 __ shrl(r1, Immediate(4)); | |
| 276 __ xorl(r0, r1); | |
| 277 // hash = hash * 2057; | |
| 278 __ imull(r0, r0, Immediate(2057)); | |
| 279 // hash = hash ^ (hash >> 16); | |
| 280 __ movl(r1, r0); | |
| 281 __ shrl(r1, Immediate(16)); | |
| 282 __ xorl(r0, r1); | |
| 283 | |
| 284 // Compute capacity mask. | |
| 285 __ SmiToInteger32(r1, | |
| 286 FieldOperand(elements, NumberDictionary::kCapacityOffset)); | |
| 287 __ decl(r1); | |
| 288 | |
| 289 // Generate an unrolled loop that performs a few probes before giving up. | |
| 290 const int kProbes = 4; | |
| 291 for (int i = 0; i < kProbes; i++) { | |
| 292 // Use r2 for index calculations and keep the hash intact in r0. | |
| 293 __ movq(r2, r0); | |
| 294 // Compute the masked index: (hash + i + i * i) & mask. | |
| 295 if (i > 0) { | |
| 296 __ addl(r2, Immediate(NumberDictionary::GetProbeOffset(i))); | |
| 297 } | |
| 298 __ and_(r2, r1); | |
| 299 | |
| 300 // Scale the index by multiplying by the entry size. | |
| 301 ASSERT(NumberDictionary::kEntrySize == 3); | |
| 302 __ lea(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3 | |
| 303 | |
| 304 // Check if the key matches. | |
| 305 __ cmpq(key, FieldOperand(elements, | |
| 306 r2, | |
| 307 times_pointer_size, | |
| 308 NumberDictionary::kElementsStartOffset)); | |
| 309 if (i != (kProbes - 1)) { | |
| 310 __ j(equal, &done); | |
| 311 } else { | |
| 312 __ j(not_equal, miss); | |
| 313 } | |
| 314 } | |
| 315 | |
| 316 __ bind(&done); | |
| 317 // Check that the value is a normal propety. | |
| 318 const int kDetailsOffset = | |
| 319 NumberDictionary::kElementsStartOffset + 2 * kPointerSize; | |
| 320 ASSERT_EQ(NORMAL, 0); | |
| 321 __ Test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset), | |
| 322 Smi::FromInt(PropertyDetails::TypeField::mask())); | |
| 323 __ j(not_zero, miss); | |
| 324 | |
| 325 // Get the value at the masked, scaled index. | |
| 326 const int kValueOffset = | |
| 327 NumberDictionary::kElementsStartOffset + kPointerSize; | |
| 328 __ movq(result, FieldOperand(elements, r2, times_pointer_size, kValueOffset)); | |
| 329 } | |
| 330 | |
| 331 | |
| 332 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { | 228 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { |
| 333 // ----------- S t a t e ------------- | 229 // ----------- S t a t e ------------- |
| 334 // -- rax : receiver | 230 // -- rax : receiver |
| 335 // -- rcx : name | 231 // -- rcx : name |
| 336 // -- rsp[0] : return address | 232 // -- rsp[0] : return address |
| 337 // ----------------------------------- | 233 // ----------------------------------- |
| 338 Label miss; | 234 Label miss; |
| 339 | 235 |
| 340 StubCompiler::GenerateLoadArrayLength(masm, rax, rdx, &miss); | 236 StubCompiler::GenerateLoadArrayLength(masm, rax, rdx, &miss); |
| 341 __ bind(&miss); | 237 __ bind(&miss); |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 501 | 397 |
| 502 // Check that the key is a smi. | 398 // Check that the key is a smi. |
| 503 __ JumpIfNotSmi(rax, &check_string); | 399 __ JumpIfNotSmi(rax, &check_string); |
| 504 __ bind(&index_smi); | 400 __ bind(&index_smi); |
| 505 // Now the key is known to be a smi. This place is also jumped to from below | 401 // Now the key is known to be a smi. This place is also jumped to from below |
| 506 // where a numeric string is converted to a smi. | 402 // where a numeric string is converted to a smi. |
| 507 | 403 |
| 508 GenerateKeyedLoadReceiverCheck( | 404 GenerateKeyedLoadReceiverCheck( |
| 509 masm, rdx, rcx, Map::kHasIndexedInterceptor, &slow); | 405 masm, rdx, rcx, Map::kHasIndexedInterceptor, &slow); |
| 510 | 406 |
| 511 // Check the "has fast elements" bit in the receiver's map which is | 407 // Check the receiver's map to see if it has fast elements. |
| 512 // now in rcx. | 408 __ CheckFastElements(rcx, &check_number_dictionary); |
| 513 __ testb(FieldOperand(rcx, Map::kBitField2Offset), | |
| 514 Immediate(1 << Map::kHasFastElements)); | |
| 515 __ j(zero, &check_number_dictionary); | |
| 516 | 409 |
| 517 GenerateFastArrayLoad(masm, | 410 GenerateFastArrayLoad(masm, |
| 518 rdx, | 411 rdx, |
| 519 rax, | 412 rax, |
| 520 rcx, | 413 rcx, |
| 521 rbx, | 414 rbx, |
| 522 rax, | 415 rax, |
| 523 NULL, | 416 NULL, |
| 524 &slow); | 417 &slow); |
| 525 Counters* counters = masm->isolate()->counters(); | 418 Counters* counters = masm->isolate()->counters(); |
| 526 __ IncrementCounter(counters->keyed_load_generic_smi(), 1); | 419 __ IncrementCounter(counters->keyed_load_generic_smi(), 1); |
| 527 __ ret(0); | 420 __ ret(0); |
| 528 | 421 |
| 529 __ bind(&check_number_dictionary); | 422 __ bind(&check_number_dictionary); |
| 530 __ SmiToInteger32(rbx, rax); | 423 __ SmiToInteger32(rbx, rax); |
| 531 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset)); | 424 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset)); |
| 532 | 425 |
| 533 // Check whether the elements is a number dictionary. | 426 // Check whether the elements is a number dictionary. |
| 534 // rdx: receiver | 427 // rdx: receiver |
| 535 // rax: key | 428 // rax: key |
| 536 // rbx: key as untagged int32 | 429 // rbx: key as untagged int32 |
| 537 // rcx: elements | 430 // rcx: elements |
| 538 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset), | 431 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset), |
| 539 Heap::kHashTableMapRootIndex); | 432 Heap::kHashTableMapRootIndex); |
| 540 __ j(not_equal, &slow); | 433 __ j(not_equal, &slow); |
| 541 GenerateNumberDictionaryLoad(masm, &slow, rcx, rax, rbx, r9, rdi, rax); | 434 __ LoadFromNumberDictionary(&slow, rcx, rax, rbx, r9, rdi, rax); |
| 542 __ ret(0); | 435 __ ret(0); |
| 543 | 436 |
| 544 __ bind(&slow); | 437 __ bind(&slow); |
| 545 // Slow case: Jump to runtime. | 438 // Slow case: Jump to runtime. |
| 546 // rdx: receiver | 439 // rdx: receiver |
| 547 // rax: key | 440 // rax: key |
| 548 __ IncrementCounter(counters->keyed_load_generic_slow(), 1); | 441 __ IncrementCounter(counters->keyed_load_generic_slow(), 1); |
| 549 GenerateRuntimeGetProperty(masm); | 442 GenerateRuntimeGetProperty(masm); |
| 550 | 443 |
| 551 __ bind(&check_string); | 444 __ bind(&check_string); |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 723 // to do this because this generic stub does not perform map checks. | 616 // to do this because this generic stub does not perform map checks. |
| 724 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), | 617 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), |
| 725 Immediate(1 << Map::kIsAccessCheckNeeded)); | 618 Immediate(1 << Map::kIsAccessCheckNeeded)); |
| 726 __ j(not_zero, &slow_with_tagged_index); | 619 __ j(not_zero, &slow_with_tagged_index); |
| 727 // Check that the key is a smi. | 620 // Check that the key is a smi. |
| 728 __ JumpIfNotSmi(rcx, &slow_with_tagged_index); | 621 __ JumpIfNotSmi(rcx, &slow_with_tagged_index); |
| 729 __ SmiToInteger32(rcx, rcx); | 622 __ SmiToInteger32(rcx, rcx); |
| 730 | 623 |
| 731 __ CmpInstanceType(rbx, JS_ARRAY_TYPE); | 624 __ CmpInstanceType(rbx, JS_ARRAY_TYPE); |
| 732 __ j(equal, &array); | 625 __ j(equal, &array); |
| 733 // Check that the object is some kind of JS object. | 626 // Check that the object is some kind of JSObject. |
| 734 __ CmpInstanceType(rbx, FIRST_JS_OBJECT_TYPE); | 627 __ CmpInstanceType(rbx, FIRST_JS_RECEIVER_TYPE); |
| 735 __ j(below, &slow); | 628 __ j(below, &slow); |
| 629 __ CmpInstanceType(rbx, JS_PROXY_TYPE); |
| 630 __ j(equal, &slow); |
| 631 __ CmpInstanceType(rbx, JS_FUNCTION_PROXY_TYPE); |
| 632 __ j(equal, &slow); |
| 736 | 633 |
| 737 // Object case: Check key against length in the elements array. | 634 // Object case: Check key against length in the elements array. |
| 738 // rax: value | 635 // rax: value |
| 739 // rdx: JSObject | 636 // rdx: JSObject |
| 740 // rcx: index | 637 // rcx: index |
| 741 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); | 638 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); |
| 742 // Check that the object is in fast mode and writable. | 639 // Check that the object is in fast mode and writable. |
| 743 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), | 640 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), |
| 744 Heap::kFixedArrayMapRootIndex); | 641 Heap::kFixedArrayMapRootIndex); |
| 745 __ j(not_equal, &slow); | 642 __ j(not_equal, &slow); |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 888 // rsp[argc * 8] : argument 1 | 785 // rsp[argc * 8] : argument 1 |
| 889 // rsp[(argc + 1) * 8] : argument 0 = receiver | 786 // rsp[(argc + 1) * 8] : argument 0 = receiver |
| 890 // ----------------------------------- | 787 // ----------------------------------- |
| 891 __ JumpIfSmi(rdi, miss); | 788 __ JumpIfSmi(rdi, miss); |
| 892 // Check that the value is a JavaScript function. | 789 // Check that the value is a JavaScript function. |
| 893 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rdx); | 790 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rdx); |
| 894 __ j(not_equal, miss); | 791 __ j(not_equal, miss); |
| 895 | 792 |
| 896 // Invoke the function. | 793 // Invoke the function. |
| 897 ParameterCount actual(argc); | 794 ParameterCount actual(argc); |
| 898 __ InvokeFunction(rdi, actual, JUMP_FUNCTION); | 795 __ InvokeFunction(rdi, actual, JUMP_FUNCTION, |
| 796 NullCallWrapper(), CALL_AS_METHOD); |
| 899 } | 797 } |
| 900 | 798 |
| 901 | 799 |
| 902 // The generated code falls through if the call should be handled by runtime. | 800 // The generated code falls through if the call should be handled by runtime. |
| 903 static void GenerateCallNormal(MacroAssembler* masm, int argc) { | 801 static void GenerateCallNormal(MacroAssembler* masm, int argc) { |
| 904 // ----------- S t a t e ------------- | 802 // ----------- S t a t e ------------- |
| 905 // rcx : function name | 803 // rcx : function name |
| 906 // rsp[0] : return address | 804 // rsp[0] : return address |
| 907 // rsp[8] : argument argc | 805 // rsp[8] : argument argc |
| 908 // rsp[16] : argument argc - 1 | 806 // rsp[16] : argument argc - 1 |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1093 | 991 |
| 1094 __ bind(&check_number_dictionary); | 992 __ bind(&check_number_dictionary); |
| 1095 // rax: elements | 993 // rax: elements |
| 1096 // rcx: smi key | 994 // rcx: smi key |
| 1097 // Check whether the elements is a number dictionary. | 995 // Check whether the elements is a number dictionary. |
| 1098 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), | 996 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), |
| 1099 Heap::kHashTableMapRootIndex); | 997 Heap::kHashTableMapRootIndex); |
| 1100 __ j(not_equal, &slow_load); | 998 __ j(not_equal, &slow_load); |
| 1101 __ SmiToInteger32(rbx, rcx); | 999 __ SmiToInteger32(rbx, rcx); |
| 1102 // ebx: untagged index | 1000 // ebx: untagged index |
| 1103 GenerateNumberDictionaryLoad(masm, &slow_load, rax, rcx, rbx, r9, rdi, rdi); | 1001 __ LoadFromNumberDictionary(&slow_load, rax, rcx, rbx, r9, rdi, rdi); |
| 1104 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1); | 1002 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1); |
| 1105 __ jmp(&do_call); | 1003 __ jmp(&do_call); |
| 1106 | 1004 |
| 1107 __ bind(&slow_load); | 1005 __ bind(&slow_load); |
| 1108 // This branch is taken when calling KeyedCallIC_Miss is neither required | 1006 // This branch is taken when calling KeyedCallIC_Miss is neither required |
| 1109 // nor beneficial. | 1007 // nor beneficial. |
| 1110 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1); | 1008 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1); |
| 1111 __ EnterInternalFrame(); | 1009 __ EnterInternalFrame(); |
| 1112 __ push(rcx); // save the key | 1010 __ push(rcx); // save the key |
| 1113 __ push(rdx); // pass the receiver | 1011 __ push(rdx); // pass the receiver |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1192 // rsp[16] : argument argc - 1 | 1090 // rsp[16] : argument argc - 1 |
| 1193 // ... | 1091 // ... |
| 1194 // rsp[argc * 8] : argument 1 | 1092 // rsp[argc * 8] : argument 1 |
| 1195 // rsp[(argc + 1) * 8] : argument 0 = receiver | 1093 // rsp[(argc + 1) * 8] : argument 0 = receiver |
| 1196 // ----------------------------------- | 1094 // ----------------------------------- |
| 1197 | 1095 |
| 1198 GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss, Code::kNoExtraICState); | 1096 GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss, Code::kNoExtraICState); |
| 1199 } | 1097 } |
| 1200 | 1098 |
| 1201 | 1099 |
| 1100 static Operand GenerateMappedArgumentsLookup(MacroAssembler* masm, |
| 1101 Register object, |
| 1102 Register key, |
| 1103 Register scratch1, |
| 1104 Register scratch2, |
| 1105 Register scratch3, |
| 1106 Label* unmapped_case, |
| 1107 Label* slow_case) { |
| 1108 Heap* heap = masm->isolate()->heap(); |
| 1109 |
| 1110 // Check that the receiver is a JSObject. Because of the elements |
| 1111 // map check later, we do not need to check for interceptors or |
| 1112 // whether it requires access checks. |
| 1113 __ JumpIfSmi(object, slow_case); |
| 1114 // Check that the object is some kind of JSObject. |
| 1115 __ CmpObjectType(object, FIRST_JS_RECEIVER_TYPE, scratch1); |
| 1116 __ j(below, slow_case); |
| 1117 |
| 1118 // Check that the key is a positive smi. |
| 1119 Condition check = masm->CheckNonNegativeSmi(key); |
| 1120 __ j(NegateCondition(check), slow_case); |
| 1121 |
| 1122 // Load the elements into scratch1 and check its map. If not, jump |
| 1123 // to the unmapped lookup with the parameter map in scratch1. |
| 1124 Handle<Map> arguments_map(heap->non_strict_arguments_elements_map()); |
| 1125 __ movq(scratch1, FieldOperand(object, JSObject::kElementsOffset)); |
| 1126 __ CheckMap(scratch1, arguments_map, slow_case, DONT_DO_SMI_CHECK); |
| 1127 |
| 1128 // Check if element is in the range of mapped arguments. |
| 1129 __ movq(scratch2, FieldOperand(scratch1, FixedArray::kLengthOffset)); |
| 1130 __ SmiSubConstant(scratch2, scratch2, Smi::FromInt(2)); |
| 1131 __ cmpq(key, scratch2); |
| 1132 __ j(greater_equal, unmapped_case); |
| 1133 |
| 1134 // Load element index and check whether it is the hole. |
| 1135 const int kHeaderSize = FixedArray::kHeaderSize + 2 * kPointerSize; |
| 1136 __ SmiToInteger64(scratch3, key); |
| 1137 __ movq(scratch2, FieldOperand(scratch1, |
| 1138 scratch3, |
| 1139 times_pointer_size, |
| 1140 kHeaderSize)); |
| 1141 __ CompareRoot(scratch2, Heap::kTheHoleValueRootIndex); |
| 1142 __ j(equal, unmapped_case); |
| 1143 |
| 1144 // Load value from context and return it. We can reuse scratch1 because |
| 1145 // we do not jump to the unmapped lookup (which requires the parameter |
| 1146 // map in scratch1). |
| 1147 __ movq(scratch1, FieldOperand(scratch1, FixedArray::kHeaderSize)); |
| 1148 __ SmiToInteger64(scratch3, scratch2); |
| 1149 return FieldOperand(scratch1, |
| 1150 scratch3, |
| 1151 times_pointer_size, |
| 1152 Context::kHeaderSize); |
| 1153 } |
| 1154 |
| 1155 |
| 1156 static Operand GenerateUnmappedArgumentsLookup(MacroAssembler* masm, |
| 1157 Register key, |
| 1158 Register parameter_map, |
| 1159 Register scratch, |
| 1160 Label* slow_case) { |
| 1161 // Element is in arguments backing store, which is referenced by the |
| 1162 // second element of the parameter_map. The parameter_map register |
| 1163 // must be loaded with the parameter map of the arguments object and is |
| 1164 // overwritten. |
| 1165 const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize; |
| 1166 Register backing_store = parameter_map; |
| 1167 __ movq(backing_store, FieldOperand(parameter_map, kBackingStoreOffset)); |
| 1168 Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map()); |
| 1169 __ CheckMap(backing_store, fixed_array_map, slow_case, DONT_DO_SMI_CHECK); |
| 1170 __ movq(scratch, FieldOperand(backing_store, FixedArray::kLengthOffset)); |
| 1171 __ cmpq(key, scratch); |
| 1172 __ j(greater_equal, slow_case); |
| 1173 __ SmiToInteger64(scratch, key); |
| 1174 return FieldOperand(backing_store, |
| 1175 scratch, |
| 1176 times_pointer_size, |
| 1177 FixedArray::kHeaderSize); |
| 1178 } |
| 1179 |
| 1180 |
| 1181 void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) { |
| 1182 // ----------- S t a t e ------------- |
| 1183 // -- rax : key |
| 1184 // -- rdx : receiver |
| 1185 // -- rsp[0] : return address |
| 1186 // ----------------------------------- |
| 1187 Label slow, notin; |
| 1188 Operand mapped_location = |
| 1189 GenerateMappedArgumentsLookup( |
| 1190 masm, rdx, rax, rbx, rcx, rdi, ¬in, &slow); |
| 1191 __ movq(rax, mapped_location); |
| 1192 __ Ret(); |
| 1193 __ bind(¬in); |
| 1194 // The unmapped lookup expects that the parameter map is in rbx. |
| 1195 Operand unmapped_location = |
| 1196 GenerateUnmappedArgumentsLookup(masm, rax, rbx, rcx, &slow); |
| 1197 __ CompareRoot(unmapped_location, Heap::kTheHoleValueRootIndex); |
| 1198 __ j(equal, &slow); |
| 1199 __ movq(rax, unmapped_location); |
| 1200 __ Ret(); |
| 1201 __ bind(&slow); |
| 1202 GenerateMiss(masm, false); |
| 1203 } |
| 1204 |
| 1205 |
| 1206 void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) { |
| 1207 // ----------- S t a t e ------------- |
| 1208 // -- rax : value |
| 1209 // -- rcx : key |
| 1210 // -- rdx : receiver |
| 1211 // -- rsp[0] : return address |
| 1212 // ----------------------------------- |
| 1213 Label slow, notin; |
| 1214 Operand mapped_location = GenerateMappedArgumentsLookup( |
| 1215 masm, rdx, rcx, rbx, rdi, r8, ¬in, &slow); |
| 1216 __ movq(mapped_location, rax); |
| 1217 __ lea(r9, mapped_location); |
| 1218 __ movq(r8, rax); |
| 1219 __ RecordWrite(rbx, |
| 1220 r9, |
| 1221 r8, |
| 1222 kDontSaveFPRegs, |
| 1223 EMIT_REMEMBERED_SET, |
| 1224 INLINE_SMI_CHECK); |
| 1225 __ Ret(); |
| 1226 __ bind(¬in); |
| 1227 // The unmapped lookup expects that the parameter map is in rbx. |
| 1228 Operand unmapped_location = |
| 1229 GenerateUnmappedArgumentsLookup(masm, rcx, rbx, rdi, &slow); |
| 1230 __ movq(unmapped_location, rax); |
| 1231 __ lea(r9, unmapped_location); |
| 1232 __ movq(r8, rax); |
| 1233 __ RecordWrite(rbx, |
| 1234 r9, |
| 1235 r8, |
| 1236 kDontSaveFPRegs, |
| 1237 EMIT_REMEMBERED_SET, |
| 1238 INLINE_SMI_CHECK); |
| 1239 __ Ret(); |
| 1240 __ bind(&slow); |
| 1241 GenerateMiss(masm, false); |
| 1242 } |
| 1243 |
| 1244 |
| 1245 void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm, |
| 1246 int argc) { |
| 1247 // ----------- S t a t e ------------- |
| 1248 // rcx : function name |
| 1249 // rsp[0] : return address |
| 1250 // rsp[8] : argument argc |
| 1251 // rsp[16] : argument argc - 1 |
| 1252 // ... |
| 1253 // rsp[argc * 8] : argument 1 |
| 1254 // rsp[(argc + 1) * 8] : argument 0 = receiver |
| 1255 // ----------------------------------- |
| 1256 Label slow, notin; |
| 1257 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); |
| 1258 Operand mapped_location = GenerateMappedArgumentsLookup( |
| 1259 masm, rdx, rcx, rbx, rax, r8, ¬in, &slow); |
| 1260 __ movq(rdi, mapped_location); |
| 1261 GenerateFunctionTailCall(masm, argc, &slow); |
| 1262 __ bind(¬in); |
| 1263 // The unmapped lookup expects that the parameter map is in rbx. |
| 1264 Operand unmapped_location = |
| 1265 GenerateUnmappedArgumentsLookup(masm, rcx, rbx, rax, &slow); |
| 1266 __ CompareRoot(unmapped_location, Heap::kTheHoleValueRootIndex); |
| 1267 __ j(equal, &slow); |
| 1268 __ movq(rdi, unmapped_location); |
| 1269 GenerateFunctionTailCall(masm, argc, &slow); |
| 1270 __ bind(&slow); |
| 1271 GenerateMiss(masm, argc); |
| 1272 } |
| 1273 |
| 1274 |
| 1202 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { | 1275 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { |
| 1203 // ----------- S t a t e ------------- | 1276 // ----------- S t a t e ------------- |
| 1204 // -- rax : receiver | 1277 // -- rax : receiver |
| 1205 // -- rcx : name | 1278 // -- rcx : name |
| 1206 // -- rsp[0] : return address | 1279 // -- rsp[0] : return address |
| 1207 // ----------------------------------- | 1280 // ----------------------------------- |
| 1208 | 1281 |
| 1209 // Probe the stub cache. | 1282 // Probe the stub cache. |
| 1210 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, | 1283 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, |
| 1211 NOT_IN_LOOP, | 1284 NOT_IN_LOOP, |
| (...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1602 Condition cc = *jmp_address == Assembler::kJncShortOpcode | 1675 Condition cc = *jmp_address == Assembler::kJncShortOpcode |
| 1603 ? not_zero | 1676 ? not_zero |
| 1604 : zero; | 1677 : zero; |
| 1605 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); | 1678 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); |
| 1606 } | 1679 } |
| 1607 | 1680 |
| 1608 | 1681 |
| 1609 } } // namespace v8::internal | 1682 } } // namespace v8::internal |
| 1610 | 1683 |
| 1611 #endif // V8_TARGET_ARCH_X64 | 1684 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |