aboutsummaryrefslogtreecommitdiff
path: root/src/crankshaft/hydrogen.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/crankshaft/hydrogen.cc')
-rw-r--r--src/crankshaft/hydrogen.cc439
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) {