| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 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/compiler/simplified-lowering.h" | 5 #include "src/compiler/simplified-lowering.h" |
| 6 | 6 |
| 7 #include <limits> | 7 #include <limits> |
| 8 | 8 |
| 9 #include "src/address-map.h" | |
| 10 #include "src/base/bits.h" | 9 #include "src/base/bits.h" |
| 11 #include "src/code-factory.h" | 10 #include "src/code-factory.h" |
| 12 #include "src/compiler/common-operator.h" | 11 #include "src/compiler/common-operator.h" |
| 13 #include "src/compiler/diamond.h" | 12 #include "src/compiler/diamond.h" |
| 14 #include "src/compiler/linkage.h" | 13 #include "src/compiler/linkage.h" |
| 15 #include "src/compiler/node-matchers.h" | 14 #include "src/compiler/node-matchers.h" |
| 16 #include "src/compiler/node-properties.h" | 15 #include "src/compiler/node-properties.h" |
| 17 #include "src/compiler/operator-properties.h" | 16 #include "src/compiler/operator-properties.h" |
| 18 #include "src/compiler/representation-change.h" | 17 #include "src/compiler/representation-change.h" |
| 19 #include "src/compiler/simplified-operator.h" | 18 #include "src/compiler/simplified-operator.h" |
| (...skipping 793 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 813 } | 812 } |
| 814 case IrOpcode::kStringLessThanOrEqual: { | 813 case IrOpcode::kStringLessThanOrEqual: { |
| 815 VisitBinop(node, kMachAnyTagged, kRepBit); | 814 VisitBinop(node, kMachAnyTagged, kRepBit); |
| 816 if (lower()) lowering->DoStringLessThanOrEqual(node); | 815 if (lower()) lowering->DoStringLessThanOrEqual(node); |
| 817 break; | 816 break; |
| 818 } | 817 } |
| 819 case IrOpcode::kAllocate: { | 818 case IrOpcode::kAllocate: { |
| 820 ProcessInput(node, 0, kMachAnyTagged); | 819 ProcessInput(node, 0, kMachAnyTagged); |
| 821 ProcessRemainingInputs(node, 1); | 820 ProcessRemainingInputs(node, 1); |
| 822 SetOutput(node, kMachAnyTagged); | 821 SetOutput(node, kMachAnyTagged); |
| 823 if (lower()) lowering->DoAllocate(node); | |
| 824 break; | 822 break; |
| 825 } | 823 } |
| 826 case IrOpcode::kLoadField: { | 824 case IrOpcode::kLoadField: { |
| 827 FieldAccess access = FieldAccessOf(node->op()); | 825 FieldAccess access = FieldAccessOf(node->op()); |
| 828 ProcessInput(node, 0, changer_->TypeForBasePointer(access)); | 826 ProcessInput(node, 0, changer_->TypeForBasePointer(access)); |
| 829 ProcessRemainingInputs(node, 1); | 827 ProcessRemainingInputs(node, 1); |
| 830 SetOutput(node, access.machine_type); | 828 SetOutput(node, access.machine_type); |
| 831 if (lower()) lowering->DoLoadField(node); | |
| 832 break; | 829 break; |
| 833 } | 830 } |
| 834 case IrOpcode::kStoreField: { | 831 case IrOpcode::kStoreField: { |
| 835 FieldAccess access = FieldAccessOf(node->op()); | 832 FieldAccess access = FieldAccessOf(node->op()); |
| 836 ProcessInput(node, 0, changer_->TypeForBasePointer(access)); | 833 ProcessInput(node, 0, changer_->TypeForBasePointer(access)); |
| 837 ProcessInput(node, 1, access.machine_type); | 834 ProcessInput(node, 1, access.machine_type); |
| 838 ProcessRemainingInputs(node, 2); | 835 ProcessRemainingInputs(node, 2); |
| 839 SetOutput(node, 0); | 836 SetOutput(node, 0); |
| 840 if (lower()) lowering->DoStoreField(node); | |
| 841 break; | 837 break; |
| 842 } | 838 } |
| 843 case IrOpcode::kLoadBuffer: { | 839 case IrOpcode::kLoadBuffer: { |
| 844 BufferAccess access = BufferAccessOf(node->op()); | 840 BufferAccess access = BufferAccessOf(node->op()); |
| 845 ProcessInput(node, 0, kMachPtr); // buffer | 841 ProcessInput(node, 0, kMachPtr); // buffer |
| 846 ProcessInput(node, 1, kMachInt32); // offset | 842 ProcessInput(node, 1, kMachInt32); // offset |
| 847 ProcessInput(node, 2, kMachInt32); // length | 843 ProcessInput(node, 2, kMachInt32); // length |
| 848 ProcessRemainingInputs(node, 3); | 844 ProcessRemainingInputs(node, 3); |
| 849 // Tagged overrides everything if we have to do a typed array bounds | 845 // Tagged overrides everything if we have to do a typed array bounds |
| 850 // check, because we may need to return undefined then. | 846 // check, because we may need to return undefined then. |
| (...skipping 25 matching lines...) Expand all Loading... |
| 876 SetOutput(node, 0); | 872 SetOutput(node, 0); |
| 877 if (lower()) lowering->DoStoreBuffer(node); | 873 if (lower()) lowering->DoStoreBuffer(node); |
| 878 break; | 874 break; |
| 879 } | 875 } |
| 880 case IrOpcode::kLoadElement: { | 876 case IrOpcode::kLoadElement: { |
| 881 ElementAccess access = ElementAccessOf(node->op()); | 877 ElementAccess access = ElementAccessOf(node->op()); |
| 882 ProcessInput(node, 0, changer_->TypeForBasePointer(access)); // base | 878 ProcessInput(node, 0, changer_->TypeForBasePointer(access)); // base |
| 883 ProcessInput(node, 1, kMachInt32); // index | 879 ProcessInput(node, 1, kMachInt32); // index |
| 884 ProcessRemainingInputs(node, 2); | 880 ProcessRemainingInputs(node, 2); |
| 885 SetOutput(node, access.machine_type); | 881 SetOutput(node, access.machine_type); |
| 886 if (lower()) lowering->DoLoadElement(node); | |
| 887 break; | 882 break; |
| 888 } | 883 } |
| 889 case IrOpcode::kStoreElement: { | 884 case IrOpcode::kStoreElement: { |
| 890 ElementAccess access = ElementAccessOf(node->op()); | 885 ElementAccess access = ElementAccessOf(node->op()); |
| 891 ProcessInput(node, 0, changer_->TypeForBasePointer(access)); // base | 886 ProcessInput(node, 0, changer_->TypeForBasePointer(access)); // base |
| 892 ProcessInput(node, 1, kMachInt32); // index | 887 ProcessInput(node, 1, kMachInt32); // index |
| 893 ProcessInput(node, 2, access.machine_type); // value | 888 ProcessInput(node, 2, access.machine_type); // value |
| 894 ProcessRemainingInputs(node, 3); | 889 ProcessRemainingInputs(node, 3); |
| 895 SetOutput(node, 0); | 890 SetOutput(node, 0); |
| 896 if (lower()) lowering->DoStoreElement(node); | |
| 897 break; | 891 break; |
| 898 } | 892 } |
| 899 case IrOpcode::kObjectIsNumber: { | 893 case IrOpcode::kObjectIsNumber: { |
| 900 ProcessInput(node, 0, kMachAnyTagged); | 894 ProcessInput(node, 0, kMachAnyTagged); |
| 901 SetOutput(node, kRepBit | kTypeBool); | 895 SetOutput(node, kRepBit | kTypeBool); |
| 902 if (lower()) lowering->DoObjectIsNumber(node); | 896 if (lower()) lowering->DoObjectIsNumber(node); |
| 903 break; | 897 break; |
| 904 } | 898 } |
| 905 case IrOpcode::kObjectIsSmi: { | 899 case IrOpcode::kObjectIsSmi: { |
| 906 ProcessInput(node, 0, kMachAnyTagged); | 900 ProcessInput(node, 0, kMachAnyTagged); |
| (...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1135 | 1129 |
| 1136 | 1130 |
| 1137 void SimplifiedLowering::LowerAllNodes() { | 1131 void SimplifiedLowering::LowerAllNodes() { |
| 1138 RepresentationChanger changer(jsgraph(), jsgraph()->isolate()); | 1132 RepresentationChanger changer(jsgraph(), jsgraph()->isolate()); |
| 1139 RepresentationSelector selector(jsgraph(), zone_, &changer, | 1133 RepresentationSelector selector(jsgraph(), zone_, &changer, |
| 1140 source_positions_); | 1134 source_positions_); |
| 1141 selector.Run(this); | 1135 selector.Run(this); |
| 1142 } | 1136 } |
| 1143 | 1137 |
| 1144 | 1138 |
| 1145 namespace { | |
| 1146 | |
| 1147 WriteBarrierKind ComputeWriteBarrierKind(BaseTaggedness base_is_tagged, | |
| 1148 MachineType representation, | |
| 1149 Type* field_type, Type* input_type) { | |
| 1150 if (field_type->Is(Type::TaggedSigned()) || | |
| 1151 input_type->Is(Type::TaggedSigned())) { | |
| 1152 // Write barriers are only for writes of heap objects. | |
| 1153 return kNoWriteBarrier; | |
| 1154 } | |
| 1155 if (input_type->Is(Type::BooleanOrNullOrUndefined())) { | |
| 1156 // Write barriers are not necessary when storing true, false, null or | |
| 1157 // undefined, because these special oddballs are always in the root set. | |
| 1158 return kNoWriteBarrier; | |
| 1159 } | |
| 1160 if (base_is_tagged == kTaggedBase && | |
| 1161 RepresentationOf(representation) == kRepTagged) { | |
| 1162 if (input_type->IsConstant() && | |
| 1163 input_type->AsConstant()->Value()->IsHeapObject()) { | |
| 1164 Handle<HeapObject> input = | |
| 1165 Handle<HeapObject>::cast(input_type->AsConstant()->Value()); | |
| 1166 if (input->IsMap()) { | |
| 1167 // Write barriers for storing maps are cheaper. | |
| 1168 return kMapWriteBarrier; | |
| 1169 } | |
| 1170 Isolate* const isolate = input->GetIsolate(); | |
| 1171 RootIndexMap root_index_map(isolate); | |
| 1172 int root_index = root_index_map.Lookup(*input); | |
| 1173 if (root_index != RootIndexMap::kInvalidRootIndex && | |
| 1174 isolate->heap()->RootIsImmortalImmovable(root_index)) { | |
| 1175 // Write barriers are unnecessary for immortal immovable roots. | |
| 1176 return kNoWriteBarrier; | |
| 1177 } | |
| 1178 } | |
| 1179 if (field_type->Is(Type::TaggedPointer()) || | |
| 1180 input_type->Is(Type::TaggedPointer())) { | |
| 1181 // Write barriers for heap objects don't need a Smi check. | |
| 1182 return kPointerWriteBarrier; | |
| 1183 } | |
| 1184 // Write barriers are only for writes into heap objects (i.e. tagged base). | |
| 1185 return kFullWriteBarrier; | |
| 1186 } | |
| 1187 return kNoWriteBarrier; | |
| 1188 } | |
| 1189 | |
| 1190 } // namespace | |
| 1191 | |
| 1192 | |
| 1193 void SimplifiedLowering::DoAllocate(Node* node) { | |
| 1194 PretenureFlag pretenure = OpParameter<PretenureFlag>(node->op()); | |
| 1195 if (pretenure == NOT_TENURED) { | |
| 1196 Callable callable = CodeFactory::AllocateInNewSpace(isolate()); | |
| 1197 Node* target = jsgraph()->HeapConstant(callable.code()); | |
| 1198 CallDescriptor* descriptor = Linkage::GetStubCallDescriptor( | |
| 1199 isolate(), jsgraph()->zone(), callable.descriptor(), 0, | |
| 1200 CallDescriptor::kNoFlags, Operator::kNoThrow); | |
| 1201 const Operator* op = common()->Call(descriptor); | |
| 1202 node->InsertInput(graph()->zone(), 0, target); | |
| 1203 node->InsertInput(graph()->zone(), 2, jsgraph()->NoContextConstant()); | |
| 1204 NodeProperties::ChangeOp(node, op); | |
| 1205 } else { | |
| 1206 DCHECK_EQ(TENURED, pretenure); | |
| 1207 AllocationSpace space = OLD_SPACE; | |
| 1208 Runtime::FunctionId f = Runtime::kAllocateInTargetSpace; | |
| 1209 Operator::Properties props = node->op()->properties(); | |
| 1210 CallDescriptor* desc = | |
| 1211 Linkage::GetRuntimeCallDescriptor(zone(), f, 2, props); | |
| 1212 ExternalReference ref(f, jsgraph()->isolate()); | |
| 1213 int32_t flags = AllocateTargetSpace::encode(space); | |
| 1214 node->InsertInput(graph()->zone(), 0, jsgraph()->CEntryStubConstant(1)); | |
| 1215 node->InsertInput(graph()->zone(), 2, jsgraph()->SmiConstant(flags)); | |
| 1216 node->InsertInput(graph()->zone(), 3, jsgraph()->ExternalConstant(ref)); | |
| 1217 node->InsertInput(graph()->zone(), 4, jsgraph()->Int32Constant(2)); | |
| 1218 node->InsertInput(graph()->zone(), 5, jsgraph()->NoContextConstant()); | |
| 1219 NodeProperties::ChangeOp(node, common()->Call(desc)); | |
| 1220 } | |
| 1221 } | |
| 1222 | |
| 1223 | |
| 1224 void SimplifiedLowering::DoLoadField(Node* node) { | |
| 1225 const FieldAccess& access = FieldAccessOf(node->op()); | |
| 1226 Node* offset = jsgraph()->IntPtrConstant(access.offset - access.tag()); | |
| 1227 node->InsertInput(graph()->zone(), 1, offset); | |
| 1228 NodeProperties::ChangeOp(node, machine()->Load(access.machine_type)); | |
| 1229 } | |
| 1230 | |
| 1231 | |
| 1232 void SimplifiedLowering::DoStoreField(Node* node) { | |
| 1233 const FieldAccess& access = FieldAccessOf(node->op()); | |
| 1234 Type* type = NodeProperties::GetType(node->InputAt(1)); | |
| 1235 WriteBarrierKind kind = ComputeWriteBarrierKind( | |
| 1236 access.base_is_tagged, access.machine_type, access.type, type); | |
| 1237 Node* offset = jsgraph()->IntPtrConstant(access.offset - access.tag()); | |
| 1238 node->InsertInput(graph()->zone(), 1, offset); | |
| 1239 NodeProperties::ChangeOp( | |
| 1240 node, machine()->Store(StoreRepresentation(access.machine_type, kind))); | |
| 1241 } | |
| 1242 | |
| 1243 | |
| 1244 Node* SimplifiedLowering::ComputeIndex(const ElementAccess& access, | |
| 1245 Node* const key) { | |
| 1246 Node* index = key; | |
| 1247 const int element_size_shift = ElementSizeLog2Of(access.machine_type); | |
| 1248 if (element_size_shift) { | |
| 1249 index = graph()->NewNode(machine()->Word32Shl(), index, | |
| 1250 jsgraph()->Int32Constant(element_size_shift)); | |
| 1251 } | |
| 1252 const int fixed_offset = access.header_size - access.tag(); | |
| 1253 if (fixed_offset) { | |
| 1254 index = graph()->NewNode(machine()->Int32Add(), index, | |
| 1255 jsgraph()->Int32Constant(fixed_offset)); | |
| 1256 } | |
| 1257 if (machine()->Is64()) { | |
| 1258 // TODO(turbofan): This is probably only correct for typed arrays, and only | |
| 1259 // if the typed arrays are at most 2GiB in size, which happens to match | |
| 1260 // exactly our current situation. | |
| 1261 index = graph()->NewNode(machine()->ChangeUint32ToUint64(), index); | |
| 1262 } | |
| 1263 return index; | |
| 1264 } | |
| 1265 | |
| 1266 | |
| 1267 void SimplifiedLowering::DoLoadBuffer(Node* node, MachineType output_type, | 1139 void SimplifiedLowering::DoLoadBuffer(Node* node, MachineType output_type, |
| 1268 RepresentationChanger* changer) { | 1140 RepresentationChanger* changer) { |
| 1269 DCHECK_EQ(IrOpcode::kLoadBuffer, node->opcode()); | 1141 DCHECK_EQ(IrOpcode::kLoadBuffer, node->opcode()); |
| 1270 DCHECK_NE(kMachNone, RepresentationOf(output_type)); | 1142 DCHECK_NE(kMachNone, RepresentationOf(output_type)); |
| 1271 MachineType const type = BufferAccessOf(node->op()).machine_type(); | 1143 MachineType const type = BufferAccessOf(node->op()).machine_type(); |
| 1272 if (output_type != type) { | 1144 if (output_type != type) { |
| 1273 Node* const buffer = node->InputAt(0); | 1145 Node* const buffer = node->InputAt(0); |
| 1274 Node* const offset = node->InputAt(1); | 1146 Node* const offset = node->InputAt(1); |
| 1275 Node* const length = node->InputAt(2); | 1147 Node* const length = node->InputAt(2); |
| 1276 Node* const effect = node->InputAt(3); | 1148 Node* const effect = node->InputAt(3); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1322 } | 1194 } |
| 1323 | 1195 |
| 1324 | 1196 |
| 1325 void SimplifiedLowering::DoStoreBuffer(Node* node) { | 1197 void SimplifiedLowering::DoStoreBuffer(Node* node) { |
| 1326 DCHECK_EQ(IrOpcode::kStoreBuffer, node->opcode()); | 1198 DCHECK_EQ(IrOpcode::kStoreBuffer, node->opcode()); |
| 1327 MachineType const type = BufferAccessOf(node->op()).machine_type(); | 1199 MachineType const type = BufferAccessOf(node->op()).machine_type(); |
| 1328 NodeProperties::ChangeOp(node, machine()->CheckedStore(type)); | 1200 NodeProperties::ChangeOp(node, machine()->CheckedStore(type)); |
| 1329 } | 1201 } |
| 1330 | 1202 |
| 1331 | 1203 |
| 1332 void SimplifiedLowering::DoLoadElement(Node* node) { | |
| 1333 const ElementAccess& access = ElementAccessOf(node->op()); | |
| 1334 node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1))); | |
| 1335 NodeProperties::ChangeOp(node, machine()->Load(access.machine_type)); | |
| 1336 } | |
| 1337 | |
| 1338 | |
| 1339 void SimplifiedLowering::DoStoreElement(Node* node) { | |
| 1340 const ElementAccess& access = ElementAccessOf(node->op()); | |
| 1341 Type* type = NodeProperties::GetType(node->InputAt(2)); | |
| 1342 node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1))); | |
| 1343 NodeProperties::ChangeOp( | |
| 1344 node, | |
| 1345 machine()->Store(StoreRepresentation( | |
| 1346 access.machine_type, | |
| 1347 ComputeWriteBarrierKind(access.base_is_tagged, access.machine_type, | |
| 1348 access.type, type)))); | |
| 1349 } | |
| 1350 | |
| 1351 | |
| 1352 void SimplifiedLowering::DoObjectIsNumber(Node* node) { | 1204 void SimplifiedLowering::DoObjectIsNumber(Node* node) { |
| 1353 Node* input = NodeProperties::GetValueInput(node, 0); | 1205 Node* input = NodeProperties::GetValueInput(node, 0); |
| 1354 // TODO(bmeurer): Optimize somewhat based on input type. | 1206 // TODO(bmeurer): Optimize somewhat based on input type. |
| 1355 Node* check = | 1207 Node* check = |
| 1356 graph()->NewNode(machine()->WordEqual(), | 1208 graph()->NewNode(machine()->WordEqual(), |
| 1357 graph()->NewNode(machine()->WordAnd(), input, | 1209 graph()->NewNode(machine()->WordAnd(), input, |
| 1358 jsgraph()->IntPtrConstant(kSmiTagMask)), | 1210 jsgraph()->IntPtrConstant(kSmiTagMask)), |
| 1359 jsgraph()->IntPtrConstant(kSmiTag)); | 1211 jsgraph()->IntPtrConstant(kSmiTag)); |
| 1360 Node* branch = graph()->NewNode(common()->Branch(), check, graph()->start()); | 1212 Node* branch = graph()->NewNode(common()->Branch(), check, graph()->start()); |
| 1361 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); | 1213 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| (...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1702 ReplaceEffectUses(node, comparison); | 1554 ReplaceEffectUses(node, comparison); |
| 1703 node->ReplaceInput(0, comparison); | 1555 node->ReplaceInput(0, comparison); |
| 1704 node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL)); | 1556 node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL)); |
| 1705 node->TrimInputCount(2); | 1557 node->TrimInputCount(2); |
| 1706 NodeProperties::ChangeOp(node, machine()->IntLessThanOrEqual()); | 1558 NodeProperties::ChangeOp(node, machine()->IntLessThanOrEqual()); |
| 1707 } | 1559 } |
| 1708 | 1560 |
| 1709 } // namespace compiler | 1561 } // namespace compiler |
| 1710 } // namespace internal | 1562 } // namespace internal |
| 1711 } // namespace v8 | 1563 } // namespace v8 |
| OLD | NEW |