Commit faf80b4e authored by ishell's avatar ishell Committed by Commit bot

[crankshaft] Ensure that we use inlined Array.prototype.shift only when...

[crankshaft] Ensure that we use inlined Array.prototype.shift only when there's no elements in the prototype chain.

BUG=chromium:663340

Review-Url: https://codereview.chromium.org/2593553002
Cr-Commit-Position: refs/heads/master@{#41846}
parent 608df933
...@@ -7567,27 +7567,38 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) { ...@@ -7567,27 +7567,38 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) {
BuildLoad(expr, expr->id()); BuildLoad(expr, expr->id());
} }
HInstruction* HGraphBuilder::BuildConstantMapCheck(Handle<JSObject> constant,
HInstruction* HGraphBuilder::BuildConstantMapCheck(Handle<JSObject> constant) { bool ensure_no_elements) {
HCheckMaps* check = Add<HCheckMaps>( HCheckMaps* check = Add<HCheckMaps>(
Add<HConstant>(constant), handle(constant->map())); Add<HConstant>(constant), handle(constant->map()));
check->ClearDependsOnFlag(kElementsKind); 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; return check;
} }
HInstruction* HGraphBuilder::BuildCheckPrototypeMaps(Handle<JSObject> prototype, HInstruction* HGraphBuilder::BuildCheckPrototypeMaps(Handle<JSObject> prototype,
Handle<JSObject> holder) { Handle<JSObject> holder,
bool ensure_no_elements) {
PrototypeIterator iter(isolate(), prototype, kStartAtReceiver); PrototypeIterator iter(isolate(), prototype, kStartAtReceiver);
while (holder.is_null() || while (holder.is_null() ||
!PrototypeIterator::GetCurrent(iter).is_identical_to(holder)) { !PrototypeIterator::GetCurrent(iter).is_identical_to(holder)) {
BuildConstantMapCheck(PrototypeIterator::GetCurrent<JSObject>(iter)); BuildConstantMapCheck(PrototypeIterator::GetCurrent<JSObject>(iter),
ensure_no_elements);
iter.Advance(); iter.Advance();
if (iter.IsAtEnd()) { if (iter.IsAtEnd()) {
return NULL; return NULL;
} }
} }
return BuildConstantMapCheck(PrototypeIterator::GetCurrent<JSObject>(iter)); return BuildConstantMapCheck(holder);
} }
...@@ -8448,6 +8459,23 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinGetterCall( ...@@ -8448,6 +8459,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( bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
Handle<JSFunction> function, Handle<Map> receiver_map, BailoutId ast_id, Handle<JSFunction> function, Handle<Map> receiver_map, BailoutId ast_id,
int args_count_no_receiver) { int args_count_no_receiver) {
...@@ -8702,6 +8730,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( ...@@ -8702,6 +8730,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
} }
case kArrayShift: { case kArrayShift: {
if (!CanInlineArrayResizeOperation(receiver_map)) return false; if (!CanInlineArrayResizeOperation(receiver_map)) return false;
if (!NoElementsInPrototypeChain(receiver_map)) return false;
ElementsKind kind = receiver_map->elements_kind(); ElementsKind kind = receiver_map->elements_kind();
// If there may be elements accessors in the prototype chain, the fast // If there may be elements accessors in the prototype chain, the fast
...@@ -8715,7 +8744,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( ...@@ -8715,7 +8744,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
// in a map change. // in a map change.
BuildCheckPrototypeMaps( BuildCheckPrototypeMaps(
handle(JSObject::cast(receiver_map->prototype()), isolate()), handle(JSObject::cast(receiver_map->prototype()), isolate()),
Handle<JSObject>::null()); Handle<JSObject>::null(), true);
// Threshold for fast inlined Array.shift(). // Threshold for fast inlined Array.shift().
HConstant* inline_threshold = Add<HConstant>(static_cast<int32_t>(16)); HConstant* inline_threshold = Add<HConstant>(static_cast<int32_t>(16));
......
...@@ -1801,9 +1801,11 @@ class HGraphBuilder { ...@@ -1801,9 +1801,11 @@ class HGraphBuilder {
HValue* previous_object_size, HValue* previous_object_size,
HValue* payload); HValue* payload);
HInstruction* BuildConstantMapCheck(Handle<JSObject> constant); HInstruction* BuildConstantMapCheck(Handle<JSObject> constant,
bool ensure_no_elements = false);
HInstruction* BuildCheckPrototypeMaps(Handle<JSObject> prototype, HInstruction* BuildCheckPrototypeMaps(Handle<JSObject> prototype,
Handle<JSObject> holder); Handle<JSObject> holder,
bool ensure_no_elements = false);
HInstruction* BuildGetNativeContext(HValue* closure); HInstruction* BuildGetNativeContext(HValue* closure);
HInstruction* BuildGetNativeContext(); HInstruction* BuildGetNativeContext();
...@@ -2377,6 +2379,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder, ...@@ -2377,6 +2379,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder,
TailCallMode syntactic_tail_call_mode); TailCallMode syntactic_tail_call_mode);
static bool IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map); static bool IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map);
static bool CanInlineArrayResizeOperation(Handle<Map> receiver_map); static bool CanInlineArrayResizeOperation(Handle<Map> receiver_map);
static bool NoElementsInPrototypeChain(Handle<Map> receiver_map);
// If --trace-inlining, print a line of the inlining trace. Inlining // If --trace-inlining, print a line of the inlining trace. Inlining
// succeeded if the reason string is NULL and failed if there is a // succeeded if the reason string is NULL and failed if there is a
......
...@@ -173,6 +173,7 @@ class PrototypeIterator { ...@@ -173,6 +173,7 @@ class PrototypeIterator {
} }
bool IsAtEnd() const { return is_at_end_; } bool IsAtEnd() const { return is_at_end_; }
Isolate* isolate() const { return isolate_; }
private: private:
Isolate* isolate_; Isolate* isolate_;
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
var expected = undefined;
function foo() {
var a = [0,,{}];
a.shift();
assertEquals(expected, a[0]);
}
foo();
foo();
%OptimizeFunctionOnNextCall(foo);
foo();
expected = 42;
Array.prototype[0] = 153;
Array.prototype[1] = expected;
foo();
function bar() {
var a = [0,,{}];
a.shift();
assertEquals(expected, a[0]);
}
bar();
bar();
%OptimizeFunctionOnNextCall(bar);
bar();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment