Index: src/crankshaft/hydrogen.cc |
diff --git a/src/crankshaft/hydrogen.cc b/src/crankshaft/hydrogen.cc |
index d17696d351117250eddbe7c84948ea78ca7085bb..75325a83075ee258cea91a99d92730794fd83d0e 100644 |
--- a/src/crankshaft/hydrogen.cc |
+++ b/src/crankshaft/hydrogen.cc |
@@ -7561,27 +7561,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); |
} |
@@ -8442,6 +8453,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) { |
@@ -8696,6 +8724,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 |
@@ -8709,7 +8738,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)); |