| 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 |