| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/hydrogen.h" | 5 #include "src/hydrogen.h" |
| 6 | 6 |
| 7 #include <sstream> | 7 #include <sstream> |
| 8 | 8 |
| 9 #include "src/v8.h" | 9 #include "src/v8.h" |
| 10 | 10 |
| (...skipping 913 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 924 DCHECK(did_then_); | 924 DCHECK(did_then_); |
| 925 DCHECK(!captured_); | 925 DCHECK(!captured_); |
| 926 DCHECK(!finished_); | 926 DCHECK(!finished_); |
| 927 AddMergeAtJoinBlock(false); | 927 AddMergeAtJoinBlock(false); |
| 928 builder()->set_current_block(first_false_block_); | 928 builder()->set_current_block(first_false_block_); |
| 929 pending_merge_block_ = true; | 929 pending_merge_block_ = true; |
| 930 did_else_ = true; | 930 did_else_ = true; |
| 931 } | 931 } |
| 932 | 932 |
| 933 | 933 |
| 934 void HGraphBuilder::IfBuilder::Deopt(const char* reason) { | 934 void HGraphBuilder::IfBuilder::Deopt(Deoptimizer::DeoptReason reason) { |
| 935 DCHECK(did_then_); | 935 DCHECK(did_then_); |
| 936 builder()->Add<HDeoptimize>(reason, Deoptimizer::EAGER); | 936 builder()->Add<HDeoptimize>(reason, Deoptimizer::EAGER); |
| 937 AddMergeAtJoinBlock(true); | 937 AddMergeAtJoinBlock(true); |
| 938 } | 938 } |
| 939 | 939 |
| 940 | 940 |
| 941 void HGraphBuilder::IfBuilder::Return(HValue* value) { | 941 void HGraphBuilder::IfBuilder::Return(HValue* value) { |
| 942 HValue* parameter_count = builder()->graph()->GetConstantMinus1(); | 942 HValue* parameter_count = builder()->graph()->GetConstantMinus1(); |
| 943 builder()->FinishExitCurrentBlock( | 943 builder()->FinishExitCurrentBlock( |
| 944 builder()->New<HReturn>(value, parameter_count)); | 944 builder()->New<HReturn>(value, parameter_count)); |
| (...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1266 return BuildDecodeField<Map::ElementsKindBits>(bit_field2); | 1266 return BuildDecodeField<Map::ElementsKindBits>(bit_field2); |
| 1267 } | 1267 } |
| 1268 | 1268 |
| 1269 | 1269 |
| 1270 HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) { | 1270 HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) { |
| 1271 if (obj->type().IsHeapObject()) return obj; | 1271 if (obj->type().IsHeapObject()) return obj; |
| 1272 return Add<HCheckHeapObject>(obj); | 1272 return Add<HCheckHeapObject>(obj); |
| 1273 } | 1273 } |
| 1274 | 1274 |
| 1275 | 1275 |
| 1276 void HGraphBuilder::FinishExitWithHardDeoptimization(const char* reason) { | 1276 void HGraphBuilder::FinishExitWithHardDeoptimization( |
| 1277 Deoptimizer::DeoptReason reason) { |
| 1277 Add<HDeoptimize>(reason, Deoptimizer::EAGER); | 1278 Add<HDeoptimize>(reason, Deoptimizer::EAGER); |
| 1278 FinishExitCurrentBlock(New<HAbnormalExit>()); | 1279 FinishExitCurrentBlock(New<HAbnormalExit>()); |
| 1279 } | 1280 } |
| 1280 | 1281 |
| 1281 | 1282 |
| 1282 HValue* HGraphBuilder::BuildCheckString(HValue* string) { | 1283 HValue* HGraphBuilder::BuildCheckString(HValue* string) { |
| 1283 if (!string->type().IsString()) { | 1284 if (!string->type().IsString()) { |
| 1284 DCHECK(!string->IsConstant() || | 1285 DCHECK(!string->IsConstant() || |
| 1285 !HConstant::cast(string)->HasStringValue()); | 1286 !HConstant::cast(string)->HasStringValue()); |
| 1286 BuildCheckHeapObject(string); | 1287 BuildCheckHeapObject(string); |
| (...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1582 HValue* max_global_type = Add<HConstant>(JS_BUILTINS_OBJECT_TYPE); | 1583 HValue* max_global_type = Add<HConstant>(JS_BUILTINS_OBJECT_TYPE); |
| 1583 | 1584 |
| 1584 IfBuilder if_global_object(this); | 1585 IfBuilder if_global_object(this); |
| 1585 if_global_object.If<HCompareNumericAndBranch>(instance_type, | 1586 if_global_object.If<HCompareNumericAndBranch>(instance_type, |
| 1586 max_global_type, | 1587 max_global_type, |
| 1587 Token::LTE); | 1588 Token::LTE); |
| 1588 if_global_object.And(); | 1589 if_global_object.And(); |
| 1589 if_global_object.If<HCompareNumericAndBranch>(instance_type, | 1590 if_global_object.If<HCompareNumericAndBranch>(instance_type, |
| 1590 min_global_type, | 1591 min_global_type, |
| 1591 Token::GTE); | 1592 Token::GTE); |
| 1592 if_global_object.ThenDeopt("receiver was a global object"); | 1593 if_global_object.ThenDeopt(Deoptimizer::kReceiverWasAGlobalObject); |
| 1593 if_global_object.End(); | 1594 if_global_object.End(); |
| 1594 } | 1595 } |
| 1595 | 1596 |
| 1596 | 1597 |
| 1597 void HGraphBuilder::BuildTestForDictionaryProperties( | 1598 void HGraphBuilder::BuildTestForDictionaryProperties( |
| 1598 HValue* object, | 1599 HValue* object, |
| 1599 HIfContinuation* continuation) { | 1600 HIfContinuation* continuation) { |
| 1600 HValue* properties = Add<HLoadNamedField>( | 1601 HValue* properties = Add<HLoadNamedField>( |
| 1601 object, nullptr, HObjectAccess::ForPropertiesPointer()); | 1602 object, nullptr, HObjectAccess::ForPropertiesPointer()); |
| 1602 HValue* properties_map = | 1603 HValue* properties_map = |
| (...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1912 if_objectiskey.Then(); | 1913 if_objectiskey.Then(); |
| 1913 { | 1914 { |
| 1914 // Make the key_index available. | 1915 // Make the key_index available. |
| 1915 Push(key_index); | 1916 Push(key_index); |
| 1916 } | 1917 } |
| 1917 if_objectiskey.JoinContinuation(&found); | 1918 if_objectiskey.JoinContinuation(&found); |
| 1918 } | 1919 } |
| 1919 if_objectissmi.Else(); | 1920 if_objectissmi.Else(); |
| 1920 { | 1921 { |
| 1921 if (type->Is(Type::SignedSmall())) { | 1922 if (type->Is(Type::SignedSmall())) { |
| 1922 if_objectissmi.Deopt("Expected smi"); | 1923 if_objectissmi.Deopt(Deoptimizer::kExpectedSmi); |
| 1923 } else { | 1924 } else { |
| 1924 // Check if the object is a heap number. | 1925 // Check if the object is a heap number. |
| 1925 IfBuilder if_objectisnumber(this); | 1926 IfBuilder if_objectisnumber(this); |
| 1926 HValue* objectisnumber = if_objectisnumber.If<HCompareMap>( | 1927 HValue* objectisnumber = if_objectisnumber.If<HCompareMap>( |
| 1927 object, isolate()->factory()->heap_number_map()); | 1928 object, isolate()->factory()->heap_number_map()); |
| 1928 if_objectisnumber.Then(); | 1929 if_objectisnumber.Then(); |
| 1929 { | 1930 { |
| 1930 // Compute hash for heap number similar to double_get_hash(). | 1931 // Compute hash for heap number similar to double_get_hash(). |
| 1931 HValue* low = Add<HLoadNamedField>( | 1932 HValue* low = Add<HLoadNamedField>( |
| 1932 object, objectisnumber, | 1933 object, objectisnumber, |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1967 } | 1968 } |
| 1968 if_keyeqobject.JoinContinuation(&found); | 1969 if_keyeqobject.JoinContinuation(&found); |
| 1969 } | 1970 } |
| 1970 if_keyisheapnumber.JoinContinuation(&found); | 1971 if_keyisheapnumber.JoinContinuation(&found); |
| 1971 } | 1972 } |
| 1972 if_keyisnotsmi.JoinContinuation(&found); | 1973 if_keyisnotsmi.JoinContinuation(&found); |
| 1973 } | 1974 } |
| 1974 if_objectisnumber.Else(); | 1975 if_objectisnumber.Else(); |
| 1975 { | 1976 { |
| 1976 if (type->Is(Type::Number())) { | 1977 if (type->Is(Type::Number())) { |
| 1977 if_objectisnumber.Deopt("Expected heap number"); | 1978 if_objectisnumber.Deopt(Deoptimizer::kExpectedHeapNumber); |
| 1978 } | 1979 } |
| 1979 } | 1980 } |
| 1980 if_objectisnumber.JoinContinuation(&found); | 1981 if_objectisnumber.JoinContinuation(&found); |
| 1981 } | 1982 } |
| 1982 } | 1983 } |
| 1983 if_objectissmi.JoinContinuation(&found); | 1984 if_objectissmi.JoinContinuation(&found); |
| 1984 | 1985 |
| 1985 // Check for cache hit. | 1986 // Check for cache hit. |
| 1986 IfBuilder if_found(this, &found); | 1987 IfBuilder if_found(this, &found); |
| 1987 if_found.Then(); | 1988 if_found.Then(); |
| (...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2440 NoObservableSideEffectsScope no_effects(this); | 2441 NoObservableSideEffectsScope no_effects(this); |
| 2441 IfBuilder length_checker(this); | 2442 IfBuilder length_checker(this); |
| 2442 length_checker.If<HCompareNumericAndBranch>(key, length, Token::LT); | 2443 length_checker.If<HCompareNumericAndBranch>(key, length, Token::LT); |
| 2443 length_checker.Then(); | 2444 length_checker.Then(); |
| 2444 IfBuilder negative_checker(this); | 2445 IfBuilder negative_checker(this); |
| 2445 HValue* bounds_check = negative_checker.If<HCompareNumericAndBranch>( | 2446 HValue* bounds_check = negative_checker.If<HCompareNumericAndBranch>( |
| 2446 key, graph()->GetConstant0(), Token::GTE); | 2447 key, graph()->GetConstant0(), Token::GTE); |
| 2447 negative_checker.Then(); | 2448 negative_checker.Then(); |
| 2448 HInstruction* result = AddElementAccess( | 2449 HInstruction* result = AddElementAccess( |
| 2449 backing_store, key, val, bounds_check, elements_kind, access_type); | 2450 backing_store, key, val, bounds_check, elements_kind, access_type); |
| 2450 negative_checker.ElseDeopt("Negative key encountered"); | 2451 negative_checker.ElseDeopt(Deoptimizer::kNegativeKeyEncountered); |
| 2451 negative_checker.End(); | 2452 negative_checker.End(); |
| 2452 length_checker.End(); | 2453 length_checker.End(); |
| 2453 return result; | 2454 return result; |
| 2454 } else { | 2455 } else { |
| 2455 DCHECK(store_mode == STANDARD_STORE); | 2456 DCHECK(store_mode == STANDARD_STORE); |
| 2456 checked_key = Add<HBoundsCheck>(key, length); | 2457 checked_key = Add<HBoundsCheck>(key, length); |
| 2457 return AddElementAccess( | 2458 return AddElementAccess( |
| 2458 backing_store, checked_key, val, | 2459 backing_store, checked_key, val, |
| 2459 checked_object, elements_kind, access_type); | 2460 checked_object, elements_kind, access_type); |
| 2460 } | 2461 } |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2525 Token::EQ); | 2526 Token::EQ); |
| 2526 if_builder.Then(); | 2527 if_builder.Then(); |
| 2527 const int initial_capacity = JSArray::kPreallocatedArrayElements; | 2528 const int initial_capacity = JSArray::kPreallocatedArrayElements; |
| 2528 HConstant* initial_capacity_node = Add<HConstant>(initial_capacity); | 2529 HConstant* initial_capacity_node = Add<HConstant>(initial_capacity); |
| 2529 Push(initial_capacity_node); // capacity | 2530 Push(initial_capacity_node); // capacity |
| 2530 Push(constant_zero); // length | 2531 Push(constant_zero); // length |
| 2531 if_builder.Else(); | 2532 if_builder.Else(); |
| 2532 if (!(top_info()->IsStub()) && | 2533 if (!(top_info()->IsStub()) && |
| 2533 IsFastPackedElementsKind(array_builder->kind())) { | 2534 IsFastPackedElementsKind(array_builder->kind())) { |
| 2534 // We'll come back later with better (holey) feedback. | 2535 // We'll come back later with better (holey) feedback. |
| 2535 if_builder.Deopt("Holey array despite packed elements_kind feedback"); | 2536 if_builder.Deopt( |
| 2537 Deoptimizer::kHoleyArrayDespitePackedElements_kindFeedback); |
| 2536 } else { | 2538 } else { |
| 2537 Push(checked_length); // capacity | 2539 Push(checked_length); // capacity |
| 2538 Push(checked_length); // length | 2540 Push(checked_length); // length |
| 2539 } | 2541 } |
| 2540 if_builder.End(); | 2542 if_builder.End(); |
| 2541 | 2543 |
| 2542 // Figure out total size | 2544 // Figure out total size |
| 2543 HValue* length = Pop(); | 2545 HValue* length = Pop(); |
| 2544 HValue* capacity = Pop(); | 2546 HValue* capacity = Pop(); |
| 2545 return array_builder->AllocateArray(capacity, max_alloc_length, length); | 2547 return array_builder->AllocateArray(capacity, max_alloc_length, length); |
| (...skipping 518 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3064 // emitted below is the actual monomorphic map. | 3066 // emitted below is the actual monomorphic map. |
| 3065 if (map_embedding == kEmbedMapsViaWeakCells) { | 3067 if (map_embedding == kEmbedMapsViaWeakCells) { |
| 3066 HValue* cell = | 3068 HValue* cell = |
| 3067 Add<HConstant>(Map::WeakCellForMap(type->Classes().Current())); | 3069 Add<HConstant>(Map::WeakCellForMap(type->Classes().Current())); |
| 3068 HValue* expected_map = Add<HLoadNamedField>( | 3070 HValue* expected_map = Add<HLoadNamedField>( |
| 3069 cell, nullptr, HObjectAccess::ForWeakCellValue()); | 3071 cell, nullptr, HObjectAccess::ForWeakCellValue()); |
| 3070 HValue* map = | 3072 HValue* map = |
| 3071 Add<HLoadNamedField>(value, nullptr, HObjectAccess::ForMap()); | 3073 Add<HLoadNamedField>(value, nullptr, HObjectAccess::ForMap()); |
| 3072 IfBuilder map_check(this); | 3074 IfBuilder map_check(this); |
| 3073 map_check.IfNot<HCompareObjectEqAndBranch>(expected_map, map); | 3075 map_check.IfNot<HCompareObjectEqAndBranch>(expected_map, map); |
| 3074 map_check.ThenDeopt("Unknown map"); | 3076 map_check.ThenDeopt(Deoptimizer::kUnknownMap); |
| 3075 map_check.End(); | 3077 map_check.End(); |
| 3076 } else { | 3078 } else { |
| 3077 DCHECK(map_embedding == kEmbedMapsDirectly); | 3079 DCHECK(map_embedding == kEmbedMapsDirectly); |
| 3078 Add<HCheckMaps>(value, type->Classes().Current()); | 3080 Add<HCheckMaps>(value, type->Classes().Current()); |
| 3079 } | 3081 } |
| 3080 } else { | 3082 } else { |
| 3081 if_nil.Deopt("Too many undetectable types"); | 3083 if_nil.Deopt(Deoptimizer::kTooManyUndetectableTypes); |
| 3082 } | 3084 } |
| 3083 } | 3085 } |
| 3084 | 3086 |
| 3085 if_nil.CaptureContinuation(continuation); | 3087 if_nil.CaptureContinuation(continuation); |
| 3086 } | 3088 } |
| 3087 | 3089 |
| 3088 | 3090 |
| 3089 void HGraphBuilder::BuildCreateAllocationMemento( | 3091 void HGraphBuilder::BuildCreateAllocationMemento( |
| 3090 HValue* previous_object, | 3092 HValue* previous_object, |
| 3091 HValue* previous_object_size, | 3093 HValue* previous_object_size, |
| (...skipping 3309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6401 } | 6403 } |
| 6402 | 6404 |
| 6403 if (current_block() != NULL) Goto(join); | 6405 if (current_block() != NULL) Goto(join); |
| 6404 set_current_block(if_false); | 6406 set_current_block(if_false); |
| 6405 } | 6407 } |
| 6406 | 6408 |
| 6407 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 6409 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 6408 // know about and do not want to handle ones we've never seen. Otherwise | 6410 // know about and do not want to handle ones we've never seen. Otherwise |
| 6409 // use a generic IC. | 6411 // use a generic IC. |
| 6410 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | 6412 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
| 6411 FinishExitWithHardDeoptimization("Unknown map in polymorphic access"); | 6413 FinishExitWithHardDeoptimization( |
| 6414 Deoptimizer::kUnknownMapInPolymorphicAccess); |
| 6412 } else { | 6415 } else { |
| 6413 HInstruction* instr = BuildNamedGeneric(access_type, expr, object, name, | 6416 HInstruction* instr = BuildNamedGeneric(access_type, expr, object, name, |
| 6414 value); | 6417 value); |
| 6415 AddInstruction(instr); | 6418 AddInstruction(instr); |
| 6416 if (!ast_context()->IsEffect()) Push(access_type == LOAD ? instr : value); | 6419 if (!ast_context()->IsEffect()) Push(access_type == LOAD ? instr : value); |
| 6417 | 6420 |
| 6418 if (join != NULL) { | 6421 if (join != NULL) { |
| 6419 Goto(join); | 6422 Goto(join); |
| 6420 } else { | 6423 } else { |
| 6421 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); | 6424 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6548 | 6551 |
| 6549 LookupIterator it(global, var->name(), LookupIterator::OWN_SKIP_INTERCEPTOR); | 6552 LookupIterator it(global, var->name(), LookupIterator::OWN_SKIP_INTERCEPTOR); |
| 6550 GlobalPropertyAccess type = LookupGlobalProperty(var, &it, STORE); | 6553 GlobalPropertyAccess type = LookupGlobalProperty(var, &it, STORE); |
| 6551 if (type == kUseCell) { | 6554 if (type == kUseCell) { |
| 6552 Handle<PropertyCell> cell = it.GetPropertyCell(); | 6555 Handle<PropertyCell> cell = it.GetPropertyCell(); |
| 6553 if (cell->type()->IsConstant()) { | 6556 if (cell->type()->IsConstant()) { |
| 6554 Handle<Object> constant = cell->type()->AsConstant()->Value(); | 6557 Handle<Object> constant = cell->type()->AsConstant()->Value(); |
| 6555 if (value->IsConstant()) { | 6558 if (value->IsConstant()) { |
| 6556 HConstant* c_value = HConstant::cast(value); | 6559 HConstant* c_value = HConstant::cast(value); |
| 6557 if (!constant.is_identical_to(c_value->handle(isolate()))) { | 6560 if (!constant.is_identical_to(c_value->handle(isolate()))) { |
| 6558 Add<HDeoptimize>("Constant global variable assignment", | 6561 Add<HDeoptimize>(Deoptimizer::kConstantGlobalVariableAssignment, |
| 6559 Deoptimizer::EAGER); | 6562 Deoptimizer::EAGER); |
| 6560 } | 6563 } |
| 6561 } else { | 6564 } else { |
| 6562 HValue* c_constant = Add<HConstant>(constant); | 6565 HValue* c_constant = Add<HConstant>(constant); |
| 6563 IfBuilder builder(this); | 6566 IfBuilder builder(this); |
| 6564 if (constant->IsNumber()) { | 6567 if (constant->IsNumber()) { |
| 6565 builder.If<HCompareNumericAndBranch>(value, c_constant, Token::EQ); | 6568 builder.If<HCompareNumericAndBranch>(value, c_constant, Token::EQ); |
| 6566 } else { | 6569 } else { |
| 6567 builder.If<HCompareObjectEqAndBranch>(value, c_constant); | 6570 builder.If<HCompareObjectEqAndBranch>(value, c_constant); |
| 6568 } | 6571 } |
| 6569 builder.Then(); | 6572 builder.Then(); |
| 6570 builder.Else(); | 6573 builder.Else(); |
| 6571 Add<HDeoptimize>("Constant global variable assignment", | 6574 Add<HDeoptimize>(Deoptimizer::kConstantGlobalVariableAssignment, |
| 6572 Deoptimizer::EAGER); | 6575 Deoptimizer::EAGER); |
| 6573 builder.End(); | 6576 builder.End(); |
| 6574 } | 6577 } |
| 6575 } | 6578 } |
| 6576 HInstruction* instr = | 6579 HInstruction* instr = |
| 6577 Add<HStoreGlobalCell>(value, cell, it.property_details()); | 6580 Add<HStoreGlobalCell>(value, cell, it.property_details()); |
| 6578 if (instr->HasObservableSideEffects()) { | 6581 if (instr->HasObservableSideEffects()) { |
| 6579 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); | 6582 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
| 6580 } | 6583 } |
| 6581 } else { | 6584 } else { |
| (...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6882 | 6885 |
| 6883 | 6886 |
| 6884 HInstruction* HOptimizedGraphBuilder::BuildNamedGeneric( | 6887 HInstruction* HOptimizedGraphBuilder::BuildNamedGeneric( |
| 6885 PropertyAccessType access_type, | 6888 PropertyAccessType access_type, |
| 6886 Expression* expr, | 6889 Expression* expr, |
| 6887 HValue* object, | 6890 HValue* object, |
| 6888 Handle<String> name, | 6891 Handle<String> name, |
| 6889 HValue* value, | 6892 HValue* value, |
| 6890 bool is_uninitialized) { | 6893 bool is_uninitialized) { |
| 6891 if (is_uninitialized) { | 6894 if (is_uninitialized) { |
| 6892 Add<HDeoptimize>("Insufficient type feedback for generic named access", | 6895 Add<HDeoptimize>( |
| 6893 Deoptimizer::SOFT); | 6896 Deoptimizer::kInsufficientTypeFeedbackForGenericNamedAccess, |
| 6897 Deoptimizer::SOFT); |
| 6894 } | 6898 } |
| 6895 if (access_type == LOAD) { | 6899 if (access_type == LOAD) { |
| 6896 HLoadNamedGeneric* result = New<HLoadNamedGeneric>(object, name); | 6900 HLoadNamedGeneric* result = New<HLoadNamedGeneric>(object, name); |
| 6897 if (FLAG_vector_ics) { | 6901 if (FLAG_vector_ics) { |
| 6898 Handle<SharedFunctionInfo> current_shared = | 6902 Handle<SharedFunctionInfo> current_shared = |
| 6899 function_state()->compilation_info()->shared_info(); | 6903 function_state()->compilation_info()->shared_info(); |
| 6900 Handle<TypeFeedbackVector> vector = | 6904 Handle<TypeFeedbackVector> vector = |
| 6901 handle(current_shared->feedback_vector(), isolate()); | 6905 handle(current_shared->feedback_vector(), isolate()); |
| 6902 FeedbackVectorICSlot slot = expr->AsProperty()->PropertyFeedbackSlot(); | 6906 FeedbackVectorICSlot slot = expr->AsProperty()->PropertyFeedbackSlot(); |
| 6903 result->SetVectorAndSlot(vector, slot); | 6907 result->SetVectorAndSlot(vector, slot); |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7183 set_current_block(other_map); | 7187 set_current_block(other_map); |
| 7184 } | 7188 } |
| 7185 | 7189 |
| 7186 // Ensure that we visited at least one map above that goes to join. This is | 7190 // Ensure that we visited at least one map above that goes to join. This is |
| 7187 // necessary because FinishExitWithHardDeoptimization does an AbnormalExit | 7191 // necessary because FinishExitWithHardDeoptimization does an AbnormalExit |
| 7188 // rather than joining the join block. If this becomes an issue, insert a | 7192 // rather than joining the join block. If this becomes an issue, insert a |
| 7189 // generic access in the case length() == 0. | 7193 // generic access in the case length() == 0. |
| 7190 DCHECK(join->predecessors()->length() > 0); | 7194 DCHECK(join->predecessors()->length() > 0); |
| 7191 // Deopt if none of the cases matched. | 7195 // Deopt if none of the cases matched. |
| 7192 NoObservableSideEffectsScope scope(this); | 7196 NoObservableSideEffectsScope scope(this); |
| 7193 FinishExitWithHardDeoptimization("Unknown map in polymorphic element access"); | 7197 FinishExitWithHardDeoptimization( |
| 7198 Deoptimizer::kUnknownMapInPolymorphicElementAccess); |
| 7194 set_current_block(join); | 7199 set_current_block(join); |
| 7195 return access_type == STORE ? val : Pop(); | 7200 return access_type == STORE ? val : Pop(); |
| 7196 } | 7201 } |
| 7197 | 7202 |
| 7198 | 7203 |
| 7199 HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( | 7204 HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( |
| 7200 HValue* obj, HValue* key, HValue* val, Expression* expr, BailoutId ast_id, | 7205 HValue* obj, HValue* key, HValue* val, Expression* expr, BailoutId ast_id, |
| 7201 BailoutId return_id, PropertyAccessType access_type, | 7206 BailoutId return_id, PropertyAccessType access_type, |
| 7202 bool* has_side_effects) { | 7207 bool* has_side_effects) { |
| 7203 // TODO(mvstanton): This optimization causes trouble for vector-based | 7208 // TODO(mvstanton): This optimization causes trouble for vector-based |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7278 obj, key, val, NULL, map, access_type, expr->GetStoreMode()); | 7283 obj, key, val, NULL, map, access_type, expr->GetStoreMode()); |
| 7279 } | 7284 } |
| 7280 } else if (!force_generic && (types != NULL && !types->is_empty())) { | 7285 } else if (!force_generic && (types != NULL && !types->is_empty())) { |
| 7281 return HandlePolymorphicElementAccess( | 7286 return HandlePolymorphicElementAccess( |
| 7282 expr, obj, key, val, types, access_type, | 7287 expr, obj, key, val, types, access_type, |
| 7283 expr->GetStoreMode(), has_side_effects); | 7288 expr->GetStoreMode(), has_side_effects); |
| 7284 } else { | 7289 } else { |
| 7285 if (access_type == STORE) { | 7290 if (access_type == STORE) { |
| 7286 if (expr->IsAssignment() && | 7291 if (expr->IsAssignment() && |
| 7287 expr->AsAssignment()->HasNoTypeInformation()) { | 7292 expr->AsAssignment()->HasNoTypeInformation()) { |
| 7288 Add<HDeoptimize>("Insufficient type feedback for keyed store", | 7293 Add<HDeoptimize>(Deoptimizer::kInsufficientTypeFeedbackForKeyedStore, |
| 7289 Deoptimizer::SOFT); | 7294 Deoptimizer::SOFT); |
| 7290 } | 7295 } |
| 7291 } else { | 7296 } else { |
| 7292 if (expr->AsProperty()->HasNoTypeInformation()) { | 7297 if (expr->AsProperty()->HasNoTypeInformation()) { |
| 7293 Add<HDeoptimize>("Insufficient type feedback for keyed load", | 7298 Add<HDeoptimize>(Deoptimizer::kInsufficientTypeFeedbackForKeyedLoad, |
| 7294 Deoptimizer::SOFT); | 7299 Deoptimizer::SOFT); |
| 7295 } | 7300 } |
| 7296 } | 7301 } |
| 7297 instr = AddInstruction(BuildKeyedGeneric(access_type, expr, obj, key, val)); | 7302 instr = AddInstruction(BuildKeyedGeneric(access_type, expr, obj, key, val)); |
| 7298 } | 7303 } |
| 7299 *has_side_effects = instr->HasObservableSideEffects(); | 7304 *has_side_effects = instr->HasObservableSideEffects(); |
| 7300 return instr; | 7305 return instr; |
| 7301 } | 7306 } |
| 7302 | 7307 |
| 7303 | 7308 |
| (...skipping 424 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7728 } | 7733 } |
| 7729 | 7734 |
| 7730 if (current_block() != NULL) Goto(join); | 7735 if (current_block() != NULL) Goto(join); |
| 7731 set_current_block(if_false); | 7736 set_current_block(if_false); |
| 7732 } | 7737 } |
| 7733 | 7738 |
| 7734 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 7739 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 7735 // know about and do not want to handle ones we've never seen. Otherwise | 7740 // know about and do not want to handle ones we've never seen. Otherwise |
| 7736 // use a generic IC. | 7741 // use a generic IC. |
| 7737 if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) { | 7742 if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) { |
| 7738 FinishExitWithHardDeoptimization("Unknown map in polymorphic call"); | 7743 FinishExitWithHardDeoptimization(Deoptimizer::kUnknownMapInPolymorphicCall); |
| 7739 } else { | 7744 } else { |
| 7740 Property* prop = expr->expression()->AsProperty(); | 7745 Property* prop = expr->expression()->AsProperty(); |
| 7741 HInstruction* function = BuildNamedGeneric( | 7746 HInstruction* function = BuildNamedGeneric( |
| 7742 LOAD, prop, receiver, name, NULL, prop->IsUninitialized()); | 7747 LOAD, prop, receiver, name, NULL, prop->IsUninitialized()); |
| 7743 AddInstruction(function); | 7748 AddInstruction(function); |
| 7744 Push(function); | 7749 Push(function); |
| 7745 AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); | 7750 AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); |
| 7746 | 7751 |
| 7747 environment()->SetExpressionStackAt(1, function); | 7752 environment()->SetExpressionStackAt(1, function); |
| 7748 environment()->SetExpressionStackAt(0, receiver); | 7753 environment()->SetExpressionStackAt(0, receiver); |
| (...skipping 1485 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9234 return; | 9239 return; |
| 9235 } else { | 9240 } else { |
| 9236 call = BuildCallConstantFunction(known_function, argument_count); | 9241 call = BuildCallConstantFunction(known_function, argument_count); |
| 9237 } | 9242 } |
| 9238 | 9243 |
| 9239 } else { | 9244 } else { |
| 9240 ArgumentsAllowedFlag arguments_flag = ARGUMENTS_NOT_ALLOWED; | 9245 ArgumentsAllowedFlag arguments_flag = ARGUMENTS_NOT_ALLOWED; |
| 9241 if (CanBeFunctionApplyArguments(expr) && expr->is_uninitialized()) { | 9246 if (CanBeFunctionApplyArguments(expr) && expr->is_uninitialized()) { |
| 9242 // We have to use EAGER deoptimization here because Deoptimizer::SOFT | 9247 // We have to use EAGER deoptimization here because Deoptimizer::SOFT |
| 9243 // gets ignored by the always-opt flag, which leads to incorrect code. | 9248 // gets ignored by the always-opt flag, which leads to incorrect code. |
| 9244 Add<HDeoptimize>("Insufficient type feedback for call with arguments", | 9249 Add<HDeoptimize>( |
| 9245 Deoptimizer::EAGER); | 9250 Deoptimizer::kInsufficientTypeFeedbackForCallWithArguments, |
| 9251 Deoptimizer::EAGER); |
| 9246 arguments_flag = ARGUMENTS_FAKED; | 9252 arguments_flag = ARGUMENTS_FAKED; |
| 9247 } | 9253 } |
| 9248 | 9254 |
| 9249 // Push the function under the receiver. | 9255 // Push the function under the receiver. |
| 9250 environment()->SetExpressionStackAt(0, function); | 9256 environment()->SetExpressionStackAt(0, function); |
| 9251 Push(receiver); | 9257 Push(receiver); |
| 9252 | 9258 |
| 9253 CHECK_ALIVE(VisitExpressions(expr->arguments(), arguments_flag)); | 9259 CHECK_ALIVE(VisitExpressions(expr->arguments(), arguments_flag)); |
| 9254 CallFunctionFlags flags = receiver->type().IsJSObject() | 9260 CallFunctionFlags flags = receiver->type().IsJSObject() |
| 9255 ? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD; | 9261 ? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD; |
| (...skipping 1209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10465 Representation left_rep = Representation::FromType(left_type); | 10471 Representation left_rep = Representation::FromType(left_type); |
| 10466 Representation right_rep = Representation::FromType(right_type); | 10472 Representation right_rep = Representation::FromType(right_type); |
| 10467 | 10473 |
| 10468 bool maybe_string_add = op == Token::ADD && | 10474 bool maybe_string_add = op == Token::ADD && |
| 10469 (left_type->Maybe(Type::String()) || | 10475 (left_type->Maybe(Type::String()) || |
| 10470 left_type->Maybe(Type::Receiver()) || | 10476 left_type->Maybe(Type::Receiver()) || |
| 10471 right_type->Maybe(Type::String()) || | 10477 right_type->Maybe(Type::String()) || |
| 10472 right_type->Maybe(Type::Receiver())); | 10478 right_type->Maybe(Type::Receiver())); |
| 10473 | 10479 |
| 10474 if (!left_type->IsInhabited()) { | 10480 if (!left_type->IsInhabited()) { |
| 10475 Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation", | 10481 Add<HDeoptimize>( |
| 10476 Deoptimizer::SOFT); | 10482 Deoptimizer::kInsufficientTypeFeedbackForLHSOfBinaryOperation, |
| 10483 Deoptimizer::SOFT); |
| 10477 // TODO(rossberg): we should be able to get rid of non-continuous | 10484 // TODO(rossberg): we should be able to get rid of non-continuous |
| 10478 // defaults. | 10485 // defaults. |
| 10479 left_type = Type::Any(zone()); | 10486 left_type = Type::Any(zone()); |
| 10480 } else { | 10487 } else { |
| 10481 if (!maybe_string_add) left = TruncateToNumber(left, &left_type); | 10488 if (!maybe_string_add) left = TruncateToNumber(left, &left_type); |
| 10482 left_rep = Representation::FromType(left_type); | 10489 left_rep = Representation::FromType(left_type); |
| 10483 } | 10490 } |
| 10484 | 10491 |
| 10485 if (!right_type->IsInhabited()) { | 10492 if (!right_type->IsInhabited()) { |
| 10486 Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation", | 10493 Add<HDeoptimize>( |
| 10487 Deoptimizer::SOFT); | 10494 Deoptimizer::kInsufficientTypeFeedbackForRHSOfBinaryOperation, |
| 10495 Deoptimizer::SOFT); |
| 10488 right_type = Type::Any(zone()); | 10496 right_type = Type::Any(zone()); |
| 10489 } else { | 10497 } else { |
| 10490 if (!maybe_string_add) right = TruncateToNumber(right, &right_type); | 10498 if (!maybe_string_add) right = TruncateToNumber(right, &right_type); |
| 10491 right_rep = Representation::FromType(right_type); | 10499 right_rep = Representation::FromType(right_type); |
| 10492 } | 10500 } |
| 10493 | 10501 |
| 10494 // Special case for string addition here. | 10502 // Special case for string addition here. |
| 10495 if (op == Token::ADD && | 10503 if (op == Token::ADD && |
| 10496 (left_type->Is(Type::String()) || right_type->Is(Type::String()))) { | 10504 (left_type->Is(Type::String()) || right_type->Is(Type::String()))) { |
| 10497 // Validate type feedback for left argument. | 10505 // Validate type feedback for left argument. |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10597 instr = AddUncasted<HMul>(left, right); | 10605 instr = AddUncasted<HMul>(left, right); |
| 10598 break; | 10606 break; |
| 10599 case Token::MOD: { | 10607 case Token::MOD: { |
| 10600 if (fixed_right_arg.has_value && | 10608 if (fixed_right_arg.has_value && |
| 10601 !right->EqualsInteger32Constant(fixed_right_arg.value)) { | 10609 !right->EqualsInteger32Constant(fixed_right_arg.value)) { |
| 10602 HConstant* fixed_right = Add<HConstant>( | 10610 HConstant* fixed_right = Add<HConstant>( |
| 10603 static_cast<int>(fixed_right_arg.value)); | 10611 static_cast<int>(fixed_right_arg.value)); |
| 10604 IfBuilder if_same(this); | 10612 IfBuilder if_same(this); |
| 10605 if_same.If<HCompareNumericAndBranch>(right, fixed_right, Token::EQ); | 10613 if_same.If<HCompareNumericAndBranch>(right, fixed_right, Token::EQ); |
| 10606 if_same.Then(); | 10614 if_same.Then(); |
| 10607 if_same.ElseDeopt("Unexpected RHS of binary operation"); | 10615 if_same.ElseDeopt(Deoptimizer::kUnexpectedRHSOfBinaryOperation); |
| 10608 right = fixed_right; | 10616 right = fixed_right; |
| 10609 } | 10617 } |
| 10610 instr = AddUncasted<HMod>(left, right); | 10618 instr = AddUncasted<HMod>(left, right); |
| 10611 break; | 10619 break; |
| 10612 } | 10620 } |
| 10613 case Token::DIV: | 10621 case Token::DIV: |
| 10614 instr = AddUncasted<HDiv>(left, right); | 10622 instr = AddUncasted<HDiv>(left, right); |
| 10615 break; | 10623 break; |
| 10616 case Token::BIT_XOR: | 10624 case Token::BIT_XOR: |
| 10617 case Token::BIT_AND: | 10625 case Token::BIT_AND: |
| (...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10971 Type* left_type, | 10979 Type* left_type, |
| 10972 Type* right_type, | 10980 Type* right_type, |
| 10973 Type* combined_type, | 10981 Type* combined_type, |
| 10974 HSourcePosition left_position, | 10982 HSourcePosition left_position, |
| 10975 HSourcePosition right_position, | 10983 HSourcePosition right_position, |
| 10976 PushBeforeSimulateBehavior push_sim_result, | 10984 PushBeforeSimulateBehavior push_sim_result, |
| 10977 BailoutId bailout_id) { | 10985 BailoutId bailout_id) { |
| 10978 // Cases handled below depend on collected type feedback. They should | 10986 // Cases handled below depend on collected type feedback. They should |
| 10979 // soft deoptimize when there is no type feedback. | 10987 // soft deoptimize when there is no type feedback. |
| 10980 if (!combined_type->IsInhabited()) { | 10988 if (!combined_type->IsInhabited()) { |
| 10981 Add<HDeoptimize>("Insufficient type feedback for combined type " | 10989 Add<HDeoptimize>( |
| 10982 "of binary operation", | 10990 Deoptimizer::kInsufficientTypeFeedbackForCombinedTypeOfBinaryOperation, |
| 10983 Deoptimizer::SOFT); | 10991 Deoptimizer::SOFT); |
| 10984 combined_type = left_type = right_type = Type::Any(zone()); | 10992 combined_type = left_type = right_type = Type::Any(zone()); |
| 10985 } | 10993 } |
| 10986 | 10994 |
| 10987 Representation left_rep = Representation::FromType(left_type); | 10995 Representation left_rep = Representation::FromType(left_type); |
| 10988 Representation right_rep = Representation::FromType(right_type); | 10996 Representation right_rep = Representation::FromType(right_type); |
| 10989 Representation combined_rep = Representation::FromType(combined_type); | 10997 Representation combined_rep = Representation::FromType(combined_type); |
| 10990 | 10998 |
| 10991 if (combined_type->Is(Type::Receiver())) { | 10999 if (combined_type->Is(Type::Receiver())) { |
| 10992 if (Token::IsEqualityOp(op)) { | 11000 if (Token::IsEqualityOp(op)) { |
| 10993 // HCompareObjectEqAndBranch can only deal with object, so | 11001 // HCompareObjectEqAndBranch can only deal with object, so |
| 10994 // exclude numbers. | 11002 // exclude numbers. |
| 10995 if ((left->IsConstant() && | 11003 if ((left->IsConstant() && |
| 10996 HConstant::cast(left)->HasNumberValue()) || | 11004 HConstant::cast(left)->HasNumberValue()) || |
| 10997 (right->IsConstant() && | 11005 (right->IsConstant() && |
| 10998 HConstant::cast(right)->HasNumberValue())) { | 11006 HConstant::cast(right)->HasNumberValue())) { |
| 10999 Add<HDeoptimize>("Type mismatch between feedback and constant", | 11007 Add<HDeoptimize>(Deoptimizer::kTypeMismatchBetweenFeedbackAndConstant, |
| 11000 Deoptimizer::SOFT); | 11008 Deoptimizer::SOFT); |
| 11001 // The caller expects a branch instruction, so make it happy. | 11009 // The caller expects a branch instruction, so make it happy. |
| 11002 return New<HBranch>(graph()->GetConstantTrue()); | 11010 return New<HBranch>(graph()->GetConstantTrue()); |
| 11003 } | 11011 } |
| 11004 // Can we get away with map check and not instance type check? | 11012 // Can we get away with map check and not instance type check? |
| 11005 HValue* operand_to_check = | 11013 HValue* operand_to_check = |
| 11006 left->block()->block_id() < right->block()->block_id() ? left : right; | 11014 left->block()->block_id() < right->block()->block_id() ? left : right; |
| 11007 if (combined_type->IsClass()) { | 11015 if (combined_type->IsClass()) { |
| 11008 Handle<Map> map = combined_type->AsClass()->Map(); | 11016 Handle<Map> map = combined_type->AsClass()->Map(); |
| 11009 AddCheckMap(operand_to_check, map); | 11017 AddCheckMap(operand_to_check, map); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 11027 return NULL; | 11035 return NULL; |
| 11028 } | 11036 } |
| 11029 } else if (combined_type->Is(Type::InternalizedString()) && | 11037 } else if (combined_type->Is(Type::InternalizedString()) && |
| 11030 Token::IsEqualityOp(op)) { | 11038 Token::IsEqualityOp(op)) { |
| 11031 // If we have a constant argument, it should be consistent with the type | 11039 // If we have a constant argument, it should be consistent with the type |
| 11032 // feedback (otherwise we fail assertions in HCompareObjectEqAndBranch). | 11040 // feedback (otherwise we fail assertions in HCompareObjectEqAndBranch). |
| 11033 if ((left->IsConstant() && | 11041 if ((left->IsConstant() && |
| 11034 !HConstant::cast(left)->HasInternalizedStringValue()) || | 11042 !HConstant::cast(left)->HasInternalizedStringValue()) || |
| 11035 (right->IsConstant() && | 11043 (right->IsConstant() && |
| 11036 !HConstant::cast(right)->HasInternalizedStringValue())) { | 11044 !HConstant::cast(right)->HasInternalizedStringValue())) { |
| 11037 Add<HDeoptimize>("Type mismatch between feedback and constant", | 11045 Add<HDeoptimize>(Deoptimizer::kTypeMismatchBetweenFeedbackAndConstant, |
| 11038 Deoptimizer::SOFT); | 11046 Deoptimizer::SOFT); |
| 11039 // The caller expects a branch instruction, so make it happy. | 11047 // The caller expects a branch instruction, so make it happy. |
| 11040 return New<HBranch>(graph()->GetConstantTrue()); | 11048 return New<HBranch>(graph()->GetConstantTrue()); |
| 11041 } | 11049 } |
| 11042 BuildCheckHeapObject(left); | 11050 BuildCheckHeapObject(left); |
| 11043 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_INTERNALIZED_STRING); | 11051 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_INTERNALIZED_STRING); |
| 11044 BuildCheckHeapObject(right); | 11052 BuildCheckHeapObject(right); |
| 11045 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_INTERNALIZED_STRING); | 11053 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_INTERNALIZED_STRING); |
| 11046 HCompareObjectEqAndBranch* result = | 11054 HCompareObjectEqAndBranch* result = |
| 11047 New<HCompareObjectEqAndBranch>(left, right); | 11055 New<HCompareObjectEqAndBranch>(left, right); |
| (...skipping 2428 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 13476 if (ShouldProduceTraceOutput()) { | 13484 if (ShouldProduceTraceOutput()) { |
| 13477 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 13485 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 13478 } | 13486 } |
| 13479 | 13487 |
| 13480 #ifdef DEBUG | 13488 #ifdef DEBUG |
| 13481 graph_->Verify(false); // No full verify. | 13489 graph_->Verify(false); // No full verify. |
| 13482 #endif | 13490 #endif |
| 13483 } | 13491 } |
| 13484 | 13492 |
| 13485 } } // namespace v8::internal | 13493 } } // namespace v8::internal |
| OLD | NEW |