diff options
Diffstat (limited to 'deps/v8/src/crankshaft/hydrogen.cc')
-rw-r--r-- | deps/v8/src/crankshaft/hydrogen.cc | 204 |
1 files changed, 91 insertions, 113 deletions
diff --git a/deps/v8/src/crankshaft/hydrogen.cc b/deps/v8/src/crankshaft/hydrogen.cc index 754da77c94..9ff2308361 100644 --- a/deps/v8/src/crankshaft/hydrogen.cc +++ b/deps/v8/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<TypeFeedbackVector> vector(current_feedback_vector(), isolate()); + HValue* vector_value = Add<HConstant>(vector); + int index = TypeFeedbackVector::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()); } @@ -5334,7 +5294,8 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) { 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)); @@ -5446,7 +5407,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 +5423,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; @@ -5509,7 +5473,8 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { site_context.ExitScope(site, boilerplate); } else { NoObservableSideEffectsScope no_effects(this); - Handle<FixedArray> constant_properties = expr->constant_properties(); + Handle<FixedArray> constant_properties = + expr->GetOrBuildConstantProperties(isolate()); int literal_index = expr->literal_index(); int flags = expr->ComputeFlags(true); @@ -5558,6 +5523,7 @@ 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()); @@ -5632,7 +5598,8 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { site_context.ExitScope(site, boilerplate_object); } else { NoObservableSideEffectsScope no_effects(this); - Handle<FixedArray> constants = expr->constant_elements(); + Handle<ConstantElementsPair> constants = + expr->GetOrBuildConstantElements(isolate()); int literal_index = expr->literal_index(); int flags = expr->ComputeFlags(true); @@ -5799,9 +5766,8 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField( } // This is a normal store. - instr = New<HStoreNamedField>( - checked_object->ActualValue(), field_access, value, - transition_to_field ? INITIALIZING_STORE : STORE_TO_INITIALIZED_ENTRY); + instr = New<HStoreNamedField>(checked_object->ActualValue(), field_access, + value, info->StoreMode()); } if (transition_to_field) { @@ -7553,6 +7519,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 +7578,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); } @@ -7965,7 +7948,7 @@ int HOptimizedGraphBuilder::InliningAstSize(Handle<JSFunction> target) { if (target_shared->force_inline()) { return 0; } - if (target->shared()->IsBuiltin()) { + if (!target->shared()->IsUserJavaScript()) { return kNotInlinable; } @@ -8078,7 +8061,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 +8144,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 +8470,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 +8741,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 +8755,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 +9683,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; @@ -10973,15 +10970,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); @@ -11208,8 +11202,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 +11497,9 @@ void HOptimizedGraphBuilder::VisitEmptyParentheses(EmptyParentheses* expr) { UNREACHABLE(); } +void HOptimizedGraphBuilder::VisitGetIterator(GetIterator* expr) { + UNREACHABLE(); +} HValue* HOptimizedGraphBuilder::AddThisFunction() { return AddInstruction(BuildThisFunction()); @@ -11653,7 +11651,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); @@ -11847,6 +11846,7 @@ void HOptimizedGraphBuilder::VisitVariableDeclaration( switch (variable->location()) { case VariableLocation::UNALLOCATED: { DCHECK(!variable->binding_needs_init()); + globals_.Add(variable->name(), zone()); FeedbackVectorSlot slot = proxy->VariableFeedbackSlot(); DCHECK(!slot.IsInvalid()); globals_.Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone()); @@ -11885,6 +11885,7 @@ void HOptimizedGraphBuilder::VisitFunctionDeclaration( Variable* variable = proxy->var(); switch (variable->location()) { case VariableLocation::UNALLOCATED: { + globals_.Add(variable->name(), zone()); FeedbackVectorSlot slot = proxy->VariableFeedbackSlot(); DCHECK(!slot.IsInvalid()); globals_.Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone()); @@ -11969,16 +11970,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,19 +12118,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()); |