OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 6346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6357 | 6357 |
6358 instr->set_position(expr->position()); | 6358 instr->set_position(expr->position()); |
6359 return ast_context()->ReturnInstruction(instr, expr->id()); | 6359 return ast_context()->ReturnInstruction(instr, expr->id()); |
6360 } | 6360 } |
6361 | 6361 |
6362 | 6362 |
6363 bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic( | 6363 bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic( |
6364 int position, | 6364 int position, |
6365 BailoutId assignment_id, | 6365 BailoutId assignment_id, |
6366 HValue* object, | 6366 HValue* object, |
6367 HValue* value, | 6367 HValue* store_value, |
| 6368 HValue* result_value, |
6368 SmallMapList* types, | 6369 SmallMapList* types, |
6369 Handle<String> name) { | 6370 Handle<String> name) { |
6370 // Use monomorphic store if property lookup results in the same field index | 6371 // Use monomorphic store if property lookup results in the same field index |
6371 // for all maps. Requires special map check on the set of all handled maps. | 6372 // for all maps. Requires special map check on the set of all handled maps. |
6372 if (types->length() > kMaxStorePolymorphism) return false; | 6373 if (types->length() > kMaxStorePolymorphism) return false; |
6373 | 6374 |
6374 // TODO(verwaest): Merge the checking logic with the code in | 6375 // TODO(verwaest): Merge the checking logic with the code in |
6375 // TryLoadPolymorphicAsMonomorphic. | 6376 // TryLoadPolymorphicAsMonomorphic. |
6376 LookupResult lookup(isolate()); | 6377 LookupResult lookup(isolate()); |
6377 int count; | 6378 int count; |
(...skipping 25 matching lines...) Expand all Loading... |
6403 } | 6404 } |
6404 | 6405 |
6405 if (count != types->length()) return false; | 6406 if (count != types->length()) return false; |
6406 | 6407 |
6407 // Everything matched; can use monomorphic store. | 6408 // Everything matched; can use monomorphic store. |
6408 BuildCheckNonSmi(object); | 6409 BuildCheckNonSmi(object); |
6409 AddInstruction(HCheckMaps::New(object, types, zone())); | 6410 AddInstruction(HCheckMaps::New(object, types, zone())); |
6410 HInstruction* store; | 6411 HInstruction* store; |
6411 CHECK_ALIVE_OR_RETURN( | 6412 CHECK_ALIVE_OR_RETURN( |
6412 store = BuildStoreNamedField( | 6413 store = BuildStoreNamedField( |
6413 object, name, value, types->at(count - 1), &lookup), | 6414 object, name, store_value, types->at(count - 1), &lookup), |
6414 true); | 6415 true); |
6415 Push(value); | 6416 if (result_value != NULL) Push(result_value); |
| 6417 Push(store_value); |
6416 store->set_position(position); | 6418 store->set_position(position); |
6417 AddInstruction(store); | 6419 AddInstruction(store); |
6418 AddSimulate(assignment_id); | 6420 AddSimulate(assignment_id); |
| 6421 if (result_value != NULL) Drop(1); |
6419 ast_context()->ReturnValue(Pop()); | 6422 ast_context()->ReturnValue(Pop()); |
6420 return true; | 6423 return true; |
6421 } | 6424 } |
6422 | 6425 |
6423 | 6426 |
6424 void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField( | 6427 void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField( |
6425 BailoutId id, | 6428 BailoutId id, |
6426 int position, | 6429 int position, |
6427 BailoutId assignment_id, | 6430 BailoutId assignment_id, |
6428 HValue* object, | 6431 HValue* object, |
6429 HValue* value, | 6432 HValue* store_value, |
| 6433 HValue* result_value, |
6430 SmallMapList* types, | 6434 SmallMapList* types, |
6431 Handle<String> name) { | 6435 Handle<String> name) { |
6432 if (TryStorePolymorphicAsMonomorphic( | 6436 if (TryStorePolymorphicAsMonomorphic( |
6433 position, assignment_id, object, value, types, name)) { | 6437 position, assignment_id, object, |
| 6438 store_value, result_value, types, name)) { |
6434 return; | 6439 return; |
6435 } | 6440 } |
6436 | 6441 |
6437 // TODO(ager): We should recognize when the prototype chains for different | 6442 // TODO(ager): We should recognize when the prototype chains for different |
6438 // maps are identical. In that case we can avoid repeatedly generating the | 6443 // maps are identical. In that case we can avoid repeatedly generating the |
6439 // same prototype map checks. | 6444 // same prototype map checks. |
6440 int count = 0; | 6445 int count = 0; |
6441 HBasicBlock* join = NULL; | 6446 HBasicBlock* join = NULL; |
6442 for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) { | 6447 for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) { |
6443 Handle<Map> map = types->at(i); | 6448 Handle<Map> map = types->at(i); |
6444 LookupResult lookup(isolate()); | 6449 LookupResult lookup(isolate()); |
6445 if (ComputeLoadStoreField(map, name, &lookup, true)) { | 6450 if (ComputeLoadStoreField(map, name, &lookup, true)) { |
6446 if (count == 0) { | 6451 if (count == 0) { |
6447 BuildCheckNonSmi(object); | 6452 BuildCheckNonSmi(object); |
6448 join = graph()->CreateBasicBlock(); | 6453 join = graph()->CreateBasicBlock(); |
6449 } | 6454 } |
6450 ++count; | 6455 ++count; |
6451 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 6456 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
6452 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 6457 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
6453 HCompareMap* compare = | 6458 HCompareMap* compare = |
6454 new(zone()) HCompareMap(object, map, if_true, if_false); | 6459 new(zone()) HCompareMap(object, map, if_true, if_false); |
6455 current_block()->Finish(compare); | 6460 current_block()->Finish(compare); |
6456 | 6461 |
6457 set_current_block(if_true); | 6462 set_current_block(if_true); |
6458 HInstruction* instr; | 6463 HInstruction* instr; |
6459 CHECK_ALIVE( | 6464 CHECK_ALIVE(instr = BuildStoreNamedField( |
6460 instr = BuildStoreNamedField(object, name, value, map, &lookup)); | 6465 object, name, store_value, map, &lookup)); |
6461 instr->set_position(position); | 6466 instr->set_position(position); |
6462 // Goto will add the HSimulate for the store. | 6467 // Goto will add the HSimulate for the store. |
6463 AddInstruction(instr); | 6468 AddInstruction(instr); |
6464 if (!ast_context()->IsEffect()) Push(value); | 6469 if (!ast_context()->IsEffect()) { |
| 6470 if (result_value != NULL) Push(result_value); |
| 6471 Push(store_value); |
| 6472 } |
6465 current_block()->Goto(join); | 6473 current_block()->Goto(join); |
6466 | 6474 |
6467 set_current_block(if_false); | 6475 set_current_block(if_false); |
6468 } | 6476 } |
6469 } | 6477 } |
6470 | 6478 |
6471 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 6479 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
6472 // know about and do not want to handle ones we've never seen. Otherwise | 6480 // know about and do not want to handle ones we've never seen. Otherwise |
6473 // use a generic IC. | 6481 // use a generic IC. |
6474 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | 6482 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
6475 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); | 6483 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); |
6476 } else { | 6484 } else { |
6477 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); | 6485 HInstruction* instr = BuildStoreNamedGeneric(object, name, store_value); |
6478 instr->set_position(position); | 6486 instr->set_position(position); |
6479 AddInstruction(instr); | 6487 AddInstruction(instr); |
6480 | 6488 |
6481 if (join != NULL) { | 6489 if (join != NULL) { |
6482 if (!ast_context()->IsEffect()) Push(value); | 6490 if (!ast_context()->IsEffect()) { |
| 6491 if (result_value != NULL) Push(result_value); |
| 6492 Push(store_value); |
| 6493 } |
6483 current_block()->Goto(join); | 6494 current_block()->Goto(join); |
6484 } else { | 6495 } else { |
6485 // The HSimulate for the store should not see the stored value in | 6496 // The HSimulate for the store should not see the stored value in |
6486 // effect contexts (it is not materialized at expr->id() in the | 6497 // effect contexts (it is not materialized at expr->id() in the |
6487 // unoptimized code). | 6498 // unoptimized code). |
6488 if (instr->HasObservableSideEffects()) { | 6499 if (instr->HasObservableSideEffects()) { |
6489 if (ast_context()->IsEffect()) { | 6500 if (ast_context()->IsEffect()) { |
6490 AddSimulate(id, REMOVABLE_SIMULATE); | 6501 AddSimulate(id, REMOVABLE_SIMULATE); |
6491 } else { | 6502 } else { |
6492 Push(value); | 6503 if (result_value != NULL) Push(result_value); |
| 6504 Push(store_value); |
6493 AddSimulate(id, REMOVABLE_SIMULATE); | 6505 AddSimulate(id, REMOVABLE_SIMULATE); |
6494 Drop(1); | 6506 Drop(result_value != NULL ? 2 : 1); |
6495 } | 6507 } |
6496 } | 6508 } |
6497 return ast_context()->ReturnValue(value); | 6509 return ast_context()->ReturnValue( |
| 6510 result_value != NULL ? result_value : store_value); |
6498 } | 6511 } |
6499 } | 6512 } |
6500 | 6513 |
6501 ASSERT(join != NULL); | 6514 ASSERT(join != NULL); |
6502 join->SetJoinId(id); | 6515 join->SetJoinId(id); |
6503 set_current_block(join); | 6516 set_current_block(join); |
6504 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); | 6517 if (!ast_context()->IsEffect()) { |
| 6518 if (result_value != NULL) Drop(1); |
| 6519 ast_context()->ReturnValue(Pop()); |
| 6520 } |
6505 } | 6521 } |
6506 | 6522 |
6507 | 6523 |
6508 void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) { | 6524 void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) { |
6509 Property* prop = expr->target()->AsProperty(); | 6525 Property* prop = expr->target()->AsProperty(); |
6510 ASSERT(prop != NULL); | 6526 ASSERT(prop != NULL); |
6511 CHECK_ALIVE(VisitForValue(prop->obj())); | 6527 CHECK_ALIVE(VisitForValue(prop->obj())); |
6512 | 6528 |
6513 if (prop->key()->IsPropertyName()) { | 6529 if (prop->key()->IsPropertyName()) { |
6514 // Named store. | 6530 // Named store. |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6575 } | 6591 } |
6576 } | 6592 } |
6577 | 6593 |
6578 | 6594 |
6579 void HOptimizedGraphBuilder::BuildStoreNamed(Expression* expr, | 6595 void HOptimizedGraphBuilder::BuildStoreNamed(Expression* expr, |
6580 BailoutId id, | 6596 BailoutId id, |
6581 int position, | 6597 int position, |
6582 BailoutId assignment_id, | 6598 BailoutId assignment_id, |
6583 Property* prop, | 6599 Property* prop, |
6584 HValue* object, | 6600 HValue* object, |
6585 HValue* value) { | 6601 HValue* store_value, |
| 6602 HValue* result_value) { |
6586 Literal* key = prop->key()->AsLiteral(); | 6603 Literal* key = prop->key()->AsLiteral(); |
6587 Handle<String> name = Handle<String>::cast(key->handle()); | 6604 Handle<String> name = Handle<String>::cast(key->handle()); |
6588 ASSERT(!name.is_null()); | 6605 ASSERT(!name.is_null()); |
6589 | 6606 |
6590 HInstruction* instr = NULL; | 6607 HInstruction* instr = NULL; |
6591 SmallMapList* types = expr->GetReceiverTypes(); | 6608 SmallMapList* types = expr->GetReceiverTypes(); |
6592 bool monomorphic = expr->IsMonomorphic(); | 6609 bool monomorphic = expr->IsMonomorphic(); |
6593 Handle<Map> map; | 6610 Handle<Map> map; |
6594 if (monomorphic) { | 6611 if (monomorphic) { |
6595 map = types->first(); | 6612 map = types->first(); |
6596 if (map->is_dictionary_map()) monomorphic = false; | 6613 if (map->is_dictionary_map()) monomorphic = false; |
6597 } | 6614 } |
6598 if (monomorphic) { | 6615 if (monomorphic) { |
6599 Handle<JSFunction> setter; | 6616 Handle<JSFunction> setter; |
6600 Handle<JSObject> holder; | 6617 Handle<JSObject> holder; |
6601 if (LookupSetter(map, name, &setter, &holder)) { | 6618 if (LookupSetter(map, name, &setter, &holder)) { |
6602 AddCheckConstantFunction(holder, object, map); | 6619 AddCheckConstantFunction(holder, object, map); |
6603 if (FLAG_inline_accessors && | 6620 // Don't try to inline if the result_value is different from the |
6604 TryInlineSetter(setter, id, assignment_id, value)) { | 6621 // store_value. That case isn't handled yet by the inlining. |
| 6622 if (result_value == NULL && |
| 6623 FLAG_inline_accessors && |
| 6624 TryInlineSetter(setter, id, assignment_id, store_value)) { |
6605 return; | 6625 return; |
6606 } | 6626 } |
6607 Drop(2); | 6627 Drop(2); |
6608 AddInstruction(new(zone()) HPushArgument(object)); | 6628 AddInstruction(new(zone()) HPushArgument(object)); |
6609 AddInstruction(new(zone()) HPushArgument(value)); | 6629 AddInstruction(new(zone()) HPushArgument(store_value)); |
6610 instr = new(zone()) HCallConstantFunction(setter, 2); | 6630 instr = new(zone()) HCallConstantFunction(setter, 2); |
6611 } else { | 6631 } else { |
6612 Drop(2); | 6632 Drop(2); |
6613 CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object, | 6633 CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object, |
6614 name, | 6634 name, |
6615 value, | 6635 store_value, |
6616 map)); | 6636 map)); |
6617 } | 6637 } |
6618 | |
6619 } else if (types != NULL && types->length() > 1) { | 6638 } else if (types != NULL && types->length() > 1) { |
6620 Drop(2); | 6639 Drop(2); |
6621 return HandlePolymorphicStoreNamedField( | 6640 return HandlePolymorphicStoreNamedField( |
6622 id, position, assignment_id, object, value, types, name); | 6641 id, position, assignment_id, object, |
| 6642 store_value, result_value, types, name); |
6623 } else { | 6643 } else { |
6624 Drop(2); | 6644 Drop(2); |
6625 instr = BuildStoreNamedGeneric(object, name, value); | 6645 instr = BuildStoreNamedGeneric(object, name, store_value); |
6626 } | 6646 } |
6627 | 6647 |
6628 Push(value); | 6648 if (result_value != NULL) Push(result_value); |
| 6649 Push(store_value); |
6629 instr->set_position(position); | 6650 instr->set_position(position); |
6630 AddInstruction(instr); | 6651 AddInstruction(instr); |
6631 if (instr->HasObservableSideEffects()) { | 6652 if (instr->HasObservableSideEffects()) { |
6632 AddSimulate(assignment_id, REMOVABLE_SIMULATE); | 6653 AddSimulate(assignment_id, REMOVABLE_SIMULATE); |
6633 } | 6654 } |
| 6655 if (result_value != NULL) Drop(1); |
6634 return ast_context()->ReturnValue(Pop()); | 6656 return ast_context()->ReturnValue(Pop()); |
6635 } | 6657 } |
6636 | 6658 |
6637 | 6659 |
6638 void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { | 6660 void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
6639 Expression* target = expr->target(); | 6661 Expression* target = expr->target(); |
6640 VariableProxy* proxy = target->AsVariableProxy(); | 6662 VariableProxy* proxy = target->AsVariableProxy(); |
6641 Property* prop = target->AsProperty(); | 6663 Property* prop = target->AsProperty(); |
6642 ASSERT(proxy == NULL || prop == NULL); | 6664 ASSERT(proxy == NULL || prop == NULL); |
6643 | 6665 |
(...skipping 2603 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9247 } else if (types != NULL && types->length() > 1) { | 9269 } else if (types != NULL && types->length() > 1) { |
9248 load = TryLoadPolymorphicAsMonomorphic(prop, object, types, name); | 9270 load = TryLoadPolymorphicAsMonomorphic(prop, object, types, name); |
9249 } | 9271 } |
9250 if (load == NULL) load = BuildLoadNamedGeneric(object, name, prop); | 9272 if (load == NULL) load = BuildLoadNamedGeneric(object, name, prop); |
9251 PushAndAdd(load); | 9273 PushAndAdd(load); |
9252 if (load->HasObservableSideEffects()) { | 9274 if (load->HasObservableSideEffects()) { |
9253 AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); | 9275 AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); |
9254 } | 9276 } |
9255 | 9277 |
9256 after = BuildIncrement(returns_original_input, expr); | 9278 after = BuildIncrement(returns_original_input, expr); |
9257 input = Pop(); | |
9258 | 9279 |
9259 HInstruction* store; | 9280 HValue* result = returns_original_input ? Pop() : NULL; |
9260 if (!monomorphic || map->is_observed()) { | |
9261 // If we don't know the monomorphic type, do a generic store. | |
9262 CHECK_ALIVE(store = BuildStoreNamedGeneric(object, name, after)); | |
9263 } else { | |
9264 Handle<JSFunction> setter; | |
9265 Handle<JSObject> holder; | |
9266 if (LookupSetter(map, name, &setter, &holder)) { | |
9267 store = BuildCallSetter(object, after, map, setter, holder); | |
9268 } else { | |
9269 CHECK_ALIVE(store = BuildStoreNamedMonomorphic(object, | |
9270 name, | |
9271 after, | |
9272 map)); | |
9273 } | |
9274 } | |
9275 AddInstruction(store); | |
9276 | 9281 |
9277 // Overwrite the receiver in the bailout environment with the result | 9282 return BuildStoreNamed(prop, expr->id(), expr->position(), |
9278 // of the operation, and the placeholder with the original value if | 9283 expr->AssignmentId(), prop, object, after, result); |
9279 // necessary. | |
9280 environment()->SetExpressionStackAt(0, after); | |
9281 if (returns_original_input) environment()->SetExpressionStackAt(1, input); | |
9282 if (store->HasObservableSideEffects()) { | |
9283 AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); | |
9284 } | |
9285 | |
9286 } else { | 9284 } else { |
9287 // Keyed property. | 9285 // Keyed property. |
9288 if (returns_original_input) Push(graph()->GetConstantUndefined()); | 9286 if (returns_original_input) Push(graph()->GetConstantUndefined()); |
9289 | 9287 |
9290 CHECK_ALIVE(VisitForValue(prop->obj())); | 9288 CHECK_ALIVE(VisitForValue(prop->obj())); |
9291 CHECK_ALIVE(VisitForValue(prop->key())); | 9289 CHECK_ALIVE(VisitForValue(prop->key())); |
9292 HValue* obj = environment()->ExpressionStackAt(1); | 9290 HValue* obj = environment()->ExpressionStackAt(1); |
9293 HValue* key = environment()->ExpressionStackAt(0); | 9291 HValue* key = environment()->ExpressionStackAt(0); |
9294 | 9292 |
9295 bool has_side_effects = false; | 9293 bool has_side_effects = false; |
(...skipping 2288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11584 } | 11582 } |
11585 } | 11583 } |
11586 | 11584 |
11587 #ifdef DEBUG | 11585 #ifdef DEBUG |
11588 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 11586 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
11589 if (allocator_ != NULL) allocator_->Verify(); | 11587 if (allocator_ != NULL) allocator_->Verify(); |
11590 #endif | 11588 #endif |
11591 } | 11589 } |
11592 | 11590 |
11593 } } // namespace v8::internal | 11591 } } // namespace v8::internal |
OLD | NEW |