diff options
Diffstat (limited to 'src/crankshaft/hydrogen.cc')
-rw-r--r-- | src/crankshaft/hydrogen.cc | 439 |
1 files changed, 228 insertions, 211 deletions
diff --git a/src/crankshaft/hydrogen.cc b/src/crankshaft/hydrogen.cc index 754da77c..d55bb37c 100644 --- a/src/crankshaft/hydrogen.cc +++ b/src/crankshaft/hydrogen.cc @@ -118,7 +118,7 @@ class HOptimizedGraphBuilderWithPositions : public HOptimizedGraphBuilder { HCompilationJob::Status HCompilationJob::PrepareJobImpl() { if (!isolate()->use_crankshaft() || - info()->shared_info()->dont_crankshaft()) { + info()->shared_info()->must_use_ignition_turbo()) { // Crankshaft is entirely disabled. return FAILED; } @@ -142,7 +142,6 @@ HCompilationJob::Status HCompilationJob::PrepareJobImpl() { } } DCHECK(info()->shared_info()->has_deoptimization_support()); - DCHECK(!info()->shared_info()->never_compiled()); // Check the whitelist for Crankshaft. if (!info()->shared_info()->PassesFilter(FLAG_hydrogen_filter)) { @@ -1363,10 +1362,6 @@ HGraph* HGraphBuilder::CreateGraph() { DCHECK(!FLAG_minimal); graph_ = new (zone()) HGraph(info_, descriptor_); if (FLAG_hydrogen_stats) isolate()->GetHStatistics()->Initialize(info_); - if (!info_->IsStub() && is_tracking_positions()) { - TraceInlinedFunction(info_->shared_info(), SourcePosition::Unknown(), - SourcePosition::kNotInlined); - } CompilationPhase phase("H_Block building", info_); set_current_block(graph()->entry_block()); if (!BuildGraph()) return NULL; @@ -1374,49 +1369,6 @@ HGraph* HGraphBuilder::CreateGraph() { return graph_; } -void HGraphBuilder::TraceInlinedFunction(Handle<SharedFunctionInfo> shared, - SourcePosition position, - int inlining_id) { - DCHECK(is_tracking_positions()); - - if (!shared->script()->IsUndefined(isolate())) { - Handle<Script> script(Script::cast(shared->script()), isolate()); - - if (FLAG_hydrogen_track_positions && - !script->source()->IsUndefined(isolate())) { - CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer()); - Object* source_name = script->name(); - OFStream os(tracing_scope.file()); - os << "--- FUNCTION SOURCE ("; - if (source_name->IsString()) { - os << String::cast(source_name)->ToCString().get() << ":"; - } - os << shared->DebugName()->ToCString().get() << ") id{"; - os << info_->optimization_id() << "," << inlining_id << "} ---\n"; - { - DisallowHeapAllocation no_allocation; - int start = shared->start_position(); - int len = shared->end_position() - start; - String::SubStringRange source(String::cast(script->source()), start, - len); - for (const auto& c : source) { - os << AsReversiblyEscapedUC16(c); - } - } - - os << "\n--- END ---\n"; - } - } - - if (FLAG_hydrogen_track_positions && - inlining_id != SourcePosition::kNotInlined) { - CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer()); - OFStream os(tracing_scope.file()); - os << "INLINE (" << shared->DebugName()->ToCString().get() << ") id{" - << info_->optimization_id() << "," << inlining_id << "} AS " - << inlining_id << " AT " << position.ScriptOffset() << std::endl; - } -} HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { DCHECK(current_block() != NULL); @@ -1764,12 +1716,12 @@ HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver, details_index->ClearFlag(HValue::kCanOverflow); HValue* details = Add<HLoadKeyed>(elements, details_index, nullptr, nullptr, FAST_ELEMENTS); - int details_mask = PropertyDetails::TypeField::kMask; + int details_mask = PropertyDetails::KindField::kMask; details = AddUncasted<HBitwise>(Token::BIT_AND, details, Add<HConstant>(details_mask)); IfBuilder details_compare(this); - details_compare.If<HCompareNumericAndBranch>( - details, graph()->GetConstant0(), Token::EQ); + details_compare.If<HCompareNumericAndBranch>(details, New<HConstant>(kData), + Token::EQ); details_compare.Then(); HValue* result_index = AddUncasted<HAdd>(base_index, Add<HConstant>(start_offset + 1)); @@ -2289,6 +2241,9 @@ HValue* HGraphBuilder::BuildUncheckedStringAdd( IfBuilder if_createcons(this); if_createcons.If<HCompareNumericAndBranch>( length, Add<HConstant>(ConsString::kMinLength), Token::GTE); + if_createcons.And(); + if_createcons.If<HCompareNumericAndBranch>( + length, Add<HConstant>(ConsString::kMaxLength), Token::LTE); if_createcons.Then(); { // Create a cons string. @@ -3994,7 +3949,7 @@ void HOptimizedGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs, bool HOptimizedGraphBuilder::BuildGraph() { - if (IsSubclassConstructor(current_info()->literal()->kind())) { + if (IsDerivedConstructor(current_info()->literal()->kind())) { Bailout(kSuperReference); return false; } @@ -5099,18 +5054,23 @@ void HOptimizedGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { // space for nested functions that don't need pretenuring. HConstant* shared_info_value = Add<HConstant>(shared_info); HInstruction* instr; + Handle<FeedbackVector> vector(current_feedback_vector(), isolate()); + HValue* vector_value = Add<HConstant>(vector); + int index = FeedbackVector::GetIndex(expr->LiteralFeedbackSlot()); + HValue* index_value = Add<HConstant>(index); if (!expr->pretenure()) { - FastNewClosureStub stub(isolate()); - FastNewClosureDescriptor descriptor(isolate()); - HValue* values[] = {shared_info_value}; - HConstant* stub_value = Add<HConstant>(stub.GetCode()); - instr = New<HCallWithDescriptor>(stub_value, 0, descriptor, + Callable callable = CodeFactory::FastNewClosure(isolate()); + HValue* values[] = {shared_info_value, vector_value, index_value}; + HConstant* stub_value = Add<HConstant>(callable.code()); + instr = New<HCallWithDescriptor>(stub_value, 0, callable.descriptor(), ArrayVector(values)); } else { Add<HPushArguments>(shared_info_value); + Add<HPushArguments>(vector_value); + Add<HPushArguments>(index_value); Runtime::FunctionId function_id = expr->pretenure() ? Runtime::kNewClosure_Tenured : Runtime::kNewClosure; - instr = New<HCallRuntime>(Runtime::FunctionForId(function_id), 1); + instr = New<HCallRuntime>(Runtime::FunctionForId(function_id), 3); } return ast_context()->ReturnInstruction(instr, expr->id()); } @@ -5326,15 +5286,17 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) { InlineGlobalPropertyLoad(&it, expr->id()); return; } else { - Handle<TypeFeedbackVector> vector(current_feedback_vector(), isolate()); + Handle<FeedbackVector> vector(current_feedback_vector(), isolate()); + FeedbackSlot slot = expr->VariableFeedbackSlot(); + DCHECK(vector->IsLoadGlobalIC(slot)); HValue* vector_value = Add<HConstant>(vector); - HValue* slot_value = - Add<HConstant>(vector->GetIndex(expr->VariableFeedbackSlot())); + HValue* slot_value = Add<HConstant>(vector->GetIndex(slot)); Callable callable = CodeFactory::LoadGlobalICInOptimizedCode( isolate(), ast_context()->typeof_mode()); HValue* stub = Add<HConstant>(callable.code()); - HValue* values[] = {slot_value, vector_value}; + HValue* name = Add<HConstant>(variable->name()); + HValue* values[] = {name, slot_value, vector_value}; HCallWithDescriptor* instr = New<HCallWithDescriptor>( Code::LOAD_GLOBAL_IC, stub, 0, callable.descriptor(), ArrayVector(values)); @@ -5393,7 +5355,8 @@ void HOptimizedGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { DCHECK(current_block() != NULL); DCHECK(current_block()->HasPredecessor()); Callable callable = CodeFactory::FastCloneRegExp(isolate()); - HValue* values[] = {AddThisFunction(), Add<HConstant>(expr->literal_index()), + int index = FeedbackVector::GetIndex(expr->literal_slot()); + HValue* values[] = {AddThisFunction(), Add<HConstant>(index), Add<HConstant>(expr->pattern()), Add<HConstant>(expr->flags())}; HConstant* stub_value = Add<HConstant>(callable.code()); @@ -5446,7 +5409,9 @@ static bool IsFastLiteral(Handle<JSObject> boilerplate, } } } - } else if (!boilerplate->HasFastDoubleElements()) { + } else if (boilerplate->HasFastDoubleElements()) { + if (elements->Size() > kMaxRegularHeapObjectSize) return false; + } else { return false; } } @@ -5460,7 +5425,8 @@ static bool IsFastLiteral(Handle<JSObject> boilerplate, int limit = boilerplate->map()->NumberOfOwnDescriptors(); for (int i = 0; i < limit; i++) { PropertyDetails details = descriptors->GetDetails(i); - if (details.type() != DATA) continue; + if (details.location() != kField) continue; + DCHECK_EQ(kData, details.kind()); if ((*max_properties)-- == 0) return false; FieldIndex field_index = FieldIndex::ForDescriptor(boilerplate->map(), i); if (boilerplate->IsUnboxedDoubleField(field_index)) continue; @@ -5491,7 +5457,7 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { // Check whether to use fast or slow deep-copying for boilerplate. int max_properties = kMaxFastLiteralProperties; Handle<Object> literals_cell( - closure->literals()->literal(expr->literal_index()), isolate()); + closure->feedback_vector()->Get(expr->literal_slot()), isolate()); Handle<AllocationSite> site; Handle<JSObject> boilerplate; if (!literals_cell->IsUndefined(isolate())) { @@ -5509,8 +5475,9 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { site_context.ExitScope(site, boilerplate); } else { NoObservableSideEffectsScope no_effects(this); - Handle<FixedArray> constant_properties = expr->constant_properties(); - int literal_index = expr->literal_index(); + Handle<BoilerplateDescription> constant_properties = + expr->GetOrBuildConstantProperties(isolate()); + int literal_index = FeedbackVector::GetIndex(expr->literal_slot()); int flags = expr->ComputeFlags(true); Add<HPushArguments>(AddThisFunction(), Add<HConstant>(literal_index), @@ -5548,7 +5515,7 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { Handle<Map> map = property->GetReceiverType(); Handle<String> name = key->AsPropertyName(); HValue* store; - FeedbackVectorSlot slot = property->GetSlot(); + FeedbackSlot slot = property->GetSlot(); if (map.is_null()) { // If we don't know the monomorphic type, do a generic store. CHECK_ALIVE(store = BuildNamedGeneric(STORE, NULL, slot, literal, @@ -5558,9 +5525,11 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { if (info.CanAccessMonomorphic()) { HValue* checked_literal = Add<HCheckMaps>(literal, map); DCHECK(!info.IsAccessorConstant()); + info.MarkAsInitializingStore(); store = BuildMonomorphicAccess( &info, literal, checked_literal, value, BailoutId::None(), BailoutId::None()); + DCHECK_NOT_NULL(store); } else { CHECK_ALIVE(store = BuildNamedGeneric(STORE, NULL, slot, literal, name, value)); @@ -5608,10 +5577,9 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { HInstruction* literal; Handle<AllocationSite> site; - Handle<LiteralsArray> literals(environment()->closure()->literals(), - isolate()); - Handle<Object> literals_cell(literals->literal(expr->literal_index()), - isolate()); + Handle<FeedbackVector> vector(environment()->closure()->feedback_vector(), + isolate()); + Handle<Object> literals_cell(vector->Get(expr->literal_slot()), isolate()); Handle<JSObject> boilerplate_object; if (!literals_cell->IsUndefined(isolate())) { DCHECK(literals_cell->IsAllocationSite()); @@ -5632,8 +5600,9 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { site_context.ExitScope(site, boilerplate_object); } else { NoObservableSideEffectsScope no_effects(this); - Handle<FixedArray> constants = expr->constant_elements(); - int literal_index = expr->literal_index(); + Handle<ConstantElementsPair> constants = + expr->GetOrBuildConstantElements(isolate()); + int literal_index = FeedbackVector::GetIndex(expr->literal_slot()); int flags = expr->ComputeFlags(true); Add<HPushArguments>(AddThisFunction(), Add<HConstant>(literal_index), @@ -5711,7 +5680,7 @@ HCheckMaps* HOptimizedGraphBuilder::AddCheckMap(HValue* object, HInstruction* HOptimizedGraphBuilder::BuildLoadNamedField( PropertyAccessInfo* info, HValue* checked_object) { - // See if this is a load for an immutable property + // Check if this is a load of an immutable or constant property. if (checked_object->ActualValue()->IsConstant()) { Handle<Object> object( HConstant::cast(checked_object->ActualValue())->handle(isolate())); @@ -5719,9 +5688,20 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedField( if (object->IsJSObject()) { LookupIterator it(object, info->name(), LookupIterator::OWN_SKIP_INTERCEPTOR); - Handle<Object> value = JSReceiver::GetDataProperty(&it); - if (it.IsFound() && it.IsReadOnly() && !it.IsConfigurable()) { - return New<HConstant>(value); + if (it.IsFound()) { + bool is_reaonly_non_configurable = + it.IsReadOnly() && !it.IsConfigurable(); + if (is_reaonly_non_configurable || + (FLAG_track_constant_fields && info->IsDataConstantField())) { + Handle<Object> value = JSReceiver::GetDataProperty(&it); + if (!is_reaonly_non_configurable) { + DCHECK(!it.is_dictionary_holder()); + // Add dependency on the map that introduced the field. + Handle<Map> field_owner_map = it.GetFieldOwnerMap(); + top_info()->dependencies()->AssumeFieldOwner(field_owner_map); + } + return New<HConstant>(value); + } } } } @@ -5750,15 +5730,17 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedField( checked_object, checked_object, access, maps, info->field_type()); } - -HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField( - PropertyAccessInfo* info, - HValue* checked_object, - HValue* value) { +HValue* HOptimizedGraphBuilder::BuildStoreNamedField(PropertyAccessInfo* info, + HValue* checked_object, + HValue* value) { bool transition_to_field = info->IsTransition(); // TODO(verwaest): Move this logic into PropertyAccessInfo. HObjectAccess field_access = info->access(); + bool store_to_constant_field = FLAG_track_constant_fields && + info->StoreMode() != INITIALIZING_STORE && + info->IsDataConstantField(); + HStoreNamedField *instr; if (field_access.representation().IsDouble() && (!FLAG_unbox_double_fields || !field_access.IsInobject())) { @@ -5784,24 +5766,57 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField( // Already holds a HeapNumber; load the box and write its value field. HInstruction* heap_number = Add<HLoadNamedField>(checked_object, nullptr, heap_number_access); - instr = New<HStoreNamedField>(heap_number, - HObjectAccess::ForHeapNumberValue(), - value, STORE_TO_INITIALIZED_ENTRY); + + if (store_to_constant_field) { + // If the field is constant check that the value we are going to store + // matches current value. + HInstruction* current_value = Add<HLoadNamedField>( + heap_number, nullptr, HObjectAccess::ForHeapNumberValue()); + IfBuilder value_checker(this); + value_checker.IfNot<HCompareNumericAndBranch>(current_value, value, + Token::EQ); + value_checker.ThenDeopt(DeoptimizeReason::kValueMismatch); + value_checker.End(); + return nullptr; + + } else { + instr = New<HStoreNamedField>(heap_number, + HObjectAccess::ForHeapNumberValue(), + value, STORE_TO_INITIALIZED_ENTRY); + } } } else { - if (field_access.representation().IsHeapObject()) { - BuildCheckHeapObject(value); - } + if (store_to_constant_field) { + // If the field is constant check that the value we are going to store + // matches current value. + HInstruction* current_value = Add<HLoadNamedField>( + checked_object->ActualValue(), checked_object, field_access); + + IfBuilder value_checker(this); + if (field_access.representation().IsDouble()) { + value_checker.IfNot<HCompareNumericAndBranch>(current_value, value, + Token::EQ); + } else { + value_checker.IfNot<HCompareObjectEqAndBranch>(current_value, value); + } + value_checker.ThenDeopt(DeoptimizeReason::kValueMismatch); + value_checker.End(); + return nullptr; - if (!info->field_maps()->is_empty()) { - DCHECK(field_access.representation().IsHeapObject()); - value = Add<HCheckMaps>(value, info->field_maps()); - } + } else { + if (field_access.representation().IsHeapObject()) { + BuildCheckHeapObject(value); + } + + if (!info->field_maps()->is_empty()) { + DCHECK(field_access.representation().IsHeapObject()); + value = Add<HCheckMaps>(value, info->field_maps()); + } - // This is a normal store. - instr = New<HStoreNamedField>( - checked_object->ActualValue(), field_access, value, - transition_to_field ? INITIALIZING_STORE : STORE_TO_INITIALIZED_ENTRY); + // This is a normal store. + instr = New<HStoreNamedField>(checked_object->ActualValue(), field_access, + value, info->StoreMode()); + } } if (transition_to_field) { @@ -6185,9 +6200,8 @@ HValue* HOptimizedGraphBuilder::BuildMonomorphicAccess( } } - void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess( - PropertyAccessType access_type, Expression* expr, FeedbackVectorSlot slot, + PropertyAccessType access_type, Expression* expr, FeedbackSlot slot, BailoutId ast_id, BailoutId return_id, HValue* object, HValue* value, SmallMapList* maps, Handle<Name> name) { // Something did not match; must use a polymorphic load. @@ -6385,8 +6399,8 @@ static bool AreStringTypes(SmallMapList* maps) { } void HOptimizedGraphBuilder::BuildStore(Expression* expr, Property* prop, - FeedbackVectorSlot slot, - BailoutId ast_id, BailoutId return_id, + FeedbackSlot slot, BailoutId ast_id, + BailoutId return_id, bool is_uninitialized) { if (!prop->key()->IsPropertyName()) { // Keyed store. @@ -6505,8 +6519,10 @@ HInstruction* HOptimizedGraphBuilder::InlineGlobalPropertyStore( // Because not every expression has a position and there is not common // superclass of Assignment and CountOperation, we cannot just pass the // owning expression instead of position and ast_id separately. -void HOptimizedGraphBuilder::HandleGlobalVariableAssignment( - Variable* var, HValue* value, FeedbackVectorSlot slot, BailoutId ast_id) { +void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(Variable* var, + HValue* value, + FeedbackSlot slot, + BailoutId ast_id) { Handle<JSGlobalObject> global(current_info()->global_object()); // Lookup in script contexts. @@ -6552,11 +6568,12 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment( HValue* global_object = Add<HLoadNamedField>( BuildGetNativeContext(), nullptr, HObjectAccess::ForContextSlot(Context::EXTENSION_INDEX)); - Handle<TypeFeedbackVector> vector = + Handle<FeedbackVector> vector = handle(current_feedback_vector(), isolate()); HValue* name = Add<HConstant>(var->name()); HValue* vector_value = Add<HConstant>(vector); HValue* slot_value = Add<HConstant>(vector->GetIndex(slot)); + DCHECK_EQ(vector->GetLanguageMode(slot), function_language_mode()); Callable callable = CodeFactory::StoreICInOptimizedCode( isolate(), function_language_mode()); HValue* stub = Add<HConstant>(callable.code()); @@ -6852,16 +6869,15 @@ HInstruction* HGraphBuilder::BuildLoadStringLength(HValue* string) { HObjectAccess::ForStringLength()); } - HInstruction* HOptimizedGraphBuilder::BuildNamedGeneric( - PropertyAccessType access_type, Expression* expr, FeedbackVectorSlot slot, + PropertyAccessType access_type, Expression* expr, FeedbackSlot slot, HValue* object, Handle<Name> name, HValue* value, bool is_uninitialized) { if (is_uninitialized) { Add<HDeoptimize>( DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess, Deoptimizer::SOFT); } - Handle<TypeFeedbackVector> vector(current_feedback_vector(), isolate()); + Handle<FeedbackVector> vector(current_feedback_vector(), isolate()); HValue* key = Add<HConstant>(name); HValue* vector_value = Add<HConstant>(vector); @@ -6870,6 +6886,7 @@ HInstruction* HOptimizedGraphBuilder::BuildNamedGeneric( if (access_type == LOAD) { HValue* values[] = {object, key, slot_value, vector_value}; if (!expr->AsProperty()->key()->IsPropertyName()) { + DCHECK(vector->IsKeyedLoadIC(slot)); // It's possible that a keyed load of a constant string was converted // to a named load. Here, at the last minute, we need to make sure to // use a generic Keyed Load if we are using the type vector, because @@ -6881,6 +6898,7 @@ HInstruction* HOptimizedGraphBuilder::BuildNamedGeneric( callable.descriptor(), ArrayVector(values)); return result; } + DCHECK(vector->IsLoadIC(slot)); Callable callable = CodeFactory::LoadICInOptimizedCode(isolate()); HValue* stub = Add<HConstant>(callable.code()); HCallWithDescriptor* result = New<HCallWithDescriptor>( @@ -6889,11 +6907,12 @@ HInstruction* HOptimizedGraphBuilder::BuildNamedGeneric( } else { HValue* values[] = {object, key, value, slot_value, vector_value}; - if (vector->GetKind(slot) == FeedbackVectorSlotKind::KEYED_STORE_IC) { + if (vector->IsKeyedStoreIC(slot)) { // It's possible that a keyed store of a constant string was converted // to a named store. Here, at the last minute, we need to make sure to // use a generic Keyed Store if we are using the type vector, because // it has to share information with full code. + DCHECK_EQ(vector->GetLanguageMode(slot), function_language_mode()); Callable callable = CodeFactory::KeyedStoreICInOptimizedCode( isolate(), function_language_mode()); HValue* stub = Add<HConstant>(callable.code()); @@ -6902,20 +6921,29 @@ HInstruction* HOptimizedGraphBuilder::BuildNamedGeneric( callable.descriptor(), ArrayVector(values)); return result; } - Callable callable = CodeFactory::StoreICInOptimizedCode( - isolate(), function_language_mode()); - HValue* stub = Add<HConstant>(callable.code()); - HCallWithDescriptor* result = New<HCallWithDescriptor>( - Code::STORE_IC, stub, 0, callable.descriptor(), ArrayVector(values)); + HCallWithDescriptor* result; + if (vector->IsStoreOwnIC(slot)) { + Callable callable = CodeFactory::StoreOwnICInOptimizedCode(isolate()); + HValue* stub = Add<HConstant>(callable.code()); + result = New<HCallWithDescriptor>( + Code::STORE_IC, stub, 0, callable.descriptor(), ArrayVector(values)); + } else { + DCHECK(vector->IsStoreIC(slot)); + DCHECK_EQ(vector->GetLanguageMode(slot), function_language_mode()); + Callable callable = CodeFactory::StoreICInOptimizedCode( + isolate(), function_language_mode()); + HValue* stub = Add<HConstant>(callable.code()); + result = New<HCallWithDescriptor>( + Code::STORE_IC, stub, 0, callable.descriptor(), ArrayVector(values)); + } return result; } } - HInstruction* HOptimizedGraphBuilder::BuildKeyedGeneric( - PropertyAccessType access_type, Expression* expr, FeedbackVectorSlot slot, + PropertyAccessType access_type, Expression* expr, FeedbackSlot slot, HValue* object, HValue* key, HValue* value) { - Handle<TypeFeedbackVector> vector(current_feedback_vector(), isolate()); + Handle<FeedbackVector> vector(current_feedback_vector(), isolate()); HValue* vector_value = Add<HConstant>(vector); HValue* slot_value = Add<HConstant>(vector->GetIndex(slot)); @@ -7108,9 +7136,8 @@ HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad( return instr; } - HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( - Expression* expr, FeedbackVectorSlot slot, HValue* object, HValue* key, + Expression* expr, FeedbackSlot slot, HValue* object, HValue* key, HValue* val, SmallMapList* maps, PropertyAccessType access_type, KeyedAccessStoreMode store_mode, bool* has_side_effects) { *has_side_effects = false; @@ -7245,12 +7272,11 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( } HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( - HValue* obj, HValue* key, HValue* val, Expression* expr, - FeedbackVectorSlot slot, BailoutId ast_id, BailoutId return_id, - PropertyAccessType access_type, bool* has_side_effects) { + HValue* obj, HValue* key, HValue* val, Expression* expr, FeedbackSlot slot, + BailoutId ast_id, BailoutId return_id, PropertyAccessType access_type, + bool* has_side_effects) { // A keyed name access with type feedback may contain the name. - Handle<TypeFeedbackVector> vector = - handle(current_feedback_vector(), isolate()); + Handle<FeedbackVector> vector = handle(current_feedback_vector(), isolate()); HValue* expected_key = key; if (!key->ActualValue()->IsConstant()) { Name* name = nullptr; @@ -7474,8 +7500,8 @@ bool HOptimizedGraphBuilder::TryArgumentsAccess(Property* expr) { HValue* HOptimizedGraphBuilder::BuildNamedAccess( PropertyAccessType access, BailoutId ast_id, BailoutId return_id, - Expression* expr, FeedbackVectorSlot slot, HValue* object, - Handle<Name> name, HValue* value, bool is_uninitialized) { + Expression* expr, FeedbackSlot slot, HValue* object, Handle<Name> name, + HValue* value, bool is_uninitialized) { SmallMapList* maps; ComputeReceiverTypes(expr, object, &maps, this); DCHECK(maps != NULL); @@ -7553,6 +7579,12 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr, HValue* string = Pop(); HInstruction* char_code = BuildStringCharCodeAt(string, index); AddInstruction(char_code); + if (char_code->IsConstant()) { + HConstant* c_code = HConstant::cast(char_code); + if (c_code->HasNumberValue() && std::isnan(c_code->DoubleValue())) { + Add<HDeoptimize>(DeoptimizeReason::kOutOfBounds, Deoptimizer::EAGER); + } + } instr = NewUncasted<HStringCharFromCode>(char_code); } else if (expr->key()->IsPropertyName()) { @@ -7606,27 +7638,38 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) { BuildLoad(expr, expr->id()); } - -HInstruction* HGraphBuilder::BuildConstantMapCheck(Handle<JSObject> constant) { +HInstruction* HGraphBuilder::BuildConstantMapCheck(Handle<JSObject> constant, + bool ensure_no_elements) { HCheckMaps* check = Add<HCheckMaps>( Add<HConstant>(constant), handle(constant->map())); check->ClearDependsOnFlag(kElementsKind); + if (ensure_no_elements) { + // TODO(ishell): remove this once we support NO_ELEMENTS elements kind. + HValue* elements = AddLoadElements(check, nullptr); + HValue* empty_elements = + Add<HConstant>(isolate()->factory()->empty_fixed_array()); + IfBuilder if_empty(this); + if_empty.IfNot<HCompareObjectEqAndBranch>(elements, empty_elements); + if_empty.ThenDeopt(DeoptimizeReason::kWrongMap); + if_empty.End(); + } return check; } - HInstruction* HGraphBuilder::BuildCheckPrototypeMaps(Handle<JSObject> prototype, - Handle<JSObject> holder) { + Handle<JSObject> holder, + bool ensure_no_elements) { PrototypeIterator iter(isolate(), prototype, kStartAtReceiver); while (holder.is_null() || !PrototypeIterator::GetCurrent(iter).is_identical_to(holder)) { - BuildConstantMapCheck(PrototypeIterator::GetCurrent<JSObject>(iter)); + BuildConstantMapCheck(PrototypeIterator::GetCurrent<JSObject>(iter), + ensure_no_elements); iter.Advance(); if (iter.IsAtEnd()) { return NULL; } } - return BuildConstantMapCheck(PrototypeIterator::GetCurrent<JSObject>(iter)); + return BuildConstantMapCheck(holder); } @@ -7685,21 +7728,21 @@ HInstruction* HOptimizedGraphBuilder::NewCallFunction( HInstruction* HOptimizedGraphBuilder::NewCallFunctionViaIC( HValue* function, int argument_count, TailCallMode syntactic_tail_call_mode, ConvertReceiverMode convert_mode, TailCallMode tail_call_mode, - FeedbackVectorSlot slot) { + FeedbackSlot slot) { if (syntactic_tail_call_mode == TailCallMode::kAllow) { BuildEnsureCallable(function); } else { DCHECK_EQ(TailCallMode::kDisallow, tail_call_mode); } int arity = argument_count - 1; - Handle<TypeFeedbackVector> vector(current_feedback_vector(), isolate()); + Handle<FeedbackVector> vector(current_feedback_vector(), isolate()); HValue* arity_val = Add<HConstant>(arity); HValue* index_val = Add<HConstant>(vector->GetIndex(slot)); HValue* vector_val = Add<HConstant>(vector); HValue* op_vals[] = {function, arity_val, index_val, vector_val}; - Callable callable = CodeFactory::CallICInOptimizedCode( - isolate(), convert_mode, tail_call_mode); + Callable callable = + CodeFactory::CallIC(isolate(), convert_mode, tail_call_mode); HConstant* stub = Add<HConstant>(callable.code()); return New<HCallWithDescriptor>(stub, argument_count, callable.descriptor(), @@ -7965,7 +8008,7 @@ int HOptimizedGraphBuilder::InliningAstSize(Handle<JSFunction> target) { if (target_shared->force_inline()) { return 0; } - if (target->shared()->IsBuiltin()) { + if (!target->shared()->IsUserJavaScript()) { return kNotInlinable; } @@ -8052,12 +8095,12 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target, // Use the same AstValueFactory for creating strings in the sub-compilation // step, but don't transfer ownership to target_info. Handle<SharedFunctionInfo> target_shared(target->shared()); - ParseInfo parse_info(zone(), target_shared); + ParseInfo parse_info(target_shared, top_info()->parse_info()->zone_shared()); parse_info.set_ast_value_factory( top_info()->parse_info()->ast_value_factory()); parse_info.set_ast_value_factory_owned(false); - CompilationInfo target_info(&parse_info, target); + CompilationInfo target_info(parse_info.zone(), &parse_info, target); if (inlining_kind != CONSTRUCT_CALL_RETURN && IsClassConstructor(target_shared->kind())) { @@ -8078,7 +8121,7 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target, TraceInline(target, caller, "parse failure"); return false; } - if (target_shared->dont_crankshaft()) { + if (target_shared->must_use_ignition_turbo()) { TraceInline(target, caller, "ParseAndAnalyze found incompatibility"); return false; } @@ -8161,10 +8204,6 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target, &bounds_) .Run(); - if (is_tracking_positions()) { - TraceInlinedFunction(target_shared, source_position(), inlining_id); - } - // Save the pending call context. Set up new one for the inlined function. // The function state is new-allocated because we need to delete it // in two different places. @@ -8491,6 +8530,23 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinGetterCall( } } +// static +bool HOptimizedGraphBuilder::NoElementsInPrototypeChain( + Handle<Map> receiver_map) { + // TODO(ishell): remove this once we support NO_ELEMENTS elements kind. + PrototypeIterator iter(receiver_map); + Handle<Object> empty_fixed_array = + iter.isolate()->factory()->empty_fixed_array(); + while (true) { + Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter); + if (current->elements() != *empty_fixed_array) return false; + iter.Advance(); + if (iter.IsAtEnd()) { + return true; + } + } +} + bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( Handle<JSFunction> function, Handle<Map> receiver_map, BailoutId ast_id, int args_count_no_receiver) { @@ -8745,6 +8801,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( } case kArrayShift: { if (!CanInlineArrayResizeOperation(receiver_map)) return false; + if (!NoElementsInPrototypeChain(receiver_map)) return false; ElementsKind kind = receiver_map->elements_kind(); // If there may be elements accessors in the prototype chain, the fast @@ -8758,7 +8815,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( // in a map change. BuildCheckPrototypeMaps( handle(JSObject::cast(receiver_map->prototype()), isolate()), - Handle<JSObject>::null()); + Handle<JSObject>::null(), true); // Threshold for fast inlined Array.shift(). HConstant* inline_threshold = Add<HConstant>(static_cast<int32_t>(16)); @@ -9686,7 +9743,7 @@ bool HOptimizedGraphBuilder::TryInlineArrayCall(Expression* expression, // Checks whether allocation using the given constructor can be inlined. static bool IsAllocationInlineable(Handle<JSFunction> constructor) { return constructor->has_initial_map() && - !IsSubclassConstructor(constructor->shared()->kind()) && + !IsDerivedConstructor(constructor->shared()->kind()) && constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && constructor->initial_map()->instance_size() < HAllocate::kMaxInlineSize; @@ -10404,7 +10461,7 @@ HInstruction* HOptimizedGraphBuilder::BuildIncrement(CountOperation* expr) { } void HOptimizedGraphBuilder::BuildStoreForEffect( - Expression* expr, Property* prop, FeedbackVectorSlot slot, BailoutId ast_id, + Expression* expr, Property* prop, FeedbackSlot slot, BailoutId ast_id, BailoutId return_id, HValue* object, HValue* key, HValue* value) { EffectContext for_effect(this); Push(object); @@ -10973,15 +11030,12 @@ static bool IsClassOfTest(CompareOperation* expr) { Literal* literal = expr->right()->AsLiteral(); if (literal == NULL) return false; if (!literal->value()->IsString()) return false; - if (!call->is_jsruntime() && - call->function()->function_id != Runtime::kInlineClassOf) { - return false; - } - DCHECK(call->arguments()->length() == 1); + if (call->is_jsruntime()) return false; + if (call->function()->function_id != Runtime::kInlineClassOf) return false; + DCHECK_EQ(call->arguments()->length(), 1); return true; } - void HOptimizedGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { DCHECK(!HasStackOverflow()); DCHECK(current_block() != NULL); @@ -11140,11 +11194,9 @@ bool IsLiteralCompareStrict(Isolate* isolate, HValue* left, Token::Value op, return op == Token::EQ_STRICT && ((left->IsConstant() && !HConstant::cast(left)->handle(isolate)->IsNumber() && - !HConstant::cast(left)->handle(isolate)->IsSimd128Value() && !HConstant::cast(left)->handle(isolate)->IsString()) || (right->IsConstant() && !HConstant::cast(right)->handle(isolate)->IsNumber() && - !HConstant::cast(right)->handle(isolate)->IsSimd128Value() && !HConstant::cast(right)->handle(isolate)->IsString())); } @@ -11208,8 +11260,9 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { Handle<JSFunction>::cast(HConstant::cast(right)->handle(isolate())); // Make sure that the {function} already has a meaningful initial map // (i.e. we constructed at least one instance using the constructor - // {function}). - if (function->has_initial_map()) { + // {function}), and has an instance as .prototype. + if (function->has_initial_map() && + !function->map()->has_non_instance_prototype()) { // Lookup @@hasInstance on the {function}. Handle<Map> function_map(function->map(), isolate()); PropertyAccessInfo has_instance( @@ -11502,6 +11555,9 @@ void HOptimizedGraphBuilder::VisitEmptyParentheses(EmptyParentheses* expr) { UNREACHABLE(); } +void HOptimizedGraphBuilder::VisitGetIterator(GetIterator* expr) { + UNREACHABLE(); +} HValue* HOptimizedGraphBuilder::AddThisFunction() { return AddInstruction(BuildThisFunction()); @@ -11653,7 +11709,8 @@ void HOptimizedGraphBuilder::BuildEmitInObjectProperties( int copied_fields = 0; for (int i = 0; i < limit; i++) { PropertyDetails details = descriptors->GetDetails(i); - if (details.type() != DATA) continue; + if (details.location() != kField) continue; + DCHECK_EQ(kData, details.kind()); copied_fields++; FieldIndex field_index = FieldIndex::ForDescriptor(*boilerplate_map, i); @@ -11833,7 +11890,7 @@ void HOptimizedGraphBuilder::VisitDeclarations( isolate()->factory()->NewFixedArray(globals_.length(), TENURED); for (int i = 0; i < globals_.length(); ++i) array->set(i, *globals_.at(i)); int flags = current_info()->GetDeclareGlobalsFlags(); - Handle<TypeFeedbackVector> vector(current_feedback_vector(), isolate()); + Handle<FeedbackVector> vector(current_feedback_vector(), isolate()); Add<HDeclareGlobals>(array, flags, vector); globals_.Rewind(0); } @@ -11847,10 +11904,12 @@ void HOptimizedGraphBuilder::VisitVariableDeclaration( switch (variable->location()) { case VariableLocation::UNALLOCATED: { DCHECK(!variable->binding_needs_init()); - FeedbackVectorSlot slot = proxy->VariableFeedbackSlot(); + globals_.Add(variable->name(), zone()); + FeedbackSlot slot = proxy->VariableFeedbackSlot(); DCHECK(!slot.IsInvalid()); globals_.Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone()); globals_.Add(isolate()->factory()->undefined_value(), zone()); + globals_.Add(isolate()->factory()->undefined_value(), zone()); return; } case VariableLocation::PARAMETER: @@ -11885,9 +11944,16 @@ void HOptimizedGraphBuilder::VisitFunctionDeclaration( Variable* variable = proxy->var(); switch (variable->location()) { case VariableLocation::UNALLOCATED: { - FeedbackVectorSlot slot = proxy->VariableFeedbackSlot(); + globals_.Add(variable->name(), zone()); + FeedbackSlot slot = proxy->VariableFeedbackSlot(); + DCHECK(!slot.IsInvalid()); + globals_.Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone()); + + // We need the slot where the literals array lives, too. + slot = declaration->fun()->LiteralFeedbackSlot(); DCHECK(!slot.IsInvalid()); globals_.Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone()); + Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo( declaration->fun(), current_info()->script(), top_info()); // Check for stack-overflow exception. @@ -11969,16 +12035,6 @@ void HOptimizedGraphBuilder::GenerateIsTypedArray(CallRuntime* call) { } -void HOptimizedGraphBuilder::GenerateIsRegExp(CallRuntime* call) { - DCHECK(call->arguments()->length() == 1); - CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); - HValue* value = Pop(); - HHasInstanceTypeAndBranch* result = - New<HHasInstanceTypeAndBranch>(value, JS_REGEXP_TYPE); - return ast_context()->ReturnControl(result, call->id()); -} - - void HOptimizedGraphBuilder::GenerateToInteger(CallRuntime* call) { DCHECK_EQ(1, call->arguments()->length()); CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); @@ -12127,45 +12183,6 @@ void HOptimizedGraphBuilder::GenerateSubString(CallRuntime* call) { return ast_context()->ReturnInstruction(result, call->id()); } -// Support for direct creation of new objects. -void HOptimizedGraphBuilder::GenerateNewObject(CallRuntime* call) { - DCHECK_EQ(2, call->arguments()->length()); - CHECK_ALIVE(VisitExpressions(call->arguments())); - FastNewObjectStub stub(isolate()); - FastNewObjectDescriptor descriptor(isolate()); - HValue* values[] = {Pop(), Pop()}; - HConstant* stub_value = Add<HConstant>(stub.GetCode()); - HInstruction* result = - New<HCallWithDescriptor>(stub_value, 0, descriptor, ArrayVector(values)); - return ast_context()->ReturnInstruction(result, call->id()); -} - -// Support for direct calls from JavaScript to native RegExp code. -void HOptimizedGraphBuilder::GenerateRegExpExec(CallRuntime* call) { - DCHECK_EQ(4, call->arguments()->length()); - CHECK_ALIVE(VisitExpressions(call->arguments())); - Callable callable = CodeFactory::RegExpExec(isolate()); - HValue* last_match_info = Pop(); - HValue* index = Pop(); - HValue* subject = Pop(); - HValue* regexp_object = Pop(); - HValue* stub = Add<HConstant>(callable.code()); - HValue* values[] = {regexp_object, subject, index, last_match_info}; - HInstruction* result = New<HCallWithDescriptor>( - stub, 0, callable.descriptor(), ArrayVector(values)); - return ast_context()->ReturnInstruction(result, call->id()); -} - - -// Fast support for number to string. -void HOptimizedGraphBuilder::GenerateNumberToString(CallRuntime* call) { - DCHECK_EQ(1, call->arguments()->length()); - CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); - HValue* number = Pop(); - HValue* result = BuildNumberToString(number, AstType::Any()); - return ast_context()->ReturnValue(result); -} - // Fast support for calls. void HOptimizedGraphBuilder::GenerateCall(CallRuntime* call) { |