| 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/ast-graph-builder.h" | 5 #include "src/compiler/ast-graph-builder.h" |
| 6 | 6 |
| 7 #include "src/compiler.h" | 7 #include "src/compiler.h" |
| 8 #include "src/compiler/ast-loop-assignment-analyzer.h" | 8 #include "src/compiler/ast-loop-assignment-analyzer.h" |
| 9 #include "src/compiler/control-builders.h" | 9 #include "src/compiler/control-builders.h" |
| 10 #include "src/compiler/js-type-feedback.h" | 10 #include "src/compiler/js-type-feedback.h" |
| (...skipping 1274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1285 } else { | 1285 } else { |
| 1286 for_loop.BreakUnless(jsgraph()->TrueConstant()); | 1286 for_loop.BreakUnless(jsgraph()->TrueConstant()); |
| 1287 } | 1287 } |
| 1288 VisitIterationBody(stmt, &for_loop); | 1288 VisitIterationBody(stmt, &for_loop); |
| 1289 for_loop.EndBody(); | 1289 for_loop.EndBody(); |
| 1290 VisitIfNotNull(stmt->next()); | 1290 VisitIfNotNull(stmt->next()); |
| 1291 for_loop.EndLoop(); | 1291 for_loop.EndLoop(); |
| 1292 } | 1292 } |
| 1293 | 1293 |
| 1294 | 1294 |
| 1295 // TODO(dcarney): this is a big function. Try to clean up some. | |
| 1296 void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) { | 1295 void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) { |
| 1297 VisitForValue(stmt->subject()); | 1296 VisitForValue(stmt->subject()); |
| 1298 Node* obj = environment()->Pop(); | 1297 Node* object = environment()->Pop(); |
| 1299 // Check for undefined or null before entering loop. | 1298 BlockBuilder for_block(this); |
| 1300 IfBuilder is_undefined(this); | 1299 for_block.BeginBlock(); |
| 1301 Node* is_undefined_cond = | 1300 // Check for null or undefined before entering loop. |
| 1302 NewNode(javascript()->StrictEqual(), obj, jsgraph()->UndefinedConstant()); | 1301 Node* is_null_cond = |
| 1303 is_undefined.If(is_undefined_cond); | 1302 NewNode(javascript()->StrictEqual(), object, jsgraph()->NullConstant()); |
| 1304 is_undefined.Then(); | 1303 for_block.BreakWhen(is_null_cond, BranchHint::kFalse); |
| 1305 is_undefined.Else(); | 1304 Node* is_undefined_cond = NewNode(javascript()->StrictEqual(), object, |
| 1305 jsgraph()->UndefinedConstant()); |
| 1306 for_block.BreakWhen(is_undefined_cond, BranchHint::kFalse); |
| 1306 { | 1307 { |
| 1307 IfBuilder is_null(this); | |
| 1308 Node* is_null_cond = | |
| 1309 NewNode(javascript()->StrictEqual(), obj, jsgraph()->NullConstant()); | |
| 1310 is_null.If(is_null_cond); | |
| 1311 is_null.Then(); | |
| 1312 is_null.Else(); | |
| 1313 // Convert object to jsobject. | 1308 // Convert object to jsobject. |
| 1314 // PrepareForBailoutForId(stmt->PrepareId(), TOS_REG); | 1309 object = BuildToObject(object, stmt->ToObjectId()); |
| 1315 obj = NewNode(javascript()->ToObject(), obj); | 1310 environment()->Push(object); |
| 1316 PrepareFrameState(obj, stmt->ToObjectId(), OutputFrameStateCombine::Push()); | 1311 |
| 1317 environment()->Push(obj); | 1312 // Prepare for-in cache. |
| 1318 // TODO(dcarney): should do a fast enum cache check here to skip runtime. | 1313 Node* prepare = NewNode(javascript()->ForInPrepare(), object); |
| 1319 Node* cache_type = NewNode( | 1314 PrepareFrameState(prepare, stmt->EnumId(), OutputFrameStateCombine::Push()); |
| 1320 javascript()->CallRuntime(Runtime::kGetPropertyNamesFast, 1), obj); | 1315 Node* cache_type = NewNode(common()->Projection(0), prepare); |
| 1321 PrepareFrameState(cache_type, stmt->EnumId(), | 1316 Node* cache_array = NewNode(common()->Projection(1), prepare); |
| 1322 OutputFrameStateCombine::Push()); | 1317 Node* cache_length = NewNode(common()->Projection(2), prepare); |
| 1323 // TODO(dcarney): these next runtime calls should be removed in favour of | 1318 |
| 1324 // a few simplified instructions. | 1319 // Construct the rest of the environment. |
| 1325 Node* cache_pair = NewNode( | 1320 environment()->Push(cache_type); |
| 1326 javascript()->CallRuntime(Runtime::kForInInit, 2), obj, cache_type); | 1321 environment()->Push(cache_array); |
| 1327 // cache_type may have been replaced. | 1322 environment()->Push(cache_length); |
| 1328 Node* cache_array = NewNode(common()->Projection(0), cache_pair); | 1323 environment()->Push(jsgraph()->ZeroConstant()); |
| 1329 cache_type = NewNode(common()->Projection(1), cache_pair); | 1324 |
| 1330 Node* cache_length = | 1325 // Build the actual loop body. |
| 1331 NewNode(javascript()->CallRuntime(Runtime::kForInCacheArrayLength, 2), | 1326 LoopBuilder for_loop(this); |
| 1332 cache_type, cache_array); | 1327 for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt)); |
| 1333 { | 1328 { |
| 1334 // Construct the rest of the environment. | 1329 // These stack values are renamed in the case of OSR, so reload them |
| 1335 environment()->Push(cache_type); | 1330 // from the environment. |
| 1336 environment()->Push(cache_array); | 1331 Node* index = environment()->Peek(0); |
| 1337 environment()->Push(cache_length); | 1332 Node* cache_length = environment()->Peek(1); |
| 1338 environment()->Push(jsgraph()->ZeroConstant()); | 1333 Node* cache_array = environment()->Peek(2); |
| 1334 Node* cache_type = environment()->Peek(3); |
| 1335 Node* object = environment()->Peek(4); |
| 1339 | 1336 |
| 1340 // Build the actual loop body. | 1337 // Check loop termination condition. |
| 1341 VisitForInBody(stmt); | 1338 Node* exit_cond = NewNode(javascript()->ForInDone(), index, cache_length); |
| 1339 for_loop.BreakWhen(exit_cond); |
| 1340 |
| 1341 // Compute the next enumerated value. |
| 1342 Node* value = NewNode(javascript()->ForInNext(), object, cache_array, |
| 1343 cache_type, index); |
| 1344 PrepareFrameState(value, stmt->FilterId(), |
| 1345 OutputFrameStateCombine::Push()); |
| 1346 IfBuilder test_value(this); |
| 1347 Node* test_value_cond = NewNode(javascript()->StrictEqual(), value, |
| 1348 jsgraph()->UndefinedConstant()); |
| 1349 test_value.If(test_value_cond, BranchHint::kFalse); |
| 1350 test_value.Then(); |
| 1351 test_value.Else(); |
| 1352 { |
| 1353 // Bind value and do loop body. |
| 1354 VisitForInAssignment(stmt->each(), value, stmt->AssignmentId()); |
| 1355 VisitIterationBody(stmt, &for_loop); |
| 1356 } |
| 1357 test_value.End(); |
| 1358 index = environment()->Peek(0); |
| 1359 for_loop.EndBody(); |
| 1360 |
| 1361 // Increment counter and continue. |
| 1362 index = NewNode(javascript()->ForInStep(), index); |
| 1363 environment()->Poke(0, index); |
| 1342 } | 1364 } |
| 1343 is_null.End(); | 1365 for_loop.EndLoop(); |
| 1366 environment()->Drop(5); |
| 1344 } | 1367 } |
| 1345 is_undefined.End(); | 1368 for_block.EndBlock(); |
| 1346 } | 1369 } |
| 1347 | 1370 |
| 1348 | 1371 |
| 1349 // TODO(dcarney): this is a big function. Try to clean up some. | |
| 1350 void AstGraphBuilder::VisitForInBody(ForInStatement* stmt) { | |
| 1351 LoopBuilder for_loop(this); | |
| 1352 for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt)); | |
| 1353 | |
| 1354 // These stack values are renamed in the case of OSR, so reload them | |
| 1355 // from the environment. | |
| 1356 Node* index = environment()->Peek(0); | |
| 1357 Node* cache_length = environment()->Peek(1); | |
| 1358 Node* cache_array = environment()->Peek(2); | |
| 1359 Node* cache_type = environment()->Peek(3); | |
| 1360 Node* obj = environment()->Peek(4); | |
| 1361 | |
| 1362 // Check loop termination condition (cannot deoptimize). | |
| 1363 { | |
| 1364 FrameStateBeforeAndAfter states(this, BailoutId::None()); | |
| 1365 Node* exit_cond = NewNode(javascript()->LessThan(LanguageMode::SLOPPY), | |
| 1366 index, cache_length); | |
| 1367 states.AddToNode(exit_cond, BailoutId::None(), | |
| 1368 OutputFrameStateCombine::Ignore()); | |
| 1369 for_loop.BreakUnless(exit_cond); | |
| 1370 } | |
| 1371 Node* pair = NewNode(javascript()->CallRuntime(Runtime::kForInNext, 4), obj, | |
| 1372 cache_array, cache_type, index); | |
| 1373 Node* value = NewNode(common()->Projection(0), pair); | |
| 1374 Node* should_filter = NewNode(common()->Projection(1), pair); | |
| 1375 environment()->Push(value); | |
| 1376 { | |
| 1377 // Test if FILTER_KEY needs to be called. | |
| 1378 IfBuilder test_should_filter(this); | |
| 1379 Node* should_filter_cond = NewNode( | |
| 1380 javascript()->StrictEqual(), should_filter, jsgraph()->TrueConstant()); | |
| 1381 test_should_filter.If(should_filter_cond); | |
| 1382 test_should_filter.Then(); | |
| 1383 value = environment()->Pop(); | |
| 1384 Node* builtins = BuildLoadBuiltinsObject(); | |
| 1385 Node* function = BuildLoadObjectField( | |
| 1386 builtins, | |
| 1387 JSBuiltinsObject::OffsetOfFunctionWithId(Builtins::FILTER_KEY)); | |
| 1388 // result is either the string key or Smi(0) indicating the property | |
| 1389 // is gone. | |
| 1390 Node* res = NewNode( | |
| 1391 javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS, language_mode()), | |
| 1392 function, obj, value); | |
| 1393 PrepareFrameState(res, stmt->FilterId(), OutputFrameStateCombine::Push()); | |
| 1394 Node* property_missing = | |
| 1395 NewNode(javascript()->StrictEqual(), res, jsgraph()->ZeroConstant()); | |
| 1396 { | |
| 1397 IfBuilder is_property_missing(this); | |
| 1398 is_property_missing.If(property_missing); | |
| 1399 is_property_missing.Then(); | |
| 1400 // Inc counter and continue (cannot deoptimize). | |
| 1401 { | |
| 1402 FrameStateBeforeAndAfter states(this, BailoutId::None()); | |
| 1403 Node* index_inc = NewNode(javascript()->Add(LanguageMode::SLOPPY), | |
| 1404 index, jsgraph()->OneConstant()); | |
| 1405 states.AddToNode(index_inc, BailoutId::None(), | |
| 1406 OutputFrameStateCombine::Ignore()); | |
| 1407 environment()->Poke(0, index_inc); | |
| 1408 } | |
| 1409 for_loop.Continue(); | |
| 1410 is_property_missing.Else(); | |
| 1411 is_property_missing.End(); | |
| 1412 } | |
| 1413 // Replace 'value' in environment. | |
| 1414 environment()->Push(res); | |
| 1415 test_should_filter.Else(); | |
| 1416 test_should_filter.End(); | |
| 1417 } | |
| 1418 value = environment()->Pop(); | |
| 1419 // Bind value and do loop body. | |
| 1420 VisitForInAssignment(stmt->each(), value, stmt->AssignmentId()); | |
| 1421 VisitIterationBody(stmt, &for_loop); | |
| 1422 index = environment()->Peek(0); | |
| 1423 for_loop.EndBody(); | |
| 1424 | |
| 1425 // Inc counter and continue (cannot deoptimize). | |
| 1426 { | |
| 1427 FrameStateBeforeAndAfter states(this, BailoutId::None()); | |
| 1428 Node* index_inc = NewNode(javascript()->Add(LanguageMode::SLOPPY), index, | |
| 1429 jsgraph()->OneConstant()); | |
| 1430 states.AddToNode(index_inc, BailoutId::None(), | |
| 1431 OutputFrameStateCombine::Ignore()); | |
| 1432 environment()->Poke(0, index_inc); | |
| 1433 } | |
| 1434 for_loop.EndLoop(); | |
| 1435 environment()->Drop(5); | |
| 1436 // PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); | |
| 1437 } | |
| 1438 | |
| 1439 | |
| 1440 void AstGraphBuilder::VisitForOfStatement(ForOfStatement* stmt) { | 1372 void AstGraphBuilder::VisitForOfStatement(ForOfStatement* stmt) { |
| 1441 LoopBuilder for_loop(this); | 1373 LoopBuilder for_loop(this); |
| 1442 VisitForEffect(stmt->assign_iterator()); | 1374 VisitForEffect(stmt->assign_iterator()); |
| 1443 for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt)); | 1375 for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt)); |
| 1444 VisitForEffect(stmt->next_result()); | 1376 VisitForEffect(stmt->next_result()); |
| 1445 VisitForTest(stmt->result_done()); | 1377 VisitForTest(stmt->result_done()); |
| 1446 Node* condition = environment()->Pop(); | 1378 Node* condition = environment()->Pop(); |
| 1447 for_loop.BreakWhen(condition); | 1379 for_loop.BreakWhen(condition); |
| 1448 VisitForEffect(stmt->assign_each()); | 1380 VisitForEffect(stmt->assign_each()); |
| 1449 VisitIterationBody(stmt, &for_loop); | 1381 VisitIterationBody(stmt, &for_loop); |
| (...skipping 1882 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3332 Node* AstGraphBuilder::BuildToName(Node* input, BailoutId bailout_id) { | 3264 Node* AstGraphBuilder::BuildToName(Node* input, BailoutId bailout_id) { |
| 3333 // TODO(turbofan): Possible optimization is to NOP on name constants. But the | 3265 // TODO(turbofan): Possible optimization is to NOP on name constants. But the |
| 3334 // same caveat as with BuildToBoolean applies, and it should be factored out | 3266 // same caveat as with BuildToBoolean applies, and it should be factored out |
| 3335 // into a JSOperatorReducer. | 3267 // into a JSOperatorReducer. |
| 3336 Node* name = NewNode(javascript()->ToName(), input); | 3268 Node* name = NewNode(javascript()->ToName(), input); |
| 3337 PrepareFrameState(name, bailout_id); | 3269 PrepareFrameState(name, bailout_id); |
| 3338 return name; | 3270 return name; |
| 3339 } | 3271 } |
| 3340 | 3272 |
| 3341 | 3273 |
| 3274 Node* AstGraphBuilder::BuildToObject(Node* input, BailoutId bailout_id) { |
| 3275 Node* object = NewNode(javascript()->ToObject(), input); |
| 3276 PrepareFrameState(object, bailout_id, OutputFrameStateCombine::Push()); |
| 3277 return object; |
| 3278 } |
| 3279 |
| 3280 |
| 3342 Node* AstGraphBuilder::BuildSetHomeObject(Node* value, Node* home_object, | 3281 Node* AstGraphBuilder::BuildSetHomeObject(Node* value, Node* home_object, |
| 3343 Expression* expr) { | 3282 Expression* expr) { |
| 3344 if (!FunctionLiteral::NeedsHomeObject(expr)) return value; | 3283 if (!FunctionLiteral::NeedsHomeObject(expr)) return value; |
| 3345 Handle<Name> name = isolate()->factory()->home_object_symbol(); | 3284 Handle<Name> name = isolate()->factory()->home_object_symbol(); |
| 3346 FrameStateBeforeAndAfter states(this, BailoutId::None()); | 3285 FrameStateBeforeAndAfter states(this, BailoutId::None()); |
| 3347 Node* store = | 3286 Node* store = |
| 3348 BuildNamedStore(value, name, home_object, TypeFeedbackId::None()); | 3287 BuildNamedStore(value, name, home_object, TypeFeedbackId::None()); |
| 3349 states.AddToNode(store, BailoutId::None(), OutputFrameStateCombine::Ignore()); | 3288 states.AddToNode(store, BailoutId::None(), OutputFrameStateCombine::Ignore()); |
| 3350 return store; | 3289 return store; |
| 3351 } | 3290 } |
| (...skipping 433 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3785 // Phi does not exist yet, introduce one. | 3724 // Phi does not exist yet, introduce one. |
| 3786 value = NewPhi(inputs, value, control); | 3725 value = NewPhi(inputs, value, control); |
| 3787 value->ReplaceInput(inputs - 1, other); | 3726 value->ReplaceInput(inputs - 1, other); |
| 3788 } | 3727 } |
| 3789 return value; | 3728 return value; |
| 3790 } | 3729 } |
| 3791 | 3730 |
| 3792 } // namespace compiler | 3731 } // namespace compiler |
| 3793 } // namespace internal | 3732 } // namespace internal |
| 3794 } // namespace v8 | 3733 } // namespace v8 |
| OLD | NEW |