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/js-typed-lowering.h" | 5 #include "src/compiler/js-typed-lowering.h" |
6 | 6 |
7 #include "src/builtins/builtins-utils.h" | 7 #include "src/builtins/builtins-utils.h" |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
9 #include "src/compilation-dependencies.h" | 9 #include "src/compilation-dependencies.h" |
10 #include "src/compiler/access-builder.h" | 10 #include "src/compiler/access-builder.h" |
(...skipping 1127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1138 Node* const frame_state = NodeProperties::GetFrameStateInput(node); | 1138 Node* const frame_state = NodeProperties::GetFrameStateInput(node); |
1139 | 1139 |
1140 // If deoptimization is disabled, we cannot optimize. | 1140 // If deoptimization is disabled, we cannot optimize. |
1141 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | 1141 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); |
1142 | 1142 |
1143 // If we are in a try block, don't optimize since the runtime call | 1143 // If we are in a try block, don't optimize since the runtime call |
1144 // in the proxy case can throw. | 1144 // in the proxy case can throw. |
1145 if (NodeProperties::IsExceptionalCall(node)) return NoChange(); | 1145 if (NodeProperties::IsExceptionalCall(node)) return NoChange(); |
1146 | 1146 |
1147 JSBinopReduction r(this, node); | 1147 JSBinopReduction r(this, node); |
| 1148 Node* object = r.left(); |
1148 Node* effect = r.effect(); | 1149 Node* effect = r.effect(); |
1149 Node* control = r.control(); | 1150 Node* control = r.control(); |
1150 | 1151 |
1151 if (!r.right_type()->IsConstant() || | 1152 if (!r.right_type()->IsConstant() || |
1152 !r.right_type()->AsConstant()->Value()->IsJSFunction()) { | 1153 !r.right_type()->AsConstant()->Value()->IsJSFunction()) { |
1153 return NoChange(); | 1154 return NoChange(); |
1154 } | 1155 } |
1155 | 1156 |
1156 Handle<JSFunction> function = | 1157 Handle<JSFunction> function = |
1157 Handle<JSFunction>::cast(r.right_type()->AsConstant()->Value()); | 1158 Handle<JSFunction>::cast(r.right_type()->AsConstant()->Value()); |
(...skipping 10 matching lines...) Expand all Loading... |
1168 | 1169 |
1169 // We can only use the fast case if @@hasInstance was not used so far. | 1170 // We can only use the fast case if @@hasInstance was not used so far. |
1170 if (!isolate()->IsHasInstanceLookupChainIntact()) return NoChange(); | 1171 if (!isolate()->IsHasInstanceLookupChainIntact()) return NoChange(); |
1171 dependencies()->AssumePropertyCell(factory()->has_instance_protector()); | 1172 dependencies()->AssumePropertyCell(factory()->has_instance_protector()); |
1172 | 1173 |
1173 Handle<Map> initial_map(function->initial_map(), isolate()); | 1174 Handle<Map> initial_map(function->initial_map(), isolate()); |
1174 dependencies()->AssumeInitialMapCantChange(initial_map); | 1175 dependencies()->AssumeInitialMapCantChange(initial_map); |
1175 Node* prototype = | 1176 Node* prototype = |
1176 jsgraph()->Constant(handle(initial_map->prototype(), isolate())); | 1177 jsgraph()->Constant(handle(initial_map->prototype(), isolate())); |
1177 | 1178 |
1178 Node* if_is_smi = nullptr; | 1179 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), object); |
1179 Node* e_is_smi = nullptr; | 1180 Node* branch0 = |
1180 // If the left hand side is an object, no smi check is needed. | 1181 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control); |
1181 if (r.left_type()->Maybe(Type::TaggedSigned())) { | |
1182 Node* is_smi = graph()->NewNode(simplified()->ObjectIsSmi(), r.left()); | |
1183 Node* branch_is_smi = | |
1184 graph()->NewNode(common()->Branch(BranchHint::kFalse), is_smi, control); | |
1185 if_is_smi = graph()->NewNode(common()->IfTrue(), branch_is_smi); | |
1186 e_is_smi = effect; | |
1187 control = graph()->NewNode(common()->IfFalse(), branch_is_smi); | |
1188 } | |
1189 | 1182 |
1190 Node* object_map = effect = | 1183 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
1191 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | 1184 Node* etrue0 = effect; |
1192 r.left(), effect, control); | 1185 Node* vtrue0 = jsgraph()->FalseConstant(); |
| 1186 |
| 1187 control = graph()->NewNode(common()->IfFalse(), branch0); |
1193 | 1188 |
1194 // Loop through the {object}s prototype chain looking for the {prototype}. | 1189 // Loop through the {object}s prototype chain looking for the {prototype}. |
1195 Node* loop = control = graph()->NewNode(common()->Loop(2), control, control); | 1190 Node* loop = control = graph()->NewNode(common()->Loop(2), control, control); |
| 1191 Node* eloop = effect = |
| 1192 graph()->NewNode(common()->EffectPhi(2), effect, effect, loop); |
| 1193 Node* vloop = object = graph()->NewNode( |
| 1194 common()->Phi(MachineRepresentation::kTagged, 2), object, object, loop); |
| 1195 // TODO(jarin): This is a very ugly hack to work-around the super-smart |
| 1196 // implicit typing of the Phi, which goes completely nuts if the {object} |
| 1197 // is for example a HeapConstant. |
| 1198 NodeProperties::SetType(vloop, Type::NonInternal()); |
1196 | 1199 |
1197 Node* loop_effect = effect = | 1200 // Load the {object} map and instance type. |
1198 graph()->NewNode(common()->EffectPhi(2), effect, effect, loop); | 1201 Node* object_map = effect = |
| 1202 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), object, |
| 1203 effect, control); |
| 1204 Node* object_instance_type = effect = graph()->NewNode( |
| 1205 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), object_map, |
| 1206 effect, control); |
1199 | 1207 |
1200 Node* loop_object_map = | 1208 // Check if the {object} is a special receiver, because for special |
1201 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), | 1209 // receivers, i.e. proxies or API objects that need access checks, |
1202 object_map, r.left(), loop); | 1210 // we have to use the %HasInPrototypeChain runtime function instead. |
| 1211 Node* check1 = graph()->NewNode( |
| 1212 simplified()->NumberLessThanOrEqual(), object_instance_type, |
| 1213 jsgraph()->Constant(LAST_SPECIAL_RECEIVER_TYPE)); |
| 1214 Node* branch1 = |
| 1215 graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, control); |
1203 | 1216 |
1204 // Check if the lhs needs access checks. | 1217 control = graph()->NewNode(common()->IfFalse(), branch1); |
1205 Node* map_bit_field = effect = | |
1206 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMapBitField()), | |
1207 loop_object_map, loop_effect, control); | |
1208 int is_access_check_needed_bit = 1 << Map::kIsAccessCheckNeeded; | |
1209 Node* is_access_check_needed_num = | |
1210 graph()->NewNode(simplified()->NumberBitwiseAnd(), map_bit_field, | |
1211 jsgraph()->Constant(is_access_check_needed_bit)); | |
1212 Node* is_access_check_needed = | |
1213 graph()->NewNode(simplified()->NumberEqual(), is_access_check_needed_num, | |
1214 jsgraph()->Constant(is_access_check_needed_bit)); | |
1215 | 1218 |
1216 Node* branch_is_access_check_needed = graph()->NewNode( | 1219 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
1217 common()->Branch(BranchHint::kFalse), is_access_check_needed, control); | 1220 Node* etrue1 = effect; |
1218 Node* if_is_access_check_needed = | 1221 Node* vtrue1; |
1219 graph()->NewNode(common()->IfTrue(), branch_is_access_check_needed); | |
1220 Node* e_is_access_check_needed = effect; | |
1221 | 1222 |
1222 control = | 1223 // Check if the {object} is not a receiver at all. |
1223 graph()->NewNode(common()->IfFalse(), branch_is_access_check_needed); | 1224 Node* check10 = |
| 1225 graph()->NewNode(simplified()->NumberLessThan(), object_instance_type, |
| 1226 jsgraph()->Constant(FIRST_JS_RECEIVER_TYPE)); |
| 1227 Node* branch10 = |
| 1228 graph()->NewNode(common()->Branch(BranchHint::kTrue), check10, if_true1); |
1224 | 1229 |
1225 // Check if the lhs is a proxy. | 1230 // A primitive value cannot match the {prototype} we're looking for. |
1226 Node* map_instance_type = effect = graph()->NewNode( | 1231 if_true1 = graph()->NewNode(common()->IfTrue(), branch10); |
1227 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), | 1232 vtrue1 = jsgraph()->FalseConstant(); |
1228 loop_object_map, loop_effect, control); | |
1229 Node* is_proxy = | |
1230 graph()->NewNode(simplified()->NumberEqual(), map_instance_type, | |
1231 jsgraph()->Constant(JS_PROXY_TYPE)); | |
1232 Node* branch_is_proxy = | |
1233 graph()->NewNode(common()->Branch(BranchHint::kFalse), is_proxy, control); | |
1234 Node* if_is_proxy = graph()->NewNode(common()->IfTrue(), branch_is_proxy); | |
1235 Node* e_is_proxy = effect; | |
1236 | 1233 |
1237 control = graph()->NewNode(common()->Merge(2), if_is_access_check_needed, | 1234 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch10); |
1238 if_is_proxy); | 1235 Node* efalse1 = etrue1; |
1239 effect = graph()->NewNode(common()->EffectPhi(2), e_is_access_check_needed, | 1236 Node* vfalse1; |
1240 e_is_proxy, control); | 1237 { |
| 1238 // Slow path, need to call the %HasInPrototypeChain runtime function. |
| 1239 vfalse1 = efalse1 = graph()->NewNode( |
| 1240 javascript()->CallRuntime(Runtime::kHasInPrototypeChain), object, |
| 1241 prototype, context, frame_state, efalse1, if_false1); |
| 1242 if_false1 = graph()->NewNode(common()->IfSuccess(), vfalse1); |
| 1243 } |
1241 | 1244 |
1242 // If we need an access check or the object is a Proxy, make a runtime call | 1245 // Load the {object} prototype. |
1243 // to finish the lowering. | 1246 Node* object_prototype = effect = graph()->NewNode( |
1244 Node* runtimecall = graph()->NewNode( | 1247 simplified()->LoadField(AccessBuilder::ForMapPrototype()), object_map, |
1245 javascript()->CallRuntime(Runtime::kHasInPrototypeChain), r.left(), | 1248 effect, control); |
1246 prototype, context, frame_state, effect, control); | |
1247 | 1249 |
1248 Node* runtimecall_control = | 1250 // Check if we reached the end of {object}s prototype chain. |
1249 graph()->NewNode(common()->IfSuccess(), runtimecall); | 1251 Node* check2 = graph()->NewNode(simplified()->ReferenceEqual(), |
| 1252 object_prototype, jsgraph()->NullConstant()); |
| 1253 Node* branch2 = graph()->NewNode(common()->Branch(), check2, control); |
1250 | 1254 |
1251 control = graph()->NewNode(common()->IfFalse(), branch_is_proxy); | 1255 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); |
| 1256 Node* etrue2 = effect; |
| 1257 Node* vtrue2 = jsgraph()->FalseConstant(); |
1252 | 1258 |
1253 Node* object_prototype = effect = graph()->NewNode( | 1259 control = graph()->NewNode(common()->IfFalse(), branch2); |
1254 simplified()->LoadField(AccessBuilder::ForMapPrototype()), | |
1255 loop_object_map, loop_effect, control); | |
1256 | 1260 |
1257 // If not, check if object prototype is the null prototype. | 1261 // Check if we reached the {prototype}. |
1258 Node* null_proto = | 1262 Node* check3 = graph()->NewNode(simplified()->ReferenceEqual(), |
1259 graph()->NewNode(simplified()->ReferenceEqual(), object_prototype, | 1263 object_prototype, prototype); |
1260 jsgraph()->NullConstant()); | 1264 Node* branch3 = graph()->NewNode(common()->Branch(), check3, control); |
1261 Node* branch_null_proto = graph()->NewNode( | |
1262 common()->Branch(BranchHint::kFalse), null_proto, control); | |
1263 Node* if_null_proto = graph()->NewNode(common()->IfTrue(), branch_null_proto); | |
1264 Node* e_null_proto = effect; | |
1265 | 1265 |
1266 control = graph()->NewNode(common()->IfFalse(), branch_null_proto); | 1266 Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3); |
| 1267 Node* etrue3 = effect; |
| 1268 Node* vtrue3 = jsgraph()->TrueConstant(); |
1267 | 1269 |
1268 // Check if object prototype is equal to function prototype. | 1270 control = graph()->NewNode(common()->IfFalse(), branch3); |
1269 Node* eq_proto = graph()->NewNode(simplified()->ReferenceEqual(), | |
1270 object_prototype, prototype); | |
1271 Node* branch_eq_proto = | |
1272 graph()->NewNode(common()->Branch(BranchHint::kFalse), eq_proto, control); | |
1273 Node* if_eq_proto = graph()->NewNode(common()->IfTrue(), branch_eq_proto); | |
1274 Node* e_eq_proto = effect; | |
1275 | 1271 |
1276 control = graph()->NewNode(common()->IfFalse(), branch_eq_proto); | |
1277 | |
1278 Node* load_object_map = effect = | |
1279 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | |
1280 object_prototype, effect, control); | |
1281 // Close the loop. | 1272 // Close the loop. |
1282 loop_effect->ReplaceInput(1, effect); | 1273 vloop->ReplaceInput(1, object_prototype); |
1283 loop_object_map->ReplaceInput(1, load_object_map); | 1274 eloop->ReplaceInput(1, effect); |
1284 loop->ReplaceInput(1, control); | 1275 loop->ReplaceInput(1, control); |
1285 | 1276 |
1286 control = graph()->NewNode(common()->Merge(3), runtimecall_control, | 1277 control = graph()->NewNode(common()->Merge(5), if_true0, if_true1, if_true2, |
1287 if_eq_proto, if_null_proto); | 1278 if_true3, if_false1); |
1288 effect = graph()->NewNode(common()->EffectPhi(3), runtimecall, e_eq_proto, | 1279 effect = graph()->NewNode(common()->EffectPhi(5), etrue0, etrue1, etrue2, |
1289 e_null_proto, control); | 1280 etrue3, efalse1, control); |
1290 | 1281 |
1291 Node* result = graph()->NewNode( | 1282 // Morph the {node} into an appropriate Phi. |
1292 common()->Phi(MachineRepresentation::kTagged, 3), runtimecall, | 1283 ReplaceWithValue(node, node, effect, control); |
1293 jsgraph()->TrueConstant(), jsgraph()->FalseConstant(), control); | 1284 node->ReplaceInput(0, vtrue0); |
1294 | 1285 node->ReplaceInput(1, vtrue1); |
1295 if (if_is_smi != nullptr) { | 1286 node->ReplaceInput(2, vtrue2); |
1296 DCHECK_NOT_NULL(e_is_smi); | 1287 node->ReplaceInput(3, vtrue3); |
1297 control = graph()->NewNode(common()->Merge(2), if_is_smi, control); | 1288 node->ReplaceInput(4, vfalse1); |
1298 effect = | 1289 node->ReplaceInput(5, control); |
1299 graph()->NewNode(common()->EffectPhi(2), e_is_smi, effect, control); | 1290 node->TrimInputCount(6); |
1300 result = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), | 1291 NodeProperties::ChangeOp(node, |
1301 jsgraph()->FalseConstant(), result, control); | 1292 common()->Phi(MachineRepresentation::kTagged, 5)); |
1302 } | 1293 return Changed(node); |
1303 | |
1304 ReplaceWithValue(node, result, effect, control); | |
1305 return Changed(result); | |
1306 } | 1294 } |
1307 | 1295 |
1308 Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) { | 1296 Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) { |
1309 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode()); | 1297 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode()); |
1310 ContextAccess const& access = ContextAccessOf(node->op()); | 1298 ContextAccess const& access = ContextAccessOf(node->op()); |
1311 Node* effect = NodeProperties::GetEffectInput(node); | 1299 Node* effect = NodeProperties::GetEffectInput(node); |
1312 Node* control = graph()->start(); | 1300 Node* control = graph()->start(); |
1313 for (size_t i = 0; i < access.depth(); ++i) { | 1301 for (size_t i = 0; i < access.depth(); ++i) { |
1314 Node* previous = effect = graph()->NewNode( | 1302 Node* previous = effect = graph()->NewNode( |
1315 simplified()->LoadField( | 1303 simplified()->LoadField( |
(...skipping 909 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2225 } | 2213 } |
2226 | 2214 |
2227 | 2215 |
2228 CompilationDependencies* JSTypedLowering::dependencies() const { | 2216 CompilationDependencies* JSTypedLowering::dependencies() const { |
2229 return dependencies_; | 2217 return dependencies_; |
2230 } | 2218 } |
2231 | 2219 |
2232 } // namespace compiler | 2220 } // namespace compiler |
2233 } // namespace internal | 2221 } // namespace internal |
2234 } // namespace v8 | 2222 } // namespace v8 |
OLD | NEW |