OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
160 // Get the value at the masked, scaled index and return. | 160 // Get the value at the masked, scaled index and return. |
161 __ ldr(result, | 161 __ ldr(result, |
162 FieldMemOperand(scratch3, kElementsStartOffset + 1 * kPointerSize)); | 162 FieldMemOperand(scratch3, kElementsStartOffset + 1 * kPointerSize)); |
163 } | 163 } |
164 | 164 |
165 | 165 |
166 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, | 166 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, |
167 Label* miss, | 167 Label* miss, |
168 Register elements, | 168 Register elements, |
169 Register key, | 169 Register key, |
| 170 Register result, |
170 Register t0, | 171 Register t0, |
171 Register t1, | 172 Register t1, |
172 Register t2) { | 173 Register t2) { |
173 // Register use: | 174 // Register use: |
174 // | 175 // |
175 // elements - holds the slow-case elements of the receiver and is unchanged. | 176 // elements - holds the slow-case elements of the receiver on entry. |
| 177 // Unchanged unless 'result' is the same register. |
176 // | 178 // |
177 // key - holds the smi key on entry and is unchanged if a branch is | 179 // key - holds the smi key on entry. |
178 // performed to the miss label. | 180 // Unchanged unless 'result' is the same register. |
179 // Holds the result on exit if the load succeeded. | 181 // |
| 182 // result - holds the result on exit if the load succeeded. |
| 183 // Allowed to be the same as 'key' or 'result'. |
| 184 // Unchanged on bailout so 'key' or 'result' can be used |
| 185 // in further computation. |
180 // | 186 // |
181 // Scratch registers: | 187 // Scratch registers: |
182 // | 188 // |
183 // t0 - holds the untagged key on entry and holds the hash once computed. | 189 // t0 - holds the untagged key on entry and holds the hash once computed. |
184 // | 190 // |
185 // t1 - used to hold the capacity mask of the dictionary | 191 // t1 - used to hold the capacity mask of the dictionary |
186 // | 192 // |
187 // t2 - used for the index into the dictionary. | 193 // t2 - used for the index into the dictionary. |
188 Label done; | 194 Label done; |
189 | 195 |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 // t2: elements + (index * kPointerSize) | 247 // t2: elements + (index * kPointerSize) |
242 const int kDetailsOffset = | 248 const int kDetailsOffset = |
243 NumberDictionary::kElementsStartOffset + 2 * kPointerSize; | 249 NumberDictionary::kElementsStartOffset + 2 * kPointerSize; |
244 __ ldr(t1, FieldMemOperand(t2, kDetailsOffset)); | 250 __ ldr(t1, FieldMemOperand(t2, kDetailsOffset)); |
245 __ tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::mask()))); | 251 __ tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::mask()))); |
246 __ b(ne, miss); | 252 __ b(ne, miss); |
247 | 253 |
248 // Get the value at the masked, scaled index and return. | 254 // Get the value at the masked, scaled index and return. |
249 const int kValueOffset = | 255 const int kValueOffset = |
250 NumberDictionary::kElementsStartOffset + kPointerSize; | 256 NumberDictionary::kElementsStartOffset + kPointerSize; |
251 __ ldr(key, FieldMemOperand(t2, kValueOffset)); | 257 __ ldr(result, FieldMemOperand(t2, kValueOffset)); |
252 } | 258 } |
253 | 259 |
254 | 260 |
255 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { | 261 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { |
256 // ----------- S t a t e ------------- | 262 // ----------- S t a t e ------------- |
257 // -- r2 : name | 263 // -- r2 : name |
258 // -- lr : return address | 264 // -- lr : return address |
259 // -- r0 : receiver | 265 // -- r0 : receiver |
260 // -- sp[0] : receiver | 266 // -- sp[0] : receiver |
261 // ----------------------------------- | 267 // ----------------------------------- |
(...skipping 29 matching lines...) Expand all Loading... |
291 // -- sp[0] : receiver | 297 // -- sp[0] : receiver |
292 // ----------------------------------- | 298 // ----------------------------------- |
293 Label miss; | 299 Label miss; |
294 | 300 |
295 StubCompiler::GenerateLoadFunctionPrototype(masm, r0, r1, r3, &miss); | 301 StubCompiler::GenerateLoadFunctionPrototype(masm, r0, r1, r3, &miss); |
296 __ bind(&miss); | 302 __ bind(&miss); |
297 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); | 303 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); |
298 } | 304 } |
299 | 305 |
300 | 306 |
| 307 // Checks the receiver for special cases (value type, slow case bits). |
| 308 // Falls through for regular JS object. |
| 309 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, |
| 310 Register receiver, |
| 311 Register scratch1, |
| 312 Register scratch2, |
| 313 Label* slow) { |
| 314 // Check that the object isn't a smi. |
| 315 __ BranchOnSmi(receiver, slow); |
| 316 // Get the map of the receiver. |
| 317 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
| 318 // Check bit field. |
| 319 __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitFieldOffset)); |
| 320 __ tst(scratch2, Operand(KeyedLoadIC::kSlowCaseBitFieldMask)); |
| 321 __ b(ne, slow); |
| 322 // Check that the object is some kind of JS object EXCEPT JS Value type. |
| 323 // In the case that the object is a value-wrapper object, |
| 324 // we enter the runtime system to make sure that indexing into string |
| 325 // objects work as intended. |
| 326 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); |
| 327 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); |
| 328 __ cmp(scratch1, Operand(JS_OBJECT_TYPE)); |
| 329 __ b(lt, slow); |
| 330 } |
| 331 |
| 332 |
| 333 // Loads an indexed element from a fast case array. |
| 334 static void GenerateFastArrayLoad(MacroAssembler* masm, |
| 335 Register receiver, |
| 336 Register key, |
| 337 Register elements, |
| 338 Register scratch1, |
| 339 Register scratch2, |
| 340 Register result, |
| 341 Label* not_fast_array, |
| 342 Label* out_of_range) { |
| 343 // Register use: |
| 344 // |
| 345 // receiver - holds the receiver on entry. |
| 346 // Unchanged unless 'result' is the same register. |
| 347 // |
| 348 // key - holds the smi key on entry. |
| 349 // Unchanged unless 'result' is the same register. |
| 350 // |
| 351 // elements - holds the elements of the receiver on exit. |
| 352 // |
| 353 // result - holds the result on exit if the load succeeded. |
| 354 // Allowed to be the the same as 'receiver' or 'key'. |
| 355 // Unchanged on bailout so 'receiver' and 'key' can be safely |
| 356 // used by further computation. |
| 357 // |
| 358 // Scratch registers: |
| 359 // |
| 360 // scratch1 - used to hold elements map and elements length. |
| 361 // Holds the elements map if not_fast_array branch is taken. |
| 362 // |
| 363 // scratch2 - used to hold the loaded value. |
| 364 |
| 365 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
| 366 // Check that the object is in fast mode (not dictionary). |
| 367 __ ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset)); |
| 368 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); |
| 369 __ cmp(scratch1, ip); |
| 370 __ b(ne, not_fast_array); |
| 371 // Check that the key (index) is within bounds. |
| 372 __ ldr(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset)); |
| 373 __ cmp(key, Operand(scratch1)); |
| 374 __ b(hs, out_of_range); |
| 375 // Fast case: Do the load. |
| 376 __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| 377 // The key is a smi. |
| 378 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); |
| 379 __ ldr(scratch2, |
| 380 MemOperand(scratch1, key, LSL, kPointerSizeLog2 - kSmiTagSize)); |
| 381 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 382 __ cmp(scratch2, ip); |
| 383 // In case the loaded value is the_hole we have to consult GetProperty |
| 384 // to ensure the prototype chain is searched. |
| 385 __ b(eq, out_of_range); |
| 386 __ mov(result, scratch2); |
| 387 } |
| 388 |
| 389 |
| 390 // Checks whether a key is an array index string or a symbol string. |
| 391 // Falls through if a key is a symbol. |
| 392 static void GenerateKeyStringCheck(MacroAssembler* masm, |
| 393 Register key, |
| 394 Register map, |
| 395 Register hash, |
| 396 Label* index_string, |
| 397 Label* not_symbol) { |
| 398 // The key is not a smi. |
| 399 // Is it a string? |
| 400 __ CompareObjectType(key, map, hash, FIRST_NONSTRING_TYPE); |
| 401 __ b(ge, not_symbol); |
| 402 |
| 403 // Is the string an array index, with cached numeric value? |
| 404 __ ldr(hash, FieldMemOperand(key, String::kHashFieldOffset)); |
| 405 __ tst(hash, Operand(String::kContainsCachedArrayIndexMask)); |
| 406 __ b(eq, index_string); |
| 407 |
| 408 // Is the string a symbol? |
| 409 // map: key map |
| 410 __ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset)); |
| 411 ASSERT(kSymbolTag != 0); |
| 412 __ tst(hash, Operand(kIsSymbolMask)); |
| 413 __ b(eq, not_symbol); |
| 414 } |
| 415 |
| 416 |
| 417 // Picks out an array index from the hash field. |
| 418 static void GenerateIndexFromHash(MacroAssembler* masm, |
| 419 Register key, |
| 420 Register hash) { |
| 421 // Register use: |
| 422 // key - holds the overwritten key on exit. |
| 423 // hash - holds the key's hash. Clobbered. |
| 424 |
| 425 // If the hash field contains an array index pick it out. The assert checks |
| 426 // that the constants for the maximum number of digits for an array index |
| 427 // cached in the hash field and the number of bits reserved for it does not |
| 428 // conflict. |
| 429 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) < |
| 430 (1 << String::kArrayIndexValueBits)); |
| 431 // We want the smi-tagged index in key. kArrayIndexValueMask has zeros in |
| 432 // the low kHashShift bits. |
| 433 ASSERT(String::kHashShift >= kSmiTagSize); |
| 434 // Here we actually clobber the key which will be used if calling into |
| 435 // runtime later. However as the new key is the numeric value of a string key |
| 436 // there is no difference in using either key. |
| 437 ASSERT(String::kHashShift >= kSmiTagSize); |
| 438 __ Ubfx(hash, hash, String::kHashShift, String::kArrayIndexValueBits); |
| 439 __ mov(key, Operand(hash, LSL, kSmiTagSize)); |
| 440 } |
| 441 |
| 442 |
301 // Defined in ic.cc. | 443 // Defined in ic.cc. |
302 Object* CallIC_Miss(Arguments args); | 444 Object* CallIC_Miss(Arguments args); |
303 | 445 |
304 void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { | 446 // The generated code does not accept smi keys. |
| 447 // The generated code falls through if both probes miss. |
| 448 static void GenerateMonomorphicCacheProbe(MacroAssembler* masm, |
| 449 int argc, |
| 450 Code::Kind kind) { |
305 // ----------- S t a t e ------------- | 451 // ----------- S t a t e ------------- |
| 452 // -- r1 : receiver |
306 // -- r2 : name | 453 // -- r2 : name |
307 // -- lr : return address | |
308 // ----------------------------------- | 454 // ----------------------------------- |
309 Label number, non_number, non_string, boolean, probe, miss; | 455 Label number, non_number, non_string, boolean, probe, miss; |
310 | 456 |
311 // Get the receiver of the function from the stack into r1. | |
312 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); | |
313 | |
314 // Probe the stub cache. | 457 // Probe the stub cache. |
315 Code::Flags flags = | 458 Code::Flags flags = |
316 Code::ComputeFlags(Code::CALL_IC, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc); | 459 Code::ComputeFlags(kind, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc); |
317 StubCache::GenerateProbe(masm, flags, r1, r2, r3, no_reg); | 460 StubCache::GenerateProbe(masm, flags, r1, r2, r3, no_reg); |
318 | 461 |
319 // If the stub cache probing failed, the receiver might be a value. | 462 // If the stub cache probing failed, the receiver might be a value. |
320 // For value objects, we use the map of the prototype objects for | 463 // For value objects, we use the map of the prototype objects for |
321 // the corresponding JSValue for the cache and that is what we need | 464 // the corresponding JSValue for the cache and that is what we need |
322 // to probe. | 465 // to probe. |
323 // | 466 // |
324 // Check for number. | 467 // Check for number. |
325 __ tst(r1, Operand(kSmiTagMask)); | 468 __ tst(r1, Operand(kSmiTagMask)); |
326 __ b(eq, &number); | 469 __ b(eq, &number); |
(...skipping 21 matching lines...) Expand all Loading... |
348 __ cmp(r1, ip); | 491 __ cmp(r1, ip); |
349 __ b(ne, &miss); | 492 __ b(ne, &miss); |
350 __ bind(&boolean); | 493 __ bind(&boolean); |
351 StubCompiler::GenerateLoadGlobalFunctionPrototype( | 494 StubCompiler::GenerateLoadGlobalFunctionPrototype( |
352 masm, Context::BOOLEAN_FUNCTION_INDEX, r1); | 495 masm, Context::BOOLEAN_FUNCTION_INDEX, r1); |
353 | 496 |
354 // Probe the stub cache for the value object. | 497 // Probe the stub cache for the value object. |
355 __ bind(&probe); | 498 __ bind(&probe); |
356 StubCache::GenerateProbe(masm, flags, r1, r2, r3, no_reg); | 499 StubCache::GenerateProbe(masm, flags, r1, r2, r3, no_reg); |
357 | 500 |
358 // Cache miss: Jump to runtime. | |
359 __ bind(&miss); | 501 __ bind(&miss); |
360 GenerateMiss(masm, argc); | |
361 } | 502 } |
362 | 503 |
363 | 504 |
364 static void GenerateNormalHelper(MacroAssembler* masm, | 505 static void GenerateNormalHelper(MacroAssembler* masm, |
365 int argc, | 506 int argc, |
366 bool is_global_object, | 507 bool is_global_object, |
367 Label* miss, | 508 Label* miss, |
368 Register scratch) { | 509 Register scratch) { |
369 // Search dictionary - put result in register r1. | 510 // Search dictionary - put result in register r1. |
370 GenerateDictionaryLoad(masm, miss, r1, r2, r1, r0, r3, r4, CHECK_DICTIONARY); | 511 GenerateDictionaryLoad(masm, miss, r1, r2, r1, r0, r3, r4, CHECK_DICTIONARY); |
(...skipping 12 matching lines...) Expand all Loading... |
383 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset)); | 524 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset)); |
384 __ str(r0, MemOperand(sp, argc * kPointerSize)); | 525 __ str(r0, MemOperand(sp, argc * kPointerSize)); |
385 } | 526 } |
386 | 527 |
387 // Invoke the function. | 528 // Invoke the function. |
388 ParameterCount actual(argc); | 529 ParameterCount actual(argc); |
389 __ InvokeFunction(r1, actual, JUMP_FUNCTION); | 530 __ InvokeFunction(r1, actual, JUMP_FUNCTION); |
390 } | 531 } |
391 | 532 |
392 | 533 |
393 void CallIC::GenerateNormal(MacroAssembler* masm, int argc) { | 534 static void GenerateCallNormal(MacroAssembler* masm, int argc) { |
394 // ----------- S t a t e ------------- | 535 // ----------- S t a t e ------------- |
395 // -- r2 : name | 536 // -- r2 : name |
396 // -- lr : return address | 537 // -- lr : return address |
397 // ----------------------------------- | 538 // ----------------------------------- |
398 Label miss, global_object, non_global_object; | 539 Label miss, global_object, non_global_object; |
399 | 540 |
400 // Get the receiver of the function from the stack into r1. | 541 // Get the receiver of the function from the stack into r1. |
401 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); | 542 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); |
402 | 543 |
403 // Check that the receiver isn't a smi. | 544 // Check that the receiver isn't a smi. |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
436 __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded)); | 577 __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded)); |
437 __ b(ne, &miss); | 578 __ b(ne, &miss); |
438 __ bind(&invoke); | 579 __ bind(&invoke); |
439 GenerateNormalHelper(masm, argc, false, &miss, r4); | 580 GenerateNormalHelper(masm, argc, false, &miss, r4); |
440 | 581 |
441 // Global object access: Check access rights. | 582 // Global object access: Check access rights. |
442 __ bind(&global_proxy); | 583 __ bind(&global_proxy); |
443 __ CheckAccessGlobalProxy(r1, r0, &miss); | 584 __ CheckAccessGlobalProxy(r1, r0, &miss); |
444 __ b(&invoke); | 585 __ b(&invoke); |
445 | 586 |
446 // Cache miss: Jump to runtime. | |
447 __ bind(&miss); | 587 __ bind(&miss); |
448 GenerateMiss(masm, argc); | |
449 } | 588 } |
450 | 589 |
451 | 590 |
452 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { | 591 static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) { |
453 // ----------- S t a t e ------------- | 592 // ----------- S t a t e ------------- |
454 // -- r2 : name | 593 // -- r2 : name |
455 // -- lr : return address | 594 // -- lr : return address |
456 // ----------------------------------- | 595 // ----------------------------------- |
457 | 596 |
458 // Get the receiver of the function from the stack. | 597 // Get the receiver of the function from the stack. |
459 __ ldr(r3, MemOperand(sp, argc * kPointerSize)); | 598 __ ldr(r3, MemOperand(sp, argc * kPointerSize)); |
460 | 599 |
461 __ EnterInternalFrame(); | 600 __ EnterInternalFrame(); |
462 | 601 |
463 // Push the receiver and the name of the function. | 602 // Push the receiver and the name of the function. |
464 __ Push(r3, r2); | 603 __ Push(r3, r2); |
465 | 604 |
466 // Call the entry. | 605 // Call the entry. |
467 __ mov(r0, Operand(2)); | 606 __ mov(r0, Operand(2)); |
468 __ mov(r1, Operand(ExternalReference(IC_Utility(kCallIC_Miss)))); | 607 __ mov(r1, Operand(ExternalReference(IC_Utility(id)))); |
469 | 608 |
470 CEntryStub stub(1); | 609 CEntryStub stub(1); |
471 __ CallStub(&stub); | 610 __ CallStub(&stub); |
472 | 611 |
473 // Move result to r1 and leave the internal frame. | 612 // Move result to r1 and leave the internal frame. |
474 __ mov(r1, Operand(r0)); | 613 __ mov(r1, Operand(r0)); |
475 __ LeaveInternalFrame(); | 614 __ LeaveInternalFrame(); |
476 | 615 |
477 // Check if the receiver is a global object of some sort. | 616 // Check if the receiver is a global object of some sort. |
478 Label invoke, global; | 617 Label invoke, global; |
(...skipping 10 matching lines...) Expand all Loading... |
489 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset)); | 628 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset)); |
490 __ str(r2, MemOperand(sp, argc * kPointerSize)); | 629 __ str(r2, MemOperand(sp, argc * kPointerSize)); |
491 | 630 |
492 // Invoke the function. | 631 // Invoke the function. |
493 ParameterCount actual(argc); | 632 ParameterCount actual(argc); |
494 __ bind(&invoke); | 633 __ bind(&invoke); |
495 __ InvokeFunction(r1, actual, JUMP_FUNCTION); | 634 __ InvokeFunction(r1, actual, JUMP_FUNCTION); |
496 } | 635 } |
497 | 636 |
498 | 637 |
| 638 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { |
| 639 // ----------- S t a t e ------------- |
| 640 // -- r2 : name |
| 641 // -- lr : return address |
| 642 // ----------------------------------- |
| 643 |
| 644 GenerateCallMiss(masm, argc, IC::kCallIC_Miss); |
| 645 } |
| 646 |
| 647 |
| 648 void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { |
| 649 // ----------- S t a t e ------------- |
| 650 // -- r2 : name |
| 651 // -- lr : return address |
| 652 // ----------------------------------- |
| 653 |
| 654 // Get the receiver of the function from the stack into r1. |
| 655 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); |
| 656 GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC); |
| 657 GenerateMiss(masm, argc); |
| 658 } |
| 659 |
| 660 |
| 661 void CallIC::GenerateNormal(MacroAssembler* masm, int argc) { |
| 662 // ----------- S t a t e ------------- |
| 663 // -- r2 : name |
| 664 // -- lr : return address |
| 665 // ----------------------------------- |
| 666 |
| 667 GenerateCallNormal(masm, argc); |
| 668 GenerateMiss(masm, argc); |
| 669 } |
| 670 |
| 671 |
499 void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) { | 672 void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) { |
500 UNREACHABLE(); | 673 // ----------- S t a t e ------------- |
| 674 // -- r2 : name |
| 675 // -- lr : return address |
| 676 // ----------------------------------- |
| 677 |
| 678 GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss); |
501 } | 679 } |
502 | 680 |
503 | 681 |
504 void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { | 682 void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { |
505 UNREACHABLE(); | 683 // ----------- S t a t e ------------- |
| 684 // -- r2 : name |
| 685 // -- lr : return address |
| 686 // ----------------------------------- |
| 687 |
| 688 // Get the receiver of the function from the stack into r1. |
| 689 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); |
| 690 |
| 691 Label do_call, slow_call, slow_load, slow_reload_receiver; |
| 692 Label check_number_dictionary, check_string, lookup_monomorphic_cache; |
| 693 Label index_smi, index_string; |
| 694 |
| 695 // Check that the key is a smi. |
| 696 __ BranchOnNotSmi(r2, &check_string); |
| 697 __ bind(&index_smi); |
| 698 // Now the key is known to be a smi. This place is also jumped to from below |
| 699 // where a numeric string is converted to a smi. |
| 700 |
| 701 GenerateKeyedLoadReceiverCheck(masm, r1, r0, r3, &slow_call); |
| 702 |
| 703 GenerateFastArrayLoad( |
| 704 masm, r1, r2, r4, r3, r0, r1, &check_number_dictionary, &slow_load); |
| 705 __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1, r0, r3); |
| 706 |
| 707 __ bind(&do_call); |
| 708 // receiver in r1 is not used after this point. |
| 709 // r2: key |
| 710 // r1: function |
| 711 |
| 712 // Check that the value in r1 is a JSFunction. |
| 713 __ BranchOnSmi(r1, &slow_call); |
| 714 __ CompareObjectType(r1, r0, r0, JS_FUNCTION_TYPE); |
| 715 __ b(ne, &slow_call); |
| 716 // Invoke the function. |
| 717 ParameterCount actual(argc); |
| 718 __ InvokeFunction(r1, actual, JUMP_FUNCTION); |
| 719 |
| 720 __ bind(&check_number_dictionary); |
| 721 // r2: key |
| 722 // r3: elements map |
| 723 // r4: elements |
| 724 // Check whether the elements is a number dictionary. |
| 725 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); |
| 726 __ cmp(r3, ip); |
| 727 __ b(ne, &slow_load); |
| 728 __ mov(r0, Operand(r2, ASR, kSmiTagSize)); |
| 729 // r0: untagged index |
| 730 GenerateNumberDictionaryLoad(masm, &slow_load, r4, r2, r1, r0, r3, r5); |
| 731 __ IncrementCounter(&Counters::keyed_call_generic_smi_dict, 1, r0, r3); |
| 732 __ jmp(&do_call); |
| 733 |
| 734 __ bind(&slow_load); |
| 735 // This branch is taken when calling KeyedCallIC_Miss is neither required |
| 736 // nor beneficial. |
| 737 __ IncrementCounter(&Counters::keyed_call_generic_slow_load, 1, r0, r3); |
| 738 __ EnterInternalFrame(); |
| 739 __ push(r2); // save the key |
| 740 __ Push(r1, r2); // pass the receiver and the key |
| 741 __ CallRuntime(Runtime::kKeyedGetProperty, 2); |
| 742 __ pop(r2); // restore the key |
| 743 __ LeaveInternalFrame(); |
| 744 __ mov(r1, r0); |
| 745 __ jmp(&do_call); |
| 746 |
| 747 __ bind(&check_string); |
| 748 GenerateKeyStringCheck(masm, r2, r0, r3, &index_string, &slow_call); |
| 749 |
| 750 // The key is known to be a symbol. |
| 751 // If the receiver is a regular JS object with slow properties then do |
| 752 // a quick inline probe of the receiver's dictionary. |
| 753 // Otherwise do the monomorphic cache probe. |
| 754 GenerateKeyedLoadReceiverCheck(masm, r1, r0, r3, &lookup_monomorphic_cache); |
| 755 |
| 756 __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset)); |
| 757 __ ldr(r3, FieldMemOperand(r3, HeapObject::kMapOffset)); |
| 758 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); |
| 759 __ cmp(r3, ip); |
| 760 __ b(ne, &lookup_monomorphic_cache); |
| 761 |
| 762 GenerateDictionaryLoad( |
| 763 masm, &slow_load, r1, r2, r1, r0, r3, r4, DICTIONARY_CHECK_DONE); |
| 764 __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1, r0, r3); |
| 765 __ jmp(&do_call); |
| 766 |
| 767 __ bind(&lookup_monomorphic_cache); |
| 768 __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1, r0, r3); |
| 769 GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC); |
| 770 // Fall through on miss. |
| 771 |
| 772 __ bind(&slow_call); |
| 773 // This branch is taken if: |
| 774 // - the receiver requires boxing or access check, |
| 775 // - the key is neither smi nor symbol, |
| 776 // - the value loaded is not a function, |
| 777 // - there is hope that the runtime will create a monomorphic call stub |
| 778 // that will get fetched next time. |
| 779 __ IncrementCounter(&Counters::keyed_call_generic_slow, 1, r0, r3); |
| 780 GenerateMiss(masm, argc); |
| 781 |
| 782 __ bind(&index_string); |
| 783 GenerateIndexFromHash(masm, r2, r3); |
| 784 // Now jump to the place where smi keys are handled. |
| 785 __ jmp(&index_smi); |
506 } | 786 } |
507 | 787 |
508 | 788 |
509 void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) { | 789 void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) { |
510 UNREACHABLE(); | 790 // ----------- S t a t e ------------- |
| 791 // -- r2 : name |
| 792 // -- lr : return address |
| 793 // ----------------------------------- |
| 794 |
| 795 GenerateCallNormal(masm, argc); |
| 796 GenerateMiss(masm, argc); |
511 } | 797 } |
512 | 798 |
513 | 799 |
514 // Defined in ic.cc. | 800 // Defined in ic.cc. |
515 Object* LoadIC_Miss(Arguments args); | 801 Object* LoadIC_Miss(Arguments args); |
516 | 802 |
517 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { | 803 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { |
518 // ----------- S t a t e ------------- | 804 // ----------- S t a t e ------------- |
519 // -- r2 : name | 805 // -- r2 : name |
520 // -- lr : return address | 806 // -- lr : return address |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
752 // -- lr : return address | 1038 // -- lr : return address |
753 // -- r0 : key | 1039 // -- r0 : key |
754 // -- r1 : receiver | 1040 // -- r1 : receiver |
755 // ----------------------------------- | 1041 // ----------------------------------- |
756 Label slow, check_string, index_smi, index_string; | 1042 Label slow, check_string, index_smi, index_string; |
757 Label check_pixel_array, probe_dictionary, check_number_dictionary; | 1043 Label check_pixel_array, probe_dictionary, check_number_dictionary; |
758 | 1044 |
759 Register key = r0; | 1045 Register key = r0; |
760 Register receiver = r1; | 1046 Register receiver = r1; |
761 | 1047 |
762 // Check that the object isn't a smi. | 1048 GenerateKeyedLoadReceiverCheck(masm, receiver, r2, r3, &slow); |
763 __ BranchOnSmi(receiver, &slow); | |
764 // Get the map of the receiver. | |
765 __ ldr(r2, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
766 // Check bit field. | |
767 __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset)); | |
768 __ tst(r3, Operand(kSlowCaseBitFieldMask)); | |
769 __ b(ne, &slow); | |
770 // Check that the object is some kind of JS object EXCEPT JS Value type. | |
771 // In the case that the object is a value-wrapper object, | |
772 // we enter the runtime system to make sure that indexing into string | |
773 // objects work as intended. | |
774 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); | |
775 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); | |
776 __ cmp(r2, Operand(JS_OBJECT_TYPE)); | |
777 __ b(lt, &slow); | |
778 | 1049 |
779 // Check that the key is a smi. | 1050 // Check that the key is a smi. |
780 __ BranchOnNotSmi(key, &check_string); | 1051 __ BranchOnNotSmi(key, &check_string); |
781 __ bind(&index_smi); | 1052 __ bind(&index_smi); |
782 // Now the key is known to be a smi. This place is also jumped to from below | 1053 // Now the key is known to be a smi. This place is also jumped to from below |
783 // where a numeric string is converted to a smi. | 1054 // where a numeric string is converted to a smi. |
784 __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 1055 |
785 // Check that the object is in fast mode (not dictionary). | 1056 GenerateFastArrayLoad( |
786 __ ldr(r3, FieldMemOperand(r4, HeapObject::kMapOffset)); | 1057 masm, receiver, key, r4, r3, r2, r0, &check_pixel_array, &slow); |
787 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); | |
788 __ cmp(r3, ip); | |
789 __ b(ne, &check_pixel_array); | |
790 // Check that the key (index) is within bounds. | |
791 __ ldr(r3, FieldMemOperand(r4, FixedArray::kLengthOffset)); | |
792 __ cmp(key, Operand(r3)); | |
793 __ b(hs, &slow); | |
794 // Fast case: Do the load. | |
795 __ add(r3, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | |
796 // The key is a smi. | |
797 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); | |
798 __ ldr(r2, MemOperand(r3, key, LSL, kPointerSizeLog2 - kSmiTagSize)); | |
799 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | |
800 __ cmp(r2, ip); | |
801 // In case the loaded value is the_hole we have to consult GetProperty | |
802 // to ensure the prototype chain is searched. | |
803 __ b(eq, &slow); | |
804 __ mov(r0, r2); | |
805 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1, r2, r3); | 1058 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1, r2, r3); |
806 __ Ret(); | 1059 __ Ret(); |
807 | 1060 |
808 // Check whether the elements is a pixel array. | 1061 // Check whether the elements is a pixel array. |
809 // r0: key | 1062 // r0: key |
810 // r3: elements map | 1063 // r3: elements map |
811 // r4: elements | 1064 // r4: elements |
812 __ bind(&check_pixel_array); | 1065 __ bind(&check_pixel_array); |
813 __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex); | 1066 __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex); |
814 __ cmp(r3, ip); | 1067 __ cmp(r3, ip); |
815 __ b(ne, &check_number_dictionary); | 1068 __ b(ne, &check_number_dictionary); |
816 __ ldr(ip, FieldMemOperand(r4, PixelArray::kLengthOffset)); | 1069 __ ldr(ip, FieldMemOperand(r4, PixelArray::kLengthOffset)); |
817 __ mov(r2, Operand(key, ASR, kSmiTagSize)); | 1070 __ mov(r2, Operand(key, ASR, kSmiTagSize)); |
818 __ cmp(r2, ip); | 1071 __ cmp(r2, ip); |
819 __ b(hs, &slow); | 1072 __ b(hs, &slow); |
820 __ ldr(ip, FieldMemOperand(r4, PixelArray::kExternalPointerOffset)); | 1073 __ ldr(ip, FieldMemOperand(r4, PixelArray::kExternalPointerOffset)); |
821 __ ldrb(r2, MemOperand(ip, r2)); | 1074 __ ldrb(r2, MemOperand(ip, r2)); |
822 __ mov(r0, Operand(r2, LSL, kSmiTagSize)); // Tag result as smi. | 1075 __ mov(r0, Operand(r2, LSL, kSmiTagSize)); // Tag result as smi. |
823 __ Ret(); | 1076 __ Ret(); |
824 | 1077 |
825 __ bind(&check_number_dictionary); | 1078 __ bind(&check_number_dictionary); |
826 // Check whether the elements is a number dictionary. | 1079 // Check whether the elements is a number dictionary. |
827 // r0: key | 1080 // r0: key |
828 // r3: elements map | 1081 // r3: elements map |
829 // r4: elements | 1082 // r4: elements |
830 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); | 1083 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); |
831 __ cmp(r3, ip); | 1084 __ cmp(r3, ip); |
832 __ b(ne, &slow); | 1085 __ b(ne, &slow); |
833 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); | 1086 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); |
834 GenerateNumberDictionaryLoad(masm, &slow, r4, r0, r2, r3, r5); | 1087 GenerateNumberDictionaryLoad(masm, &slow, r4, r0, r0, r2, r3, r5); |
835 __ Ret(); | 1088 __ Ret(); |
836 | 1089 |
837 // Slow case, key and receiver still in r0 and r1. | 1090 // Slow case, key and receiver still in r0 and r1. |
838 __ bind(&slow); | 1091 __ bind(&slow); |
839 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r2, r3); | 1092 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r2, r3); |
840 GenerateRuntimeGetProperty(masm); | 1093 GenerateRuntimeGetProperty(masm); |
841 | 1094 |
842 __ bind(&check_string); | 1095 __ bind(&check_string); |
843 // The key is not a smi. | 1096 GenerateKeyStringCheck(masm, key, r2, r3, &index_string, &slow); |
844 // Is it a string? | |
845 // r0: key | |
846 // r1: receiver | |
847 __ CompareObjectType(r0, r2, r3, FIRST_NONSTRING_TYPE); | |
848 __ b(ge, &slow); | |
849 | |
850 // Is the string an array index, with cached numeric value? | |
851 __ ldr(r3, FieldMemOperand(r0, String::kHashFieldOffset)); | |
852 __ tst(r3, Operand(String::kContainsCachedArrayIndexMask)); | |
853 __ b(eq, &index_string); | |
854 | |
855 // Is the string a symbol? | |
856 // r2: key map | |
857 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceTypeOffset)); | |
858 ASSERT(kSymbolTag != 0); | |
859 __ tst(r3, Operand(kIsSymbolMask)); | |
860 __ b(eq, &slow); | |
861 | 1097 |
862 // If the receiver is a fast-case object, check the keyed lookup | 1098 // If the receiver is a fast-case object, check the keyed lookup |
863 // cache. Otherwise probe the dictionary. | 1099 // cache. Otherwise probe the dictionary. |
864 __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset)); | 1100 __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset)); |
865 __ ldr(r3, FieldMemOperand(r3, HeapObject::kMapOffset)); | 1101 __ ldr(r3, FieldMemOperand(r3, HeapObject::kMapOffset)); |
866 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); | 1102 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); |
867 __ cmp(r3, ip); | 1103 __ cmp(r3, ip); |
868 __ b(eq, &probe_dictionary); | 1104 __ b(eq, &probe_dictionary); |
869 | 1105 |
870 // Load the map of the receiver, compute the keyed lookup cache hash | 1106 // Load the map of the receiver, compute the keyed lookup cache hash |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
911 | 1147 |
912 // Do a quick inline probe of the receiver's dictionary, if it | 1148 // Do a quick inline probe of the receiver's dictionary, if it |
913 // exists. | 1149 // exists. |
914 __ bind(&probe_dictionary); | 1150 __ bind(&probe_dictionary); |
915 // Load the property to r0. | 1151 // Load the property to r0. |
916 GenerateDictionaryLoad( | 1152 GenerateDictionaryLoad( |
917 masm, &slow, r1, r0, r0, r2, r3, r4, DICTIONARY_CHECK_DONE); | 1153 masm, &slow, r1, r0, r0, r2, r3, r4, DICTIONARY_CHECK_DONE); |
918 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1, r2, r3); | 1154 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1, r2, r3); |
919 __ Ret(); | 1155 __ Ret(); |
920 | 1156 |
921 __ b(&slow); | |
922 // If the hash field contains an array index pick it out. The assert checks | |
923 // that the constants for the maximum number of digits for an array index | |
924 // cached in the hash field and the number of bits reserved for it does not | |
925 // conflict. | |
926 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) < | |
927 (1 << String::kArrayIndexValueBits)); | |
928 __ bind(&index_string); | 1157 __ bind(&index_string); |
929 // r0: key (string) | 1158 GenerateIndexFromHash(masm, key, r3); |
930 // r1: receiver | |
931 // r3: hash field | |
932 // We want the smi-tagged index in r0. kArrayIndexValueMask has zeros in | |
933 // the low kHashShift bits. | |
934 ASSERT(String::kHashShift >= kSmiTagSize); | |
935 __ Ubfx(r3, r3, String::kHashShift, String::kArrayIndexValueBits); | |
936 // Here we actually clobber the key (r0) which will be used if calling into | |
937 // runtime later. However as the new key is the numeric value of a string key | |
938 // there is no difference in using either key. | |
939 __ mov(r0, Operand(r3, LSL, kSmiTagSize)); | |
940 // Now jump to the place where smi keys are handled. | 1159 // Now jump to the place where smi keys are handled. |
941 __ jmp(&index_smi); | 1160 __ jmp(&index_smi); |
942 } | 1161 } |
943 | 1162 |
944 | 1163 |
945 void KeyedLoadIC::GenerateString(MacroAssembler* masm) { | 1164 void KeyedLoadIC::GenerateString(MacroAssembler* masm) { |
946 // ---------- S t a t e -------------- | 1165 // ---------- S t a t e -------------- |
947 // -- lr : return address | 1166 // -- lr : return address |
948 // -- r0 : key (index) | 1167 // -- r0 : key (index) |
949 // -- r1 : receiver | 1168 // -- r1 : receiver |
(...skipping 985 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1935 GenerateMiss(masm); | 2154 GenerateMiss(masm); |
1936 } | 2155 } |
1937 | 2156 |
1938 | 2157 |
1939 #undef __ | 2158 #undef __ |
1940 | 2159 |
1941 | 2160 |
1942 } } // namespace v8::internal | 2161 } } // namespace v8::internal |
1943 | 2162 |
1944 #endif // V8_TARGET_ARCH_ARM | 2163 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |