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/ast/modules.h" | 7 #include "src/ast/modules.h" |
8 #include "src/builtins/builtins-utils.h" | 8 #include "src/builtins/builtins-utils.h" |
9 #include "src/code-factory.h" | 9 #include "src/code-factory.h" |
10 #include "src/compilation-dependencies.h" | 10 #include "src/compilation-dependencies.h" |
(...skipping 1308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1319 } | 1319 } |
1320 return NoChange(); | 1320 return NoChange(); |
1321 } | 1321 } |
1322 | 1322 |
1323 Reduction JSTypedLowering::ReduceJSOrdinaryHasInstance(Node* node) { | 1323 Reduction JSTypedLowering::ReduceJSOrdinaryHasInstance(Node* node) { |
1324 DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode()); | 1324 DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode()); |
1325 Node* constructor = NodeProperties::GetValueInput(node, 0); | 1325 Node* constructor = NodeProperties::GetValueInput(node, 0); |
1326 Type* constructor_type = NodeProperties::GetType(constructor); | 1326 Type* constructor_type = NodeProperties::GetType(constructor); |
1327 Node* object = NodeProperties::GetValueInput(node, 1); | 1327 Node* object = NodeProperties::GetValueInput(node, 1); |
1328 Type* object_type = NodeProperties::GetType(object); | 1328 Type* object_type = NodeProperties::GetType(object); |
1329 Node* context = NodeProperties::GetContextInput(node); | |
1330 Node* frame_state = NodeProperties::GetFrameStateInput(node); | |
1331 Node* effect = NodeProperties::GetEffectInput(node); | |
1332 Node* control = NodeProperties::GetControlInput(node); | |
1333 | 1329 |
1334 // Check if the {constructor} cannot be callable. | 1330 // Check if the {constructor} cannot be callable. |
1335 // See ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) step 1. | 1331 // See ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) step 1. |
1336 if (!constructor_type->Maybe(Type::Callable())) { | 1332 if (!constructor_type->Maybe(Type::Callable())) { |
1337 Node* value = jsgraph()->FalseConstant(); | 1333 Node* value = jsgraph()->FalseConstant(); |
1338 ReplaceWithValue(node, value, effect, control); | 1334 ReplaceWithValue(node, value); |
1339 return Replace(value); | 1335 return Replace(value); |
1340 } | 1336 } |
1341 | 1337 |
1342 // If the {constructor} cannot be a JSBoundFunction and then {object} | 1338 // If the {constructor} cannot be a JSBoundFunction and then {object} |
1343 // cannot be a JSReceiver, then this can be constant-folded to false. | 1339 // cannot be a JSReceiver, then this can be constant-folded to false. |
1344 // See ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) step 2 and 3. | 1340 // See ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) step 2 and 3. |
1345 if (!object_type->Maybe(Type::Receiver()) && | 1341 if (!object_type->Maybe(Type::Receiver()) && |
1346 !constructor_type->Maybe(Type::BoundFunction())) { | 1342 !constructor_type->Maybe(Type::BoundFunction())) { |
1347 Node* value = jsgraph()->FalseConstant(); | 1343 Node* value = jsgraph()->FalseConstant(); |
1348 ReplaceWithValue(node, value, effect, control); | 1344 ReplaceWithValue(node, value); |
1349 return Replace(value); | 1345 return Replace(value); |
1350 } | 1346 } |
1351 | 1347 |
1352 // Check if the {constructor} is a (known) JSFunction. | 1348 return NoChange(); |
1353 if (!constructor_type->IsHeapConstant() || | |
1354 !constructor_type->AsHeapConstant()->Value()->IsJSFunction()) { | |
1355 return NoChange(); | |
1356 } | |
1357 Handle<JSFunction> function = | |
1358 Handle<JSFunction>::cast(constructor_type->AsHeapConstant()->Value()); | |
1359 | |
1360 // Check if the {function} already has an initial map (i.e. the | |
1361 // {function} has been used as a constructor at least once). | |
1362 if (!function->has_initial_map()) return NoChange(); | |
1363 | |
1364 // Check if the {function}s "prototype" is a JSReceiver. | |
1365 if (!function->prototype()->IsJSReceiver()) return NoChange(); | |
1366 | |
1367 // Install a code dependency on the {function}s initial map. | |
1368 Handle<Map> initial_map(function->initial_map(), isolate()); | |
1369 dependencies()->AssumeInitialMapCantChange(initial_map); | |
1370 | |
1371 Node* prototype = | |
1372 jsgraph()->Constant(handle(initial_map->prototype(), isolate())); | |
1373 | |
1374 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), object); | |
1375 Node* branch0 = | |
1376 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control); | |
1377 | |
1378 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); | |
1379 Node* etrue0 = effect; | |
1380 Node* vtrue0 = jsgraph()->FalseConstant(); | |
1381 | |
1382 control = graph()->NewNode(common()->IfFalse(), branch0); | |
1383 | |
1384 // Loop through the {object}s prototype chain looking for the {prototype}. | |
1385 Node* loop = control = graph()->NewNode(common()->Loop(2), control, control); | |
1386 Node* eloop = effect = | |
1387 graph()->NewNode(common()->EffectPhi(2), effect, effect, loop); | |
1388 Node* vloop = object = graph()->NewNode( | |
1389 common()->Phi(MachineRepresentation::kTagged, 2), object, object, loop); | |
1390 // TODO(jarin): This is a very ugly hack to work-around the super-smart | |
1391 // implicit typing of the Phi, which goes completely nuts if the {object} | |
1392 // is for example a HeapConstant. | |
1393 NodeProperties::SetType(vloop, Type::NonInternal()); | |
1394 | |
1395 // Load the {object} map and instance type. | |
1396 Node* object_map = effect = | |
1397 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), object, | |
1398 effect, control); | |
1399 Node* object_instance_type = effect = graph()->NewNode( | |
1400 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), object_map, | |
1401 effect, control); | |
1402 | |
1403 // Check if the {object} is a special receiver, because for special | |
1404 // receivers, i.e. proxies or API objects that need access checks, | |
1405 // we have to use the %HasInPrototypeChain runtime function instead. | |
1406 Node* check1 = graph()->NewNode( | |
1407 simplified()->NumberLessThanOrEqual(), object_instance_type, | |
1408 jsgraph()->Constant(LAST_SPECIAL_RECEIVER_TYPE)); | |
1409 Node* branch1 = | |
1410 graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, control); | |
1411 | |
1412 control = graph()->NewNode(common()->IfFalse(), branch1); | |
1413 | |
1414 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); | |
1415 Node* etrue1 = effect; | |
1416 Node* vtrue1; | |
1417 | |
1418 // Check if the {object} is not a receiver at all. | |
1419 Node* check10 = | |
1420 graph()->NewNode(simplified()->NumberLessThan(), object_instance_type, | |
1421 jsgraph()->Constant(FIRST_JS_RECEIVER_TYPE)); | |
1422 Node* branch10 = | |
1423 graph()->NewNode(common()->Branch(BranchHint::kTrue), check10, if_true1); | |
1424 | |
1425 // A primitive value cannot match the {prototype} we're looking for. | |
1426 if_true1 = graph()->NewNode(common()->IfTrue(), branch10); | |
1427 vtrue1 = jsgraph()->FalseConstant(); | |
1428 | |
1429 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch10); | |
1430 Node* efalse1 = etrue1; | |
1431 Node* vfalse1; | |
1432 { | |
1433 // Slow path, need to call the %HasInPrototypeChain runtime function. | |
1434 vfalse1 = efalse1 = if_false1 = graph()->NewNode( | |
1435 javascript()->CallRuntime(Runtime::kHasInPrototypeChain), object, | |
1436 prototype, context, frame_state, efalse1, if_false1); | |
1437 | |
1438 // Replace any potential {IfException} uses of {node} to catch exceptions | |
1439 // from this %HasInPrototypeChain runtime call instead. | |
1440 Node* on_exception = nullptr; | |
1441 if (NodeProperties::IsExceptionalCall(node, &on_exception)) { | |
1442 NodeProperties::ReplaceControlInput(on_exception, vfalse1); | |
1443 NodeProperties::ReplaceEffectInput(on_exception, efalse1); | |
1444 if_false1 = graph()->NewNode(common()->IfSuccess(), vfalse1); | |
1445 Revisit(on_exception); | |
1446 } | |
1447 } | |
1448 | |
1449 // Load the {object} prototype. | |
1450 Node* object_prototype = effect = graph()->NewNode( | |
1451 simplified()->LoadField(AccessBuilder::ForMapPrototype()), object_map, | |
1452 effect, control); | |
1453 | |
1454 // Check if we reached the end of {object}s prototype chain. | |
1455 Node* check2 = graph()->NewNode(simplified()->ReferenceEqual(), | |
1456 object_prototype, jsgraph()->NullConstant()); | |
1457 Node* branch2 = graph()->NewNode(common()->Branch(), check2, control); | |
1458 | |
1459 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); | |
1460 Node* etrue2 = effect; | |
1461 Node* vtrue2 = jsgraph()->FalseConstant(); | |
1462 | |
1463 control = graph()->NewNode(common()->IfFalse(), branch2); | |
1464 | |
1465 // Check if we reached the {prototype}. | |
1466 Node* check3 = graph()->NewNode(simplified()->ReferenceEqual(), | |
1467 object_prototype, prototype); | |
1468 Node* branch3 = graph()->NewNode(common()->Branch(), check3, control); | |
1469 | |
1470 Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3); | |
1471 Node* etrue3 = effect; | |
1472 Node* vtrue3 = jsgraph()->TrueConstant(); | |
1473 | |
1474 control = graph()->NewNode(common()->IfFalse(), branch3); | |
1475 | |
1476 // Close the loop. | |
1477 vloop->ReplaceInput(1, object_prototype); | |
1478 eloop->ReplaceInput(1, effect); | |
1479 loop->ReplaceInput(1, control); | |
1480 | |
1481 control = graph()->NewNode(common()->Merge(5), if_true0, if_true1, if_true2, | |
1482 if_true3, if_false1); | |
1483 effect = graph()->NewNode(common()->EffectPhi(5), etrue0, etrue1, etrue2, | |
1484 etrue3, efalse1, control); | |
1485 | |
1486 // Morph the {node} into an appropriate Phi. | |
1487 ReplaceWithValue(node, node, effect, control); | |
1488 node->ReplaceInput(0, vtrue0); | |
1489 node->ReplaceInput(1, vtrue1); | |
1490 node->ReplaceInput(2, vtrue2); | |
1491 node->ReplaceInput(3, vtrue3); | |
1492 node->ReplaceInput(4, vfalse1); | |
1493 node->ReplaceInput(5, control); | |
1494 node->TrimInputCount(6); | |
1495 NodeProperties::ChangeOp(node, | |
1496 common()->Phi(MachineRepresentation::kTagged, 5)); | |
1497 return Changed(node); | |
1498 } | 1349 } |
1499 | 1350 |
1500 Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) { | 1351 Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) { |
1501 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode()); | 1352 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode()); |
1502 ContextAccess const& access = ContextAccessOf(node->op()); | 1353 ContextAccess const& access = ContextAccessOf(node->op()); |
1503 Node* effect = NodeProperties::GetEffectInput(node); | 1354 Node* effect = NodeProperties::GetEffectInput(node); |
1504 Node* context = NodeProperties::GetContextInput(node); | 1355 Node* context = NodeProperties::GetContextInput(node); |
1505 Node* control = graph()->start(); | 1356 Node* control = graph()->start(); |
1506 for (size_t i = 0; i < access.depth(); ++i) { | 1357 for (size_t i = 0; i < access.depth(); ++i) { |
1507 context = effect = graph()->NewNode( | 1358 context = effect = graph()->NewNode( |
(...skipping 882 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2390 } | 2241 } |
2391 | 2242 |
2392 | 2243 |
2393 CompilationDependencies* JSTypedLowering::dependencies() const { | 2244 CompilationDependencies* JSTypedLowering::dependencies() const { |
2394 return dependencies_; | 2245 return dependencies_; |
2395 } | 2246 } |
2396 | 2247 |
2397 } // namespace compiler | 2248 } // namespace compiler |
2398 } // namespace internal | 2249 } // namespace internal |
2399 } // namespace v8 | 2250 } // namespace v8 |
OLD | NEW |