Chromium Code Reviews| 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 |