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 5874 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5885 HValue* val, | 5885 HValue* val, |
5886 Expression* prop, | 5886 Expression* prop, |
5887 BailoutId ast_id, | 5887 BailoutId ast_id, |
5888 int position, | 5888 int position, |
5889 bool is_store, | 5889 bool is_store, |
5890 KeyedAccessStoreMode store_mode, | 5890 KeyedAccessStoreMode store_mode, |
5891 bool* has_side_effects) { | 5891 bool* has_side_effects) { |
5892 *has_side_effects = false; | 5892 *has_side_effects = false; |
5893 BuildCheckHeapObject(object); | 5893 BuildCheckHeapObject(object); |
5894 SmallMapList* maps = prop->GetReceiverTypes(); | 5894 SmallMapList* maps = prop->GetReceiverTypes(); |
5895 bool todo_external_array = false; | |
5896 | 5895 |
5897 if (!is_store) { | 5896 if (!is_store) { |
5898 HInstruction* consolidated_load = | 5897 HInstruction* consolidated_load = |
5899 TryBuildConsolidatedElementLoad(object, key, val, maps); | 5898 TryBuildConsolidatedElementLoad(object, key, val, maps); |
5900 if (consolidated_load != NULL) { | 5899 if (consolidated_load != NULL) { |
5901 *has_side_effects |= consolidated_load->HasObservableSideEffects(); | 5900 *has_side_effects |= consolidated_load->HasObservableSideEffects(); |
5902 if (position != RelocInfo::kNoPosition) { | 5901 if (position != RelocInfo::kNoPosition) { |
5903 consolidated_load->set_position(position); | 5902 consolidated_load->set_position(position); |
5904 } | 5903 } |
5905 return consolidated_load; | 5904 return consolidated_load; |
5906 } | 5905 } |
5907 } | 5906 } |
5908 | 5907 |
5909 static const int kNumElementTypes = kElementsKindCount; | |
5910 bool type_todo[kNumElementTypes]; | |
5911 for (int i = 0; i < kNumElementTypes; ++i) { | |
5912 type_todo[i] = false; | |
5913 } | |
5914 | |
5915 // Elements_kind transition support. | 5908 // Elements_kind transition support. |
5916 MapHandleList transition_target(maps->length()); | 5909 MapHandleList transition_target(maps->length()); |
5917 // Collect possible transition targets. | 5910 // Collect possible transition targets. |
5918 MapHandleList possible_transitioned_maps(maps->length()); | 5911 MapHandleList possible_transitioned_maps(maps->length()); |
5919 for (int i = 0; i < maps->length(); ++i) { | 5912 for (int i = 0; i < maps->length(); ++i) { |
5920 Handle<Map> map = maps->at(i); | 5913 Handle<Map> map = maps->at(i); |
5921 ElementsKind elements_kind = map->elements_kind(); | 5914 ElementsKind elements_kind = map->elements_kind(); |
5922 if (IsFastElementsKind(elements_kind) && | 5915 if (IsFastElementsKind(elements_kind) && |
5923 elements_kind != GetInitialFastElementsKind()) { | 5916 elements_kind != GetInitialFastElementsKind()) { |
5924 possible_transitioned_maps.Add(map); | 5917 possible_transitioned_maps.Add(map); |
5925 } | 5918 } |
5926 } | 5919 } |
5927 // Get transition target for each map (NULL == no transition). | 5920 // Get transition target for each map (NULL == no transition). |
5928 for (int i = 0; i < maps->length(); ++i) { | 5921 for (int i = 0; i < maps->length(); ++i) { |
5929 Handle<Map> map = maps->at(i); | 5922 Handle<Map> map = maps->at(i); |
5930 Handle<Map> transitioned_map = | 5923 Handle<Map> transitioned_map = |
5931 map->FindTransitionedMap(&possible_transitioned_maps); | 5924 map->FindTransitionedMap(&possible_transitioned_maps); |
5932 transition_target.Add(transitioned_map); | 5925 transition_target.Add(transitioned_map); |
5933 } | 5926 } |
5934 | 5927 |
5935 int num_untransitionable_maps = 0; | 5928 MapHandleList untransitionable_maps(maps->length()); |
5936 Handle<Map> untransitionable_map; | |
5937 HTransitionElementsKind* transition = NULL; | 5929 HTransitionElementsKind* transition = NULL; |
5938 for (int i = 0; i < maps->length(); ++i) { | 5930 for (int i = 0; i < maps->length(); ++i) { |
5939 Handle<Map> map = maps->at(i); | 5931 Handle<Map> map = maps->at(i); |
5940 ASSERT(map->IsMap()); | 5932 ASSERT(map->IsMap()); |
5941 if (!transition_target.at(i).is_null()) { | 5933 if (!transition_target.at(i).is_null()) { |
5942 ASSERT(Map::IsValidElementsTransition( | 5934 ASSERT(Map::IsValidElementsTransition( |
5943 map->elements_kind(), | 5935 map->elements_kind(), |
5944 transition_target.at(i)->elements_kind())); | 5936 transition_target.at(i)->elements_kind())); |
5945 HValue* context = environment()->LookupContext(); | 5937 HValue* context = environment()->LookupContext(); |
5946 transition = Add<HTransitionElementsKind>(context, object, map, | 5938 transition = Add<HTransitionElementsKind>(context, object, map, |
5947 transition_target.at(i)); | 5939 transition_target.at(i)); |
5948 } else { | 5940 } else { |
5949 type_todo[map->elements_kind()] = true; | 5941 untransitionable_maps.Add(map); |
5950 if (IsExternalArrayElementsKind(map->elements_kind())) { | |
5951 todo_external_array = true; | |
5952 } | |
5953 num_untransitionable_maps++; | |
5954 untransitionable_map = map; | |
5955 } | 5942 } |
5956 } | 5943 } |
5957 | 5944 |
5958 // If only one map is left after transitioning, handle this case | 5945 // If only one map is left after transitioning, handle this case |
5959 // monomorphically. | 5946 // monomorphically. |
5960 ASSERT(num_untransitionable_maps >= 1); | 5947 ASSERT(untransitionable_maps.length() >= 1); |
5961 if (num_untransitionable_maps == 1) { | 5948 if (untransitionable_maps.length() == 1) { |
| 5949 Handle<Map> untransitionable_map = untransitionable_maps[0]; |
5962 HInstruction* instr = NULL; | 5950 HInstruction* instr = NULL; |
5963 if (untransitionable_map->has_slow_elements_kind()) { | 5951 if (untransitionable_map->has_slow_elements_kind()) { |
5964 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) | 5952 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) |
5965 : BuildLoadKeyedGeneric(object, key)); | 5953 : BuildLoadKeyedGeneric(object, key)); |
5966 } else { | 5954 } else { |
5967 instr = BuildMonomorphicElementAccess( | 5955 instr = BuildMonomorphicElementAccess( |
5968 object, key, val, transition, untransitionable_map, is_store, | 5956 object, key, val, transition, untransitionable_map, is_store, |
5969 store_mode); | 5957 store_mode); |
5970 } | 5958 } |
5971 *has_side_effects |= instr->HasObservableSideEffects(); | 5959 *has_side_effects |= instr->HasObservableSideEffects(); |
5972 if (position != RelocInfo::kNoPosition) instr->set_position(position); | 5960 if (position != RelocInfo::kNoPosition) instr->set_position(position); |
5973 return is_store ? NULL : instr; | 5961 return is_store ? NULL : instr; |
5974 } | 5962 } |
5975 | 5963 |
5976 HInstruction* checkspec = | 5964 HInstruction* checkspec = |
5977 AddInstruction(HCheckInstanceType::NewIsSpecObject(object, zone())); | 5965 AddInstruction(HCheckInstanceType::NewIsSpecObject(object, zone())); |
5978 HBasicBlock* join = graph()->CreateBasicBlock(); | 5966 HBasicBlock* join = graph()->CreateBasicBlock(); |
5979 | 5967 |
5980 HInstruction* elements_kind_instr = Add<HElementsKind>(object); | |
5981 HInstruction* elements = AddLoadElements(object, checkspec); | 5968 HInstruction* elements = AddLoadElements(object, checkspec); |
5982 HLoadExternalArrayPointer* external_elements = NULL; | |
5983 HInstruction* checked_key = NULL; | |
5984 | 5969 |
5985 // Generated code assumes that FAST_* and DICTIONARY_ELEMENTS ElementsKinds | 5970 for (int i = 0; i < untransitionable_maps.length(); ++i) { |
5986 // are handled before external arrays. | 5971 Handle<Map> map = untransitionable_maps[i]; |
5987 STATIC_ASSERT(FAST_SMI_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); | 5972 ElementsKind elements_kind = map->elements_kind(); |
5988 STATIC_ASSERT(FAST_HOLEY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); | 5973 HBasicBlock* this_map = graph()->CreateBasicBlock(); |
5989 STATIC_ASSERT(FAST_DOUBLE_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); | 5974 HBasicBlock* other_map = graph()->CreateBasicBlock(); |
5990 STATIC_ASSERT(DICTIONARY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); | 5975 HCompareMap* mapcompare = |
| 5976 new(zone()) HCompareMap(object, map, this_map, other_map); |
| 5977 current_block()->Finish(mapcompare); |
5991 | 5978 |
5992 for (ElementsKind elements_kind = FIRST_ELEMENTS_KIND; | 5979 set_current_block(this_map); |
5993 elements_kind <= LAST_ELEMENTS_KIND; | 5980 HInstruction* checked_key = NULL; |
5994 elements_kind = ElementsKind(elements_kind + 1)) { | 5981 HInstruction* access = NULL; |
5995 // After having handled FAST_* and DICTIONARY_ELEMENTS, we need to add some | 5982 if (IsFastElementsKind(elements_kind)) { |
5996 // code that's executed for all external array cases. | 5983 if (is_store && !IsFastDoubleElementsKind(elements_kind)) { |
5997 STATIC_ASSERT(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND == | 5984 AddInstruction(HCheckMaps::New( |
5998 LAST_ELEMENTS_KIND); | 5985 elements, isolate()->factory()->fixed_array_map(), |
5999 if (elements_kind == FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND | 5986 zone(), mapcompare)); |
6000 && todo_external_array) { | 5987 } |
| 5988 if (map->IsJSArray()) { |
| 5989 HInstruction* length = AddLoad(object, HObjectAccess::ForArrayLength(), |
| 5990 mapcompare, Representation::Smi()); |
| 5991 length->set_type(HType::Smi()); |
| 5992 checked_key = Add<HBoundsCheck>(key, length); |
| 5993 } else { |
| 5994 HInstruction* length = AddLoadFixedArrayLength(elements); |
| 5995 checked_key = Add<HBoundsCheck>(key, length); |
| 5996 } |
| 5997 access = AddInstruction(BuildFastElementAccess( |
| 5998 elements, checked_key, val, mapcompare, |
| 5999 elements_kind, is_store, NEVER_RETURN_HOLE, STANDARD_STORE)); |
| 6000 } else if (IsDictionaryElementsKind(elements_kind)) { |
| 6001 if (is_store) { |
| 6002 access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); |
| 6003 } else { |
| 6004 access = AddInstruction(BuildLoadKeyedGeneric(object, key)); |
| 6005 } |
| 6006 } else { |
| 6007 ASSERT(IsExternalArrayElementsKind(elements_kind)); |
6001 HInstruction* length = AddLoadFixedArrayLength(elements); | 6008 HInstruction* length = AddLoadFixedArrayLength(elements); |
6002 checked_key = Add<HBoundsCheck>(key, length); | 6009 checked_key = Add<HBoundsCheck>(key, length); |
6003 external_elements = Add<HLoadExternalArrayPointer>(elements); | 6010 HLoadExternalArrayPointer* external_elements = |
| 6011 Add<HLoadExternalArrayPointer>(elements); |
| 6012 access = AddInstruction(BuildExternalArrayElementAccess( |
| 6013 external_elements, checked_key, val, |
| 6014 mapcompare, elements_kind, is_store)); |
6004 } | 6015 } |
6005 if (type_todo[elements_kind]) { | 6016 *has_side_effects |= access->HasObservableSideEffects(); |
6006 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 6017 // The caller will use has_side_effects and add a correct Simulate. |
6007 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 6018 access->SetFlag(HValue::kHasNoObservableSideEffects); |
6008 HCompareConstantEqAndBranch* elements_kind_branch = | 6019 if (position != RelocInfo::kNoPosition) access->set_position(position); |
6009 new(zone()) HCompareConstantEqAndBranch( | 6020 if (!is_store) { |
6010 elements_kind_instr, elements_kind, Token::EQ_STRICT); | 6021 Push(access); |
6011 elements_kind_branch->SetSuccessorAt(0, if_true); | |
6012 elements_kind_branch->SetSuccessorAt(1, if_false); | |
6013 current_block()->Finish(elements_kind_branch); | |
6014 | |
6015 set_current_block(if_true); | |
6016 HInstruction* access; | |
6017 if (IsFastElementsKind(elements_kind)) { | |
6018 if (is_store && !IsFastDoubleElementsKind(elements_kind)) { | |
6019 AddInstruction(HCheckMaps::New( | |
6020 elements, isolate()->factory()->fixed_array_map(), | |
6021 zone(), elements_kind_branch)); | |
6022 } | |
6023 // TODO(jkummerow): The need for these two blocks could be avoided | |
6024 // in one of two ways: | |
6025 // (1) Introduce ElementsKinds for JSArrays that are distinct from | |
6026 // those for fast objects. | |
6027 // (2) Put the common instructions into a third "join" block. This | |
6028 // requires additional AST IDs that we can deopt to from inside | |
6029 // that join block. They must be added to the Property class (when | |
6030 // it's a keyed property) and registered in the full codegen. | |
6031 HBasicBlock* if_jsarray = graph()->CreateBasicBlock(); | |
6032 HBasicBlock* if_fastobject = graph()->CreateBasicBlock(); | |
6033 HHasInstanceTypeAndBranch* typecheck = | |
6034 new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE); | |
6035 typecheck->SetSuccessorAt(0, if_jsarray); | |
6036 typecheck->SetSuccessorAt(1, if_fastobject); | |
6037 current_block()->Finish(typecheck); | |
6038 | |
6039 set_current_block(if_jsarray); | |
6040 HInstruction* length = AddLoad(object, HObjectAccess::ForArrayLength(), | |
6041 typecheck, Representation::Smi()); | |
6042 length->set_type(HType::Smi()); | |
6043 | |
6044 checked_key = Add<HBoundsCheck>(key, length); | |
6045 access = AddInstruction(BuildFastElementAccess( | |
6046 elements, checked_key, val, elements_kind_branch, | |
6047 elements_kind, is_store, NEVER_RETURN_HOLE, STANDARD_STORE)); | |
6048 if (!is_store) { | |
6049 Push(access); | |
6050 } | |
6051 | |
6052 *has_side_effects |= access->HasObservableSideEffects(); | |
6053 // The caller will use has_side_effects and add correct Simulate. | |
6054 access->SetFlag(HValue::kHasNoObservableSideEffects); | |
6055 if (position != -1) { | |
6056 access->set_position(position); | |
6057 } | |
6058 if_jsarray->GotoNoSimulate(join); | |
6059 | |
6060 set_current_block(if_fastobject); | |
6061 length = AddLoadFixedArrayLength(elements); | |
6062 checked_key = Add<HBoundsCheck>(key, length); | |
6063 access = AddInstruction(BuildFastElementAccess( | |
6064 elements, checked_key, val, elements_kind_branch, | |
6065 elements_kind, is_store, NEVER_RETURN_HOLE, STANDARD_STORE)); | |
6066 } else if (elements_kind == DICTIONARY_ELEMENTS) { | |
6067 if (is_store) { | |
6068 access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); | |
6069 } else { | |
6070 access = AddInstruction(BuildLoadKeyedGeneric(object, key)); | |
6071 } | |
6072 } else { // External array elements. | |
6073 access = AddInstruction(BuildExternalArrayElementAccess( | |
6074 external_elements, checked_key, val, | |
6075 elements_kind_branch, elements_kind, is_store)); | |
6076 } | |
6077 *has_side_effects |= access->HasObservableSideEffects(); | |
6078 // The caller will use has_side_effects and add correct Simulate. | |
6079 access->SetFlag(HValue::kHasNoObservableSideEffects); | |
6080 if (position != RelocInfo::kNoPosition) access->set_position(position); | |
6081 if (!is_store) { | |
6082 Push(access); | |
6083 } | |
6084 current_block()->GotoNoSimulate(join); | |
6085 set_current_block(if_false); | |
6086 } | 6022 } |
| 6023 current_block()->GotoNoSimulate(join); |
| 6024 set_current_block(other_map); |
6087 } | 6025 } |
6088 | 6026 |
6089 // Deopt if none of the cases matched. | 6027 // Deopt if none of the cases matched. |
6090 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); | 6028 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); |
6091 set_current_block(join); | 6029 set_current_block(join); |
6092 return is_store ? NULL : Pop(); | 6030 return is_store ? NULL : Pop(); |
6093 } | 6031 } |
6094 | 6032 |
6095 | 6033 |
6096 HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( | 6034 HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( |
(...skipping 4143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10240 if (ShouldProduceTraceOutput()) { | 10178 if (ShouldProduceTraceOutput()) { |
10241 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 10179 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
10242 } | 10180 } |
10243 | 10181 |
10244 #ifdef DEBUG | 10182 #ifdef DEBUG |
10245 graph_->Verify(false); // No full verify. | 10183 graph_->Verify(false); // No full verify. |
10246 #endif | 10184 #endif |
10247 } | 10185 } |
10248 | 10186 |
10249 } } // namespace v8::internal | 10187 } } // namespace v8::internal |
OLD | NEW |