| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 3987 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3998 | 3998 |
| 3999 HRegExpLiteral* instr = new(zone()) HRegExpLiteral(context, | 3999 HRegExpLiteral* instr = new(zone()) HRegExpLiteral(context, |
| 4000 literals, | 4000 literals, |
| 4001 expr->pattern(), | 4001 expr->pattern(), |
| 4002 expr->flags(), | 4002 expr->flags(), |
| 4003 expr->literal_index()); | 4003 expr->literal_index()); |
| 4004 return ast_context()->ReturnInstruction(instr, expr->id()); | 4004 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 4005 } | 4005 } |
| 4006 | 4006 |
| 4007 | 4007 |
| 4008 static bool CanInlinePropertyAccess(Map* type) { |
| 4009 return !type->is_dictionary_map() && !type->has_named_interceptor(); |
| 4010 } |
| 4011 |
| 4012 |
| 4008 static void LookupInPrototypes(Handle<Map> map, | 4013 static void LookupInPrototypes(Handle<Map> map, |
| 4009 Handle<String> name, | 4014 Handle<String> name, |
| 4010 LookupResult* lookup) { | 4015 LookupResult* lookup) { |
| 4011 while (map->prototype()->IsJSObject()) { | 4016 while (map->prototype()->IsJSObject()) { |
| 4012 Handle<JSObject> holder(JSObject::cast(map->prototype())); | 4017 Handle<JSObject> holder(JSObject::cast(map->prototype())); |
| 4013 if (!holder->HasFastProperties()) break; | |
| 4014 map = Handle<Map>(holder->map()); | 4018 map = Handle<Map>(holder->map()); |
| 4019 if (!CanInlinePropertyAccess(*map)) break; |
| 4015 map->LookupDescriptor(*holder, *name, lookup); | 4020 map->LookupDescriptor(*holder, *name, lookup); |
| 4016 if (lookup->IsFound()) return; | 4021 if (lookup->IsFound()) return; |
| 4017 } | 4022 } |
| 4018 lookup->NotFound(); | 4023 lookup->NotFound(); |
| 4019 } | 4024 } |
| 4020 | 4025 |
| 4021 | 4026 |
| 4022 // Tries to find a JavaScript accessor of the given name in the prototype chain | 4027 // Tries to find a JavaScript accessor of the given name in the prototype chain |
| 4023 // starting at the given map. Return true iff there is one, including the | 4028 // starting at the given map. Return true iff there is one, including the |
| 4024 // corresponding AccessorPair plus its holder (which could be null when the | 4029 // corresponding AccessorPair plus its holder (which could be null when the |
| (...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4392 return ast_context()->ReturnValue(Pop()); | 4397 return ast_context()->ReturnValue(Pop()); |
| 4393 } | 4398 } |
| 4394 | 4399 |
| 4395 | 4400 |
| 4396 // Sets the lookup result and returns true if the load/store can be inlined. | 4401 // Sets the lookup result and returns true if the load/store can be inlined. |
| 4397 static bool ComputeLoadStoreField(Handle<Map> type, | 4402 static bool ComputeLoadStoreField(Handle<Map> type, |
| 4398 Handle<String> name, | 4403 Handle<String> name, |
| 4399 LookupResult* lookup, | 4404 LookupResult* lookup, |
| 4400 bool is_store) { | 4405 bool is_store) { |
| 4401 ASSERT(!is_store || !type->is_observed()); | 4406 ASSERT(!is_store || !type->is_observed()); |
| 4402 if (type->has_named_interceptor()) { | 4407 if (!CanInlinePropertyAccess(*type)) { |
| 4403 lookup->InterceptorResult(NULL); | 4408 lookup->NotFound(); |
| 4404 return false; | 4409 return false; |
| 4405 } | 4410 } |
| 4406 // If we directly find a field, the access can be inlined. | 4411 // If we directly find a field, the access can be inlined. |
| 4407 type->LookupDescriptor(NULL, *name, lookup); | 4412 type->LookupDescriptor(NULL, *name, lookup); |
| 4408 if (lookup->IsField()) return true; | 4413 if (lookup->IsField()) return true; |
| 4409 | 4414 |
| 4410 // For a load, we are out of luck if there is no such field. | 4415 // For a load, we are out of luck if there is no such field. |
| 4411 if (!is_store) return false; | 4416 if (!is_store) return false; |
| 4412 | 4417 |
| 4413 // 2nd chance: A store into a non-existent field can still be inlined if we | 4418 // 2nd chance: A store into a non-existent field can still be inlined if we |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4536 } | 4541 } |
| 4537 | 4542 |
| 4538 // No luck, do a generic store. | 4543 // No luck, do a generic store. |
| 4539 return BuildStoreNamedGeneric(object, name, value); | 4544 return BuildStoreNamedGeneric(object, name, value); |
| 4540 } | 4545 } |
| 4541 | 4546 |
| 4542 | 4547 |
| 4543 static bool CanLoadPropertyFromPrototype(Handle<Map> map, | 4548 static bool CanLoadPropertyFromPrototype(Handle<Map> map, |
| 4544 Handle<Name> name, | 4549 Handle<Name> name, |
| 4545 LookupResult* lookup) { | 4550 LookupResult* lookup) { |
| 4546 if (map->has_named_interceptor()) return false; | 4551 if (!CanInlinePropertyAccess(*map)) return false; |
| 4547 if (map->is_dictionary_map()) return false; | |
| 4548 map->LookupDescriptor(NULL, *name, lookup); | 4552 map->LookupDescriptor(NULL, *name, lookup); |
| 4549 if (lookup->IsFound()) return false; | 4553 if (lookup->IsFound()) return false; |
| 4550 return true; | 4554 return true; |
| 4551 } | 4555 } |
| 4552 | 4556 |
| 4553 | 4557 |
| 4554 HInstruction* HOptimizedGraphBuilder::TryLoadPolymorphicAsMonomorphic( | 4558 HInstruction* HOptimizedGraphBuilder::TryLoadPolymorphicAsMonomorphic( |
| 4555 Property* expr, | |
| 4556 HValue* object, | 4559 HValue* object, |
| 4557 SmallMapList* types, | 4560 SmallMapList* types, |
| 4558 Handle<String> name) { | 4561 Handle<String> name) { |
| 4559 // Use monomorphic load if property lookup results in the same field index | 4562 // Use monomorphic load if property lookup results in the same field index |
| 4560 // for all maps. Requires special map check on the set of all handled maps. | 4563 // for all maps. Requires special map check on the set of all handled maps. |
| 4561 if (types->length() > kMaxLoadPolymorphism) return NULL; | 4564 if (types->length() > kMaxLoadPolymorphism) return NULL; |
| 4562 | 4565 |
| 4563 LookupResult lookup(isolate()); | 4566 LookupResult lookup(isolate()); |
| 4564 int count; | 4567 int count; |
| 4565 HObjectAccess access = HObjectAccess::ForMap(); // initial value unused. | 4568 HObjectAccess access = HObjectAccess::ForMap(); // initial value unused. |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4629 // polymorphic loads where the property is sometimes found in the prototype | 4632 // polymorphic loads where the property is sometimes found in the prototype |
| 4630 // chain. | 4633 // chain. |
| 4631 static bool PrototypeChainCanNeverResolve( | 4634 static bool PrototypeChainCanNeverResolve( |
| 4632 Handle<Map> map, Handle<String> name) { | 4635 Handle<Map> map, Handle<String> name) { |
| 4633 Isolate* isolate = map->GetIsolate(); | 4636 Isolate* isolate = map->GetIsolate(); |
| 4634 Object* current = map->prototype(); | 4637 Object* current = map->prototype(); |
| 4635 while (current != isolate->heap()->null_value()) { | 4638 while (current != isolate->heap()->null_value()) { |
| 4636 if (current->IsJSGlobalProxy() || | 4639 if (current->IsJSGlobalProxy() || |
| 4637 current->IsGlobalObject() || | 4640 current->IsGlobalObject() || |
| 4638 !current->IsJSObject() || | 4641 !current->IsJSObject() || |
| 4639 JSObject::cast(current)->map()->has_named_interceptor() || | 4642 !CanInlinePropertyAccess(JSObject::cast(current)->map()) || |
| 4640 JSObject::cast(current)->IsAccessCheckNeeded() || | 4643 JSObject::cast(current)->IsAccessCheckNeeded()) { |
| 4641 !JSObject::cast(current)->HasFastProperties()) { | |
| 4642 return false; | 4644 return false; |
| 4643 } | 4645 } |
| 4644 | 4646 |
| 4645 LookupResult lookup(isolate); | 4647 LookupResult lookup(isolate); |
| 4646 Map* map = JSObject::cast(current)->map(); | 4648 Map* map = JSObject::cast(current)->map(); |
| 4647 map->LookupDescriptor(NULL, *name, &lookup); | 4649 map->LookupDescriptor(NULL, *name, &lookup); |
| 4648 if (lookup.IsFound()) return false; | 4650 if (lookup.IsFound()) return false; |
| 4649 if (!lookup.IsCacheable()) return false; | 4651 if (!lookup.IsCacheable()) return false; |
| 4650 current = JSObject::cast(current)->GetPrototype(); | 4652 current = JSObject::cast(current)->GetPrototype(); |
| 4651 } | 4653 } |
| 4652 return true; | 4654 return true; |
| 4653 } | 4655 } |
| 4654 | 4656 |
| 4655 | 4657 |
| 4656 void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( | 4658 void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( |
| 4657 Property* expr, | 4659 int position, |
| 4660 BailoutId ast_id, |
| 4658 HValue* object, | 4661 HValue* object, |
| 4659 SmallMapList* types, | 4662 SmallMapList* types, |
| 4660 Handle<String> name) { | 4663 Handle<String> name) { |
| 4661 HInstruction* instr = TryLoadPolymorphicAsMonomorphic( | 4664 HInstruction* instr = TryLoadPolymorphicAsMonomorphic(object, types, name); |
| 4662 expr, object, types, name); | |
| 4663 if (instr != NULL) { | 4665 if (instr != NULL) { |
| 4664 instr->set_position(expr->position()); | 4666 instr->set_position(position); |
| 4665 return ast_context()->ReturnInstruction(instr, expr->id()); | 4667 return ast_context()->ReturnInstruction(instr, ast_id); |
| 4666 } | 4668 } |
| 4667 | 4669 |
| 4668 // Something did not match; must use a polymorphic load. | 4670 // Something did not match; must use a polymorphic load. |
| 4669 int count = 0; | 4671 int count = 0; |
| 4670 HBasicBlock* join = NULL; | 4672 HBasicBlock* join = NULL; |
| 4671 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { | 4673 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { |
| 4672 Handle<Map> map = types->at(i); | 4674 Handle<Map> map = types->at(i); |
| 4673 LookupResult lookup(isolate()); | 4675 LookupResult lookup(isolate()); |
| 4674 if (ComputeLoadStoreField(map, name, &lookup, false) || | 4676 if (ComputeLoadStoreField(map, name, &lookup, false) || |
| 4675 (lookup.IsCacheable() && | 4677 (lookup.IsCacheable() && |
| 4676 !map->is_dictionary_map() && | 4678 CanInlinePropertyAccess(*map) && |
| 4677 !map->has_named_interceptor() && | |
| 4678 (lookup.IsConstant() || | 4679 (lookup.IsConstant() || |
| 4679 (!lookup.IsFound() && | 4680 (!lookup.IsFound() && |
| 4680 PrototypeChainCanNeverResolve(map, name))))) { | 4681 PrototypeChainCanNeverResolve(map, name))))) { |
| 4681 if (count == 0) { | 4682 if (count == 0) { |
| 4682 BuildCheckHeapObject(object); | 4683 BuildCheckHeapObject(object); |
| 4683 join = graph()->CreateBasicBlock(); | 4684 join = graph()->CreateBasicBlock(); |
| 4684 } | 4685 } |
| 4685 ++count; | 4686 ++count; |
| 4686 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 4687 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 4687 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 4688 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 4688 HCompareMap* compare = | 4689 HCompareMap* compare = |
| 4689 new(zone()) HCompareMap(object, map, if_true, if_false); | 4690 new(zone()) HCompareMap(object, map, if_true, if_false); |
| 4690 current_block()->Finish(compare); | 4691 current_block()->Finish(compare); |
| 4691 | 4692 |
| 4692 set_current_block(if_true); | 4693 set_current_block(if_true); |
| 4693 | 4694 |
| 4694 // TODO(verwaest): Merge logic with BuildLoadNamedMonomorphic. | 4695 // TODO(verwaest): Merge logic with BuildLoadNamedMonomorphic. |
| 4695 if (lookup.IsField()) { | 4696 if (lookup.IsField()) { |
| 4696 HObjectAccess access = HObjectAccess::ForField(map, &lookup, name); | 4697 HObjectAccess access = HObjectAccess::ForField(map, &lookup, name); |
| 4697 HLoadNamedField* load = BuildLoadNamedField(compare, access); | 4698 HLoadNamedField* load = BuildLoadNamedField(compare, access); |
| 4698 load->set_position(expr->position()); | 4699 load->set_position(position); |
| 4699 AddInstruction(load); | 4700 AddInstruction(load); |
| 4700 if (!ast_context()->IsEffect()) Push(load); | 4701 if (!ast_context()->IsEffect()) Push(load); |
| 4701 } else if (lookup.IsConstant()) { | 4702 } else if (lookup.IsConstant()) { |
| 4702 Handle<Object> constant(lookup.GetConstantFromMap(*map), isolate()); | 4703 Handle<Object> constant(lookup.GetConstantFromMap(*map), isolate()); |
| 4703 HConstant* hconstant = Add<HConstant>(constant); | 4704 HConstant* hconstant = Add<HConstant>(constant); |
| 4704 if (!ast_context()->IsEffect()) Push(hconstant); | 4705 if (!ast_context()->IsEffect()) Push(hconstant); |
| 4705 } else { | 4706 } else { |
| 4706 ASSERT(!lookup.IsFound()); | 4707 ASSERT(!lookup.IsFound()); |
| 4707 if (map->prototype()->IsJSObject()) { | 4708 if (map->prototype()->IsJSObject()) { |
| 4708 Handle<JSObject> prototype(JSObject::cast(map->prototype())); | 4709 Handle<JSObject> prototype(JSObject::cast(map->prototype())); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 4719 set_current_block(if_false); | 4720 set_current_block(if_false); |
| 4720 } | 4721 } |
| 4721 } | 4722 } |
| 4722 | 4723 |
| 4723 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 4724 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 4724 // know about and do not want to handle ones we've never seen. Otherwise | 4725 // know about and do not want to handle ones we've never seen. Otherwise |
| 4725 // use a generic IC. | 4726 // use a generic IC. |
| 4726 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | 4727 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
| 4727 FinishExitWithHardDeoptimization("Unknown map in polymorphic load", join); | 4728 FinishExitWithHardDeoptimization("Unknown map in polymorphic load", join); |
| 4728 } else { | 4729 } else { |
| 4729 HInstruction* load = BuildLoadNamedGeneric(object, name, expr); | 4730 HValue* context = environment()->context(); |
| 4730 load->set_position(expr->position()); | 4731 HInstruction* load = new(zone()) HLoadNamedGeneric(context, object, name); |
| 4732 load->set_position(position); |
| 4731 AddInstruction(load); | 4733 AddInstruction(load); |
| 4732 if (!ast_context()->IsEffect()) Push(load); | 4734 if (!ast_context()->IsEffect()) Push(load); |
| 4733 | 4735 |
| 4734 if (join != NULL) { | 4736 if (join != NULL) { |
| 4735 current_block()->Goto(join); | 4737 current_block()->Goto(join); |
| 4736 } else { | 4738 } else { |
| 4737 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); | 4739 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
| 4738 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); | 4740 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
| 4739 return; | 4741 return; |
| 4740 } | 4742 } |
| 4741 } | 4743 } |
| 4742 | 4744 |
| 4743 ASSERT(join != NULL); | 4745 ASSERT(join != NULL); |
| 4744 join->SetJoinId(expr->id()); | 4746 join->SetJoinId(ast_id); |
| 4745 set_current_block(join); | 4747 set_current_block(join); |
| 4746 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); | 4748 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
| 4747 } | 4749 } |
| 4748 | 4750 |
| 4749 | 4751 |
| 4750 bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic( | 4752 bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic( |
| 4751 int position, | 4753 int position, |
| 4752 BailoutId assignment_id, | 4754 BailoutId assignment_id, |
| 4753 HValue* object, | 4755 HValue* object, |
| 4754 HValue* store_value, | 4756 HValue* value, |
| 4755 HValue* result_value, | |
| 4756 SmallMapList* types, | 4757 SmallMapList* types, |
| 4757 Handle<String> name) { | 4758 Handle<String> name) { |
| 4758 // Use monomorphic store if property lookup results in the same field index | 4759 // Use monomorphic store if property lookup results in the same field index |
| 4759 // for all maps. Requires special map check on the set of all handled maps. | 4760 // for all maps. Requires special map check on the set of all handled maps. |
| 4760 if (types->length() > kMaxStorePolymorphism) return false; | 4761 if (types->length() > kMaxStorePolymorphism) return false; |
| 4761 | 4762 |
| 4762 // TODO(verwaest): Merge the checking logic with the code in | 4763 // TODO(verwaest): Merge the checking logic with the code in |
| 4763 // TryLoadPolymorphicAsMonomorphic. | 4764 // TryLoadPolymorphicAsMonomorphic. |
| 4764 LookupResult lookup(isolate()); | 4765 LookupResult lookup(isolate()); |
| 4765 int count; | 4766 int count; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 4791 } | 4792 } |
| 4792 | 4793 |
| 4793 if (count != types->length()) return false; | 4794 if (count != types->length()) return false; |
| 4794 | 4795 |
| 4795 // Everything matched; can use monomorphic store. | 4796 // Everything matched; can use monomorphic store. |
| 4796 BuildCheckHeapObject(object); | 4797 BuildCheckHeapObject(object); |
| 4797 HCheckMaps* checked_object = Add<HCheckMaps>(object, types); | 4798 HCheckMaps* checked_object = Add<HCheckMaps>(object, types); |
| 4798 HInstruction* store; | 4799 HInstruction* store; |
| 4799 CHECK_ALIVE_OR_RETURN( | 4800 CHECK_ALIVE_OR_RETURN( |
| 4800 store = BuildStoreNamedField( | 4801 store = BuildStoreNamedField( |
| 4801 checked_object, name, store_value, types->at(count - 1), &lookup), | 4802 checked_object, name, value, types->at(count - 1), &lookup), |
| 4802 true); | 4803 true); |
| 4803 if (!ast_context()->IsEffect()) Push(result_value); | 4804 if (!ast_context()->IsEffect()) Push(value); |
| 4804 store->set_position(position); | 4805 store->set_position(position); |
| 4805 AddInstruction(store); | 4806 AddInstruction(store); |
| 4806 Add<HSimulate>(assignment_id); | 4807 Add<HSimulate>(assignment_id); |
| 4807 if (!ast_context()->IsEffect()) Drop(1); | 4808 if (!ast_context()->IsEffect()) Drop(1); |
| 4808 ast_context()->ReturnValue(result_value); | 4809 ast_context()->ReturnValue(value); |
| 4809 return true; | 4810 return true; |
| 4810 } | 4811 } |
| 4811 | 4812 |
| 4812 | 4813 |
| 4813 void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField( | 4814 void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField( |
| 4814 int position, | 4815 int position, |
| 4815 BailoutId assignment_id, | 4816 BailoutId assignment_id, |
| 4816 HValue* object, | 4817 HValue* object, |
| 4817 HValue* store_value, | 4818 HValue* value, |
| 4818 HValue* result_value, | |
| 4819 SmallMapList* types, | 4819 SmallMapList* types, |
| 4820 Handle<String> name) { | 4820 Handle<String> name) { |
| 4821 if (TryStorePolymorphicAsMonomorphic( | 4821 if (TryStorePolymorphicAsMonomorphic( |
| 4822 position, assignment_id, object, | 4822 position, assignment_id, object, value, types, name)) { |
| 4823 store_value, result_value, types, name)) { | |
| 4824 return; | 4823 return; |
| 4825 } | 4824 } |
| 4826 | 4825 |
| 4827 // TODO(ager): We should recognize when the prototype chains for different | 4826 // TODO(ager): We should recognize when the prototype chains for different |
| 4828 // maps are identical. In that case we can avoid repeatedly generating the | 4827 // maps are identical. In that case we can avoid repeatedly generating the |
| 4829 // same prototype map checks. | 4828 // same prototype map checks. |
| 4830 int count = 0; | 4829 int count = 0; |
| 4831 HBasicBlock* join = NULL; | 4830 HBasicBlock* join = NULL; |
| 4832 for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) { | 4831 for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) { |
| 4833 Handle<Map> map = types->at(i); | 4832 Handle<Map> map = types->at(i); |
| 4834 LookupResult lookup(isolate()); | 4833 LookupResult lookup(isolate()); |
| 4835 if (ComputeLoadStoreField(map, name, &lookup, true)) { | 4834 if (ComputeLoadStoreField(map, name, &lookup, true)) { |
| 4836 if (count == 0) { | 4835 if (count == 0) { |
| 4837 BuildCheckHeapObject(object); | 4836 BuildCheckHeapObject(object); |
| 4838 join = graph()->CreateBasicBlock(); | 4837 join = graph()->CreateBasicBlock(); |
| 4839 } | 4838 } |
| 4840 ++count; | 4839 ++count; |
| 4841 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 4840 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 4842 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 4841 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 4843 HCompareMap* compare = | 4842 HCompareMap* compare = |
| 4844 new(zone()) HCompareMap(object, map, if_true, if_false); | 4843 new(zone()) HCompareMap(object, map, if_true, if_false); |
| 4845 current_block()->Finish(compare); | 4844 current_block()->Finish(compare); |
| 4846 | 4845 |
| 4847 set_current_block(if_true); | 4846 set_current_block(if_true); |
| 4848 HInstruction* instr; | 4847 HInstruction* instr; |
| 4849 CHECK_ALIVE(instr = BuildStoreNamedField( | 4848 CHECK_ALIVE(instr = BuildStoreNamedField( |
| 4850 compare, name, store_value, map, &lookup)); | 4849 compare, name, value, map, &lookup)); |
| 4851 instr->set_position(position); | 4850 instr->set_position(position); |
| 4852 // Goto will add the HSimulate for the store. | 4851 // Goto will add the HSimulate for the store. |
| 4853 AddInstruction(instr); | 4852 AddInstruction(instr); |
| 4854 if (!ast_context()->IsEffect()) Push(result_value); | 4853 if (!ast_context()->IsEffect()) Push(value); |
| 4855 current_block()->Goto(join); | 4854 current_block()->Goto(join); |
| 4856 | 4855 |
| 4857 set_current_block(if_false); | 4856 set_current_block(if_false); |
| 4858 } | 4857 } |
| 4859 } | 4858 } |
| 4860 | 4859 |
| 4861 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 4860 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 4862 // know about and do not want to handle ones we've never seen. Otherwise | 4861 // know about and do not want to handle ones we've never seen. Otherwise |
| 4863 // use a generic IC. | 4862 // use a generic IC. |
| 4864 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | 4863 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
| 4865 FinishExitWithHardDeoptimization("Unknown map in polymorphic store", join); | 4864 FinishExitWithHardDeoptimization("Unknown map in polymorphic store", join); |
| 4866 } else { | 4865 } else { |
| 4867 HInstruction* instr = BuildStoreNamedGeneric(object, name, store_value); | 4866 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); |
| 4868 instr->set_position(position); | 4867 instr->set_position(position); |
| 4869 AddInstruction(instr); | 4868 AddInstruction(instr); |
| 4870 | 4869 |
| 4871 if (join != NULL) { | 4870 if (join != NULL) { |
| 4872 if (!ast_context()->IsEffect()) { | 4871 if (!ast_context()->IsEffect()) { |
| 4873 Push(result_value); | 4872 Push(value); |
| 4874 } | 4873 } |
| 4875 current_block()->Goto(join); | 4874 current_block()->Goto(join); |
| 4876 } else { | 4875 } else { |
| 4877 // The HSimulate for the store should not see the stored value in | 4876 // The HSimulate for the store should not see the stored value in |
| 4878 // effect contexts (it is not materialized at expr->id() in the | 4877 // effect contexts (it is not materialized at expr->id() in the |
| 4879 // unoptimized code). | 4878 // unoptimized code). |
| 4880 if (instr->HasObservableSideEffects()) { | 4879 if (instr->HasObservableSideEffects()) { |
| 4881 if (ast_context()->IsEffect()) { | 4880 if (ast_context()->IsEffect()) { |
| 4882 Add<HSimulate>(assignment_id, REMOVABLE_SIMULATE); | 4881 Add<HSimulate>(assignment_id, REMOVABLE_SIMULATE); |
| 4883 } else { | 4882 } else { |
| 4884 Push(result_value); | 4883 Push(value); |
| 4885 Add<HSimulate>(assignment_id, REMOVABLE_SIMULATE); | 4884 Add<HSimulate>(assignment_id, REMOVABLE_SIMULATE); |
| 4886 Drop(1); | 4885 Drop(1); |
| 4887 } | 4886 } |
| 4888 } | 4887 } |
| 4889 return ast_context()->ReturnValue(result_value); | 4888 return ast_context()->ReturnValue(value); |
| 4890 } | 4889 } |
| 4891 } | 4890 } |
| 4892 | 4891 |
| 4893 ASSERT(join != NULL); | 4892 ASSERT(join != NULL); |
| 4894 join->SetJoinId(assignment_id); | 4893 join->SetJoinId(assignment_id); |
| 4895 set_current_block(join); | 4894 set_current_block(join); |
| 4896 if (!ast_context()->IsEffect()) { | 4895 if (!ast_context()->IsEffect()) { |
| 4897 ast_context()->ReturnValue(Pop()); | 4896 ast_context()->ReturnValue(Pop()); |
| 4898 } | 4897 } |
| 4899 } | 4898 } |
| 4900 | 4899 |
| 4901 | 4900 |
| 4901 static bool ComputeReceiverTypes(Expression* expr, |
| 4902 HValue* receiver, |
| 4903 SmallMapList** t) { |
| 4904 SmallMapList* types = expr->GetReceiverTypes(); |
| 4905 *t = types; |
| 4906 bool monomorphic = expr->IsMonomorphic(); |
| 4907 if (types != NULL && receiver->HasMonomorphicJSObjectType()) { |
| 4908 Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap(); |
| 4909 types->FilterForPossibleTransitions(root_map); |
| 4910 monomorphic = types->length() == 1; |
| 4911 } |
| 4912 return monomorphic && CanInlinePropertyAccess(*types->first()); |
| 4913 } |
| 4914 |
| 4915 |
| 4916 void HOptimizedGraphBuilder::BuildStore(Expression* expr, |
| 4917 Property* prop, |
| 4918 BailoutId ast_id, |
| 4919 BailoutId return_id, |
| 4920 bool is_uninitialized) { |
| 4921 HValue* value = environment()->ExpressionStackAt(0); |
| 4922 |
| 4923 if (!prop->key()->IsPropertyName()) { |
| 4924 // Keyed store. |
| 4925 HValue* key = environment()->ExpressionStackAt(1); |
| 4926 HValue* object = environment()->ExpressionStackAt(2); |
| 4927 bool has_side_effects = false; |
| 4928 HandleKeyedElementAccess(object, key, value, expr, return_id, |
| 4929 expr->position(), |
| 4930 true, // is_store |
| 4931 &has_side_effects); |
| 4932 Drop(3); |
| 4933 Push(value); |
| 4934 Add<HSimulate>(return_id, REMOVABLE_SIMULATE); |
| 4935 return ast_context()->ReturnValue(Pop()); |
| 4936 } |
| 4937 |
| 4938 // Named store. |
| 4939 HValue* object = environment()->ExpressionStackAt(1); |
| 4940 |
| 4941 if (is_uninitialized) { |
| 4942 Add<HDeoptimize>("Insufficient type feedback for property assignment", |
| 4943 Deoptimizer::SOFT); |
| 4944 } |
| 4945 |
| 4946 Literal* key = prop->key()->AsLiteral(); |
| 4947 Handle<String> name = Handle<String>::cast(key->value()); |
| 4948 ASSERT(!name.is_null()); |
| 4949 |
| 4950 HInstruction* instr = NULL; |
| 4951 |
| 4952 SmallMapList* types; |
| 4953 bool monomorphic = ComputeReceiverTypes(expr, object, &types); |
| 4954 |
| 4955 if (monomorphic) { |
| 4956 Handle<Map> map = types->first(); |
| 4957 Handle<JSFunction> setter; |
| 4958 Handle<JSObject> holder; |
| 4959 if (LookupSetter(map, name, &setter, &holder)) { |
| 4960 AddCheckConstantFunction(holder, object, map); |
| 4961 if (FLAG_inline_accessors && |
| 4962 TryInlineSetter(setter, ast_id, return_id, value)) { |
| 4963 return; |
| 4964 } |
| 4965 Drop(2); |
| 4966 Add<HPushArgument>(object); |
| 4967 Add<HPushArgument>(value); |
| 4968 instr = new(zone()) HCallConstantFunction(setter, 2); |
| 4969 } else { |
| 4970 Drop(2); |
| 4971 CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object, |
| 4972 name, |
| 4973 value, |
| 4974 map)); |
| 4975 } |
| 4976 } else if (types != NULL && types->length() > 1) { |
| 4977 Drop(2); |
| 4978 return HandlePolymorphicStoreNamedField( |
| 4979 expr->position(), ast_id, object, value, types, name); |
| 4980 } else { |
| 4981 Drop(2); |
| 4982 instr = BuildStoreNamedGeneric(object, name, value); |
| 4983 } |
| 4984 |
| 4985 if (!ast_context()->IsEffect()) Push(value); |
| 4986 instr->set_position(expr->position()); |
| 4987 AddInstruction(instr); |
| 4988 if (instr->HasObservableSideEffects()) { |
| 4989 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
| 4990 } |
| 4991 if (!ast_context()->IsEffect()) Drop(1); |
| 4992 return ast_context()->ReturnValue(value); |
| 4993 } |
| 4994 |
| 4995 |
| 4902 void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) { | 4996 void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) { |
| 4903 Property* prop = expr->target()->AsProperty(); | 4997 Property* prop = expr->target()->AsProperty(); |
| 4904 ASSERT(prop != NULL); | 4998 ASSERT(prop != NULL); |
| 4905 CHECK_ALIVE(VisitForValue(prop->obj())); | 4999 CHECK_ALIVE(VisitForValue(prop->obj())); |
| 4906 | 5000 if (!prop->key()->IsPropertyName()) { |
| 4907 if (prop->key()->IsPropertyName()) { | |
| 4908 // Named store. | |
| 4909 CHECK_ALIVE(VisitForValue(expr->value())); | |
| 4910 HValue* value = environment()->ExpressionStackAt(0); | |
| 4911 HValue* object = environment()->ExpressionStackAt(1); | |
| 4912 | |
| 4913 if (expr->IsUninitialized()) { | |
| 4914 Add<HDeoptimize>("Insufficient type feedback for property assignment", | |
| 4915 Deoptimizer::SOFT); | |
| 4916 } | |
| 4917 return BuildStoreNamed(expr, expr->id(), expr->position(), | |
| 4918 expr->AssignmentId(), prop, object, value, value); | |
| 4919 } else { | |
| 4920 // Keyed store. | |
| 4921 CHECK_ALIVE(VisitForValue(prop->key())); | 5001 CHECK_ALIVE(VisitForValue(prop->key())); |
| 4922 CHECK_ALIVE(VisitForValue(expr->value())); | |
| 4923 HValue* value = environment()->ExpressionStackAt(0); | |
| 4924 HValue* key = environment()->ExpressionStackAt(1); | |
| 4925 HValue* object = environment()->ExpressionStackAt(2); | |
| 4926 bool has_side_effects = false; | |
| 4927 HandleKeyedElementAccess(object, key, value, expr, expr->AssignmentId(), | |
| 4928 expr->position(), | |
| 4929 true, // is_store | |
| 4930 &has_side_effects); | |
| 4931 Drop(3); | |
| 4932 Push(value); | |
| 4933 Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); | |
| 4934 return ast_context()->ReturnValue(Pop()); | |
| 4935 } | 5002 } |
| 5003 CHECK_ALIVE(VisitForValue(expr->value())); |
| 5004 BuildStore(expr, prop, expr->id(), |
| 5005 expr->AssignmentId(), expr->IsUninitialized()); |
| 4936 } | 5006 } |
| 4937 | 5007 |
| 4938 | 5008 |
| 4939 // Because not every expression has a position and there is not common | 5009 // Because not every expression has a position and there is not common |
| 4940 // superclass of Assignment and CountOperation, we cannot just pass the | 5010 // superclass of Assignment and CountOperation, we cannot just pass the |
| 4941 // owning expression instead of position and ast_id separately. | 5011 // owning expression instead of position and ast_id separately. |
| 4942 void HOptimizedGraphBuilder::HandleGlobalVariableAssignment( | 5012 void HOptimizedGraphBuilder::HandleGlobalVariableAssignment( |
| 4943 Variable* var, | 5013 Variable* var, |
| 4944 HValue* value, | 5014 HValue* value, |
| 4945 int position, | 5015 int position, |
| (...skipping 28 matching lines...) Expand all Loading... |
| 4974 HStoreGlobalGeneric* instr = | 5044 HStoreGlobalGeneric* instr = |
| 4975 Add<HStoreGlobalGeneric>(global_object, var->name(), | 5045 Add<HStoreGlobalGeneric>(global_object, var->name(), |
| 4976 value, function_strict_mode_flag()); | 5046 value, function_strict_mode_flag()); |
| 4977 instr->set_position(position); | 5047 instr->set_position(position); |
| 4978 ASSERT(instr->HasObservableSideEffects()); | 5048 ASSERT(instr->HasObservableSideEffects()); |
| 4979 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); | 5049 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
| 4980 } | 5050 } |
| 4981 } | 5051 } |
| 4982 | 5052 |
| 4983 | 5053 |
| 4984 void HOptimizedGraphBuilder::BuildStoreNamed(Expression* expr, | |
| 4985 BailoutId id, | |
| 4986 int position, | |
| 4987 BailoutId assignment_id, | |
| 4988 Property* prop, | |
| 4989 HValue* object, | |
| 4990 HValue* store_value, | |
| 4991 HValue* result_value) { | |
| 4992 Literal* key = prop->key()->AsLiteral(); | |
| 4993 Handle<String> name = Handle<String>::cast(key->value()); | |
| 4994 ASSERT(!name.is_null()); | |
| 4995 | |
| 4996 HInstruction* instr = NULL; | |
| 4997 SmallMapList* types = expr->GetReceiverTypes(); | |
| 4998 bool monomorphic = expr->IsMonomorphic(); | |
| 4999 Handle<Map> map; | |
| 5000 if (monomorphic) { | |
| 5001 map = types->first(); | |
| 5002 if (map->is_dictionary_map()) monomorphic = false; | |
| 5003 } | |
| 5004 if (monomorphic) { | |
| 5005 Handle<JSFunction> setter; | |
| 5006 Handle<JSObject> holder; | |
| 5007 if (LookupSetter(map, name, &setter, &holder)) { | |
| 5008 AddCheckConstantFunction(holder, object, map); | |
| 5009 // Don't try to inline if the result_value is different from the | |
| 5010 // store_value. That case isn't handled yet by the inlining. | |
| 5011 if (result_value == store_value && | |
| 5012 FLAG_inline_accessors && | |
| 5013 TryInlineSetter(setter, id, assignment_id, store_value)) { | |
| 5014 return; | |
| 5015 } | |
| 5016 Drop(2); | |
| 5017 Add<HPushArgument>(object); | |
| 5018 Add<HPushArgument>(store_value); | |
| 5019 instr = new(zone()) HCallConstantFunction(setter, 2); | |
| 5020 } else { | |
| 5021 Drop(2); | |
| 5022 CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object, | |
| 5023 name, | |
| 5024 store_value, | |
| 5025 map)); | |
| 5026 } | |
| 5027 } else if (types != NULL && types->length() > 1) { | |
| 5028 Drop(2); | |
| 5029 return HandlePolymorphicStoreNamedField( | |
| 5030 position, id, object, | |
| 5031 store_value, result_value, types, name); | |
| 5032 } else { | |
| 5033 Drop(2); | |
| 5034 instr = BuildStoreNamedGeneric(object, name, store_value); | |
| 5035 } | |
| 5036 | |
| 5037 if (!ast_context()->IsEffect()) Push(result_value); | |
| 5038 instr->set_position(position); | |
| 5039 AddInstruction(instr); | |
| 5040 if (instr->HasObservableSideEffects()) { | |
| 5041 Add<HSimulate>(id, REMOVABLE_SIMULATE); | |
| 5042 } | |
| 5043 if (!ast_context()->IsEffect()) Drop(1); | |
| 5044 return ast_context()->ReturnValue(result_value); | |
| 5045 } | |
| 5046 | |
| 5047 | |
| 5048 void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { | 5054 void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
| 5049 Expression* target = expr->target(); | 5055 Expression* target = expr->target(); |
| 5050 VariableProxy* proxy = target->AsVariableProxy(); | 5056 VariableProxy* proxy = target->AsVariableProxy(); |
| 5051 Property* prop = target->AsProperty(); | 5057 Property* prop = target->AsProperty(); |
| 5052 ASSERT(proxy == NULL || prop == NULL); | 5058 ASSERT(proxy == NULL || prop == NULL); |
| 5053 | 5059 |
| 5054 // We have a second position recorded in the FullCodeGenerator to have | 5060 // We have a second position recorded in the FullCodeGenerator to have |
| 5055 // type feedback for the binary operation. | 5061 // type feedback for the binary operation. |
| 5056 BinaryOperation* operation = expr->binary_operation(); | 5062 BinaryOperation* operation = expr->binary_operation(); |
| 5057 | 5063 |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5119 } | 5125 } |
| 5120 break; | 5126 break; |
| 5121 } | 5127 } |
| 5122 | 5128 |
| 5123 case Variable::LOOKUP: | 5129 case Variable::LOOKUP: |
| 5124 return Bailout(kCompoundAssignmentToLookupSlot); | 5130 return Bailout(kCompoundAssignmentToLookupSlot); |
| 5125 } | 5131 } |
| 5126 return ast_context()->ReturnValue(Pop()); | 5132 return ast_context()->ReturnValue(Pop()); |
| 5127 | 5133 |
| 5128 } else if (prop != NULL) { | 5134 } else if (prop != NULL) { |
| 5129 if (prop->key()->IsPropertyName()) { | 5135 CHECK_ALIVE(VisitForValue(prop->obj())); |
| 5130 // Named property. | 5136 HValue* object = Top(); |
| 5131 CHECK_ALIVE(VisitForValue(prop->obj())); | 5137 HValue* key = NULL; |
| 5132 HValue* object = Top(); | 5138 if ((!prop->IsStringLength() && |
| 5133 | 5139 !prop->IsFunctionPrototype() && |
| 5134 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 5140 !prop->key()->IsPropertyName()) || |
| 5135 Handle<Map> map; | 5141 prop->IsStringAccess()) { |
| 5136 HInstruction* load = NULL; | |
| 5137 SmallMapList* types = prop->GetReceiverTypes(); | |
| 5138 bool monomorphic = prop->IsMonomorphic(); | |
| 5139 if (monomorphic) { | |
| 5140 map = types->first(); | |
| 5141 // We can't generate code for a monomorphic dict mode load so | |
| 5142 // just pretend it is not monomorphic. | |
| 5143 if (map->is_dictionary_map()) monomorphic = false; | |
| 5144 } | |
| 5145 if (monomorphic) { | |
| 5146 Handle<JSFunction> getter; | |
| 5147 Handle<JSObject> holder; | |
| 5148 if (LookupGetter(map, name, &getter, &holder)) { | |
| 5149 load = BuildCallGetter(object, map, getter, holder); | |
| 5150 } else { | |
| 5151 load = BuildLoadNamedMonomorphic(object, name, prop, map); | |
| 5152 } | |
| 5153 } else if (types != NULL && types->length() > 1) { | |
| 5154 load = TryLoadPolymorphicAsMonomorphic(prop, object, types, name); | |
| 5155 } | |
| 5156 if (load == NULL) load = BuildLoadNamedGeneric(object, name, prop); | |
| 5157 PushAndAdd(load); | |
| 5158 if (load->HasObservableSideEffects()) { | |
| 5159 Add<HSimulate>(prop->LoadId(), REMOVABLE_SIMULATE); | |
| 5160 } | |
| 5161 | |
| 5162 CHECK_ALIVE(VisitForValue(expr->value())); | |
| 5163 HValue* right = Pop(); | |
| 5164 HValue* left = Pop(); | |
| 5165 | |
| 5166 HInstruction* instr = BuildBinaryOperation(operation, left, right); | |
| 5167 PushAndAdd(instr); | |
| 5168 if (instr->HasObservableSideEffects()) { | |
| 5169 Add<HSimulate>(operation->id(), REMOVABLE_SIMULATE); | |
| 5170 } | |
| 5171 | |
| 5172 return BuildStoreNamed(expr, expr->id(), expr->position(), | |
| 5173 expr->AssignmentId(), prop, object, instr, instr); | |
| 5174 } else { | |
| 5175 // Keyed property. | |
| 5176 CHECK_ALIVE(VisitForValue(prop->obj())); | |
| 5177 CHECK_ALIVE(VisitForValue(prop->key())); | 5142 CHECK_ALIVE(VisitForValue(prop->key())); |
| 5178 HValue* obj = environment()->ExpressionStackAt(1); | 5143 key = Top(); |
| 5179 HValue* key = environment()->ExpressionStackAt(0); | |
| 5180 | |
| 5181 bool has_side_effects = false; | |
| 5182 HValue* load = HandleKeyedElementAccess( | |
| 5183 obj, key, NULL, prop, prop->LoadId(), RelocInfo::kNoPosition, | |
| 5184 false, // is_store | |
| 5185 &has_side_effects); | |
| 5186 Push(load); | |
| 5187 if (has_side_effects) Add<HSimulate>(prop->LoadId(), REMOVABLE_SIMULATE); | |
| 5188 | |
| 5189 CHECK_ALIVE(VisitForValue(expr->value())); | |
| 5190 HValue* right = Pop(); | |
| 5191 HValue* left = Pop(); | |
| 5192 | |
| 5193 HInstruction* instr = BuildBinaryOperation(operation, left, right); | |
| 5194 PushAndAdd(instr); | |
| 5195 if (instr->HasObservableSideEffects()) { | |
| 5196 Add<HSimulate>(operation->id(), REMOVABLE_SIMULATE); | |
| 5197 } | |
| 5198 | |
| 5199 HandleKeyedElementAccess(obj, key, instr, expr, expr->AssignmentId(), | |
| 5200 RelocInfo::kNoPosition, | |
| 5201 true, // is_store | |
| 5202 &has_side_effects); | |
| 5203 | |
| 5204 // Drop the simulated receiver, key, and value. Return the value. | |
| 5205 Drop(3); | |
| 5206 Push(instr); | |
| 5207 ASSERT(has_side_effects); // Stores always have side effects. | |
| 5208 Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); | |
| 5209 return ast_context()->ReturnValue(Pop()); | |
| 5210 } | 5144 } |
| 5211 | 5145 |
| 5146 CHECK_ALIVE(PushLoad(prop, object, key, expr->position())); |
| 5147 |
| 5148 CHECK_ALIVE(VisitForValue(expr->value())); |
| 5149 HValue* right = Pop(); |
| 5150 HValue* left = Pop(); |
| 5151 |
| 5152 HInstruction* instr = BuildBinaryOperation(operation, left, right); |
| 5153 PushAndAdd(instr); |
| 5154 if (instr->HasObservableSideEffects()) { |
| 5155 Add<HSimulate>(operation->id(), REMOVABLE_SIMULATE); |
| 5156 } |
| 5157 BuildStore(expr, prop, expr->id(), |
| 5158 expr->AssignmentId(), expr->IsUninitialized()); |
| 5212 } else { | 5159 } else { |
| 5213 return Bailout(kInvalidLhsInCompoundAssignment); | 5160 return Bailout(kInvalidLhsInCompoundAssignment); |
| 5214 } | 5161 } |
| 5215 } | 5162 } |
| 5216 | 5163 |
| 5217 | 5164 |
| 5218 void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) { | 5165 void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) { |
| 5219 ASSERT(!HasStackOverflow()); | 5166 ASSERT(!HasStackOverflow()); |
| 5220 ASSERT(current_block() != NULL); | 5167 ASSERT(current_block() != NULL); |
| 5221 ASSERT(current_block()->HasPredecessor()); | 5168 ASSERT(current_block()->HasPredecessor()); |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5389 } | 5336 } |
| 5390 return BuildLoadNamedField(checked_string, HObjectAccess::ForStringLength()); | 5337 return BuildLoadNamedField(checked_string, HObjectAccess::ForStringLength()); |
| 5391 } | 5338 } |
| 5392 | 5339 |
| 5393 | 5340 |
| 5394 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedGeneric( | 5341 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedGeneric( |
| 5395 HValue* object, | 5342 HValue* object, |
| 5396 Handle<String> name, | 5343 Handle<String> name, |
| 5397 Property* expr) { | 5344 Property* expr) { |
| 5398 if (expr->IsUninitialized()) { | 5345 if (expr->IsUninitialized()) { |
| 5399 Add<HDeoptimize>("Insufficient feedback for generic named load", | 5346 Add<HDeoptimize>("Insufficient type feedback for generic named load", |
| 5400 Deoptimizer::SOFT); | 5347 Deoptimizer::SOFT); |
| 5401 } | 5348 } |
| 5402 HValue* context = environment()->context(); | 5349 HValue* context = environment()->context(); |
| 5403 return new(zone()) HLoadNamedGeneric(context, object, name); | 5350 return new(zone()) HLoadNamedGeneric(context, object, name); |
| 5404 } | 5351 } |
| 5405 | 5352 |
| 5406 | 5353 |
| 5407 HInstruction* HOptimizedGraphBuilder::BuildCallGetter( | 5354 HInstruction* HOptimizedGraphBuilder::BuildCallGetter( |
| 5408 HValue* object, | 5355 HValue* object, |
| 5409 Handle<Map> map, | 5356 Handle<Map> map, |
| 5410 Handle<JSFunction> getter, | 5357 Handle<JSFunction> getter, |
| 5411 Handle<JSObject> holder) { | 5358 Handle<JSObject> holder) { |
| 5412 AddCheckConstantFunction(holder, object, map); | 5359 AddCheckConstantFunction(holder, object, map); |
| 5413 Add<HPushArgument>(object); | 5360 Add<HPushArgument>(object); |
| 5414 return new(zone()) HCallConstantFunction(getter, 1); | 5361 return new(zone()) HCallConstantFunction(getter, 1); |
| 5415 } | 5362 } |
| 5416 | 5363 |
| 5417 | 5364 |
| 5418 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic( | 5365 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic( |
| 5419 HValue* object, | 5366 HValue* object, |
| 5420 Handle<String> name, | 5367 Handle<String> name, |
| 5421 Property* expr, | |
| 5422 Handle<Map> map) { | 5368 Handle<Map> map) { |
| 5423 // Handle a load from a known field. | 5369 // Handle a load from a known field. |
| 5424 ASSERT(!map->is_dictionary_map()); | 5370 ASSERT(!map->is_dictionary_map()); |
| 5425 | 5371 |
| 5426 // Handle access to various length properties | 5372 // Handle access to various length properties |
| 5427 if (name->Equals(isolate()->heap()->length_string())) { | 5373 if (name->Equals(isolate()->heap()->length_string())) { |
| 5428 if (map->instance_type() == JS_ARRAY_TYPE) { | 5374 if (map->instance_type() == JS_ARRAY_TYPE) { |
| 5429 HCheckMaps* checked_object = AddCheckMap(object, map); | 5375 HCheckMaps* checked_object = AddCheckMap(object, map); |
| 5430 return New<HLoadNamedField>( | 5376 return New<HLoadNamedField>( |
| 5431 checked_object, HObjectAccess::ForArrayLength(map->elements_kind())); | 5377 checked_object, HObjectAccess::ForArrayLength(map->elements_kind())); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5464 Handle<JSObject> prototype(JSObject::cast(map->prototype())); | 5410 Handle<JSObject> prototype(JSObject::cast(map->prototype())); |
| 5465 Handle<JSObject> holder(lookup.holder()); | 5411 Handle<JSObject> holder(lookup.holder()); |
| 5466 Handle<Map> holder_map(holder->map()); | 5412 Handle<Map> holder_map(holder->map()); |
| 5467 AddCheckMap(object, map); | 5413 AddCheckMap(object, map); |
| 5468 BuildCheckPrototypeMaps(prototype, holder); | 5414 BuildCheckPrototypeMaps(prototype, holder); |
| 5469 Handle<Object> constant(lookup.GetConstantFromMap(*holder_map), isolate()); | 5415 Handle<Object> constant(lookup.GetConstantFromMap(*holder_map), isolate()); |
| 5470 return New<HConstant>(constant); | 5416 return New<HConstant>(constant); |
| 5471 } | 5417 } |
| 5472 | 5418 |
| 5473 // No luck, do a generic load. | 5419 // No luck, do a generic load. |
| 5474 return BuildLoadNamedGeneric(object, name, expr); | 5420 HValue* context = environment()->context(); |
| 5421 return new(zone()) HLoadNamedGeneric(context, object, name); |
| 5475 } | 5422 } |
| 5476 | 5423 |
| 5477 | 5424 |
| 5478 HInstruction* HOptimizedGraphBuilder::BuildLoadKeyedGeneric(HValue* object, | 5425 HInstruction* HOptimizedGraphBuilder::BuildLoadKeyedGeneric(HValue* object, |
| 5479 HValue* key) { | 5426 HValue* key) { |
| 5480 HValue* context = environment()->context(); | 5427 HValue* context = environment()->context(); |
| 5481 return new(zone()) HLoadKeyedGeneric(context, object, key); | 5428 return new(zone()) HLoadKeyedGeneric(context, object, key); |
| 5482 } | 5429 } |
| 5483 | 5430 |
| 5484 | 5431 |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5703 if (!is_store) { | 5650 if (!is_store) { |
| 5704 Push(access); | 5651 Push(access); |
| 5705 } | 5652 } |
| 5706 NoObservableSideEffectsScope scope(this); | 5653 NoObservableSideEffectsScope scope(this); |
| 5707 current_block()->GotoNoSimulate(join); | 5654 current_block()->GotoNoSimulate(join); |
| 5708 set_current_block(other_map); | 5655 set_current_block(other_map); |
| 5709 } | 5656 } |
| 5710 | 5657 |
| 5711 // Deopt if none of the cases matched. | 5658 // Deopt if none of the cases matched. |
| 5712 NoObservableSideEffectsScope scope(this); | 5659 NoObservableSideEffectsScope scope(this); |
| 5713 FinishExitWithHardDeoptimization("Unknown type in polymorphic element access", | 5660 FinishExitWithHardDeoptimization("Unknown map in polymorphic element access", |
| 5714 join); | 5661 join); |
| 5715 set_current_block(join); | 5662 set_current_block(join); |
| 5716 return is_store ? NULL : Pop(); | 5663 return is_store ? NULL : Pop(); |
| 5717 } | 5664 } |
| 5718 | 5665 |
| 5719 | 5666 |
| 5720 HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( | 5667 HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( |
| 5721 HValue* obj, | 5668 HValue* obj, |
| 5722 HValue* key, | 5669 HValue* key, |
| 5723 HValue* val, | 5670 HValue* val, |
| 5724 Expression* expr, | 5671 Expression* expr, |
| 5725 BailoutId ast_id, | 5672 BailoutId ast_id, |
| 5726 int position, | 5673 int position, |
| 5727 bool is_store, | 5674 bool is_store, |
| 5728 bool* has_side_effects) { | 5675 bool* has_side_effects) { |
| 5729 ASSERT(!expr->IsPropertyName()); | 5676 ASSERT(!expr->IsPropertyName()); |
| 5730 HInstruction* instr = NULL; | 5677 HInstruction* instr = NULL; |
| 5731 if (expr->IsMonomorphic()) { | 5678 |
| 5732 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 5679 SmallMapList* types; |
| 5680 bool monomorphic = ComputeReceiverTypes(expr, obj, &types); |
| 5681 |
| 5682 if (monomorphic) { |
| 5683 Handle<Map> map = types->first(); |
| 5733 if (map->has_slow_elements_kind()) { | 5684 if (map->has_slow_elements_kind()) { |
| 5734 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) | 5685 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) |
| 5735 : BuildLoadKeyedGeneric(obj, key); | 5686 : BuildLoadKeyedGeneric(obj, key); |
| 5736 AddInstruction(instr); | 5687 AddInstruction(instr); |
| 5737 } else { | 5688 } else { |
| 5738 BuildCheckHeapObject(obj); | 5689 BuildCheckHeapObject(obj); |
| 5739 instr = BuildMonomorphicElementAccess( | 5690 instr = BuildMonomorphicElementAccess( |
| 5740 obj, key, val, NULL, map, is_store, expr->GetStoreMode()); | 5691 obj, key, val, NULL, map, is_store, expr->GetStoreMode()); |
| 5741 } | 5692 } |
| 5742 } else if (expr->GetReceiverTypes() != NULL && | 5693 } else if (expr->GetReceiverTypes() != NULL && |
| 5743 !expr->GetReceiverTypes()->is_empty()) { | 5694 !expr->GetReceiverTypes()->is_empty()) { |
| 5744 return HandlePolymorphicElementAccess( | 5695 return HandlePolymorphicElementAccess( |
| 5745 obj, key, val, expr, ast_id, position, is_store, | 5696 obj, key, val, expr, ast_id, position, is_store, |
| 5746 expr->GetStoreMode(), has_side_effects); | 5697 expr->GetStoreMode(), has_side_effects); |
| 5747 } else { | 5698 } else { |
| 5748 if (is_store) { | 5699 if (is_store) { |
| 5749 if (expr->IsAssignment() && expr->AsAssignment()->IsUninitialized()) { | 5700 if (expr->IsAssignment() && expr->AsAssignment()->IsUninitialized()) { |
| 5750 Add<HDeoptimize>("Insufficient feedback for keyed store", | 5701 Add<HDeoptimize>("Insufficient type feedback for keyed store", |
| 5751 Deoptimizer::SOFT); | 5702 Deoptimizer::SOFT); |
| 5752 } | 5703 } |
| 5753 instr = BuildStoreKeyedGeneric(obj, key, val); | 5704 instr = BuildStoreKeyedGeneric(obj, key, val); |
| 5754 } else { | 5705 } else { |
| 5755 if (expr->AsProperty()->IsUninitialized()) { | 5706 if (expr->AsProperty()->IsUninitialized()) { |
| 5756 Add<HDeoptimize>("Insufficient feedback for keyed load", | 5707 Add<HDeoptimize>("Insufficient type feedback for keyed load", |
| 5757 Deoptimizer::SOFT); | 5708 Deoptimizer::SOFT); |
| 5758 } | 5709 } |
| 5759 instr = BuildLoadKeyedGeneric(obj, key); | 5710 instr = BuildLoadKeyedGeneric(obj, key); |
| 5760 } | 5711 } |
| 5761 AddInstruction(instr); | 5712 AddInstruction(instr); |
| 5762 } | 5713 } |
| 5763 if (position != RelocInfo::kNoPosition) instr->set_position(position); | 5714 if (position != RelocInfo::kNoPosition) instr->set_position(position); |
| 5764 *has_side_effects = instr->HasObservableSideEffects(); | 5715 *has_side_effects = instr->HasObservableSideEffects(); |
| 5765 return instr; | 5716 return instr; |
| 5766 } | 5717 } |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5825 HInstruction* elements = Add<HArgumentsElements>(false); | 5776 HInstruction* elements = Add<HArgumentsElements>(false); |
| 5826 result = New<HArgumentsLength>(elements); | 5777 result = New<HArgumentsLength>(elements); |
| 5827 } else { | 5778 } else { |
| 5828 // Number of arguments without receiver. | 5779 // Number of arguments without receiver. |
| 5829 int argument_count = environment()-> | 5780 int argument_count = environment()-> |
| 5830 arguments_environment()->parameter_count() - 1; | 5781 arguments_environment()->parameter_count() - 1; |
| 5831 result = New<HConstant>(argument_count); | 5782 result = New<HConstant>(argument_count); |
| 5832 } | 5783 } |
| 5833 } else { | 5784 } else { |
| 5834 Push(graph()->GetArgumentsObject()); | 5785 Push(graph()->GetArgumentsObject()); |
| 5835 VisitForValue(expr->key()); | 5786 CHECK_ALIVE_OR_RETURN(VisitForValue(expr->key()), true); |
| 5836 if (HasStackOverflow() || current_block() == NULL) return true; | |
| 5837 HValue* key = Pop(); | 5787 HValue* key = Pop(); |
| 5838 Drop(1); // Arguments object. | 5788 Drop(1); // Arguments object. |
| 5839 if (function_state()->outer() == NULL) { | 5789 if (function_state()->outer() == NULL) { |
| 5840 HInstruction* elements = Add<HArgumentsElements>(false); | 5790 HInstruction* elements = Add<HArgumentsElements>(false); |
| 5841 HInstruction* length = Add<HArgumentsLength>(elements); | 5791 HInstruction* length = Add<HArgumentsLength>(elements); |
| 5842 HInstruction* checked_key = Add<HBoundsCheck>(key, length); | 5792 HInstruction* checked_key = Add<HBoundsCheck>(key, length); |
| 5843 result = new(zone()) HAccessArgumentsAt(elements, length, checked_key); | 5793 result = new(zone()) HAccessArgumentsAt(elements, length, checked_key); |
| 5844 } else { | 5794 } else { |
| 5845 EnsureArgumentsArePushedForAccess(); | 5795 EnsureArgumentsArePushedForAccess(); |
| 5846 | 5796 |
| 5847 // Number of arguments without receiver. | 5797 // Number of arguments without receiver. |
| 5848 HInstruction* elements = function_state()->arguments_elements(); | 5798 HInstruction* elements = function_state()->arguments_elements(); |
| 5849 int argument_count = environment()-> | 5799 int argument_count = environment()-> |
| 5850 arguments_environment()->parameter_count() - 1; | 5800 arguments_environment()->parameter_count() - 1; |
| 5851 HInstruction* length = Add<HConstant>(argument_count); | 5801 HInstruction* length = Add<HConstant>(argument_count); |
| 5852 HInstruction* checked_key = Add<HBoundsCheck>(key, length); | 5802 HInstruction* checked_key = Add<HBoundsCheck>(key, length); |
| 5853 result = new(zone()) HAccessArgumentsAt(elements, length, checked_key); | 5803 result = new(zone()) HAccessArgumentsAt(elements, length, checked_key); |
| 5854 } | 5804 } |
| 5855 } | 5805 } |
| 5856 ast_context()->ReturnInstruction(result, expr->id()); | 5806 ast_context()->ReturnInstruction(result, expr->id()); |
| 5857 return true; | 5807 return true; |
| 5858 } | 5808 } |
| 5859 | 5809 |
| 5860 | 5810 |
| 5861 void HOptimizedGraphBuilder::VisitProperty(Property* expr) { | 5811 void HOptimizedGraphBuilder::PushLoad(Property* expr, |
| 5862 ASSERT(!HasStackOverflow()); | 5812 HValue* object, |
| 5863 ASSERT(current_block() != NULL); | 5813 HValue* key, |
| 5864 ASSERT(current_block()->HasPredecessor()); | 5814 int position) { |
| 5815 ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED); |
| 5816 Push(object); |
| 5817 if (key != NULL) Push(key); |
| 5818 BuildLoad(expr, position, expr->LoadId()); |
| 5819 } |
| 5865 | 5820 |
| 5866 if (TryArgumentsAccess(expr)) return; | |
| 5867 | 5821 |
| 5868 CHECK_ALIVE(VisitForValue(expr->obj())); | 5822 void HOptimizedGraphBuilder::BuildLoad(Property* expr, |
| 5869 | 5823 int position, |
| 5824 BailoutId ast_id) { |
| 5870 HInstruction* instr = NULL; | 5825 HInstruction* instr = NULL; |
| 5871 if (expr->IsStringLength()) { | 5826 if (expr->IsStringLength()) { |
| 5872 HValue* string = Pop(); | 5827 HValue* string = Pop(); |
| 5873 BuildCheckHeapObject(string); | 5828 BuildCheckHeapObject(string); |
| 5874 HInstruction* checkstring = | 5829 HInstruction* checkstring = |
| 5875 AddInstruction(HCheckInstanceType::NewIsString(string, zone())); | 5830 AddInstruction(HCheckInstanceType::NewIsString(string, zone())); |
| 5876 instr = BuildLoadStringLength(string, checkstring); | 5831 instr = BuildLoadStringLength(string, checkstring); |
| 5877 } else if (expr->IsStringAccess()) { | 5832 } else if (expr->IsStringAccess()) { |
| 5878 CHECK_ALIVE(VisitForValue(expr->key())); | |
| 5879 HValue* index = Pop(); | 5833 HValue* index = Pop(); |
| 5880 HValue* string = Pop(); | 5834 HValue* string = Pop(); |
| 5881 HValue* context = environment()->context(); | 5835 HValue* context = environment()->context(); |
| 5882 HInstruction* char_code = | 5836 HInstruction* char_code = |
| 5883 BuildStringCharCodeAt(string, index); | 5837 BuildStringCharCodeAt(string, index); |
| 5884 AddInstruction(char_code); | 5838 AddInstruction(char_code); |
| 5885 instr = HStringCharFromCode::New(zone(), context, char_code); | 5839 instr = HStringCharFromCode::New(zone(), context, char_code); |
| 5886 | 5840 |
| 5887 } else if (expr->IsFunctionPrototype()) { | 5841 } else if (expr->IsFunctionPrototype()) { |
| 5888 HValue* function = Pop(); | 5842 HValue* function = Pop(); |
| 5889 BuildCheckHeapObject(function); | 5843 BuildCheckHeapObject(function); |
| 5890 instr = new(zone()) HLoadFunctionPrototype(function); | 5844 instr = new(zone()) HLoadFunctionPrototype(function); |
| 5891 | 5845 |
| 5892 } else if (expr->key()->IsPropertyName()) { | 5846 } else if (expr->key()->IsPropertyName()) { |
| 5893 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); | 5847 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); |
| 5894 SmallMapList* types = expr->GetReceiverTypes(); | |
| 5895 HValue* object = Top(); | 5848 HValue* object = Top(); |
| 5896 | 5849 |
| 5897 Handle<Map> map; | 5850 SmallMapList* types; |
| 5898 bool monomorphic = false; | 5851 bool monomorphic = ComputeReceiverTypes(expr, object, &types); |
| 5899 if (expr->IsMonomorphic()) { | 5852 |
| 5900 map = types->first(); | |
| 5901 monomorphic = !map->is_dictionary_map(); | |
| 5902 } else if (object->HasMonomorphicJSObjectType()) { | |
| 5903 map = object->GetMonomorphicJSObjectMap(); | |
| 5904 monomorphic = !map->is_dictionary_map(); | |
| 5905 } | |
| 5906 if (monomorphic) { | 5853 if (monomorphic) { |
| 5854 Handle<Map> map = types->first(); |
| 5907 Handle<JSFunction> getter; | 5855 Handle<JSFunction> getter; |
| 5908 Handle<JSObject> holder; | 5856 Handle<JSObject> holder; |
| 5909 if (LookupGetter(map, name, &getter, &holder)) { | 5857 if (LookupGetter(map, name, &getter, &holder)) { |
| 5910 AddCheckConstantFunction(holder, Top(), map); | 5858 AddCheckConstantFunction(holder, Top(), map); |
| 5911 if (FLAG_inline_accessors && TryInlineGetter(getter, expr)) return; | 5859 if (FLAG_inline_accessors && |
| 5860 TryInlineGetter(getter, ast_id, expr->LoadId())) { |
| 5861 return; |
| 5862 } |
| 5912 Add<HPushArgument>(Pop()); | 5863 Add<HPushArgument>(Pop()); |
| 5913 instr = new(zone()) HCallConstantFunction(getter, 1); | 5864 instr = new(zone()) HCallConstantFunction(getter, 1); |
| 5914 } else { | 5865 } else { |
| 5915 instr = BuildLoadNamedMonomorphic(Pop(), name, expr, map); | 5866 instr = BuildLoadNamedMonomorphic(Pop(), name, map); |
| 5916 } | 5867 } |
| 5917 } else if (types != NULL && types->length() > 1) { | 5868 } else if (types != NULL && types->length() > 1) { |
| 5918 return HandlePolymorphicLoadNamedField(expr, Pop(), types, name); | 5869 return HandlePolymorphicLoadNamedField( |
| 5870 position, ast_id, Pop(), types, name); |
| 5919 } else { | 5871 } else { |
| 5920 instr = BuildLoadNamedGeneric(Pop(), name, expr); | 5872 instr = BuildLoadNamedGeneric(Pop(), name, expr); |
| 5921 } | 5873 } |
| 5922 | 5874 |
| 5923 } else { | 5875 } else { |
| 5924 CHECK_ALIVE(VisitForValue(expr->key())); | |
| 5925 | |
| 5926 HValue* key = Pop(); | 5876 HValue* key = Pop(); |
| 5927 HValue* obj = Pop(); | 5877 HValue* obj = Pop(); |
| 5928 | 5878 |
| 5929 bool has_side_effects = false; | 5879 bool has_side_effects = false; |
| 5930 HValue* load = HandleKeyedElementAccess( | 5880 HValue* load = HandleKeyedElementAccess( |
| 5931 obj, key, NULL, expr, expr->id(), expr->position(), | 5881 obj, key, NULL, expr, ast_id, position, |
| 5932 false, // is_store | 5882 false, // is_store |
| 5933 &has_side_effects); | 5883 &has_side_effects); |
| 5934 if (has_side_effects) { | 5884 if (has_side_effects) { |
| 5935 if (ast_context()->IsEffect()) { | 5885 if (ast_context()->IsEffect()) { |
| 5936 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); | 5886 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
| 5937 } else { | 5887 } else { |
| 5938 Push(load); | 5888 Push(load); |
| 5939 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); | 5889 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
| 5940 Drop(1); | 5890 Drop(1); |
| 5941 } | 5891 } |
| 5942 } | 5892 } |
| 5943 return ast_context()->ReturnValue(load); | 5893 return ast_context()->ReturnValue(load); |
| 5944 } | 5894 } |
| 5945 instr->set_position(expr->position()); | 5895 instr->set_position(position); |
| 5946 return ast_context()->ReturnInstruction(instr, expr->id()); | 5896 return ast_context()->ReturnInstruction(instr, ast_id); |
| 5947 } | 5897 } |
| 5948 | 5898 |
| 5949 | 5899 |
| 5900 void HOptimizedGraphBuilder::VisitProperty(Property* expr) { |
| 5901 ASSERT(!HasStackOverflow()); |
| 5902 ASSERT(current_block() != NULL); |
| 5903 ASSERT(current_block()->HasPredecessor()); |
| 5904 |
| 5905 if (TryArgumentsAccess(expr)) return; |
| 5906 |
| 5907 CHECK_ALIVE(VisitForValue(expr->obj())); |
| 5908 if ((!expr->IsStringLength() && |
| 5909 !expr->IsFunctionPrototype() && |
| 5910 !expr->key()->IsPropertyName()) || |
| 5911 expr->IsStringAccess()) { |
| 5912 CHECK_ALIVE(VisitForValue(expr->key())); |
| 5913 } |
| 5914 |
| 5915 BuildLoad(expr, expr->position(), expr->id()); |
| 5916 } |
| 5917 |
| 5918 |
| 5950 HInstruction* HGraphBuilder::BuildConstantMapCheck(Handle<JSObject> constant, | 5919 HInstruction* HGraphBuilder::BuildConstantMapCheck(Handle<JSObject> constant, |
| 5951 CompilationInfo* info) { | 5920 CompilationInfo* info) { |
| 5952 HConstant* constant_value = New<HConstant>(constant); | 5921 HConstant* constant_value = New<HConstant>(constant); |
| 5953 | 5922 |
| 5954 if (constant->map()->CanOmitMapChecks()) { | 5923 if (constant->map()->CanOmitMapChecks()) { |
| 5955 constant->map()->AddDependentCompilationInfo( | 5924 constant->map()->AddDependentCompilationInfo( |
| 5956 DependentCode::kPrototypeCheckGroup, info); | 5925 DependentCode::kPrototypeCheckGroup, info); |
| 5957 return constant_value; | 5926 return constant_value; |
| 5958 } | 5927 } |
| 5959 | 5928 |
| (...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6367 FunctionLiteral* function = target_info.function(); | 6336 FunctionLiteral* function = target_info.function(); |
| 6368 | 6337 |
| 6369 // The following conditions must be checked again after re-parsing, because | 6338 // The following conditions must be checked again after re-parsing, because |
| 6370 // earlier the information might not have been complete due to lazy parsing. | 6339 // earlier the information might not have been complete due to lazy parsing. |
| 6371 nodes_added = function->ast_node_count(); | 6340 nodes_added = function->ast_node_count(); |
| 6372 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { | 6341 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { |
| 6373 TraceInline(target, caller, "target AST is too large [late]"); | 6342 TraceInline(target, caller, "target AST is too large [late]"); |
| 6374 return false; | 6343 return false; |
| 6375 } | 6344 } |
| 6376 AstProperties::Flags* flags(function->flags()); | 6345 AstProperties::Flags* flags(function->flags()); |
| 6377 if (flags->Contains(kDontInline) || flags->Contains(kDontOptimize)) { | 6346 if (flags->Contains(kDontInline) || function->dont_optimize()) { |
| 6378 TraceInline(target, caller, "target contains unsupported syntax [late]"); | 6347 TraceInline(target, caller, "target contains unsupported syntax [late]"); |
| 6379 return false; | 6348 return false; |
| 6380 } | 6349 } |
| 6381 | 6350 |
| 6382 // If the function uses the arguments object check that inlining of functions | 6351 // If the function uses the arguments object check that inlining of functions |
| 6383 // with arguments object is enabled and the arguments-variable is | 6352 // with arguments object is enabled and the arguments-variable is |
| 6384 // stack allocated. | 6353 // stack allocated. |
| 6385 if (function->scope()->arguments() != NULL) { | 6354 if (function->scope()->arguments() != NULL) { |
| 6386 if (!FLAG_inline_arguments) { | 6355 if (!FLAG_inline_arguments) { |
| 6387 TraceInline(target, caller, "target uses arguments object"); | 6356 TraceInline(target, caller, "target uses arguments object"); |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6613 expr->target(), | 6582 expr->target(), |
| 6614 expr->arguments()->length(), | 6583 expr->arguments()->length(), |
| 6615 implicit_return_value, | 6584 implicit_return_value, |
| 6616 expr->id(), | 6585 expr->id(), |
| 6617 expr->ReturnId(), | 6586 expr->ReturnId(), |
| 6618 CONSTRUCT_CALL_RETURN); | 6587 CONSTRUCT_CALL_RETURN); |
| 6619 } | 6588 } |
| 6620 | 6589 |
| 6621 | 6590 |
| 6622 bool HOptimizedGraphBuilder::TryInlineGetter(Handle<JSFunction> getter, | 6591 bool HOptimizedGraphBuilder::TryInlineGetter(Handle<JSFunction> getter, |
| 6623 Property* prop) { | 6592 BailoutId ast_id, |
| 6593 BailoutId return_id) { |
| 6624 return TryInline(CALL_AS_METHOD, | 6594 return TryInline(CALL_AS_METHOD, |
| 6625 getter, | 6595 getter, |
| 6626 0, | 6596 0, |
| 6627 NULL, | 6597 NULL, |
| 6628 prop->id(), | 6598 ast_id, |
| 6629 prop->LoadId(), | 6599 return_id, |
| 6630 GETTER_CALL_RETURN); | 6600 GETTER_CALL_RETURN); |
| 6631 } | 6601 } |
| 6632 | 6602 |
| 6633 | 6603 |
| 6634 bool HOptimizedGraphBuilder::TryInlineSetter(Handle<JSFunction> setter, | 6604 bool HOptimizedGraphBuilder::TryInlineSetter(Handle<JSFunction> setter, |
| 6635 BailoutId id, | 6605 BailoutId id, |
| 6636 BailoutId assignment_id, | 6606 BailoutId assignment_id, |
| 6637 HValue* implicit_return_value) { | 6607 HValue* implicit_return_value) { |
| 6638 return TryInline(CALL_AS_METHOD, | 6608 return TryInline(CALL_AS_METHOD, |
| 6639 setter, | 6609 setter, |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6874 | 6844 |
| 6875 ZoneList<Expression*>* args = expr->arguments(); | 6845 ZoneList<Expression*>* args = expr->arguments(); |
| 6876 if (args->length() != 2) return false; | 6846 if (args->length() != 2) return false; |
| 6877 | 6847 |
| 6878 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); | 6848 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); |
| 6879 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; | 6849 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; |
| 6880 HValue* arg_two_value = LookupAndMakeLive(arg_two->var()); | 6850 HValue* arg_two_value = LookupAndMakeLive(arg_two->var()); |
| 6881 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; | 6851 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; |
| 6882 | 6852 |
| 6883 // Found pattern f.apply(receiver, arguments). | 6853 // Found pattern f.apply(receiver, arguments). |
| 6884 VisitForValue(prop->obj()); | 6854 CHECK_ALIVE_OR_RETURN(VisitForValue(prop->obj()), true); |
| 6885 if (HasStackOverflow() || current_block() == NULL) return true; | |
| 6886 HValue* function = Top(); | 6855 HValue* function = Top(); |
| 6887 AddCheckConstantFunction(expr->holder(), function, function_map); | 6856 AddCheckConstantFunction(expr->holder(), function, function_map); |
| 6888 Drop(1); | 6857 Drop(1); |
| 6889 | 6858 |
| 6890 VisitForValue(args->at(0)); | 6859 CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true); |
| 6891 if (HasStackOverflow() || current_block() == NULL) return true; | |
| 6892 HValue* receiver = Pop(); | 6860 HValue* receiver = Pop(); |
| 6893 | 6861 |
| 6894 if (function_state()->outer() == NULL) { | 6862 if (function_state()->outer() == NULL) { |
| 6895 HInstruction* elements = Add<HArgumentsElements>(false); | 6863 HInstruction* elements = Add<HArgumentsElements>(false); |
| 6896 HInstruction* length = Add<HArgumentsLength>(elements); | 6864 HInstruction* length = Add<HArgumentsLength>(elements); |
| 6897 HValue* wrapped_receiver = BuildWrapReceiver(receiver, function); | 6865 HValue* wrapped_receiver = BuildWrapReceiver(receiver, function); |
| 6898 HInstruction* result = | 6866 HInstruction* result = |
| 6899 new(zone()) HApplyArguments(function, | 6867 new(zone()) HApplyArguments(function, |
| 6900 wrapped_receiver, | 6868 wrapped_receiver, |
| 6901 length, | 6869 length, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 6912 const ZoneList<HValue*>* arguments_values = args->arguments_values(); | 6880 const ZoneList<HValue*>* arguments_values = args->arguments_values(); |
| 6913 int arguments_count = arguments_values->length(); | 6881 int arguments_count = arguments_values->length(); |
| 6914 Push(BuildWrapReceiver(receiver, function)); | 6882 Push(BuildWrapReceiver(receiver, function)); |
| 6915 for (int i = 1; i < arguments_count; i++) { | 6883 for (int i = 1; i < arguments_count; i++) { |
| 6916 Push(arguments_values->at(i)); | 6884 Push(arguments_values->at(i)); |
| 6917 } | 6885 } |
| 6918 | 6886 |
| 6919 Handle<JSFunction> known_function; | 6887 Handle<JSFunction> known_function; |
| 6920 if (function->IsConstant()) { | 6888 if (function->IsConstant()) { |
| 6921 HConstant* constant_function = HConstant::cast(function); | 6889 HConstant* constant_function = HConstant::cast(function); |
| 6922 known_function = Handle<JSFunction>::cast(constant_function->handle()); | 6890 known_function = Handle<JSFunction>::cast( |
| 6891 constant_function->handle(isolate())); |
| 6923 int args_count = arguments_count - 1; // Excluding receiver. | 6892 int args_count = arguments_count - 1; // Excluding receiver. |
| 6924 if (TryInlineApply(known_function, expr, args_count)) return true; | 6893 if (TryInlineApply(known_function, expr, args_count)) return true; |
| 6925 } | 6894 } |
| 6926 | 6895 |
| 6927 Drop(arguments_count - 1); | 6896 Drop(arguments_count - 1); |
| 6928 PushAndAdd(New<HPushArgument>(Pop())); | 6897 PushAndAdd(New<HPushArgument>(Pop())); |
| 6929 for (int i = 1; i < arguments_count; i++) { | 6898 for (int i = 1; i < arguments_count; i++) { |
| 6930 PushAndAdd(New<HPushArgument>(arguments_values->at(i))); | 6899 PushAndAdd(New<HPushArgument>(arguments_values->at(i))); |
| 6931 } | 6900 } |
| 6932 | 6901 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6974 return ast_context()->ReturnInstruction(call, expr->id()); | 6943 return ast_context()->ReturnInstruction(call, expr->id()); |
| 6975 } | 6944 } |
| 6976 | 6945 |
| 6977 // Named function call. | 6946 // Named function call. |
| 6978 if (TryCallApply(expr)) return; | 6947 if (TryCallApply(expr)) return; |
| 6979 | 6948 |
| 6980 CHECK_ALIVE(VisitForValue(prop->obj())); | 6949 CHECK_ALIVE(VisitForValue(prop->obj())); |
| 6981 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 6950 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 6982 | 6951 |
| 6983 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 6952 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 6984 SmallMapList* types = expr->GetReceiverTypes(); | 6953 HValue* receiver = |
| 6954 environment()->ExpressionStackAt(expr->arguments()->length()); |
| 6985 | 6955 |
| 6986 bool monomorphic = expr->IsMonomorphic(); | 6956 SmallMapList* types; |
| 6987 Handle<Map> receiver_map; | 6957 bool was_monomorphic = expr->IsMonomorphic(); |
| 6988 if (monomorphic) { | 6958 bool monomorphic = ComputeReceiverTypes(expr, receiver, &types); |
| 6989 receiver_map = (types == NULL || types->is_empty()) | 6959 if (!was_monomorphic && monomorphic) { |
| 6990 ? Handle<Map>::null() | 6960 monomorphic = expr->ComputeTarget(types->first(), name); |
| 6991 : types->first(); | |
| 6992 } | 6961 } |
| 6993 | 6962 |
| 6994 HValue* receiver = | |
| 6995 environment()->ExpressionStackAt(expr->arguments()->length()); | |
| 6996 if (monomorphic) { | 6963 if (monomorphic) { |
| 6997 if (TryInlineBuiltinMethodCall(expr, | 6964 Handle<Map> map = types->first(); |
| 6998 receiver, | 6965 if (TryInlineBuiltinMethodCall(expr, receiver, map, expr->check_type())) { |
| 6999 receiver_map, | |
| 7000 expr->check_type())) { | |
| 7001 if (FLAG_trace_inlining) { | 6966 if (FLAG_trace_inlining) { |
| 7002 PrintF("Inlining builtin "); | 6967 PrintF("Inlining builtin "); |
| 7003 expr->target()->ShortPrint(); | 6968 expr->target()->ShortPrint(); |
| 7004 PrintF("\n"); | 6969 PrintF("\n"); |
| 7005 } | 6970 } |
| 7006 return; | 6971 return; |
| 7007 } | 6972 } |
| 7008 | 6973 |
| 7009 if (CallStubCompiler::HasCustomCallGenerator(expr->target()) || | 6974 if (CallStubCompiler::HasCustomCallGenerator(expr->target()) || |
| 7010 expr->check_type() != RECEIVER_MAP_CHECK) { | 6975 expr->check_type() != RECEIVER_MAP_CHECK) { |
| 7011 // When the target has a custom call IC generator, use the IC, | 6976 // When the target has a custom call IC generator, use the IC, |
| 7012 // because it is likely to generate better code. Also use the IC | 6977 // because it is likely to generate better code. Also use the IC |
| 7013 // when a primitive receiver check is required. | 6978 // when a primitive receiver check is required. |
| 7014 HValue* context = environment()->context(); | 6979 HValue* context = environment()->context(); |
| 7015 call = PreProcessCall( | 6980 call = PreProcessCall( |
| 7016 new(zone()) HCallNamed(context, name, argument_count)); | 6981 new(zone()) HCallNamed(context, name, argument_count)); |
| 7017 } else { | 6982 } else { |
| 7018 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | 6983 AddCheckConstantFunction(expr->holder(), receiver, map); |
| 7019 | 6984 |
| 7020 if (TryInlineCall(expr)) return; | 6985 if (TryInlineCall(expr)) return; |
| 7021 call = PreProcessCall( | 6986 call = PreProcessCall( |
| 7022 new(zone()) HCallConstantFunction(expr->target(), | 6987 new(zone()) HCallConstantFunction(expr->target(), |
| 7023 argument_count)); | 6988 argument_count)); |
| 7024 } | 6989 } |
| 7025 } else if (types != NULL && types->length() > 1) { | 6990 } else if (types != NULL && types->length() > 1) { |
| 7026 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); | 6991 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); |
| 7027 HandlePolymorphicCallNamed(expr, receiver, types, name); | 6992 HandlePolymorphicCallNamed(expr, receiver, types, name); |
| 7028 return; | 6993 return; |
| (...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7483 HAdd* add = HAdd::cast(instr); | 7448 HAdd* add = HAdd::cast(instr); |
| 7484 add->set_observed_input_representation(1, rep); | 7449 add->set_observed_input_representation(1, rep); |
| 7485 add->set_observed_input_representation(2, Representation::Smi()); | 7450 add->set_observed_input_representation(2, Representation::Smi()); |
| 7486 } | 7451 } |
| 7487 instr->SetFlag(HInstruction::kCannotBeTagged); | 7452 instr->SetFlag(HInstruction::kCannotBeTagged); |
| 7488 instr->ClearAllSideEffects(); | 7453 instr->ClearAllSideEffects(); |
| 7489 return instr; | 7454 return instr; |
| 7490 } | 7455 } |
| 7491 | 7456 |
| 7492 | 7457 |
| 7458 void HOptimizedGraphBuilder::BuildStoreForEffect(Expression* expr, |
| 7459 Property* prop, |
| 7460 BailoutId ast_id, |
| 7461 BailoutId return_id, |
| 7462 HValue* object, |
| 7463 HValue* key, |
| 7464 HValue* value) { |
| 7465 EffectContext for_effect(this); |
| 7466 Push(object); |
| 7467 if (key != NULL) Push(key); |
| 7468 Push(value); |
| 7469 BuildStore(expr, prop, ast_id, return_id); |
| 7470 } |
| 7471 |
| 7472 |
| 7493 void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { | 7473 void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { |
| 7494 ASSERT(!HasStackOverflow()); | 7474 ASSERT(!HasStackOverflow()); |
| 7495 ASSERT(current_block() != NULL); | 7475 ASSERT(current_block() != NULL); |
| 7496 ASSERT(current_block()->HasPredecessor()); | 7476 ASSERT(current_block()->HasPredecessor()); |
| 7497 Expression* target = expr->expression(); | 7477 Expression* target = expr->expression(); |
| 7498 VariableProxy* proxy = target->AsVariableProxy(); | 7478 VariableProxy* proxy = target->AsVariableProxy(); |
| 7499 Property* prop = target->AsProperty(); | 7479 Property* prop = target->AsProperty(); |
| 7500 if (proxy == NULL && prop == NULL) { | 7480 if (proxy == NULL && prop == NULL) { |
| 7501 return Bailout(kInvalidLhsInCountOperation); | 7481 return Bailout(kInvalidLhsInCountOperation); |
| 7502 } | 7482 } |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7559 if (instr->HasObservableSideEffects()) { | 7539 if (instr->HasObservableSideEffects()) { |
| 7560 Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); | 7540 Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); |
| 7561 } | 7541 } |
| 7562 break; | 7542 break; |
| 7563 } | 7543 } |
| 7564 | 7544 |
| 7565 case Variable::LOOKUP: | 7545 case Variable::LOOKUP: |
| 7566 return Bailout(kLookupVariableInCountOperation); | 7546 return Bailout(kLookupVariableInCountOperation); |
| 7567 } | 7547 } |
| 7568 | 7548 |
| 7569 } else { | 7549 Drop(returns_original_input ? 2 : 1); |
| 7570 // Argument of the count operation is a property. | 7550 return ast_context()->ReturnValue(expr->is_postfix() ? input : after); |
| 7571 ASSERT(prop != NULL); | |
| 7572 | |
| 7573 if (prop->key()->IsPropertyName()) { | |
| 7574 // Named property. | |
| 7575 if (returns_original_input) Push(graph()->GetConstantUndefined()); | |
| 7576 | |
| 7577 CHECK_ALIVE(VisitForValue(prop->obj())); | |
| 7578 HValue* object = Top(); | |
| 7579 | |
| 7580 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | |
| 7581 Handle<Map> map; | |
| 7582 HInstruction* load = NULL; | |
| 7583 bool monomorphic = prop->IsMonomorphic(); | |
| 7584 SmallMapList* types = prop->GetReceiverTypes(); | |
| 7585 if (monomorphic) { | |
| 7586 map = types->first(); | |
| 7587 if (map->is_dictionary_map()) monomorphic = false; | |
| 7588 } | |
| 7589 if (monomorphic) { | |
| 7590 Handle<JSFunction> getter; | |
| 7591 Handle<JSObject> holder; | |
| 7592 if (LookupGetter(map, name, &getter, &holder)) { | |
| 7593 load = BuildCallGetter(object, map, getter, holder); | |
| 7594 } else { | |
| 7595 load = BuildLoadNamedMonomorphic(object, name, prop, map); | |
| 7596 } | |
| 7597 } else if (types != NULL && types->length() > 1) { | |
| 7598 load = TryLoadPolymorphicAsMonomorphic(prop, object, types, name); | |
| 7599 } | |
| 7600 if (load == NULL) load = BuildLoadNamedGeneric(object, name, prop); | |
| 7601 PushAndAdd(load); | |
| 7602 if (load->HasObservableSideEffects()) { | |
| 7603 Add<HSimulate>(prop->LoadId(), REMOVABLE_SIMULATE); | |
| 7604 } | |
| 7605 | |
| 7606 after = BuildIncrement(returns_original_input, expr); | |
| 7607 HValue* result = returns_original_input ? Pop() : after; | |
| 7608 | |
| 7609 return BuildStoreNamed(expr, expr->id(), expr->position(), | |
| 7610 expr->AssignmentId(), prop, object, after, result); | |
| 7611 } else { | |
| 7612 // Keyed property. | |
| 7613 if (returns_original_input) Push(graph()->GetConstantUndefined()); | |
| 7614 | |
| 7615 CHECK_ALIVE(VisitForValue(prop->obj())); | |
| 7616 CHECK_ALIVE(VisitForValue(prop->key())); | |
| 7617 HValue* obj = environment()->ExpressionStackAt(1); | |
| 7618 HValue* key = environment()->ExpressionStackAt(0); | |
| 7619 | |
| 7620 bool has_side_effects = false; | |
| 7621 HValue* load = HandleKeyedElementAccess( | |
| 7622 obj, key, NULL, prop, prop->LoadId(), RelocInfo::kNoPosition, | |
| 7623 false, // is_store | |
| 7624 &has_side_effects); | |
| 7625 Push(load); | |
| 7626 if (has_side_effects) Add<HSimulate>(prop->LoadId(), REMOVABLE_SIMULATE); | |
| 7627 | |
| 7628 after = BuildIncrement(returns_original_input, expr); | |
| 7629 input = environment()->ExpressionStackAt(0); | |
| 7630 | |
| 7631 HandleKeyedElementAccess(obj, key, after, expr, expr->AssignmentId(), | |
| 7632 RelocInfo::kNoPosition, | |
| 7633 true, // is_store | |
| 7634 &has_side_effects); | |
| 7635 | |
| 7636 // Drop the key and the original value from the bailout environment. | |
| 7637 // Overwrite the receiver with the result of the operation, and the | |
| 7638 // placeholder with the original value if necessary. | |
| 7639 Drop(2); | |
| 7640 environment()->SetExpressionStackAt(0, after); | |
| 7641 if (returns_original_input) environment()->SetExpressionStackAt(1, input); | |
| 7642 ASSERT(has_side_effects); // Stores always have side effects. | |
| 7643 Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); | |
| 7644 } | |
| 7645 } | 7551 } |
| 7646 | 7552 |
| 7647 Drop(returns_original_input ? 2 : 1); | 7553 // Argument of the count operation is a property. |
| 7648 return ast_context()->ReturnValue(expr->is_postfix() ? input : after); | 7554 ASSERT(prop != NULL); |
| 7555 if (returns_original_input) Push(graph()->GetConstantUndefined()); |
| 7556 |
| 7557 CHECK_ALIVE(VisitForValue(prop->obj())); |
| 7558 HValue* object = Top(); |
| 7559 |
| 7560 HValue* key = NULL; |
| 7561 if ((!prop->IsStringLength() && |
| 7562 !prop->IsFunctionPrototype() && |
| 7563 !prop->key()->IsPropertyName()) || |
| 7564 prop->IsStringAccess()) { |
| 7565 CHECK_ALIVE(VisitForValue(prop->key())); |
| 7566 key = Top(); |
| 7567 } |
| 7568 |
| 7569 CHECK_ALIVE(PushLoad(prop, object, key, expr->position())); |
| 7570 |
| 7571 after = BuildIncrement(returns_original_input, expr); |
| 7572 |
| 7573 if (returns_original_input) { |
| 7574 input = Pop(); |
| 7575 // Drop object and key to push it again in the effect context below. |
| 7576 Drop(key == NULL ? 1 : 2); |
| 7577 environment()->SetExpressionStackAt(0, input); |
| 7578 CHECK_ALIVE(BuildStoreForEffect( |
| 7579 expr, prop, expr->id(), expr->AssignmentId(), object, key, after)); |
| 7580 return ast_context()->ReturnValue(Pop()); |
| 7581 } |
| 7582 |
| 7583 environment()->SetExpressionStackAt(0, after); |
| 7584 return BuildStore(expr, prop, expr->id(), expr->AssignmentId()); |
| 7649 } | 7585 } |
| 7650 | 7586 |
| 7651 | 7587 |
| 7652 HInstruction* HOptimizedGraphBuilder::BuildStringCharCodeAt( | 7588 HInstruction* HOptimizedGraphBuilder::BuildStringCharCodeAt( |
| 7653 HValue* string, | 7589 HValue* string, |
| 7654 HValue* index) { | 7590 HValue* index) { |
| 7655 if (string->IsConstant() && index->IsConstant()) { | 7591 if (string->IsConstant() && index->IsConstant()) { |
| 7656 HConstant* c_string = HConstant::cast(string); | 7592 HConstant* c_string = HConstant::cast(string); |
| 7657 HConstant* c_index = HConstant::cast(index); | 7593 HConstant* c_index = HConstant::cast(index); |
| 7658 if (c_string->HasStringValue() && c_index->HasNumberValue()) { | 7594 if (c_string->HasStringValue() && c_index->HasNumberValue()) { |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7761 | 7697 |
| 7762 if (expr->op() != Token::ADD || | 7698 if (expr->op() != Token::ADD || |
| 7763 (left->type().IsNonString() && right->type().IsNonString())) { | 7699 (left->type().IsNonString() && right->type().IsNonString())) { |
| 7764 // For addition we can only truncate the arguments to number if we can | 7700 // For addition we can only truncate the arguments to number if we can |
| 7765 // prove that we will not end up in string concatenation mode. | 7701 // prove that we will not end up in string concatenation mode. |
| 7766 left = TruncateToNumber(left, &left_type); | 7702 left = TruncateToNumber(left, &left_type); |
| 7767 right = TruncateToNumber(right, &right_type); | 7703 right = TruncateToNumber(right, &right_type); |
| 7768 } | 7704 } |
| 7769 | 7705 |
| 7770 if (left_type->Is(Type::None())) { | 7706 if (left_type->Is(Type::None())) { |
| 7771 Add<HDeoptimize>("Insufficient type feedback for left side", | 7707 Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation", |
| 7772 Deoptimizer::SOFT); | 7708 Deoptimizer::SOFT); |
| 7773 // TODO(rossberg): we should be able to get rid of non-continuous defaults. | 7709 // TODO(rossberg): we should be able to get rid of non-continuous defaults. |
| 7774 left_type = handle(Type::Any(), isolate()); | 7710 left_type = handle(Type::Any(), isolate()); |
| 7775 } | 7711 } |
| 7776 if (right_type->Is(Type::None())) { | 7712 if (right_type->Is(Type::None())) { |
| 7777 Add<HDeoptimize>("Insufficient type feedback for right side", | 7713 Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation", |
| 7778 Deoptimizer::SOFT); | 7714 Deoptimizer::SOFT); |
| 7779 right_type = handle(Type::Any(), isolate()); | 7715 right_type = handle(Type::Any(), isolate()); |
| 7780 } | 7716 } |
| 7781 HInstruction* instr = NULL; | 7717 HInstruction* instr = NULL; |
| 7782 switch (expr->op()) { | 7718 switch (expr->op()) { |
| 7783 case Token::ADD: | 7719 case Token::ADD: |
| 7784 if (left_type->Is(Type::String()) && right_type->Is(Type::String())) { | 7720 if (left_type->Is(Type::String()) && right_type->Is(Type::String())) { |
| 7785 BuildCheckHeapObject(left); | 7721 BuildCheckHeapObject(left); |
| 7786 AddInstruction(HCheckInstanceType::NewIsString(left, zone())); | 7722 AddInstruction(HCheckInstanceType::NewIsString(left, zone())); |
| 7787 BuildCheckHeapObject(right); | 7723 BuildCheckHeapObject(right); |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8000 Expression* sub_expr, | 7936 Expression* sub_expr, |
| 8001 Handle<String> check) { | 7937 Handle<String> check) { |
| 8002 CHECK_ALIVE(VisitForTypeOf(sub_expr)); | 7938 CHECK_ALIVE(VisitForTypeOf(sub_expr)); |
| 8003 HValue* value = Pop(); | 7939 HValue* value = Pop(); |
| 8004 HTypeofIsAndBranch* instr = new(zone()) HTypeofIsAndBranch(value, check); | 7940 HTypeofIsAndBranch* instr = new(zone()) HTypeofIsAndBranch(value, check); |
| 8005 instr->set_position(expr->position()); | 7941 instr->set_position(expr->position()); |
| 8006 return ast_context()->ReturnControl(instr, expr->id()); | 7942 return ast_context()->ReturnControl(instr, expr->id()); |
| 8007 } | 7943 } |
| 8008 | 7944 |
| 8009 | 7945 |
| 8010 static bool IsLiteralCompareBool(HValue* left, | 7946 static bool IsLiteralCompareBool(Isolate* isolate, |
| 7947 HValue* left, |
| 8011 Token::Value op, | 7948 Token::Value op, |
| 8012 HValue* right) { | 7949 HValue* right) { |
| 8013 return op == Token::EQ_STRICT && | 7950 return op == Token::EQ_STRICT && |
| 8014 ((left->IsConstant() && HConstant::cast(left)->handle()->IsBoolean()) || | 7951 ((left->IsConstant() && |
| 8015 (right->IsConstant() && HConstant::cast(right)->handle()->IsBoolean())); | 7952 HConstant::cast(left)->handle(isolate)->IsBoolean()) || |
| 7953 (right->IsConstant() && |
| 7954 HConstant::cast(right)->handle(isolate)->IsBoolean())); |
| 8016 } | 7955 } |
| 8017 | 7956 |
| 8018 | 7957 |
| 8019 void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { | 7958 void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { |
| 8020 ASSERT(!HasStackOverflow()); | 7959 ASSERT(!HasStackOverflow()); |
| 8021 ASSERT(current_block() != NULL); | 7960 ASSERT(current_block() != NULL); |
| 8022 ASSERT(current_block()->HasPredecessor()); | 7961 ASSERT(current_block()->HasPredecessor()); |
| 8023 | 7962 |
| 8024 // Check for a few fast cases. The AST visiting behavior must be in sync | 7963 // Check for a few fast cases. The AST visiting behavior must be in sync |
| 8025 // with the full codegen: We don't push both left and right values onto | 7964 // with the full codegen: We don't push both left and right values onto |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8057 Representation right_rep = Representation::FromType(right_type); | 7996 Representation right_rep = Representation::FromType(right_type); |
| 8058 | 7997 |
| 8059 CHECK_ALIVE(VisitForValue(expr->left())); | 7998 CHECK_ALIVE(VisitForValue(expr->left())); |
| 8060 CHECK_ALIVE(VisitForValue(expr->right())); | 7999 CHECK_ALIVE(VisitForValue(expr->right())); |
| 8061 | 8000 |
| 8062 HValue* context = environment()->context(); | 8001 HValue* context = environment()->context(); |
| 8063 HValue* right = Pop(); | 8002 HValue* right = Pop(); |
| 8064 HValue* left = Pop(); | 8003 HValue* left = Pop(); |
| 8065 Token::Value op = expr->op(); | 8004 Token::Value op = expr->op(); |
| 8066 | 8005 |
| 8067 if (IsLiteralCompareBool(left, op, right)) { | 8006 if (IsLiteralCompareBool(isolate(), left, op, right)) { |
| 8068 HCompareObjectEqAndBranch* result = | 8007 HCompareObjectEqAndBranch* result = |
| 8069 New<HCompareObjectEqAndBranch>(left, right); | 8008 New<HCompareObjectEqAndBranch>(left, right); |
| 8070 result->set_position(expr->position()); | 8009 result->set_position(expr->position()); |
| 8071 return ast_context()->ReturnControl(result, expr->id()); | 8010 return ast_context()->ReturnControl(result, expr->id()); |
| 8072 } | 8011 } |
| 8073 | 8012 |
| 8074 if (op == Token::INSTANCEOF) { | 8013 if (op == Token::INSTANCEOF) { |
| 8075 // Check to see if the rhs of the instanceof is a global function not | 8014 // Check to see if the rhs of the instanceof is a global function not |
| 8076 // residing in new space. If it is we assume that the function will stay the | 8015 // residing in new space. If it is we assume that the function will stay the |
| 8077 // same. | 8016 // same. |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8118 // TODO(olivf) InvokeFunction produces a check for the parameter count, | 8057 // TODO(olivf) InvokeFunction produces a check for the parameter count, |
| 8119 // even though we are certain to pass the correct number of arguments here. | 8058 // even though we are certain to pass the correct number of arguments here. |
| 8120 HInstruction* result = new(zone()) HInvokeFunction(context, function, 2); | 8059 HInstruction* result = new(zone()) HInvokeFunction(context, function, 2); |
| 8121 result->set_position(expr->position()); | 8060 result->set_position(expr->position()); |
| 8122 return ast_context()->ReturnInstruction(result, expr->id()); | 8061 return ast_context()->ReturnInstruction(result, expr->id()); |
| 8123 } | 8062 } |
| 8124 | 8063 |
| 8125 // Cases handled below depend on collected type feedback. They should | 8064 // Cases handled below depend on collected type feedback. They should |
| 8126 // soft deoptimize when there is no type feedback. | 8065 // soft deoptimize when there is no type feedback. |
| 8127 if (combined_type->Is(Type::None())) { | 8066 if (combined_type->Is(Type::None())) { |
| 8128 Add<HDeoptimize>("insufficient type feedback for combined type", | 8067 Add<HDeoptimize>("Insufficient type feedback for combined type " |
| 8068 "of binary operation", |
| 8129 Deoptimizer::SOFT); | 8069 Deoptimizer::SOFT); |
| 8130 combined_type = left_type = right_type = handle(Type::Any(), isolate()); | 8070 combined_type = left_type = right_type = handle(Type::Any(), isolate()); |
| 8131 } | 8071 } |
| 8132 | 8072 |
| 8133 if (combined_type->Is(Type::Receiver())) { | 8073 if (combined_type->Is(Type::Receiver())) { |
| 8134 switch (op) { | 8074 switch (op) { |
| 8135 case Token::EQ: | 8075 case Token::EQ: |
| 8136 case Token::EQ_STRICT: { | 8076 case Token::EQ_STRICT: { |
| 8137 // Can we get away with map check and not instance type check? | 8077 // Can we get away with map check and not instance type check? |
| 8138 if (combined_type->IsClass()) { | 8078 if (combined_type->IsClass()) { |
| (...skipping 1602 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9741 if (ShouldProduceTraceOutput()) { | 9681 if (ShouldProduceTraceOutput()) { |
| 9742 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 9682 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 9743 } | 9683 } |
| 9744 | 9684 |
| 9745 #ifdef DEBUG | 9685 #ifdef DEBUG |
| 9746 graph_->Verify(false); // No full verify. | 9686 graph_->Verify(false); // No full verify. |
| 9747 #endif | 9687 #endif |
| 9748 } | 9688 } |
| 9749 | 9689 |
| 9750 } } // namespace v8::internal | 9690 } } // namespace v8::internal |
| OLD | NEW |