| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 // | 4 // |
| 5 // The intrinsic code below is executed before a method has built its frame. | 5 // The intrinsic code below is executed before a method has built its frame. |
| 6 // The return address is on the stack and the arguments below it. | 6 // The return address is on the stack and the arguments below it. |
| 7 // Registers EDX (arguments descriptor) and ECX (function) must be preserved. | 7 // Registers EDX (arguments descriptor) and ECX (function) must be preserved. |
| 8 // Each intrinsification method returns true if the corresponding | 8 // Each intrinsification method returns true if the corresponding |
| 9 // Dart method was intrinsified. | 9 // Dart method was intrinsified. |
| 10 | 10 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 #include "vm/symbols.h" | 22 #include "vm/symbols.h" |
| 23 | 23 |
| 24 namespace dart { | 24 namespace dart { |
| 25 | 25 |
| 26 DECLARE_FLAG(bool, enable_type_checks); | 26 DECLARE_FLAG(bool, enable_type_checks); |
| 27 | 27 |
| 28 | 28 |
| 29 #define __ assembler-> | 29 #define __ assembler-> |
| 30 | 30 |
| 31 | 31 |
| 32 void Intrinsifier::ObjectArrayAllocate(Assembler* assembler) { |
| 33 Label fall_through; |
| 34 const intptr_t kTypeArgumentsOffset = 3 * kWordSize; |
| 35 const intptr_t kLengthOffset = 2 * kWordSize; |
| 36 const Immediate& raw_null = |
| 37 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 38 |
| 39 __ pushl(EDX); |
| 40 __ movl(EDX, Address(ESP, kLengthOffset)); |
| 41 __ movl(ECX, Address(ESP, kTypeArgumentsOffset)); |
| 42 |
| 43 // Compute the size to be allocated, it is based on the array length |
| 44 // and is computed as: |
| 45 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)). |
| 46 // Assert that length is a Smi. |
| 47 __ testl(EDX, Immediate(kSmiTagMask)); |
| 48 __ j(NOT_ZERO, &fall_through); |
| 49 __ cmpl(EDX, Immediate(0)); |
| 50 __ j(LESS, &fall_through); |
| 51 |
| 52 // Check for maximum allowed length. |
| 53 const Immediate& max_len = |
| 54 Immediate(reinterpret_cast<int32_t>(Smi::New(Array::kMaxElements))); |
| 55 __ cmpl(EDX, max_len); |
| 56 __ j(GREATER, &fall_through); |
| 57 |
| 58 const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1; |
| 59 __ leal(EDI, Address(EDX, TIMES_2, fixed_size)); // EDX is Smi. |
| 60 ASSERT(kSmiTagShift == 1); |
| 61 __ andl(EDI, Immediate(-kObjectAlignment)); |
| 62 |
| 63 // ECX: array element type. |
| 64 // EDX: array length as Smi. |
| 65 // EDI: allocation size. |
| 66 |
| 67 Isolate* isolate = Isolate::Current(); |
| 68 Heap* heap = isolate->heap(); |
| 69 |
| 70 __ movl(EAX, Address::Absolute(heap->TopAddress())); |
| 71 __ movl(EBX, EAX); |
| 72 |
| 73 // EDI: allocation size. |
| 74 __ addl(EBX, EDI); |
| 75 __ j(CARRY, &fall_through); |
| 76 |
| 77 // Check if the allocation fits into the remaining space. |
| 78 // EAX: potential new object start. |
| 79 // EBX: potential next object start. |
| 80 // EDI: allocation size. |
| 81 // ECX: array element type. |
| 82 // EDX: array length as Smi). |
| 83 __ cmpl(EBX, Address::Absolute(heap->EndAddress())); |
| 84 __ j(ABOVE_EQUAL, &fall_through); |
| 85 |
| 86 // Successfully allocated the object(s), now update top to point to |
| 87 // next object start and initialize the object. |
| 88 __ movl(Address::Absolute(heap->TopAddress()), EBX); |
| 89 __ addl(EAX, Immediate(kHeapObjectTag)); |
| 90 __ UpdateAllocationStatsWithSize(kArrayCid, EDI, kNoRegister); |
| 91 |
| 92 // Initialize the tags. |
| 93 // EAX: new object start as a tagged pointer. |
| 94 // EBX: new object end address. |
| 95 // EDI: allocation size. |
| 96 // ECX: array element type. |
| 97 // EDX: array length as Smi. |
| 98 { |
| 99 Label size_tag_overflow, done; |
| 100 __ cmpl(EDI, Immediate(RawObject::SizeTag::kMaxSizeTag)); |
| 101 __ j(ABOVE, &size_tag_overflow, Assembler::kNearJump); |
| 102 __ shll(EDI, Immediate(RawObject::kSizeTagPos - kObjectAlignmentLog2)); |
| 103 __ jmp(&done, Assembler::kNearJump); |
| 104 |
| 105 __ Bind(&size_tag_overflow); |
| 106 __ movl(EDI, Immediate(0)); |
| 107 __ Bind(&done); |
| 108 |
| 109 // Get the class index and insert it into the tags. |
| 110 const Class& cls = Class::Handle(isolate->object_store()->array_class()); |
| 111 __ orl(EDI, Immediate(RawObject::ClassIdTag::encode(cls.id()))); |
| 112 __ movl(FieldAddress(EAX, Array::tags_offset()), EDI); // Tags. |
| 113 } |
| 114 // EAX: new object start as a tagged pointer. |
| 115 // EBX: new object end address. |
| 116 // ECX: array element type. |
| 117 // EDX: Array length as Smi (preserved). |
| 118 // Store the type argument field. |
| 119 __ StoreIntoObjectNoBarrier(EAX, |
| 120 FieldAddress(EAX, Array::type_arguments_offset()), |
| 121 ECX); |
| 122 |
| 123 // Set the length field. |
| 124 __ StoreIntoObjectNoBarrier(EAX, |
| 125 FieldAddress(EAX, Array::length_offset()), |
| 126 EDX); |
| 127 |
| 128 // Initialize all array elements to raw_null. |
| 129 // EAX: new object start as a tagged pointer. |
| 130 // EBX: new object end address. |
| 131 // EDI: iterator which initially points to the start of the variable |
| 132 // data area to be initialized. |
| 133 // ECX: array element type. |
| 134 // EDX: array length as Smi. |
| 135 __ leal(EDI, FieldAddress(EAX, sizeof(RawArray))); |
| 136 Label done; |
| 137 Label init_loop; |
| 138 __ Bind(&init_loop); |
| 139 __ cmpl(EDI, EBX); |
| 140 __ j(ABOVE_EQUAL, &done, Assembler::kNearJump); |
| 141 __ movl(Address(EDI, 0), raw_null); |
| 142 __ addl(EDI, Immediate(kWordSize)); |
| 143 __ jmp(&init_loop, Assembler::kNearJump); |
| 144 __ Bind(&done); |
| 145 __ popl(EDX); |
| 146 __ ret(); // returns the newly allocated object in EAX. |
| 147 __ Bind(&fall_through); |
| 148 __ popl(EDX); |
| 149 } |
| 150 |
| 151 |
| 32 void Intrinsifier::ObjectArrayLength(Assembler* assembler) { | 152 void Intrinsifier::ObjectArrayLength(Assembler* assembler) { |
| 33 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 153 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 34 __ movl(EAX, FieldAddress(EAX, Array::length_offset())); | 154 __ movl(EAX, FieldAddress(EAX, Array::length_offset())); |
| 35 __ ret(); | 155 __ ret(); |
| 36 } | 156 } |
| 37 | 157 |
| 38 | 158 |
| 39 void Intrinsifier::ImmutableArrayLength(Assembler* assembler) { | 159 void Intrinsifier::ImmutableArrayLength(Assembler* assembler) { |
| 40 ObjectArrayLength(assembler); | 160 ObjectArrayLength(assembler); |
| 41 } | 161 } |
| (...skipping 1346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1388 __ j(NOT_EQUAL, &try_two_byte_string, Assembler::kNearJump); | 1508 __ j(NOT_EQUAL, &try_two_byte_string, Assembler::kNearJump); |
| 1389 __ SmiUntag(EBX); | 1509 __ SmiUntag(EBX); |
| 1390 __ movzxb(EAX, FieldAddress(EAX, EBX, TIMES_1, OneByteString::data_offset())); | 1510 __ movzxb(EAX, FieldAddress(EAX, EBX, TIMES_1, OneByteString::data_offset())); |
| 1391 __ SmiTag(EAX); | 1511 __ SmiTag(EAX); |
| 1392 __ ret(); | 1512 __ ret(); |
| 1393 | 1513 |
| 1394 __ Bind(&try_two_byte_string); | 1514 __ Bind(&try_two_byte_string); |
| 1395 __ CompareClassId(EAX, kTwoByteStringCid, EDI); | 1515 __ CompareClassId(EAX, kTwoByteStringCid, EDI); |
| 1396 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); | 1516 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); |
| 1397 ASSERT(kSmiTagShift == 1); | 1517 ASSERT(kSmiTagShift == 1); |
| 1398 __ movzxw(EAX, FieldAddress(EAX, EBX, TIMES_1, OneByteString::data_offset())); | 1518 __ movzxw(EAX, FieldAddress(EAX, EBX, TIMES_1, TwoByteString::data_offset())); |
| 1399 __ SmiTag(EAX); | 1519 __ SmiTag(EAX); |
| 1400 __ ret(); | 1520 __ ret(); |
| 1401 | 1521 |
| 1402 __ Bind(&fall_through); | 1522 __ Bind(&fall_through); |
| 1403 } | 1523 } |
| 1404 | 1524 |
| 1405 | 1525 |
| 1526 void Intrinsifier::StringBase_charAt(Assembler* assembler) { |
| 1527 Label fall_through, try_two_byte_string; |
| 1528 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Index. |
| 1529 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // String. |
| 1530 __ testl(EBX, Immediate(kSmiTagMask)); |
| 1531 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Non-smi index. |
| 1532 // Range check. |
| 1533 __ cmpl(EBX, FieldAddress(EAX, String::length_offset())); |
| 1534 // Runtime throws exception. |
| 1535 __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump); |
| 1536 __ CompareClassId(EAX, kOneByteStringCid, EDI); |
| 1537 __ j(NOT_EQUAL, &try_two_byte_string, Assembler::kNearJump); |
| 1538 __ SmiUntag(EBX); |
| 1539 __ movzxb(EBX, FieldAddress(EAX, EBX, TIMES_1, OneByteString::data_offset())); |
| 1540 __ cmpl(EBX, Immediate(Symbols::kNumberOfOneCharCodeSymbols)); |
| 1541 __ j(GREATER_EQUAL, &fall_through); |
| 1542 __ movl(EAX, |
| 1543 Immediate(reinterpret_cast<uword>(Symbols::PredefinedAddress()))); |
| 1544 __ movl(EAX, Address(EAX, |
| 1545 EBX, |
| 1546 TIMES_4, |
| 1547 Symbols::kNullCharCodeSymbolOffset * kWordSize)); |
| 1548 __ ret(); |
| 1549 |
| 1550 __ Bind(&try_two_byte_string); |
| 1551 __ CompareClassId(EAX, kTwoByteStringCid, EDI); |
| 1552 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); |
| 1553 ASSERT(kSmiTagShift == 1); |
| 1554 __ movzxw(EBX, FieldAddress(EAX, EBX, TIMES_1, TwoByteString::data_offset())); |
| 1555 __ cmpl(EBX, Immediate(Symbols::kNumberOfOneCharCodeSymbols)); |
| 1556 __ j(GREATER_EQUAL, &fall_through); |
| 1557 __ movl(EAX, |
| 1558 Immediate(reinterpret_cast<uword>(Symbols::PredefinedAddress()))); |
| 1559 __ movl(EAX, Address(EAX, |
| 1560 EBX, |
| 1561 TIMES_4, |
| 1562 Symbols::kNullCharCodeSymbolOffset * kWordSize)); |
| 1563 __ ret(); |
| 1564 |
| 1565 __ Bind(&fall_through); |
| 1566 } |
| 1567 |
| 1568 |
| 1406 void Intrinsifier::StringBaseIsEmpty(Assembler* assembler) { | 1569 void Intrinsifier::StringBaseIsEmpty(Assembler* assembler) { |
| 1407 Label is_true; | 1570 Label is_true; |
| 1408 // Get length. | 1571 // Get length. |
| 1409 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // String object. | 1572 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // String object. |
| 1410 __ movl(EAX, FieldAddress(EAX, String::length_offset())); | 1573 __ movl(EAX, FieldAddress(EAX, String::length_offset())); |
| 1411 __ cmpl(EAX, Immediate(Smi::RawValue(0))); | 1574 __ cmpl(EAX, Immediate(Smi::RawValue(0))); |
| 1412 __ j(EQUAL, &is_true, Assembler::kNearJump); | 1575 __ j(EQUAL, &is_true, Assembler::kNearJump); |
| 1413 __ LoadObject(EAX, Bool::False()); | 1576 __ LoadObject(EAX, Bool::False()); |
| 1414 __ ret(); | 1577 __ ret(); |
| 1415 __ Bind(&is_true); | 1578 __ Bind(&is_true); |
| (...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1747 Isolate::current_tag_offset()); | 1910 Isolate::current_tag_offset()); |
| 1748 // Set return value to Isolate::current_tag_. | 1911 // Set return value to Isolate::current_tag_. |
| 1749 __ movl(EAX, current_tag_addr); | 1912 __ movl(EAX, current_tag_addr); |
| 1750 __ ret(); | 1913 __ ret(); |
| 1751 } | 1914 } |
| 1752 | 1915 |
| 1753 #undef __ | 1916 #undef __ |
| 1754 } // namespace dart | 1917 } // namespace dart |
| 1755 | 1918 |
| 1756 #endif // defined TARGET_ARCH_IA32 | 1919 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |