OLD | NEW |
---|---|
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/code-stub-assembler.h" | 5 #include "src/code-stub-assembler.h" |
6 #include "src/code-factory.h" | 6 #include "src/code-factory.h" |
7 #include "src/frames-inl.h" | 7 #include "src/frames-inl.h" |
8 #include "src/frames.h" | 8 #include "src/frames.h" |
9 #include "src/ic/handler-configuration.h" | 9 #include "src/ic/handler-configuration.h" |
10 #include "src/ic/stub-cache.h" | 10 #include "src/ic/stub-cache.h" |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
64 | 64 |
65 Node* CodeStubAssembler::IntPtrOrSmiConstant(int value, ParameterMode mode) { | 65 Node* CodeStubAssembler::IntPtrOrSmiConstant(int value, ParameterMode mode) { |
66 if (mode == SMI_PARAMETERS) { | 66 if (mode == SMI_PARAMETERS) { |
67 return SmiConstant(Smi::FromInt(value)); | 67 return SmiConstant(Smi::FromInt(value)); |
68 } else { | 68 } else { |
69 DCHECK(mode == INTEGER_PARAMETERS || mode == INTPTR_PARAMETERS); | 69 DCHECK(mode == INTEGER_PARAMETERS || mode == INTPTR_PARAMETERS); |
70 return IntPtrConstant(value); | 70 return IntPtrConstant(value); |
71 } | 71 } |
72 } | 72 } |
73 | 73 |
74 Node* CodeStubAssembler::IntPtrAddFoldConstants(Node* left, Node* right) { | |
75 int32_t left_constant; | |
76 bool is_left_constant = ToInt32Constant(left, left_constant); | |
77 int32_t right_constant; | |
78 bool is_right_constant = ToInt32Constant(right, right_constant); | |
79 if (is_left_constant) { | |
80 if (is_right_constant) { | |
81 return IntPtrConstant(left_constant + right_constant); | |
82 } | |
83 if (left_constant == 0) { | |
84 return right; | |
85 } | |
86 } else if (is_right_constant) { | |
87 if (right_constant == 0) { | |
88 return left; | |
89 } | |
90 } | |
91 return IntPtrAdd(left, right); | |
92 } | |
93 | |
94 Node* CodeStubAssembler::IntPtrSubFoldConstants(Node* left, Node* right) { | |
95 int32_t left_constant; | |
96 bool is_left_constant = ToInt32Constant(left, left_constant); | |
97 int32_t right_constant; | |
98 bool is_right_constant = ToInt32Constant(right, right_constant); | |
99 if (is_left_constant) { | |
100 if (is_right_constant) { | |
101 return IntPtrConstant(left_constant - right_constant); | |
102 } | |
103 } else if (is_right_constant) { | |
104 if (right_constant == 0) { | |
105 return left; | |
106 } | |
107 } | |
108 return IntPtrSub(left, right); | |
109 } | |
110 | |
74 Node* CodeStubAssembler::Float64Round(Node* x) { | 111 Node* CodeStubAssembler::Float64Round(Node* x) { |
75 Node* one = Float64Constant(1.0); | 112 Node* one = Float64Constant(1.0); |
76 Node* one_half = Float64Constant(0.5); | 113 Node* one_half = Float64Constant(0.5); |
77 | 114 |
78 Variable var_x(this, MachineRepresentation::kFloat64); | 115 Variable var_x(this, MachineRepresentation::kFloat64); |
79 Label return_x(this); | 116 Label return_x(this); |
80 | 117 |
81 // Round up {x} towards Infinity. | 118 // Round up {x} towards Infinity. |
82 var_x.Bind(Float64Ceil(x)); | 119 var_x.Bind(Float64Ceil(x)); |
83 | 120 |
(...skipping 1121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1205 return result; | 1242 return result; |
1206 } | 1243 } |
1207 | 1244 |
1208 Node* CodeStubAssembler::AllocateHeapNumberWithValue(Node* value, | 1245 Node* CodeStubAssembler::AllocateHeapNumberWithValue(Node* value, |
1209 MutableMode mode) { | 1246 MutableMode mode) { |
1210 Node* result = AllocateHeapNumber(mode); | 1247 Node* result = AllocateHeapNumber(mode); |
1211 StoreHeapNumberValue(result, value); | 1248 StoreHeapNumberValue(result, value); |
1212 return result; | 1249 return result; |
1213 } | 1250 } |
1214 | 1251 |
1215 Node* CodeStubAssembler::AllocateSeqOneByteString(int length) { | 1252 Node* CodeStubAssembler::AllocateSeqOneByteString(int length, |
1216 Node* result = Allocate(SeqOneByteString::SizeFor(length)); | 1253 AllocationFlags flags) { |
1254 Node* result = Allocate(SeqOneByteString::SizeFor(length), flags); | |
1255 DCHECK(Heap::RootIsImmortalImmovable(Heap::kOneByteStringMapRootIndex)); | |
1217 StoreMapNoWriteBarrier(result, LoadRoot(Heap::kOneByteStringMapRootIndex)); | 1256 StoreMapNoWriteBarrier(result, LoadRoot(Heap::kOneByteStringMapRootIndex)); |
1218 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kLengthOffset, | 1257 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kLengthOffset, |
1219 SmiConstant(Smi::FromInt(length))); | 1258 SmiConstant(Smi::FromInt(length))); |
1220 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kHashFieldOffset, | 1259 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kHashFieldOffset, |
1221 IntPtrConstant(String::kEmptyHashField), | 1260 IntPtrConstant(String::kEmptyHashField), |
1222 MachineRepresentation::kWord32); | 1261 MachineRepresentation::kWord32); |
1223 return result; | 1262 return result; |
1224 } | 1263 } |
1225 | 1264 |
1226 Node* CodeStubAssembler::AllocateSeqOneByteString(Node* context, Node* length) { | 1265 Node* CodeStubAssembler::AllocateSeqOneByteString(Node* context, Node* length, |
1266 AllocationFlags flags) { | |
1227 Variable var_result(this, MachineRepresentation::kTagged); | 1267 Variable var_result(this, MachineRepresentation::kTagged); |
1228 | 1268 |
1229 // Compute the SeqOneByteString size and check if it fits into new space. | 1269 // Compute the SeqOneByteString size and check if it fits into new space. |
1230 Label if_sizeissmall(this), if_notsizeissmall(this, Label::kDeferred), | 1270 Label if_sizeissmall(this), if_notsizeissmall(this, Label::kDeferred), |
1231 if_join(this); | 1271 if_join(this); |
1232 Node* size = WordAnd( | 1272 Node* size = WordAnd( |
1233 IntPtrAdd( | 1273 IntPtrAdd( |
1234 IntPtrAdd(length, IntPtrConstant(SeqOneByteString::kHeaderSize)), | 1274 IntPtrAdd(length, IntPtrConstant(SeqOneByteString::kHeaderSize)), |
1235 IntPtrConstant(kObjectAlignmentMask)), | 1275 IntPtrConstant(kObjectAlignmentMask)), |
1236 IntPtrConstant(~kObjectAlignmentMask)); | 1276 IntPtrConstant(~kObjectAlignmentMask)); |
1237 Branch(IntPtrLessThanOrEqual(size, IntPtrConstant(kMaxRegularHeapObjectSize)), | 1277 Branch(IntPtrLessThanOrEqual(size, IntPtrConstant(kMaxRegularHeapObjectSize)), |
1238 &if_sizeissmall, &if_notsizeissmall); | 1278 &if_sizeissmall, &if_notsizeissmall); |
1239 | 1279 |
1240 Bind(&if_sizeissmall); | 1280 Bind(&if_sizeissmall); |
1241 { | 1281 { |
1242 // Just allocate the SeqOneByteString in new space. | 1282 // Just allocate the SeqOneByteString in new space. |
1243 Node* result = Allocate(size); | 1283 Node* result = Allocate(size, flags); |
1284 DCHECK(Heap::RootIsImmortalImmovable(Heap::kOneByteStringMapRootIndex)); | |
1244 StoreMapNoWriteBarrier(result, LoadRoot(Heap::kOneByteStringMapRootIndex)); | 1285 StoreMapNoWriteBarrier(result, LoadRoot(Heap::kOneByteStringMapRootIndex)); |
1245 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kLengthOffset, | 1286 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kLengthOffset, |
1246 SmiFromWord(length)); | 1287 SmiFromWord(length)); |
1247 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kHashFieldOffset, | 1288 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kHashFieldOffset, |
1248 IntPtrConstant(String::kEmptyHashField), | 1289 IntPtrConstant(String::kEmptyHashField), |
1249 MachineRepresentation::kWord32); | 1290 MachineRepresentation::kWord32); |
1250 var_result.Bind(result); | 1291 var_result.Bind(result); |
1251 Goto(&if_join); | 1292 Goto(&if_join); |
1252 } | 1293 } |
1253 | 1294 |
1254 Bind(&if_notsizeissmall); | 1295 Bind(&if_notsizeissmall); |
1255 { | 1296 { |
1256 // We might need to allocate in large object space, go to the runtime. | 1297 // We might need to allocate in large object space, go to the runtime. |
1257 Node* result = CallRuntime(Runtime::kAllocateSeqOneByteString, context, | 1298 Node* result = CallRuntime(Runtime::kAllocateSeqOneByteString, context, |
1258 SmiFromWord(length)); | 1299 SmiFromWord(length)); |
1259 var_result.Bind(result); | 1300 var_result.Bind(result); |
1260 Goto(&if_join); | 1301 Goto(&if_join); |
1261 } | 1302 } |
1262 | 1303 |
1263 Bind(&if_join); | 1304 Bind(&if_join); |
1264 return var_result.value(); | 1305 return var_result.value(); |
1265 } | 1306 } |
1266 | 1307 |
1267 Node* CodeStubAssembler::AllocateSeqTwoByteString(int length) { | 1308 Node* CodeStubAssembler::AllocateSeqTwoByteString(int length, |
1268 Node* result = Allocate(SeqTwoByteString::SizeFor(length)); | 1309 AllocationFlags flags) { |
1310 Node* result = Allocate(SeqTwoByteString::SizeFor(length), flags); | |
1311 DCHECK(Heap::RootIsImmortalImmovable(Heap::kStringMapRootIndex)); | |
1269 StoreMapNoWriteBarrier(result, LoadRoot(Heap::kStringMapRootIndex)); | 1312 StoreMapNoWriteBarrier(result, LoadRoot(Heap::kStringMapRootIndex)); |
1270 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kLengthOffset, | 1313 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kLengthOffset, |
1271 SmiConstant(Smi::FromInt(length))); | 1314 SmiConstant(Smi::FromInt(length))); |
1272 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kHashFieldOffset, | 1315 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kHashFieldOffset, |
1273 IntPtrConstant(String::kEmptyHashField), | 1316 IntPtrConstant(String::kEmptyHashField), |
1274 MachineRepresentation::kWord32); | 1317 MachineRepresentation::kWord32); |
1275 return result; | 1318 return result; |
1276 } | 1319 } |
1277 | 1320 |
1278 Node* CodeStubAssembler::AllocateSeqTwoByteString(Node* context, Node* length) { | 1321 Node* CodeStubAssembler::AllocateSeqTwoByteString(Node* context, Node* length, |
1322 AllocationFlags flags) { | |
1279 Variable var_result(this, MachineRepresentation::kTagged); | 1323 Variable var_result(this, MachineRepresentation::kTagged); |
1280 | 1324 |
1281 // Compute the SeqTwoByteString size and check if it fits into new space. | 1325 // Compute the SeqTwoByteString size and check if it fits into new space. |
1282 Label if_sizeissmall(this), if_notsizeissmall(this, Label::kDeferred), | 1326 Label if_sizeissmall(this), if_notsizeissmall(this, Label::kDeferred), |
1283 if_join(this); | 1327 if_join(this); |
1284 Node* size = WordAnd( | 1328 Node* size = WordAnd( |
1285 IntPtrAdd(IntPtrAdd(WordShl(length, 1), | 1329 IntPtrAdd(IntPtrAdd(WordShl(length, 1), |
1286 IntPtrConstant(SeqTwoByteString::kHeaderSize)), | 1330 IntPtrConstant(SeqTwoByteString::kHeaderSize)), |
1287 IntPtrConstant(kObjectAlignmentMask)), | 1331 IntPtrConstant(kObjectAlignmentMask)), |
1288 IntPtrConstant(~kObjectAlignmentMask)); | 1332 IntPtrConstant(~kObjectAlignmentMask)); |
1289 Branch(IntPtrLessThanOrEqual(size, IntPtrConstant(kMaxRegularHeapObjectSize)), | 1333 Branch(IntPtrLessThanOrEqual(size, IntPtrConstant(kMaxRegularHeapObjectSize)), |
1290 &if_sizeissmall, &if_notsizeissmall); | 1334 &if_sizeissmall, &if_notsizeissmall); |
1291 | 1335 |
1292 Bind(&if_sizeissmall); | 1336 Bind(&if_sizeissmall); |
1293 { | 1337 { |
1294 // Just allocate the SeqTwoByteString in new space. | 1338 // Just allocate the SeqTwoByteString in new space. |
1295 Node* result = Allocate(size); | 1339 Node* result = Allocate(size, flags); |
1340 DCHECK(Heap::RootIsImmortalImmovable(Heap::kStringMapRootIndex)); | |
1296 StoreMapNoWriteBarrier(result, LoadRoot(Heap::kStringMapRootIndex)); | 1341 StoreMapNoWriteBarrier(result, LoadRoot(Heap::kStringMapRootIndex)); |
1297 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kLengthOffset, | 1342 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kLengthOffset, |
1298 SmiFromWord(length)); | 1343 SmiFromWord(length)); |
1299 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kHashFieldOffset, | 1344 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kHashFieldOffset, |
1300 IntPtrConstant(String::kEmptyHashField), | 1345 IntPtrConstant(String::kEmptyHashField), |
1301 MachineRepresentation::kWord32); | 1346 MachineRepresentation::kWord32); |
1302 var_result.Bind(result); | 1347 var_result.Bind(result); |
1303 Goto(&if_join); | 1348 Goto(&if_join); |
1304 } | 1349 } |
1305 | 1350 |
(...skipping 410 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1716 Bind(&done); | 1761 Bind(&done); |
1717 IncrementCounter(isolate()->counters()->inlined_copied_elements(), 1); | 1762 IncrementCounter(isolate()->counters()->inlined_copied_elements(), 1); |
1718 Comment("] CopyFixedArrayElements"); | 1763 Comment("] CopyFixedArrayElements"); |
1719 } | 1764 } |
1720 | 1765 |
1721 void CodeStubAssembler::CopyStringCharacters(compiler::Node* from_string, | 1766 void CodeStubAssembler::CopyStringCharacters(compiler::Node* from_string, |
1722 compiler::Node* to_string, | 1767 compiler::Node* to_string, |
1723 compiler::Node* from_index, | 1768 compiler::Node* from_index, |
1724 compiler::Node* to_index, | 1769 compiler::Node* to_index, |
1725 compiler::Node* character_count, | 1770 compiler::Node* character_count, |
1726 String::Encoding encoding) { | 1771 String::Encoding encoding, |
1727 Label out(this); | 1772 ParameterMode mode) { |
1773 bool one_byte = encoding == String::ONE_BYTE_ENCODING; | |
1774 Comment(one_byte ? "CopyStringCharacters ONE_BYTE_ENCODING" | |
1775 : "CopyStringCharacters TWO_BYTE_ENCODING"); | |
1728 | 1776 |
1729 // Nothing to do for zero characters. | 1777 ElementsKind kind = one_byte ? UINT8_ELEMENTS : UINT16_ELEMENTS; |
1778 int header_size = (one_byte ? SeqOneByteString::kHeaderSize | |
1779 : SeqTwoByteString::kHeaderSize) - | |
1780 kHeapObjectTag; | |
1781 Node* from_offset = ElementOffsetFromIndex(from_index, kind, mode); | |
1782 Node* to_offset = ElementOffsetFromIndex(to_index, kind, mode); | |
1783 Node* byte_count = ElementOffsetFromIndex(character_count, kind, mode); | |
1784 Node* limit_offset = IntPtrAddFoldConstants(from_offset, byte_count); | |
1730 | 1785 |
1731 GotoIf(SmiLessThanOrEqual(character_count, SmiConstant(Smi::kZero)), &out); | 1786 // Prepare the fast loop |
1787 MachineType type = one_byte ? MachineType::Uint8() : MachineType::Uint16(); | |
1788 MachineRepresentation rep = | |
1789 one_byte ? MachineRepresentation::kWord8 : MachineRepresentation::kWord16; | |
1790 int increment = -(1 << ElementsKindToShiftSize(kind)); | |
1732 | 1791 |
1733 // Calculate offsets into the strings. | 1792 Node* to_string_adjusted = IntPtrAddFoldConstants( |
1793 to_string, IntPtrSubFoldConstants(to_offset, from_offset)); | |
1794 limit_offset = | |
1795 IntPtrAddFoldConstants(limit_offset, IntPtrConstant(header_size)); | |
1796 from_offset = | |
1797 IntPtrAddFoldConstants(from_offset, IntPtrConstant(header_size)); | |
1734 | 1798 |
1735 Node* from_offset; | 1799 BuildFastLoop(MachineType::PointerRepresentation(), limit_offset, from_offset, |
1736 Node* limit_offset; | 1800 [from_string, to_string_adjusted, type, rep]( |
1737 Node* to_offset; | 1801 CodeStubAssembler* assembler, Node* offset) { |
1738 | 1802 Node* value = assembler->Load(type, from_string, offset); |
1739 { | 1803 assembler->StoreNoWriteBarrier(rep, to_string_adjusted, |
1740 Node* byte_count = SmiUntag(character_count); | 1804 offset, value); |
1741 Node* from_byte_index = SmiUntag(from_index); | 1805 }, |
1742 Node* to_byte_index = SmiUntag(to_index); | 1806 increment); |
1743 if (encoding == String::ONE_BYTE_ENCODING) { | |
1744 const int offset = SeqOneByteString::kHeaderSize - kHeapObjectTag; | |
1745 from_offset = IntPtrAdd(IntPtrConstant(offset), from_byte_index); | |
1746 limit_offset = IntPtrAdd(from_offset, byte_count); | |
1747 to_offset = IntPtrAdd(IntPtrConstant(offset), to_byte_index); | |
1748 } else { | |
1749 STATIC_ASSERT(2 == sizeof(uc16)); | |
1750 byte_count = WordShl(byte_count, 1); | |
1751 from_byte_index = WordShl(from_byte_index, 1); | |
1752 to_byte_index = WordShl(to_byte_index, 1); | |
1753 | |
1754 const int offset = SeqTwoByteString::kHeaderSize - kHeapObjectTag; | |
1755 from_offset = IntPtrAdd(IntPtrConstant(offset), from_byte_index); | |
1756 limit_offset = IntPtrAdd(from_offset, byte_count); | |
1757 to_offset = IntPtrAdd(IntPtrConstant(offset), to_byte_index); | |
1758 } | |
1759 } | |
1760 | |
1761 Variable var_from_offset(this, MachineType::PointerRepresentation()); | |
1762 Variable var_to_offset(this, MachineType::PointerRepresentation()); | |
1763 | |
1764 var_from_offset.Bind(from_offset); | |
1765 var_to_offset.Bind(to_offset); | |
1766 | |
1767 Variable* vars[] = {&var_from_offset, &var_to_offset}; | |
1768 Label decrement(this, 2, vars); | |
1769 | |
1770 Label loop(this, 2, vars); | |
1771 Goto(&loop); | |
1772 Bind(&loop); | |
1773 { | |
1774 from_offset = var_from_offset.value(); | |
1775 to_offset = var_to_offset.value(); | |
1776 | |
1777 // TODO(jgruber): We could make this faster through larger copy unit sizes. | |
1778 Node* value = Load(MachineType::Uint8(), from_string, from_offset); | |
1779 StoreNoWriteBarrier(MachineRepresentation::kWord8, to_string, to_offset, | |
1780 value); | |
1781 | |
1782 Node* new_from_offset = IntPtrAdd(from_offset, IntPtrConstant(1)); | |
1783 var_from_offset.Bind(new_from_offset); | |
1784 var_to_offset.Bind(IntPtrAdd(to_offset, IntPtrConstant(1))); | |
1785 | |
1786 Branch(WordNotEqual(new_from_offset, limit_offset), &loop, &out); | |
1787 } | |
1788 | |
1789 Bind(&out); | |
1790 } | 1807 } |
1791 | 1808 |
1792 Node* CodeStubAssembler::LoadElementAndPrepareForStore(Node* array, | 1809 Node* CodeStubAssembler::LoadElementAndPrepareForStore(Node* array, |
1793 Node* offset, | 1810 Node* offset, |
1794 ElementsKind from_kind, | 1811 ElementsKind from_kind, |
1795 ElementsKind to_kind, | 1812 ElementsKind to_kind, |
1796 Label* if_hole) { | 1813 Label* if_hole) { |
1797 if (IsFastDoubleElementsKind(from_kind)) { | 1814 if (IsFastDoubleElementsKind(from_kind)) { |
1798 Node* value = | 1815 Node* value = |
1799 LoadDoubleWithHoleCheck(array, offset, if_hole, MachineType::Float64()); | 1816 LoadDoubleWithHoleCheck(array, offset, if_hole, MachineType::Float64()); |
(...skipping 758 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2558 a->GotoIf(a->Word32Equal(a->Word32And(from_instance_type, | 2575 a->GotoIf(a->Word32Equal(a->Word32And(from_instance_type, |
2559 a->Int32Constant(kStringEncodingMask)), | 2576 a->Int32Constant(kStringEncodingMask)), |
2560 a->Int32Constant(0)), | 2577 a->Int32Constant(0)), |
2561 &two_byte_sequential); | 2578 &two_byte_sequential); |
2562 | 2579 |
2563 // The subject string is a sequential one-byte string. | 2580 // The subject string is a sequential one-byte string. |
2564 { | 2581 { |
2565 Node* result = | 2582 Node* result = |
2566 a->AllocateSeqOneByteString(context, a->SmiToWord(character_count)); | 2583 a->AllocateSeqOneByteString(context, a->SmiToWord(character_count)); |
2567 a->CopyStringCharacters(from, result, from_index, smi_zero, character_count, | 2584 a->CopyStringCharacters(from, result, from_index, smi_zero, character_count, |
2568 String::ONE_BYTE_ENCODING); | 2585 String::ONE_BYTE_ENCODING, |
2586 CodeStubAssembler::SMI_PARAMETERS); | |
2569 var_result.Bind(result); | 2587 var_result.Bind(result); |
2570 | 2588 |
2571 a->Goto(&end); | 2589 a->Goto(&end); |
2572 } | 2590 } |
2573 | 2591 |
2574 // The subject string is a sequential two-byte string. | 2592 // The subject string is a sequential two-byte string. |
2575 a->Bind(&two_byte_sequential); | 2593 a->Bind(&two_byte_sequential); |
2576 { | 2594 { |
2577 Node* result = | 2595 Node* result = |
2578 a->AllocateSeqTwoByteString(context, a->SmiToWord(character_count)); | 2596 a->AllocateSeqTwoByteString(context, a->SmiToWord(character_count)); |
2579 a->CopyStringCharacters(from, result, from_index, smi_zero, character_count, | 2597 a->CopyStringCharacters(from, result, from_index, smi_zero, character_count, |
2580 String::TWO_BYTE_ENCODING); | 2598 String::TWO_BYTE_ENCODING, |
2599 CodeStubAssembler::SMI_PARAMETERS); | |
2581 var_result.Bind(result); | 2600 var_result.Bind(result); |
2582 | 2601 |
2583 a->Goto(&end); | 2602 a->Goto(&end); |
2584 } | 2603 } |
2585 | 2604 |
2586 a->Bind(&end); | 2605 a->Bind(&end); |
2587 return var_result.value(); | 2606 return var_result.value(); |
2588 } | 2607 } |
2589 | 2608 |
2590 } // namespace | 2609 } // namespace |
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2842 Node* const min_cons_length = | 2861 Node* const min_cons_length = |
2843 SmiConstant(Smi::FromInt(ConsString::kMinLength)); | 2862 SmiConstant(Smi::FromInt(ConsString::kMinLength)); |
2844 Branch(SmiLessThan(length, min_cons_length), &if_makeseqstring, | 2863 Branch(SmiLessThan(length, min_cons_length), &if_makeseqstring, |
2845 &if_makeconsstring); | 2864 &if_makeconsstring); |
2846 | 2865 |
2847 Bind(&if_makeseqstring); | 2866 Bind(&if_makeseqstring); |
2848 { | 2867 { |
2849 Node* result = AllocateSeqOneByteString(context, SmiToWord(length)); | 2868 Node* result = AllocateSeqOneByteString(context, SmiToWord(length)); |
2850 | 2869 |
2851 CopyStringCharacters(first, result, smi_zero, smi_zero, first_length, | 2870 CopyStringCharacters(first, result, smi_zero, smi_zero, first_length, |
2852 String::ONE_BYTE_ENCODING); | 2871 String::ONE_BYTE_ENCODING, SMI_PARAMETERS); |
2853 CopyStringCharacters(second, result, smi_zero, first_length, second_length, | 2872 CopyStringCharacters(second, result, smi_zero, first_length, second_length, |
2854 String::ONE_BYTE_ENCODING); | 2873 String::ONE_BYTE_ENCODING, SMI_PARAMETERS); |
2855 | 2874 |
2856 var_result.Bind(result); | 2875 var_result.Bind(result); |
2857 Goto(&out); | 2876 Goto(&out); |
2858 } | 2877 } |
2859 | 2878 |
2860 Bind(&if_makeconsstring); | 2879 Bind(&if_makeconsstring); |
2861 { | 2880 { |
2862 Node* result = AllocateOneByteConsString(length, first, second); | 2881 Node* result = AllocateOneByteConsString(length, first, second); |
2863 var_result.Bind(result); | 2882 var_result.Bind(result); |
2864 Goto(&out); | 2883 Goto(&out); |
(...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3268 { | 3287 { |
3269 var_result.Bind(NonNumberToNumber(context, input)); | 3288 var_result.Bind(NonNumberToNumber(context, input)); |
3270 Goto(&end); | 3289 Goto(&end); |
3271 } | 3290 } |
3272 } | 3291 } |
3273 | 3292 |
3274 Bind(&end); | 3293 Bind(&end); |
3275 return var_result.value(); | 3294 return var_result.value(); |
3276 } | 3295 } |
3277 | 3296 |
3297 Node* CodeStubAssembler::ToString(Node* context, Node* input) { | |
3298 Label is_number(this); | |
3299 Label runtime(this, Label::kDeferred); | |
3300 Variable result(this, MachineRepresentation::kTagged); | |
3301 Label done(this, &result); | |
3302 | |
3303 GotoIf(TaggedIsSmi(input), &is_number); | |
3304 | |
3305 Node* input_map = LoadMap(input); | |
3306 Node* input_instance_type = LoadMapInstanceType(input_map); | |
3307 | |
3308 result.Bind(input); | |
3309 GotoIf(IsStringInstanceType(input_instance_type), &done); | |
3310 | |
3311 Label not_heap_number(this); | |
3312 Branch(WordNotEqual(input_map, HeapNumberMapConstant()), ¬_heap_number, | |
3313 &is_number); | |
3314 | |
3315 Bind(&is_number); | |
3316 result.Bind(NumberToString(context, input)); | |
3317 Goto(&done); | |
3318 | |
3319 Bind(¬_heap_number); | |
3320 { | |
3321 GotoIf(Word32NotEqual(input_instance_type, Int32Constant(ODDBALL_TYPE)), | |
3322 &runtime); | |
3323 result.Bind(LoadObjectField(input, Oddball::kToStringOffset)); | |
3324 Goto(&done); | |
3325 } | |
3326 | |
3327 Bind(&runtime); | |
3328 { | |
3329 result.Bind(CallRuntime(Runtime::kToString, context, input)); | |
3330 Goto(&done); | |
3331 } | |
3332 | |
3333 Bind(&done); | |
3334 return result.value(); | |
3335 } | |
3336 | |
3337 Node* CodeStubAssembler::JSReceiverToPrimitive(Node* context, Node* input) { | |
3338 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); | |
3339 Label if_isreceiver(this, Label::kDeferred), if_isnotreceiver(this); | |
3340 Variable result(this, MachineRepresentation::kTagged); | |
3341 Label done(this, &result); | |
3342 | |
3343 GotoIf(TaggedIsSmi(input), &if_isnotreceiver); | |
3344 | |
3345 Node* map = LoadMap(input); | |
3346 Node* instance_type = LoadMapInstanceType(map); | |
3347 Branch(IsJSReceiverInstanceType(instance_type), &if_isreceiver, | |
3348 &if_isnotreceiver); | |
3349 | |
3350 Bind(&if_isreceiver); | |
3351 { | |
3352 // Convert {input} to a primitive first passing Number hint. | |
3353 Callable callable = CodeFactory::NonPrimitiveToPrimitive(isolate()); | |
3354 result.Bind(CallStub(callable, context, input)); | |
3355 Goto(&done); | |
3356 } | |
3357 | |
3358 Bind(&if_isnotreceiver); | |
3359 { | |
3360 result.Bind(input); | |
3361 Goto(&done); | |
3362 } | |
3363 | |
3364 Bind(&done); | |
3365 return result.value(); | |
3366 } | |
3367 | |
3368 Node* CodeStubAssembler::NewConsString(Node* context, Node* length, Node* left, | |
3369 Node* right, AllocationFlags flags) { | |
3370 // Added string can be a cons string. | |
3371 Comment("Allocating ConsString"); | |
3372 Node* left_instance_type = LoadInstanceType(left); | |
3373 Node* right_instance_type = LoadInstanceType(right); | |
3374 | |
3375 // Allocate the cons string object. After the allocation we decide whether the | |
3376 // cons string is one-byte or two-byte and set the appropriate map. | |
3377 Node* cons_string = Allocate(IntPtrConstant(ConsString::kSize), flags); | |
3378 | |
3379 // Compute intersection and difference of instance types. | |
3380 Node* anded_instance_types = WordAnd(left_instance_type, right_instance_type); | |
3381 Node* xored_instance_types = WordXor(left_instance_type, right_instance_type); | |
3382 | |
3383 // We create a one-byte cons string if | |
3384 // 1. both strings are one-byte, or | |
3385 // 2. at least one of the strings is two-byte, but happens to contain only | |
3386 // one-byte characters. | |
3387 // To do this, we check | |
3388 // 1. if both strings are one-byte, or if the one-byte data hint is set in | |
3389 // both strings, or | |
Igor Sheludko
2016/10/13 15:41:33
I wonder why does kOneByteStringTag not imply kOne
danno
2016/10/17 14:23:26
Good question, although before pulling on this str
| |
3390 // 2. if one of the strings has the one-byte data hint set and the other | |
3391 // string is one-byte. | |
3392 STATIC_ASSERT(kOneByteStringTag != 0); | |
3393 STATIC_ASSERT(kOneByteDataHintMask != 0); | |
Igor Sheludko
2016/10/13 15:41:33
kOneByteDataHintTag != 0
danno
2016/10/17 14:23:26
Done.
| |
3394 Label one_byte_map(this); | |
3395 Label two_byte_map(this); | |
3396 Label map_done(this); | |
3397 GotoIf(WordNotEqual( | |
3398 WordAnd(anded_instance_types, | |
3399 IntPtrConstant(kOneByteStringTag | kOneByteDataHintTag)), | |
3400 IntPtrConstant(0)), | |
3401 &one_byte_map); | |
3402 Branch(WordNotEqual( | |
3403 WordAnd(xored_instance_types, | |
3404 IntPtrConstant(kOneByteStringTag | kOneByteDataHintMask)), | |
Igor Sheludko
2016/10/13 15:41:33
kOneByteStringTag -> kStringEncodingMask
danno
2016/10/17 14:23:26
Done.
| |
3405 IntPtrConstant(kOneByteStringTag | kOneByteDataHintTag)), | |
3406 &two_byte_map, &one_byte_map); | |
3407 | |
3408 Bind(&one_byte_map); | |
3409 Comment("One-byte ConsString"); | |
3410 DCHECK(Heap::RootIsImmortalImmovable(Heap::kConsOneByteStringMapRootIndex)); | |
3411 StoreMapNoWriteBarrier(cons_string, | |
3412 LoadRoot(Heap::kConsOneByteStringMapRootIndex)); | |
jgruber
2016/10/13 14:10:16
Would it make sense to reuse Allocate{One,Two}Byte
danno
2016/10/17 14:23:26
Yes! Good catch!
| |
3413 Goto(&map_done); | |
3414 | |
3415 Bind(&two_byte_map); | |
3416 Comment("Two-byte ConsString"); | |
3417 DCHECK(Heap::RootIsImmortalImmovable(Heap::kConsStringMapRootIndex)); | |
3418 StoreMapNoWriteBarrier(cons_string, LoadRoot(Heap::kConsStringMapRootIndex)); | |
3419 Goto(&map_done); | |
3420 | |
3421 Bind(&map_done); | |
3422 StoreObjectFieldNoWriteBarrier(cons_string, String::kHashFieldOffset, | |
3423 IntPtrConstant(String::kEmptyHashField)); | |
3424 StoreObjectFieldNoWriteBarrier(cons_string, String::kLengthOffset, | |
3425 SmiTag(length)); | |
3426 bool const new_space = !(flags & kPretenured); | |
3427 if (new_space) { | |
3428 StoreObjectFieldNoWriteBarrier(cons_string, ConsString::kFirstOffset, left); | |
3429 StoreObjectFieldNoWriteBarrier(cons_string, ConsString::kSecondOffset, | |
3430 right); | |
3431 } else { | |
3432 StoreObjectField(cons_string, ConsString::kFirstOffset, left); | |
3433 StoreObjectField(cons_string, ConsString::kSecondOffset, right); | |
3434 } | |
3435 | |
3436 return cons_string; | |
3437 } | |
3438 | |
3439 Node* CodeStubAssembler::StringAdd(Node* context, Node* left, Node* right, | |
jgruber
2016/10/13 14:10:16
This is basically a more complete version of Strin
danno
2016/10/17 14:23:26
I totally missed that this existed when I ported f
| |
3440 AllocationFlags flags) { | |
3441 Label check_right(this); | |
3442 Label runtime(this, Label::kDeferred); | |
3443 Label cons(this); | |
3444 Label non_cons(this); | |
3445 Variable result(this, MachineRepresentation::kTagged); | |
3446 Label done(this, &result); | |
3447 Label done_native(this, &result); | |
3448 Counters* counters = isolate()->counters(); | |
3449 | |
3450 Node* left_length = LoadStringLength(left); | |
3451 GotoIf(WordNotEqual(IntPtrConstant(0), left_length), &check_right); | |
3452 result.Bind(right); | |
3453 Goto(&done_native); | |
3454 | |
3455 Bind(&check_right); | |
3456 Node* right_length = LoadStringLength(right); | |
3457 GotoIf(WordNotEqual(IntPtrConstant(0), right_length), &cons); | |
3458 result.Bind(left); | |
3459 Goto(&done_native); | |
3460 | |
3461 Bind(&cons); | |
3462 Node* new_length = IntPtrAdd(SmiUntag(left_length), SmiUntag(right_length)); | |
3463 GotoIf(IntPtrLessThan(new_length, IntPtrConstant(0)), &runtime); | |
3464 GotoIf(IntPtrGreaterThan(new_length, IntPtrConstant(String::kMaxLength)), | |
Igor Sheludko
2016/10/13 15:41:33
How about doing one unsigned comparison instead of
danno
2016/10/17 14:23:26
Done.
| |
3465 &runtime); | |
3466 | |
3467 GotoIf(IntPtrLessThan(new_length, IntPtrConstant(ConsString::kMinLength)), | |
3468 &non_cons); | |
3469 | |
3470 result.Bind(NewConsString(context, new_length, left, right, flags)); | |
3471 Goto(&done_native); | |
3472 | |
3473 Bind(&non_cons); | |
3474 | |
3475 Comment("Full string concatenate"); | |
3476 Node* left_instance_type = LoadInstanceType(left); | |
3477 Node* right_instance_type = LoadInstanceType(right); | |
3478 // Compute intersection and difference of instance types. | |
3479 | |
3480 Node* ored_instance_types = WordOr(left_instance_type, right_instance_type); | |
3481 Node* xored_instance_types = WordXor(left_instance_type, right_instance_type); | |
3482 | |
3483 // Check if both strings have the same encoding and both are sequential. | |
3484 GotoIf(WordNotEqual( | |
3485 WordAnd(xored_instance_types, IntPtrConstant(kStringEncodingMask)), | |
3486 IntPtrConstant(0)), | |
3487 &runtime); | |
3488 GotoIf(WordNotEqual(WordAnd(ored_instance_types, | |
3489 IntPtrConstant(kStringRepresentationMask)), | |
3490 IntPtrConstant(0)), | |
3491 &runtime); | |
3492 | |
3493 Label two_byte(this); | |
3494 GotoIf(WordEqual( | |
3495 WordAnd(ored_instance_types, IntPtrConstant(kStringEncodingMask)), | |
3496 IntPtrConstant(0)), | |
Igor Sheludko
2016/10/13 15:41:33
0 -> kTwoByteStringTag or STATIC_ASSERT
danno
2016/10/17 14:23:26
Done.
| |
3497 &two_byte); | |
3498 // One-byte sequential string case | |
3499 Node* new_string = AllocateSeqOneByteString(context, new_length); | |
3500 CopyStringCharacters(left, new_string, SmiConstant(Smi::kZero), | |
3501 SmiConstant(Smi::kZero), left_length, | |
3502 String::ONE_BYTE_ENCODING, SMI_PARAMETERS); | |
3503 CopyStringCharacters(right, new_string, SmiConstant(Smi::kZero), left_length, | |
3504 right_length, String::ONE_BYTE_ENCODING, SMI_PARAMETERS); | |
3505 result.Bind(new_string); | |
3506 Goto(&done_native); | |
3507 | |
3508 Bind(&two_byte); | |
3509 { | |
3510 // Two-byte sequential string case | |
3511 new_string = AllocateSeqTwoByteString(context, new_length); | |
3512 CopyStringCharacters(left, new_string, SmiConstant(Smi::kZero), | |
3513 SmiConstant(Smi::kZero), left_length, | |
3514 String::TWO_BYTE_ENCODING, SMI_PARAMETERS); | |
3515 CopyStringCharacters(right, new_string, SmiConstant(Smi::kZero), | |
3516 left_length, right_length, String::TWO_BYTE_ENCODING, | |
3517 SMI_PARAMETERS); | |
3518 result.Bind(new_string); | |
3519 Goto(&done_native); | |
3520 } | |
3521 | |
3522 Bind(&runtime); | |
3523 { | |
3524 result.Bind(CallRuntime(Runtime::kStringAdd, context, left, right)); | |
3525 Goto(&done); | |
3526 } | |
3527 | |
3528 Bind(&done_native); | |
3529 { | |
3530 IncrementCounter(counters->string_add_native(), 1); | |
3531 Goto(&done); | |
3532 } | |
3533 | |
3534 Bind(&done); | |
3535 return result.value(); | |
3536 } | |
3537 | |
3278 Node* CodeStubAssembler::ToInteger(Node* context, Node* input, | 3538 Node* CodeStubAssembler::ToInteger(Node* context, Node* input, |
3279 ToIntegerTruncationMode mode) { | 3539 ToIntegerTruncationMode mode) { |
3280 // We might need to loop once for ToNumber conversion. | 3540 // We might need to loop once for ToNumber conversion. |
3281 Variable var_arg(this, MachineRepresentation::kTagged); | 3541 Variable var_arg(this, MachineRepresentation::kTagged); |
3282 Label loop(this, &var_arg), out(this); | 3542 Label loop(this, &var_arg), out(this); |
3283 var_arg.Bind(input); | 3543 var_arg.Bind(input); |
3284 Goto(&loop); | 3544 Goto(&loop); |
3285 Bind(&loop); | 3545 Bind(&loop); |
3286 { | 3546 { |
3287 // Shared entry points. | 3547 // Shared entry points. |
(...skipping 1043 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4331 } else { | 4591 } else { |
4332 DCHECK(mode == INTPTR_PARAMETERS); | 4592 DCHECK(mode == INTPTR_PARAMETERS); |
4333 constant_index = ToIntPtrConstant(index_node, index); | 4593 constant_index = ToIntPtrConstant(index_node, index); |
4334 } | 4594 } |
4335 if (constant_index) { | 4595 if (constant_index) { |
4336 return IntPtrConstant(base_size + element_size * index); | 4596 return IntPtrConstant(base_size + element_size * index); |
4337 } | 4597 } |
4338 if (Is64() && mode == INTEGER_PARAMETERS) { | 4598 if (Is64() && mode == INTEGER_PARAMETERS) { |
4339 index_node = ChangeInt32ToInt64(index_node); | 4599 index_node = ChangeInt32ToInt64(index_node); |
4340 } | 4600 } |
4341 if (base_size == 0) { | 4601 |
4342 return (element_size_shift >= 0) | 4602 Node* shifted_index = |
4343 ? WordShl(index_node, IntPtrConstant(element_size_shift)) | 4603 (element_size_shift == 0) |
4344 : WordShr(index_node, IntPtrConstant(-element_size_shift)); | 4604 ? index_node |
4345 } | 4605 : ((element_size_shift > 0) |
4346 return IntPtrAdd( | 4606 ? WordShl(index_node, IntPtrConstant(element_size_shift)) |
4347 IntPtrConstant(base_size), | 4607 : WordShr(index_node, IntPtrConstant(-element_size_shift))); |
4348 (element_size_shift >= 0) | 4608 return IntPtrAddFoldConstants(IntPtrConstant(base_size), shifted_index); |
4349 ? WordShl(index_node, IntPtrConstant(element_size_shift)) | |
4350 : WordShr(index_node, IntPtrConstant(-element_size_shift))); | |
4351 } | 4609 } |
4352 | 4610 |
4353 compiler::Node* CodeStubAssembler::LoadTypeFeedbackVectorForStub() { | 4611 compiler::Node* CodeStubAssembler::LoadTypeFeedbackVectorForStub() { |
4354 Node* function = | 4612 Node* function = |
4355 LoadFromParentFrame(JavaScriptFrameConstants::kFunctionOffset); | 4613 LoadFromParentFrame(JavaScriptFrameConstants::kFunctionOffset); |
4356 Node* literals = LoadObjectField(function, JSFunction::kLiteralsOffset); | 4614 Node* literals = LoadObjectField(function, JSFunction::kLiteralsOffset); |
4357 return LoadObjectField(literals, LiteralsArray::kFeedbackVectorOffset); | 4615 return LoadObjectField(literals, LiteralsArray::kFeedbackVectorOffset); |
4358 } | 4616 } |
4359 | 4617 |
4360 void CodeStubAssembler::UpdateFeedback(compiler::Node* feedback, | 4618 void CodeStubAssembler::UpdateFeedback(compiler::Node* feedback, |
(...skipping 3055 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7416 result.Bind(CallRuntime(Runtime::kInstanceOf, context, object, callable)); | 7674 result.Bind(CallRuntime(Runtime::kInstanceOf, context, object, callable)); |
7417 Goto(&end); | 7675 Goto(&end); |
7418 } | 7676 } |
7419 | 7677 |
7420 Bind(&end); | 7678 Bind(&end); |
7421 return result.value(); | 7679 return result.value(); |
7422 } | 7680 } |
7423 | 7681 |
7424 } // namespace internal | 7682 } // namespace internal |
7425 } // namespace v8 | 7683 } // namespace v8 |
OLD | NEW |