OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 3256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3267 // If the subexpression is a literal or a simple materialized literal it | 3267 // If the subexpression is a literal or a simple materialized literal it |
3268 // is already set in the cloned array. | 3268 // is already set in the cloned array. |
3269 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; | 3269 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; |
3270 | 3270 |
3271 CHECK_ALIVE(VisitForValue(subexpr)); | 3271 CHECK_ALIVE(VisitForValue(subexpr)); |
3272 HValue* value = Pop(); | 3272 HValue* value = Pop(); |
3273 if (!Smi::IsValid(i)) return Bailout("Non-smi key in array literal"); | 3273 if (!Smi::IsValid(i)) return Bailout("Non-smi key in array literal"); |
3274 | 3274 |
3275 // Load the elements array before the first store. | 3275 // Load the elements array before the first store. |
3276 if (elements == NULL) { | 3276 if (elements == NULL) { |
3277 elements = new(zone()) HLoadElements(literal); | 3277 elements = new(zone()) HLoadElements(literal); |
3278 AddInstruction(elements); | 3278 AddInstruction(elements); |
3279 } | 3279 } |
3280 | 3280 |
3281 HValue* key = AddInstruction( | 3281 HValue* key = AddInstruction( |
3282 new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)), | 3282 new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)), |
3283 Representation::Integer32())); | 3283 Representation::Integer32())); |
3284 AddInstruction(new(zone()) HStoreKeyedFastElement(elements, key, value)); | 3284 AddInstruction(new(zone()) HStoreKeyedFastElement(elements, key, value)); |
3285 AddSimulate(expr->GetIdForElement(i)); | 3285 AddSimulate(expr->GetIdForElement(i)); |
3286 } | 3286 } |
3287 return ast_context()->ReturnValue(Pop()); | 3287 return ast_context()->ReturnValue(Pop()); |
3288 } | 3288 } |
(...skipping 610 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3899 HValue* val, | 3899 HValue* val, |
3900 Expression* expr, | 3900 Expression* expr, |
3901 bool is_store) { | 3901 bool is_store) { |
3902 ASSERT(expr->IsMonomorphic()); | 3902 ASSERT(expr->IsMonomorphic()); |
3903 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 3903 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
3904 if (!map->has_fast_elements() && !map->has_external_array_elements()) { | 3904 if (!map->has_fast_elements() && !map->has_external_array_elements()) { |
3905 return is_store ? BuildStoreKeyedGeneric(object, key, val) | 3905 return is_store ? BuildStoreKeyedGeneric(object, key, val) |
3906 : BuildLoadKeyedGeneric(object, key); | 3906 : BuildLoadKeyedGeneric(object, key); |
3907 } | 3907 } |
3908 AddInstruction(new(zone()) HCheckNonSmi(object)); | 3908 AddInstruction(new(zone()) HCheckNonSmi(object)); |
3909 AddInstruction(new(zone()) HCheckMap(object, map)); | 3909 HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMap(object, map)); |
3910 HInstruction* elements = new(zone()) HLoadElements(object); | 3910 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); |
| 3911 if (is_store) { |
| 3912 AddInstruction(new(zone()) HCheckMap( |
| 3913 elements, isolate()->factory()->fixed_array_map())); |
| 3914 } |
3911 HInstruction* length = NULL; | 3915 HInstruction* length = NULL; |
3912 HInstruction* checked_key = NULL; | 3916 HInstruction* checked_key = NULL; |
3913 if (map->has_external_array_elements()) { | 3917 if (map->has_external_array_elements()) { |
3914 AddInstruction(elements); | |
3915 length = AddInstruction(new(zone()) HExternalArrayLength(elements)); | 3918 length = AddInstruction(new(zone()) HExternalArrayLength(elements)); |
3916 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 3919 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
3917 HLoadExternalArrayPointer* external_elements = | 3920 HLoadExternalArrayPointer* external_elements = |
3918 new(zone()) HLoadExternalArrayPointer(elements); | 3921 new(zone()) HLoadExternalArrayPointer(elements); |
3919 AddInstruction(external_elements); | 3922 AddInstruction(external_elements); |
3920 return BuildExternalArrayElementAccess(external_elements, checked_key, | 3923 return BuildExternalArrayElementAccess(external_elements, checked_key, |
3921 val, map->elements_kind(), is_store); | 3924 val, map->elements_kind(), is_store); |
3922 } | 3925 } |
3923 ASSERT(map->has_fast_elements()); | 3926 ASSERT(map->has_fast_elements()); |
3924 if (map->instance_type() == JS_ARRAY_TYPE) { | 3927 if (map->instance_type() == JS_ARRAY_TYPE) { |
3925 length = AddInstruction(new(zone()) HJSArrayLength(object)); | 3928 length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck)); |
3926 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | |
3927 AddInstruction(elements); | |
3928 if (is_store) { | |
3929 AddInstruction(new(zone()) HCheckMap( | |
3930 elements, isolate()->factory()->fixed_array_map())); | |
3931 } | |
3932 } else { | 3929 } else { |
3933 AddInstruction(elements); | |
3934 if (is_store) { | |
3935 AddInstruction(new(zone()) HCheckMap( | |
3936 elements, isolate()->factory()->fixed_array_map())); | |
3937 } | |
3938 length = AddInstruction(new(zone()) HFixedArrayLength(elements)); | 3930 length = AddInstruction(new(zone()) HFixedArrayLength(elements)); |
3939 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | |
3940 } | 3931 } |
| 3932 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
3941 if (is_store) { | 3933 if (is_store) { |
3942 return new(zone()) HStoreKeyedFastElement(elements, checked_key, val); | 3934 return new(zone()) HStoreKeyedFastElement(elements, checked_key, val); |
3943 } else { | 3935 } else { |
3944 return new(zone()) HLoadKeyedFastElement(elements, checked_key); | 3936 return new(zone()) HLoadKeyedFastElement(elements, checked_key); |
3945 } | 3937 } |
3946 } | 3938 } |
3947 | 3939 |
3948 | 3940 |
3949 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, | 3941 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, |
3950 HValue* key, | 3942 HValue* key, |
(...skipping 23 matching lines...) Expand all Loading... |
3974 todo_external_array = true; | 3966 todo_external_array = true; |
3975 } | 3967 } |
3976 } | 3968 } |
3977 // Support for FAST_DOUBLE_ELEMENTS isn't implemented yet, so we deopt. | 3969 // Support for FAST_DOUBLE_ELEMENTS isn't implemented yet, so we deopt. |
3978 type_todo[JSObject::FAST_DOUBLE_ELEMENTS] = false; | 3970 type_todo[JSObject::FAST_DOUBLE_ELEMENTS] = false; |
3979 | 3971 |
3980 HBasicBlock* join = graph()->CreateBasicBlock(); | 3972 HBasicBlock* join = graph()->CreateBasicBlock(); |
3981 | 3973 |
3982 HInstruction* elements_kind_instr = | 3974 HInstruction* elements_kind_instr = |
3983 AddInstruction(new(zone()) HElementsKind(object)); | 3975 AddInstruction(new(zone()) HElementsKind(object)); |
3984 HInstruction* elements = NULL; | 3976 HCompareConstantEqAndBranch* elements_kind_branch = NULL; |
| 3977 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); |
3985 HLoadExternalArrayPointer* external_elements = NULL; | 3978 HLoadExternalArrayPointer* external_elements = NULL; |
3986 HInstruction* checked_key = NULL; | 3979 HInstruction* checked_key = NULL; |
3987 | 3980 |
3988 // FAST_ELEMENTS is assumed to be the first case. | 3981 // FAST_ELEMENTS is assumed to be the first case. |
3989 STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0); | 3982 STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0); |
3990 | 3983 |
3991 for (JSObject::ElementsKind elements_kind = JSObject::FAST_ELEMENTS; | 3984 for (JSObject::ElementsKind elements_kind = JSObject::FAST_ELEMENTS; |
3992 elements_kind <= JSObject::LAST_ELEMENTS_KIND; | 3985 elements_kind <= JSObject::LAST_ELEMENTS_KIND; |
3993 elements_kind = JSObject::ElementsKind(elements_kind + 1)) { | 3986 elements_kind = JSObject::ElementsKind(elements_kind + 1)) { |
3994 // After having handled FAST_ELEMENTS and DICTIONARY_ELEMENTS, we | 3987 // After having handled FAST_ELEMENTS and DICTIONARY_ELEMENTS, we |
3995 // need to add some code that's executed for all external array cases. | 3988 // need to add some code that's executed for all external array cases. |
3996 STATIC_ASSERT(JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND == | 3989 STATIC_ASSERT(JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND == |
3997 JSObject::LAST_ELEMENTS_KIND); | 3990 JSObject::LAST_ELEMENTS_KIND); |
3998 if (elements_kind == JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND | 3991 if (elements_kind == JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND |
3999 && todo_external_array) { | 3992 && todo_external_array) { |
4000 elements = AddInstruction(new(zone()) HLoadElements(object)); | |
4001 // We need to forcibly prevent some ElementsKind-dependent instructions | |
4002 // from being hoisted out of any loops they might occur in, because | |
4003 // the current loop-invariant-code-motion algorithm isn't clever enough | |
4004 // to deal with them properly. | |
4005 // There's some performance to be gained by developing a smarter | |
4006 // solution for this. | |
4007 elements->ClearFlag(HValue::kUseGVN); | |
4008 HInstruction* length = | 3993 HInstruction* length = |
4009 AddInstruction(new(zone()) HExternalArrayLength(elements)); | 3994 AddInstruction(new(zone()) HExternalArrayLength(elements)); |
4010 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 3995 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
4011 external_elements = new(zone()) HLoadExternalArrayPointer(elements); | 3996 external_elements = new(zone()) HLoadExternalArrayPointer(elements); |
4012 AddInstruction(external_elements); | 3997 AddInstruction(external_elements); |
4013 } | 3998 } |
4014 if (type_todo[elements_kind]) { | 3999 if (type_todo[elements_kind]) { |
4015 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 4000 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
4016 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 4001 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
4017 HCompareConstantEqAndBranch* compare = | 4002 elements_kind_branch = new(zone()) HCompareConstantEqAndBranch( |
4018 new(zone()) HCompareConstantEqAndBranch(elements_kind_instr, | 4003 elements_kind_instr, elements_kind, Token::EQ_STRICT); |
4019 elements_kind, | 4004 elements_kind_branch->SetSuccessorAt(0, if_true); |
4020 Token::EQ_STRICT); | 4005 elements_kind_branch->SetSuccessorAt(1, if_false); |
4021 compare->SetSuccessorAt(0, if_true); | 4006 current_block()->Finish(elements_kind_branch); |
4022 compare->SetSuccessorAt(1, if_false); | |
4023 current_block()->Finish(compare); | |
4024 | 4007 |
4025 set_current_block(if_true); | 4008 set_current_block(if_true); |
4026 HInstruction* access; | 4009 HInstruction* access; |
4027 if (elements_kind == JSObject::FAST_ELEMENTS) { | 4010 if (elements_kind == JSObject::FAST_ELEMENTS) { |
| 4011 if (is_store) { |
| 4012 AddInstruction(new(zone()) HCheckMap( |
| 4013 elements, isolate()->factory()->fixed_array_map())); |
| 4014 } |
4028 HBasicBlock* if_jsarray = graph()->CreateBasicBlock(); | 4015 HBasicBlock* if_jsarray = graph()->CreateBasicBlock(); |
4029 HBasicBlock* if_fastobject = graph()->CreateBasicBlock(); | 4016 HBasicBlock* if_fastobject = graph()->CreateBasicBlock(); |
4030 HHasInstanceTypeAndBranch* typecheck = | 4017 HHasInstanceTypeAndBranch* typecheck = |
4031 new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE); | 4018 new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE); |
4032 typecheck->SetSuccessorAt(0, if_jsarray); | 4019 typecheck->SetSuccessorAt(0, if_jsarray); |
4033 typecheck->SetSuccessorAt(1, if_fastobject); | 4020 typecheck->SetSuccessorAt(1, if_fastobject); |
4034 current_block()->Finish(typecheck); | 4021 current_block()->Finish(typecheck); |
4035 | 4022 |
4036 set_current_block(if_jsarray); | 4023 set_current_block(if_jsarray); |
4037 HInstruction* length = new(zone()) HJSArrayLength(object); | 4024 HInstruction* length = new(zone()) HJSArrayLength(object, typecheck); |
4038 AddInstruction(length); | 4025 AddInstruction(length); |
4039 length->ClearFlag(HValue::kUseGVN); | |
4040 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 4026 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
4041 elements = AddInstruction(new(zone()) HLoadElements(object)); | |
4042 elements->ClearFlag(HValue::kUseGVN); | |
4043 if (is_store) { | 4027 if (is_store) { |
4044 AddInstruction(new(zone()) HCheckMap( | |
4045 elements, isolate()->factory()->fixed_array_map())); | |
4046 access = AddInstruction( | 4028 access = AddInstruction( |
4047 new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); | 4029 new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); |
4048 } else { | 4030 } else { |
4049 access = AddInstruction( | 4031 access = AddInstruction( |
4050 new(zone()) HLoadKeyedFastElement(elements, checked_key)); | 4032 new(zone()) HLoadKeyedFastElement(elements, checked_key)); |
4051 Push(access); | 4033 Push(access); |
4052 } | 4034 } |
4053 *has_side_effects |= access->HasSideEffects(); | 4035 *has_side_effects |= access->HasSideEffects(); |
4054 if (position != -1) { | 4036 if (position != -1) { |
4055 access->set_position(position); | 4037 access->set_position(position); |
4056 } | 4038 } |
4057 if_jsarray->Goto(join); | 4039 if_jsarray->Goto(join); |
4058 | 4040 |
4059 set_current_block(if_fastobject); | 4041 set_current_block(if_fastobject); |
4060 elements = AddInstruction(new(zone()) HLoadElements(object)); | |
4061 elements->ClearFlag(HValue::kUseGVN); | |
4062 if (is_store) { | |
4063 AddInstruction(new(zone()) HCheckMap( | |
4064 elements, isolate()->factory()->fixed_array_map())); | |
4065 } | |
4066 length = AddInstruction(new(zone()) HFixedArrayLength(elements)); | 4042 length = AddInstruction(new(zone()) HFixedArrayLength(elements)); |
4067 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 4043 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
4068 if (is_store) { | 4044 if (is_store) { |
4069 access = AddInstruction( | 4045 access = AddInstruction( |
4070 new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); | 4046 new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); |
4071 } else { | 4047 } else { |
4072 access = AddInstruction( | 4048 access = AddInstruction( |
4073 new(zone()) HLoadKeyedFastElement(elements, checked_key)); | 4049 new(zone()) HLoadKeyedFastElement(elements, checked_key)); |
4074 } | 4050 } |
4075 } else if (elements_kind == JSObject::DICTIONARY_ELEMENTS) { | 4051 } else if (elements_kind == JSObject::DICTIONARY_ELEMENTS) { |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4188 expr->RecordTypeFeedback(oracle()); | 4164 expr->RecordTypeFeedback(oracle()); |
4189 | 4165 |
4190 if (TryArgumentsAccess(expr)) return; | 4166 if (TryArgumentsAccess(expr)) return; |
4191 | 4167 |
4192 CHECK_ALIVE(VisitForValue(expr->obj())); | 4168 CHECK_ALIVE(VisitForValue(expr->obj())); |
4193 | 4169 |
4194 HInstruction* instr = NULL; | 4170 HInstruction* instr = NULL; |
4195 if (expr->IsArrayLength()) { | 4171 if (expr->IsArrayLength()) { |
4196 HValue* array = Pop(); | 4172 HValue* array = Pop(); |
4197 AddInstruction(new(zone()) HCheckNonSmi(array)); | 4173 AddInstruction(new(zone()) HCheckNonSmi(array)); |
4198 AddInstruction(HCheckInstanceType::NewIsJSArray(array)); | 4174 HInstruction* mapcheck = |
4199 instr = new(zone()) HJSArrayLength(array); | 4175 AddInstruction(HCheckInstanceType::NewIsJSArray(array)); |
| 4176 instr = new(zone()) HJSArrayLength(array, mapcheck); |
4200 | 4177 |
4201 } else if (expr->IsStringLength()) { | 4178 } else if (expr->IsStringLength()) { |
4202 HValue* string = Pop(); | 4179 HValue* string = Pop(); |
4203 AddInstruction(new(zone()) HCheckNonSmi(string)); | 4180 AddInstruction(new(zone()) HCheckNonSmi(string)); |
4204 AddInstruction(HCheckInstanceType::NewIsString(string)); | 4181 AddInstruction(HCheckInstanceType::NewIsString(string)); |
4205 instr = new(zone()) HStringLength(string); | 4182 instr = new(zone()) HStringLength(string); |
4206 } else if (expr->IsStringAccess()) { | 4183 } else if (expr->IsStringAccess()) { |
4207 CHECK_ALIVE(VisitForValue(expr->key())); | 4184 CHECK_ALIVE(VisitForValue(expr->key())); |
4208 HValue* index = Pop(); | 4185 HValue* index = Pop(); |
4209 HValue* string = Pop(); | 4186 HValue* string = Pop(); |
(...skipping 2496 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6706 } | 6683 } |
6707 } | 6684 } |
6708 | 6685 |
6709 #ifdef DEBUG | 6686 #ifdef DEBUG |
6710 if (graph_ != NULL) graph_->Verify(); | 6687 if (graph_ != NULL) graph_->Verify(); |
6711 if (allocator_ != NULL) allocator_->Verify(); | 6688 if (allocator_ != NULL) allocator_->Verify(); |
6712 #endif | 6689 #endif |
6713 } | 6690 } |
6714 | 6691 |
6715 } } // namespace v8::internal | 6692 } } // namespace v8::internal |
OLD | NEW |