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) {
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);
}
......@@ -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(
Handle<JSFunction> function, Handle<Map> receiver_map, BailoutId ast_id,
int args_count_no_receiver) {
......@@ -8702,6 +8730,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
......@@ -8715,7 +8744,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));
......
......@@ -1801,9 +1801,11 @@ class HGraphBuilder {
HValue* previous_object_size,
HValue* payload);
HInstruction* BuildConstantMapCheck(Handle<JSObject> constant);
HInstruction* BuildConstantMapCheck(Handle<JSObject> constant,
bool ensure_no_elements = false);
HInstruction* BuildCheckPrototypeMaps(Handle<JSObject> prototype,
Handle<JSObject> holder);
Handle<JSObject> holder,
bool ensure_no_elements = false);
HInstruction* BuildGetNativeContext(HValue* closure);
HInstruction* BuildGetNativeContext();
......@@ -2377,6 +2379,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder,
TailCallMode syntactic_tail_call_mode);
static bool IsReadOnlyLengthDescriptor(Handle<Map> jsarray_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
// succeeded if the reason string is NULL and failed if there is a
......
......@@ -173,6 +173,7 @@ class PrototypeIterator {
}
bool IsAtEnd() const { return is_at_end_; }
Isolate* isolate() const { return isolate_; }
private:
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