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 |