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 26 matching lines...) Expand all Loading... |
37 | 37 |
38 // ---------------------------------------------------------------------------- | 38 // ---------------------------------------------------------------------------- |
39 // Static IC stub generators. | 39 // Static IC stub generators. |
40 // | 40 // |
41 | 41 |
42 #define __ masm-> | 42 #define __ masm-> |
43 | 43 |
44 | 44 |
45 // Helper function used from LoadIC/CallIC GenerateNormal. | 45 // Helper function used from LoadIC/CallIC GenerateNormal. |
46 static void GenerateDictionaryLoad(MacroAssembler* masm, | 46 static void GenerateDictionaryLoad(MacroAssembler* masm, |
47 Label* done_label, | 47 Label* miss, |
48 Label* miss_label, | |
49 Register t0, | 48 Register t0, |
50 Register t1) { | 49 Register t1) { |
51 // Register use: | 50 // Register use: |
52 // | 51 // |
53 // t0 - used to hold the property dictionary. | 52 // t0 - used to hold the property dictionary. |
54 // | 53 // |
55 // t1 - initially the receiver | 54 // t1 - initially the receiver |
56 // - used for the index into the property dictionary | 55 // - used for the index into the property dictionary |
57 // - holds the result on exit. | 56 // - holds the result on exit. |
58 // | 57 // |
59 // r3 - used as temporary and to hold the capacity of the property | 58 // r3 - used as temporary and to hold the capacity of the property |
60 // dictionary. | 59 // dictionary. |
61 // | 60 // |
62 // r2 - holds the name of the property and is unchanges. | 61 // r2 - holds the name of the property and is unchanges. |
63 | 62 |
| 63 Label done; |
| 64 |
64 // Check for the absence of an interceptor. | 65 // Check for the absence of an interceptor. |
65 // Load the map into t0. | 66 // Load the map into t0. |
66 __ ldr(t0, FieldMemOperand(t1, JSObject::kMapOffset)); | 67 __ ldr(t0, FieldMemOperand(t1, JSObject::kMapOffset)); |
67 // Test the has_named_interceptor bit in the map. | 68 // Test the has_named_interceptor bit in the map. |
68 __ ldr(t0, FieldMemOperand(t1, Map::kInstanceAttributesOffset)); | 69 __ ldr(t0, FieldMemOperand(t1, Map::kInstanceAttributesOffset)); |
69 __ tst(t0, Operand(1 << (Map::kHasNamedInterceptor + (3 * 8)))); | 70 __ tst(t0, Operand(1 << (Map::kHasNamedInterceptor + (3 * 8)))); |
70 // Jump to miss if the interceptor bit is set. | 71 // Jump to miss if the interceptor bit is set. |
71 __ b(ne, miss_label); | 72 __ b(ne, miss); |
72 | 73 |
73 | 74 |
74 // Check that the properties array is a dictionary. | 75 // Check that the properties array is a dictionary. |
75 __ ldr(t0, FieldMemOperand(t1, JSObject::kPropertiesOffset)); | 76 __ ldr(t0, FieldMemOperand(t1, JSObject::kPropertiesOffset)); |
76 __ ldr(r3, FieldMemOperand(t0, HeapObject::kMapOffset)); | 77 __ ldr(r3, FieldMemOperand(t0, HeapObject::kMapOffset)); |
77 __ cmp(r3, Operand(Factory::hash_table_map())); | 78 __ cmp(r3, Operand(Factory::hash_table_map())); |
78 __ b(ne, miss_label); | 79 __ b(ne, miss); |
79 | 80 |
80 // Compute the capacity mask. | 81 // Compute the capacity mask. |
81 const int kCapacityOffset = | 82 const int kCapacityOffset = |
82 Array::kHeaderSize + Dictionary::kCapacityIndex * kPointerSize; | 83 Array::kHeaderSize + Dictionary::kCapacityIndex * kPointerSize; |
83 __ ldr(r3, FieldMemOperand(t0, kCapacityOffset)); | 84 __ ldr(r3, FieldMemOperand(t0, kCapacityOffset)); |
84 __ mov(r3, Operand(r3, ASR, kSmiTagSize)); // convert smi to int | 85 __ mov(r3, Operand(r3, ASR, kSmiTagSize)); // convert smi to int |
85 __ sub(r3, r3, Operand(1)); | 86 __ sub(r3, r3, Operand(1)); |
86 | 87 |
87 const int kElementsStartOffset = | 88 const int kElementsStartOffset = |
88 Array::kHeaderSize + Dictionary::kElementsStartIndex * kPointerSize; | 89 Array::kHeaderSize + Dictionary::kElementsStartIndex * kPointerSize; |
(...skipping 11 matching lines...) Expand all Loading... |
100 | 101 |
101 // Scale the index by multiplying by the element size. | 102 // Scale the index by multiplying by the element size. |
102 ASSERT(Dictionary::kElementSize == 3); | 103 ASSERT(Dictionary::kElementSize == 3); |
103 __ add(t1, t1, Operand(t1, LSL, 1)); // t1 = t1 * 3 | 104 __ add(t1, t1, Operand(t1, LSL, 1)); // t1 = t1 * 3 |
104 | 105 |
105 // Check if the key is identical to the name. | 106 // Check if the key is identical to the name. |
106 __ add(t1, t0, Operand(t1, LSL, 2)); | 107 __ add(t1, t0, Operand(t1, LSL, 2)); |
107 __ ldr(ip, FieldMemOperand(t1, kElementsStartOffset)); | 108 __ ldr(ip, FieldMemOperand(t1, kElementsStartOffset)); |
108 __ cmp(r2, Operand(ip)); | 109 __ cmp(r2, Operand(ip)); |
109 if (i != kProbes - 1) { | 110 if (i != kProbes - 1) { |
110 __ b(eq, done_label); | 111 __ b(eq, &done); |
111 } else { | 112 } else { |
112 __ b(ne, miss_label); | 113 __ b(ne, miss); |
113 } | 114 } |
114 } | 115 } |
115 | 116 |
116 // Check that the value is a normal property. | 117 // Check that the value is a normal property. |
117 __ bind(done_label); // t1 == t0 + 4*index | 118 __ bind(&done); // t1 == t0 + 4*index |
118 __ ldr(r3, FieldMemOperand(t1, kElementsStartOffset + 2 * kPointerSize)); | 119 __ ldr(r3, FieldMemOperand(t1, kElementsStartOffset + 2 * kPointerSize)); |
119 __ tst(r3, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize)); | 120 __ tst(r3, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize)); |
120 __ b(ne, miss_label); | 121 __ b(ne, miss); |
121 | 122 |
122 // Get the value at the masked, scaled index and return. | 123 // Get the value at the masked, scaled index and return. |
123 __ ldr(t1, FieldMemOperand(t1, kElementsStartOffset + 1 * kPointerSize)); | 124 __ ldr(t1, FieldMemOperand(t1, kElementsStartOffset + 1 * kPointerSize)); |
124 } | 125 } |
125 | 126 |
126 | 127 |
127 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { | 128 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { |
128 // ----------- S t a t e ------------- | 129 // ----------- S t a t e ------------- |
129 // -- r2 : name | 130 // -- r2 : name |
130 // -- lr : return address | 131 // -- lr : return address |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
333 // Probe the stub cache for the value object. | 334 // Probe the stub cache for the value object. |
334 __ bind(&probe); | 335 __ bind(&probe); |
335 StubCache::GenerateProbe(masm, flags, r1, r2, r3); | 336 StubCache::GenerateProbe(masm, flags, r1, r2, r3); |
336 | 337 |
337 // Cache miss: Jump to runtime. | 338 // Cache miss: Jump to runtime. |
338 __ bind(&miss); | 339 __ bind(&miss); |
339 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); | 340 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); |
340 } | 341 } |
341 | 342 |
342 | 343 |
| 344 static void GenerateNormalHelper(MacroAssembler* masm, |
| 345 int argc, |
| 346 bool is_global_object, |
| 347 Label* miss) { |
| 348 // Search dictionary - put result in register r1. |
| 349 GenerateDictionaryLoad(masm, miss, r0, r1); |
| 350 |
| 351 // Check that the value isn't a smi. |
| 352 __ tst(r1, Operand(kSmiTagMask)); |
| 353 __ b(eq, miss); |
| 354 |
| 355 // Check that the value is a JSFunction. |
| 356 __ ldr(r0, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 357 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); |
| 358 __ cmp(r0, Operand(JS_FUNCTION_TYPE)); |
| 359 __ b(ne, miss); |
| 360 |
| 361 // Patch the receiver with the global proxy if necessary. |
| 362 if (is_global_object) { |
| 363 __ ldr(r2, MemOperand(sp, argc * kPointerSize)); |
| 364 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset)); |
| 365 __ str(r2, MemOperand(sp, argc * kPointerSize)); |
| 366 } |
| 367 |
| 368 // Invoke the function. |
| 369 ParameterCount actual(argc); |
| 370 __ InvokeFunction(r1, actual, JUMP_FUNCTION); |
| 371 } |
| 372 |
| 373 |
343 void CallIC::GenerateNormal(MacroAssembler* masm, int argc) { | 374 void CallIC::GenerateNormal(MacroAssembler* masm, int argc) { |
344 // ----------- S t a t e ------------- | 375 // ----------- S t a t e ------------- |
345 // -- lr: return address | 376 // -- lr: return address |
346 // ----------------------------------- | 377 // ----------------------------------- |
347 | 378 |
348 Label miss, probe, done, global; | 379 Label miss, global_object, non_global_object; |
349 | 380 |
350 // Get the receiver of the function from the stack into r1. | 381 // Get the receiver of the function from the stack into r1. |
351 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); | 382 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); |
352 // Get the name of the function from the stack; 1 ~ receiver. | 383 // Get the name of the function from the stack; 1 ~ receiver. |
353 __ ldr(r2, MemOperand(sp, (argc + 1) * kPointerSize)); | 384 __ ldr(r2, MemOperand(sp, (argc + 1) * kPointerSize)); |
354 | 385 |
355 // Check that the receiver isn't a smi. | 386 // Check that the receiver isn't a smi. |
356 __ tst(r1, Operand(kSmiTagMask)); | 387 __ tst(r1, Operand(kSmiTagMask)); |
357 __ b(eq, &miss); | 388 __ b(eq, &miss); |
358 | 389 |
359 // Check that the receiver is a valid JS object. | 390 // Check that the receiver is a valid JS object. |
360 __ ldr(r0, FieldMemOperand(r1, HeapObject::kMapOffset)); | 391 __ ldr(r0, FieldMemOperand(r1, HeapObject::kMapOffset)); |
361 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); | 392 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); |
362 __ cmp(r0, Operand(FIRST_JS_OBJECT_TYPE)); | 393 __ cmp(r0, Operand(FIRST_JS_OBJECT_TYPE)); |
363 __ b(lt, &miss); | 394 __ b(lt, &miss); |
364 | 395 |
365 // If this assert fails, we have to check upper bound too. | 396 // If this assert fails, we have to check upper bound too. |
366 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 397 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
367 | 398 |
368 // Check for access to global proxy. | 399 // Check for access to global object. |
| 400 __ cmp(r0, Operand(JS_GLOBAL_OBJECT_TYPE)); |
| 401 __ b(eq, &global_object); |
| 402 __ cmp(r0, Operand(JS_BUILTINS_OBJECT_TYPE)); |
| 403 __ b(ne, &non_global_object); |
| 404 |
| 405 // Accessing global object: Load and invoke. |
| 406 __ bind(&global_object); |
| 407 GenerateNormalHelper(masm, argc, true, &miss); |
| 408 |
| 409 // Accessing non-global object: Check for access to global proxy. |
| 410 Label global_proxy, invoke; |
| 411 __ bind(&non_global_object); |
369 __ cmp(r0, Operand(JS_GLOBAL_PROXY_TYPE)); | 412 __ cmp(r0, Operand(JS_GLOBAL_PROXY_TYPE)); |
370 __ b(eq, &global); | 413 __ b(eq, &global_proxy); |
371 | 414 __ bind(&invoke); |
372 // Search the dictionary placing the result in r1. | 415 GenerateNormalHelper(masm, argc, false, &miss); |
373 __ bind(&probe); | |
374 GenerateDictionaryLoad(masm, &done, &miss, r0, r1); | |
375 | |
376 // Check that the value isn't a smi. | |
377 __ tst(r1, Operand(kSmiTagMask)); | |
378 __ b(eq, &miss); | |
379 | |
380 // Check that the value is a JSFunction. | |
381 __ ldr(r0, FieldMemOperand(r1, HeapObject::kMapOffset)); | |
382 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); | |
383 __ cmp(r0, Operand(JS_FUNCTION_TYPE)); | |
384 __ b(ne, &miss); | |
385 | |
386 // TODO(120): Check for access to global object. Needs patching of | |
387 // receiver but no security check. | |
388 | |
389 // Invoke the function. | |
390 ParameterCount actual(argc); | |
391 __ InvokeFunction(r1, actual, JUMP_FUNCTION); | |
392 | 416 |
393 // Global object access: Check access rights. | 417 // Global object access: Check access rights. |
394 __ bind(&global); | 418 __ bind(&global_proxy); |
395 __ CheckAccessGlobalProxy(r1, r0, &miss); | 419 __ CheckAccessGlobalProxy(r1, r0, &miss); |
396 __ b(&probe); | 420 __ b(&invoke); |
397 | 421 |
398 // Cache miss: Jump to runtime. | 422 // Cache miss: Jump to runtime. |
399 __ bind(&miss); | 423 __ bind(&miss); |
400 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); | 424 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); |
401 } | 425 } |
402 | 426 |
403 | 427 |
404 void CallIC::Generate(MacroAssembler* masm, | 428 void CallIC::Generate(MacroAssembler* masm, |
405 int argc, | 429 int argc, |
406 const ExternalReference& f) { | 430 const ExternalReference& f) { |
(...skipping 15 matching lines...) Expand all Loading... |
422 __ mov(r0, Operand(2)); | 446 __ mov(r0, Operand(2)); |
423 __ mov(r1, Operand(f)); | 447 __ mov(r1, Operand(f)); |
424 | 448 |
425 CEntryStub stub; | 449 CEntryStub stub; |
426 __ CallStub(&stub); | 450 __ CallStub(&stub); |
427 | 451 |
428 // Move result to r1 and leave the internal frame. | 452 // Move result to r1 and leave the internal frame. |
429 __ mov(r1, Operand(r0)); | 453 __ mov(r1, Operand(r0)); |
430 __ LeaveInternalFrame(); | 454 __ LeaveInternalFrame(); |
431 | 455 |
432 // TODO(120): Check for access to to global object. Needs patching | 456 // Check if the receiver is a global object of some sort. |
433 // of receiver but no security check. | 457 Label invoke, global; |
| 458 __ ldr(r2, MemOperand(sp, argc * kPointerSize)); // receiver |
| 459 __ tst(r2, Operand(kSmiTagMask)); |
| 460 __ b(eq, &invoke); |
| 461 __ ldr(r3, FieldMemOperand(r2, HeapObject::kMapOffset)); |
| 462 __ ldrb(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset)); |
| 463 __ cmp(r3, Operand(JS_GLOBAL_OBJECT_TYPE)); |
| 464 __ b(eq, &global); |
| 465 __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE)); |
| 466 __ b(ne, &invoke); |
| 467 |
| 468 // Patch the receiver on the stack. |
| 469 __ bind(&global); |
| 470 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset)); |
| 471 __ str(r2, MemOperand(sp, argc * kPointerSize)); |
434 | 472 |
435 // Invoke the function. | 473 // Invoke the function. |
436 ParameterCount actual(argc); | 474 ParameterCount actual(argc); |
| 475 __ bind(&invoke); |
437 __ InvokeFunction(r1, actual, JUMP_FUNCTION); | 476 __ InvokeFunction(r1, actual, JUMP_FUNCTION); |
438 } | 477 } |
439 | 478 |
440 | 479 |
441 // Defined in ic.cc. | 480 // Defined in ic.cc. |
442 Object* LoadIC_Miss(Arguments args); | 481 Object* LoadIC_Miss(Arguments args); |
443 | 482 |
444 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { | 483 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { |
445 // ----------- S t a t e ------------- | 484 // ----------- S t a t e ------------- |
446 // -- r2 : name | 485 // -- r2 : name |
(...skipping 11 matching lines...) Expand all Loading... |
458 } | 497 } |
459 | 498 |
460 | 499 |
461 void LoadIC::GenerateNormal(MacroAssembler* masm) { | 500 void LoadIC::GenerateNormal(MacroAssembler* masm) { |
462 // ----------- S t a t e ------------- | 501 // ----------- S t a t e ------------- |
463 // -- r2 : name | 502 // -- r2 : name |
464 // -- lr : return address | 503 // -- lr : return address |
465 // -- [sp] : receiver | 504 // -- [sp] : receiver |
466 // ----------------------------------- | 505 // ----------------------------------- |
467 | 506 |
468 Label miss, probe, done, global; | 507 Label miss, probe, global; |
469 | 508 |
470 __ ldr(r0, MemOperand(sp, 0)); | 509 __ ldr(r0, MemOperand(sp, 0)); |
471 // Check that the receiver isn't a smi. | 510 // Check that the receiver isn't a smi. |
472 __ tst(r0, Operand(kSmiTagMask)); | 511 __ tst(r0, Operand(kSmiTagMask)); |
473 __ b(eq, &miss); | 512 __ b(eq, &miss); |
474 | 513 |
475 // Check that the receiver is a valid JS object. | 514 // Check that the receiver is a valid JS object. |
476 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); | 515 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); |
477 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); | 516 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); |
478 __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE)); | 517 __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE)); |
479 __ b(lt, &miss); | 518 __ b(lt, &miss); |
480 // If this assert fails, we have to check upper bound too. | 519 // If this assert fails, we have to check upper bound too. |
481 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 520 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
482 | 521 |
483 // Check for access to global object (unlikely). | 522 // Check for access to global object (unlikely). |
484 __ cmp(r1, Operand(JS_GLOBAL_PROXY_TYPE)); | 523 __ cmp(r1, Operand(JS_GLOBAL_PROXY_TYPE)); |
485 __ b(eq, &global); | 524 __ b(eq, &global); |
486 | 525 |
487 __ bind(&probe); | 526 __ bind(&probe); |
488 GenerateDictionaryLoad(masm, &done, &miss, r1, r0); | 527 GenerateDictionaryLoad(masm, &miss, r1, r0); |
489 __ Ret(); | 528 __ Ret(); |
490 | 529 |
491 // Global object access: Check access rights. | 530 // Global object access: Check access rights. |
492 __ bind(&global); | 531 __ bind(&global); |
493 __ CheckAccessGlobalProxy(r0, r1, &miss); | 532 __ CheckAccessGlobalProxy(r0, r1, &miss); |
494 __ b(&probe); | 533 __ b(&probe); |
495 | 534 |
496 // Cache miss: Restore receiver from stack and jump to runtime. | 535 // Cache miss: Restore receiver from stack and jump to runtime. |
497 __ bind(&miss); | 536 __ bind(&miss); |
498 Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss))); | 537 Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss))); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
589 | 628 |
590 // Perform tail call to the entry. | 629 // Perform tail call to the entry. |
591 __ TailCallRuntime(f, 3); | 630 __ TailCallRuntime(f, 3); |
592 } | 631 } |
593 | 632 |
594 | 633 |
595 #undef __ | 634 #undef __ |
596 | 635 |
597 | 636 |
598 } } // namespace v8::internal | 637 } } // namespace v8::internal |
OLD | NEW |