Commit aaab2907 authored by Creddy's avatar Creddy Committed by Commit Bot

[Interpreter] Create and use CallNoFeedback bytecode for one-shot code

We do not have to collect feedback for function calls in one-shot code.
This CL avoids allocating CallICslots for each function call by
emitting CallNoFeedback bytecodes. We save one CallICSlot (two entries
in feedback vector) per function call in One-shot.

Bug: v8:8072
Cq-Include-Trybots: luci.chromium.try:linux_chromium_headless_rel;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: Ic2580e5972acd5124c2e71d540985736ce797fe8
Reviewed-on: https://chromium-review.googlesource.com/1178051
Commit-Queue: Chandan Reddy <chandanreddy@google.com>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55951}
parent 796292a9
......@@ -1790,6 +1790,22 @@ void BytecodeGraphBuilder::VisitCallAnyReceiver() {
BuildCallVarArgs(ConvertReceiverMode::kAny);
}
void BytecodeGraphBuilder::VisitCallNoFeedback() {
PrepareEagerCheckpoint();
// CallNoFeedback is emitted only for one-shot code. Normally the compiler
// will not have to optimize one-shot code. But when the --always-opt or
// --stress-opt flags are set compiler is forced to optimize one-shot code.
// Emiting SoftDeopt to prevent compiler from inlining CallNoFeedback in
// one-shot.
Node* effect = environment()->GetEffectDependency();
Node* control = environment()->GetControlDependency();
JSTypeHintLowering::LoweringResult deoptimize =
type_hint_lowering().BuildSoftDeopt(effect, control,
DeoptimizeReason::kDeoptimizeNow);
ApplyEarlyReduction(deoptimize);
}
void BytecodeGraphBuilder::VisitCallProperty() {
BuildCallVarArgs(ConvertReceiverMode::kNotNullOrUndefined);
}
......
......@@ -492,17 +492,23 @@ JSTypeHintLowering::ReduceStoreKeyedOperation(const Operator* op, Node* obj,
return LoweringResult::NoChange();
}
JSTypeHintLowering::LoweringResult JSTypeHintLowering::BuildSoftDeopt(
Node* effect, Node* control, DeoptimizeReason reason) const {
Node* deoptimize = jsgraph()->graph()->NewNode(
jsgraph()->common()->Deoptimize(DeoptimizeKind::kSoft, reason,
VectorSlotPair()),
jsgraph()->Dead(), effect, control);
Node* frame_state = NodeProperties::FindFrameStateBefore(deoptimize);
deoptimize->ReplaceInput(0, frame_state);
return LoweringResult::Exit(deoptimize);
}
Node* JSTypeHintLowering::TryBuildSoftDeopt(FeedbackNexus& nexus, Node* effect,
Node* control,
DeoptimizeReason reason) const {
if ((flags() & kBailoutOnUninitialized) && nexus.IsUninitialized()) {
Node* deoptimize = jsgraph()->graph()->NewNode(
jsgraph()->common()->Deoptimize(DeoptimizeKind::kSoft, reason,
VectorSlotPair()),
jsgraph()->Dead(), effect, control);
Node* frame_state = NodeProperties::FindFrameStateBefore(deoptimize);
deoptimize->ReplaceInput(0, frame_state);
return deoptimize;
LoweringResult deoptimize = BuildSoftDeopt(effect, control, reason);
return deoptimize.control();
}
return nullptr;
}
......
......@@ -151,6 +151,9 @@ class JSTypeHintLowering {
Node* control,
FeedbackSlot slot) const;
LoweringResult BuildSoftDeopt(Node* effect, Node* control,
DeoptimizeReason reson) const;
private:
friend class JSSpeculativeBinopBuilder;
Node* TryBuildSoftDeopt(FeedbackNexus& nexus, Node* effect, Node* control,
......
......@@ -1380,6 +1380,12 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CallAnyReceiver(Register callable,
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CallNoFeedback(Register callable,
RegisterList args) {
OutputCallNoFeedback(callable, args, args.register_count());
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CallWithSpread(Register callable,
RegisterList args,
int feedback_slot) {
......
......@@ -277,6 +277,11 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final {
BytecodeArrayBuilder& CallAnyReceiver(Register callable, RegisterList args,
int feedback_slot);
// Call a JS function with an any receiver, possibly (but not necessarily)
// undefined. The JSFunction or Callable to be called should be in |callable|.
// The arguments should be in |args|, with the receiver in |args[0]|.
BytecodeArrayBuilder& CallNoFeedback(Register callable, RegisterList args);
// Tail call into a JS function. The JSFunction or Callable to be called
// should be in |callable|. The arguments should be in |args|, with the
// receiver in |args[0]|. Type feedback is recorded in the |feedback_slot| in
......
......@@ -3593,6 +3593,7 @@ void BytecodeGenerator::VisitCall(Call* expr) {
// When a call contains a spread, a Call AST node is only created if there is
// exactly one spread, and it is the last argument.
bool is_spread_call = expr->only_last_arg_is_spread();
bool optimize_as_one_shot = ShouldOptimizeAsOneShot();
// TODO(petermarshall): We have a lot of call bytecodes that are very similar,
// see if we can reduce the number by adding a separate argument which
......@@ -3617,7 +3618,7 @@ void BytecodeGenerator::VisitCall(Call* expr) {
}
case Call::GLOBAL_CALL: {
// Receiver is undefined for global calls.
if (!is_spread_call) {
if (!is_spread_call && !optimize_as_one_shot) {
implicit_undefined_receiver = true;
} else {
// TODO(leszeks): There's no special bytecode for tail calls or spread
......@@ -3653,7 +3654,7 @@ void BytecodeGenerator::VisitCall(Call* expr) {
}
case Call::OTHER_CALL: {
// Receiver is undefined for other calls.
if (!is_spread_call) {
if (!is_spread_call && !optimize_as_one_shot) {
implicit_undefined_receiver = true;
} else {
// TODO(leszeks): There's no special bytecode for tail calls or spread
......@@ -3717,20 +3718,25 @@ void BytecodeGenerator::VisitCall(Call* expr) {
builder()->SetExpressionPosition(expr);
int feedback_slot_index = feedback_index(feedback_spec()->AddCallICSlot());
if (is_spread_call) {
DCHECK(!implicit_undefined_receiver);
builder()->CallWithSpread(callee, args, feedback_slot_index);
builder()->CallWithSpread(callee, args,
feedback_index(feedback_spec()->AddCallICSlot()));
} else if (optimize_as_one_shot) {
DCHECK(!implicit_undefined_receiver);
builder()->CallNoFeedback(callee, args);
} else if (call_type == Call::NAMED_PROPERTY_CALL ||
call_type == Call::KEYED_PROPERTY_CALL ||
call_type == Call::RESOLVED_PROPERTY_CALL) {
DCHECK(!implicit_undefined_receiver);
builder()->CallProperty(callee, args, feedback_slot_index);
builder()->CallProperty(callee, args,
feedback_index(feedback_spec()->AddCallICSlot()));
} else if (implicit_undefined_receiver) {
builder()->CallUndefinedReceiver(callee, args, feedback_slot_index);
builder()->CallUndefinedReceiver(
callee, args, feedback_index(feedback_spec()->AddCallICSlot()));
} else {
builder()->CallAnyReceiver(callee, args, feedback_slot_index);
builder()->CallAnyReceiver(
callee, args, feedback_index(feedback_spec()->AddCallICSlot()));
}
}
......
......@@ -283,6 +283,7 @@ bool Bytecodes::IsStarLookahead(Bytecode bytecode, OperandScale operand_scale) {
case Bytecode::kDec:
case Bytecode::kTypeOf:
case Bytecode::kCallAnyReceiver:
case Bytecode::kCallNoFeedback:
case Bytecode::kCallProperty:
case Bytecode::kCallProperty0:
case Bytecode::kCallProperty1:
......
......@@ -194,6 +194,8 @@ namespace interpreter {
OperandType::kReg, OperandType::kIdx) \
V(CallUndefinedReceiver2, AccumulatorUse::kWrite, OperandType::kReg, \
OperandType::kReg, OperandType::kReg, OperandType::kIdx) \
V(CallNoFeedback, AccumulatorUse::kWrite, OperandType::kReg, \
OperandType::kRegList, OperandType::kRegCount) \
V(CallWithSpread, AccumulatorUse::kWrite, OperandType::kReg, \
OperandType::kRegList, OperandType::kRegCount, OperandType::kIdx) \
V(CallRuntime, AccumulatorUse::kWrite, OperandType::kRuntimeId, \
......@@ -667,6 +669,7 @@ class V8_EXPORT_PRIVATE Bytecodes final : public AllStatic {
bytecode == Bytecode::kCallUndefinedReceiver0 ||
bytecode == Bytecode::kCallUndefinedReceiver1 ||
bytecode == Bytecode::kCallUndefinedReceiver2 ||
bytecode == Bytecode::kCallNoFeedback ||
bytecode == Bytecode::kConstruct ||
bytecode == Bytecode::kCallWithSpread ||
bytecode == Bytecode::kConstructWithSpread ||
......@@ -804,6 +807,7 @@ class V8_EXPORT_PRIVATE Bytecodes final : public AllStatic {
case Bytecode::kCallJSRuntime:
return ConvertReceiverMode::kNullOrUndefined;
case Bytecode::kCallAnyReceiver:
case Bytecode::kCallNoFeedback:
case Bytecode::kConstruct:
case Bytecode::kCallWithSpread:
case Bytecode::kConstructWithSpread:
......
......@@ -1502,6 +1502,16 @@ class InterpreterJSCallAssembler : public InterpreterAssembler {
CallJSAndDispatch(function, context, args, receiver_mode);
}
// Generates code to perform a JS call without collecting feedback.
void JSCallNoFeedback(ConvertReceiverMode receiver_mode) {
Node* function = LoadRegisterAtOperandIndex(0);
RegListNodePair args = GetRegisterListAtOperandIndex(1);
Node* context = GetContext();
// Call the function and dispatch to the next handler.
CallJSAndDispatch(function, context, args, receiver_mode);
}
// Generates code to perform a JS call with a known number of arguments that
// collects type feedback.
void JSCallN(int arg_count, ConvertReceiverMode receiver_mode) {
......@@ -1591,6 +1601,10 @@ IGNITION_HANDLER(CallUndefinedReceiver2, InterpreterJSCallAssembler) {
JSCallN(2, ConvertReceiverMode::kNullOrUndefined);
}
IGNITION_HANDLER(CallNoFeedback, InterpreterJSCallAssembler) {
JSCallNoFeedback(ConvertReceiverMode::kAny);
}
// CallRuntime <function_id> <first_arg> <arg_count>
//
// Call the runtime function |function_id| with the first argument in
......
......@@ -406,3 +406,224 @@ constant pool: [
handlers: [
]
---
snippet: "
this.f0 = function() {};
this.f1 = function(a) {};
this.f2 = function(a, b) {};
this.f3 = function(a, b, c) {};
this.f4 = function(a, b, c, d) {};
this.f5 = function(a, b, c, d, e) {};
(function() {
this.f0();
this.f1(1);
this.f2(1, 2);
this.f3(1, 2, 3);
this.f4(1, 2, 3, 4);
this.f5(1, 2, 3, 4, 5);
return arguments.callee;
})();
"
frame size: 8
parameter count: 1
bytecode array length: 193
bytecodes: [
B(CreateMappedArguments),
B(Star), R(0),
/* 237 E> */ B(StackCheck),
/* 250 S> */ B(LdaConstant), U8(0),
B(Star), R(4),
B(Mov), R(this), R(3),
/* 255 E> */ B(InvokeIntrinsic), U8(Runtime::k_GetProperty), R(3), U8(2),
B(Star), R(1),
/* 255 E> */ B(CallNoFeedback), R(1), R(3), U8(1),
/* 269 S> */ B(LdaConstant), U8(1),
B(Star), R(4),
B(Mov), R(this), R(3),
/* 274 E> */ B(InvokeIntrinsic), U8(Runtime::k_GetProperty), R(3), U8(2),
B(Star), R(1),
B(LdaSmi), I8(1),
B(Star), R(3),
B(Mov), R(this), R(2),
/* 274 E> */ B(CallNoFeedback), R(1), R(2), U8(2),
/* 289 S> */ B(LdaConstant), U8(2),
B(Star), R(4),
B(Mov), R(this), R(3),
/* 294 E> */ B(InvokeIntrinsic), U8(Runtime::k_GetProperty), R(3), U8(2),
B(Star), R(1),
B(LdaSmi), I8(1),
B(Star), R(3),
B(LdaSmi), I8(2),
B(Star), R(4),
B(Mov), R(this), R(2),
/* 294 E> */ B(CallNoFeedback), R(1), R(2), U8(3),
/* 312 S> */ B(LdaConstant), U8(3),
B(Star), R(4),
B(Mov), R(this), R(3),
/* 317 E> */ B(InvokeIntrinsic), U8(Runtime::k_GetProperty), R(3), U8(2),
B(Star), R(1),
B(LdaSmi), I8(1),
B(Star), R(3),
B(LdaSmi), I8(2),
B(Star), R(4),
B(LdaSmi), I8(3),
B(Star), R(5),
B(Mov), R(this), R(2),
/* 317 E> */ B(CallNoFeedback), R(1), R(2), U8(4),
/* 338 S> */ B(LdaConstant), U8(4),
B(Star), R(4),
B(Mov), R(this), R(3),
/* 343 E> */ B(InvokeIntrinsic), U8(Runtime::k_GetProperty), R(3), U8(2),
B(Star), R(1),
B(LdaSmi), I8(1),
B(Star), R(3),
B(LdaSmi), I8(2),
B(Star), R(4),
B(LdaSmi), I8(3),
B(Star), R(5),
B(LdaSmi), I8(4),
B(Star), R(6),
B(Mov), R(this), R(2),
/* 343 E> */ B(CallNoFeedback), R(1), R(2), U8(5),
/* 367 S> */ B(LdaConstant), U8(5),
B(Star), R(4),
B(Mov), R(this), R(3),
/* 372 E> */ B(InvokeIntrinsic), U8(Runtime::k_GetProperty), R(3), U8(2),
B(Star), R(1),
B(LdaSmi), I8(1),
B(Star), R(3),
B(LdaSmi), I8(2),
B(Star), R(4),
B(LdaSmi), I8(3),
B(Star), R(5),
B(LdaSmi), I8(4),
B(Star), R(6),
B(LdaSmi), I8(5),
B(Star), R(7),
B(Mov), R(this), R(2),
/* 372 E> */ B(CallNoFeedback), R(1), R(2), U8(6),
/* 399 S> */ B(LdaConstant), U8(6),
B(Star), R(3),
B(Mov), R(0), R(2),
/* 416 E> */ B(InvokeIntrinsic), U8(Runtime::k_GetProperty), R(2), U8(2),
/* 423 S> */ B(Return),
]
constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f0"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f1"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f2"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f3"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f4"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f5"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["callee"],
]
handlers: [
]
---
snippet: "
function f0() {}
function f1(a) {}
function f2(a, b) {}
function f3(a, b, c) {}
function f4(a, b, c, d) {}
function f5(a, b, c, d, e) {}
(function() {
f0();
f1(1);
f2(1, 2);
f3(1, 2, 3);
f4(1, 2, 3, 4);
f5(1, 2, 3, 4, 5);
return arguments.callee;
})();
"
frame size: 8
parameter count: 1
bytecode array length: 148
bytecodes: [
B(CreateMappedArguments),
B(Star), R(0),
/* 189 E> */ B(StackCheck),
/* 202 S> */ B(LdaUndefined),
B(Star), R(2),
B(LdaGlobal), U8(0), U8(0),
B(Star), R(1),
/* 202 E> */ B(CallNoFeedback), R(1), R(2), U8(1),
/* 216 S> */ B(LdaUndefined),
B(Star), R(2),
B(LdaGlobal), U8(1), U8(2),
B(Star), R(1),
B(LdaSmi), I8(1),
B(Star), R(3),
/* 216 E> */ B(CallNoFeedback), R(1), R(2), U8(2),
/* 231 S> */ B(LdaUndefined),
B(Star), R(2),
B(LdaGlobal), U8(2), U8(4),
B(Star), R(1),
B(LdaSmi), I8(1),
B(Star), R(3),
B(LdaSmi), I8(2),
B(Star), R(4),
/* 231 E> */ B(CallNoFeedback), R(1), R(2), U8(3),
/* 249 S> */ B(LdaUndefined),
B(Star), R(2),
B(LdaGlobal), U8(3), U8(6),
B(Star), R(1),
B(LdaSmi), I8(1),
B(Star), R(3),
B(LdaSmi), I8(2),
B(Star), R(4),
B(LdaSmi), I8(3),
B(Star), R(5),
/* 249 E> */ B(CallNoFeedback), R(1), R(2), U8(4),
/* 270 S> */ B(LdaUndefined),
B(Star), R(2),
B(LdaGlobal), U8(4), U8(8),
B(Star), R(1),
B(LdaSmi), I8(1),
B(Star), R(3),
B(LdaSmi), I8(2),
B(Star), R(4),
B(LdaSmi), I8(3),
B(Star), R(5),
B(LdaSmi), I8(4),
B(Star), R(6),
/* 270 E> */ B(CallNoFeedback), R(1), R(2), U8(5),
/* 294 S> */ B(LdaUndefined),
B(Star), R(2),
B(LdaGlobal), U8(5), U8(10),
B(Star), R(1),
B(LdaSmi), I8(1),
B(Star), R(3),
B(LdaSmi), I8(2),
B(Star), R(4),
B(LdaSmi), I8(3),
B(Star), R(5),
B(LdaSmi), I8(4),
B(Star), R(6),
B(LdaSmi), I8(5),
B(Star), R(7),
/* 294 E> */ B(CallNoFeedback), R(1), R(2), U8(6),
/* 321 S> */ B(LdaConstant), U8(6),
B(Star), R(3),
B(Mov), R(0), R(2),
/* 338 E> */ B(InvokeIntrinsic), U8(Runtime::k_GetProperty), R(2), U8(2),
/* 345 S> */ B(Return),
]
constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f0"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f1"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f2"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f3"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f4"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f5"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["callee"],
]
handlers: [
]
......@@ -107,3 +107,186 @@ constant pool: [
handlers: [
]
---
snippet: "
this.f0 = function() {};
this.f1 = function(a) {};
this.f2 = function(a, b) {};
this.f3 = function(a, b, c) {};
this.f4 = function(a, b, c, d) {};
this.f5 = function(a, b, c, d, e) {};
(function() {
this.f0();
this.f1(1);
this.f2(1, 2);
this.f3(1, 2, 3);
this.f4(1, 2, 3, 4);
this.f5(1, 2, 3, 4, 5);
return arguments.callee;
})();
"
frame size: 8
parameter count: 1
bytecode array length: 144
bytecodes: [
B(CreateMappedArguments),
B(Star), R(0),
/* 237 E> */ B(StackCheck),
/* 255 S> */ B(LdaNamedProperty), R(this), U8(0), U8(0),
B(Star), R(1),
/* 255 E> */ B(CallProperty0), R(1), R(this), U8(2),
/* 274 S> */ B(LdaNamedProperty), R(this), U8(1), U8(4),
B(Star), R(1),
B(LdaSmi), I8(1),
B(Star), R(3),
/* 274 E> */ B(CallProperty1), R(1), R(this), R(3), U8(6),
/* 294 S> */ B(LdaNamedProperty), R(this), U8(2), U8(8),
B(Star), R(1),
B(LdaSmi), I8(1),
B(Star), R(3),
B(LdaSmi), I8(2),
B(Star), R(4),
/* 294 E> */ B(CallProperty2), R(1), R(this), R(3), R(4), U8(10),
/* 317 S> */ B(LdaNamedProperty), R(this), U8(3), U8(12),
B(Star), R(1),
B(LdaSmi), I8(1),
B(Star), R(3),
B(LdaSmi), I8(2),
B(Star), R(4),
B(LdaSmi), I8(3),
B(Star), R(5),
B(Mov), R(this), R(2),
/* 317 E> */ B(CallProperty), R(1), R(2), U8(4), U8(14),
/* 343 S> */ B(LdaNamedProperty), R(this), U8(4), U8(16),
B(Star), R(1),
B(LdaSmi), I8(1),
B(Star), R(3),
B(LdaSmi), I8(2),
B(Star), R(4),
B(LdaSmi), I8(3),
B(Star), R(5),
B(LdaSmi), I8(4),
B(Star), R(6),
B(Mov), R(this), R(2),
/* 343 E> */ B(CallProperty), R(1), R(2), U8(5), U8(18),
/* 372 S> */ B(LdaNamedProperty), R(this), U8(5), U8(20),
B(Star), R(1),
B(LdaSmi), I8(1),
B(Star), R(3),
B(LdaSmi), I8(2),
B(Star), R(4),
B(LdaSmi), I8(3),
B(Star), R(5),
B(LdaSmi), I8(4),
B(Star), R(6),
B(LdaSmi), I8(5),
B(Star), R(7),
B(Mov), R(this), R(2),
/* 372 E> */ B(CallProperty), R(1), R(2), U8(6), U8(22),
/* 416 S> */ B(LdaNamedProperty), R(0), U8(6), U8(24),
/* 423 S> */ B(Return),
]
constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f0"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f1"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f2"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f3"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f4"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f5"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["callee"],
]
handlers: [
]
---
snippet: "
function f0() {}
function f1(a) {}
function f2(a, b) {}
function f3(a, b, c) {}
function f4(a, b, c, d) {}
function f5(a, b, c, d, e) {}
(function() {
f0();
f1(1);
f2(1, 2);
f3(1, 2, 3);
f4(1, 2, 3, 4);
f5(1, 2, 3, 4, 5);
return arguments.callee;
})();
"
frame size: 7
parameter count: 1
bytecode array length: 126
bytecodes: [
B(CreateMappedArguments),
B(Star), R(0),
/* 189 E> */ B(StackCheck),
/* 202 S> */ B(LdaGlobal), U8(0), U8(0),
B(Star), R(1),
/* 202 E> */ B(CallUndefinedReceiver0), R(1), U8(2),
/* 216 S> */ B(LdaGlobal), U8(1), U8(4),
B(Star), R(1),
B(LdaSmi), I8(1),
B(Star), R(2),
/* 216 E> */ B(CallUndefinedReceiver1), R(1), R(2), U8(6),
/* 231 S> */ B(LdaGlobal), U8(2), U8(8),
B(Star), R(1),
B(LdaSmi), I8(1),
B(Star), R(2),
B(LdaSmi), I8(2),
B(Star), R(3),
/* 231 E> */ B(CallUndefinedReceiver2), R(1), R(2), R(3), U8(10),
/* 249 S> */ B(LdaGlobal), U8(3), U8(12),
B(Star), R(1),
B(LdaSmi), I8(1),
B(Star), R(2),
B(LdaSmi), I8(2),
B(Star), R(3),
B(LdaSmi), I8(3),
B(Star), R(4),
/* 249 E> */ B(CallUndefinedReceiver), R(1), R(2), U8(3), U8(14),
/* 270 S> */ B(LdaGlobal), U8(4), U8(16),
B(Star), R(1),
B(LdaSmi), I8(1),
B(Star), R(2),
B(LdaSmi), I8(2),
B(Star), R(3),
B(LdaSmi), I8(3),
B(Star), R(4),
B(LdaSmi), I8(4),
B(Star), R(5),
/* 270 E> */ B(CallUndefinedReceiver), R(1), R(2), U8(4), U8(18),
/* 294 S> */ B(LdaGlobal), U8(5), U8(20),
B(Star), R(1),
B(LdaSmi), I8(1),
B(Star), R(2),
B(LdaSmi), I8(2),
B(Star), R(3),
B(LdaSmi), I8(3),
B(Star), R(4),
B(LdaSmi), I8(4),
B(Star), R(5),
B(LdaSmi), I8(5),
B(Star), R(6),
/* 294 E> */ B(CallUndefinedReceiver), R(1), R(2), U8(5), U8(22),
/* 338 S> */ B(LdaNamedProperty), R(0), U8(6), U8(24),
/* 345 S> */ B(Return),
]
constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f0"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f1"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f2"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f3"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f4"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["f5"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["callee"],
]
handlers: [
]
......@@ -627,6 +627,42 @@ TEST(IIFEWithOneshotOpt) {
return arguments.callee;
})();
)",
// CallNoFeedback instead of CallProperty
R"(
this.f0 = function() {};
this.f1 = function(a) {};
this.f2 = function(a, b) {};
this.f3 = function(a, b, c) {};
this.f4 = function(a, b, c, d) {};
this.f5 = function(a, b, c, d, e) {};
(function() {
this.f0();
this.f1(1);
this.f2(1, 2);
this.f3(1, 2, 3);
this.f4(1, 2, 3, 4);
this.f5(1, 2, 3, 4, 5);
return arguments.callee;
})();
)",
// CallNoFeedback instead of CallUndefinedReceiver
R"(
function f0() {}
function f1(a) {}
function f2(a, b) {}
function f3(a, b, c) {}
function f4(a, b, c, d) {}
function f5(a, b, c, d, e) {}
(function() {
f0();
f1(1);
f2(1, 2);
f3(1, 2, 3);
f4(1, 2, 3, 4);
f5(1, 2, 3, 4, 5);
return arguments.callee;
})();
)",
};
CHECK(CompareTexts(BuildActual(printer, snippets),
LoadGolden("IIFEWithOneshotOpt.golden")));
......@@ -663,6 +699,40 @@ TEST(IIFEWithoutOneshotOpt) {
return arguments.callee;
})();
)",
R"(
this.f0 = function() {};
this.f1 = function(a) {};
this.f2 = function(a, b) {};
this.f3 = function(a, b, c) {};
this.f4 = function(a, b, c, d) {};
this.f5 = function(a, b, c, d, e) {};
(function() {
this.f0();
this.f1(1);
this.f2(1, 2);
this.f3(1, 2, 3);
this.f4(1, 2, 3, 4);
this.f5(1, 2, 3, 4, 5);
return arguments.callee;
})();
)",
R"(
function f0() {}
function f1(a) {}
function f2(a, b) {}
function f3(a, b, c) {}
function f4(a, b, c, d) {}
function f5(a, b, c, d, e) {}
(function() {
f0();
f1(1);
f2(1, 2);
f3(1, 2, 3);
f4(1, 2, 3, 4);
f5(1, 2, 3, 4, 5);
return arguments.callee;
})();
)",
};
CHECK(CompareTexts(BuildActual(printer, snippets),
LoadGolden("IIFEWithoutOneshotOpt.golden")));
......
......@@ -236,6 +236,68 @@ TEST(VectorCallFeedbackForArray) {
CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
}
size_t GetFeedbackVectorLength(Isolate* isolate, const char* src,
bool with_oneshot_opt) {
i::FLAG_enable_one_shot_optimization = with_oneshot_opt;
i::Handle<i::Object> i_object = v8::Utils::OpenHandle(*CompileRun(src));
i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(i_object);
Handle<FeedbackVector> feedback_vector =
Handle<FeedbackVector>(f->feedback_vector(), isolate);
return feedback_vector->length();
}
TEST(OneShotCallICSlotCount) {
if (i::FLAG_always_opt) return;
CcTest::InitializeVM();
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
Isolate* isolate = CcTest::i_isolate();
i::FLAG_compilation_cache = false;
const char* no_call = R"(
function f1() {};
function f2() {};
(function() {
return arguments.callee;
})();
)";
// len = 2 * 1 ldaNamed property
CHECK_EQ(GetFeedbackVectorLength(isolate, no_call, false), 2);
// no slots of named property loads/stores in one shot
CHECK_EQ(GetFeedbackVectorLength(isolate, no_call, true), 0);
const char* single_call = R"(
function f1() {};
function f2() {};
(function() {
f1();
return arguments.callee;
})();
)";
// len = 2 * 1 ldaNamed Slot + 2 * 1 CachedGlobalSlot + 2 * 1 CallICSlot
CHECK_EQ(GetFeedbackVectorLength(isolate, single_call, false), 6);
// len = 2 * 1 CachedGlobalSlot
CHECK_EQ(GetFeedbackVectorLength(isolate, single_call, true), 2);
const char* multiple_calls = R"(
function f1() {};
function f2() {};
(function() {
f1();
f2();
f1();
f2();
return arguments.callee;
})();
)";
// len = 2 * 1 ldaNamedSlot + 2 * 2 CachedGlobalSlot (one for each unique
// function) + 2 * 4 CallICSlot (one for each function call)
CHECK_EQ(GetFeedbackVectorLength(isolate, multiple_calls, false), 14);
// CachedGlobalSlot (one for each unique function)
// len = 2 * 2 CachedGlobalSlot (one for each unique function)
CHECK_EQ(GetFeedbackVectorLength(isolate, multiple_calls, true), 4);
}
TEST(VectorCallCounts) {
if (i::FLAG_always_opt) return;
CcTest::InitializeVM();
......
......@@ -558,6 +558,7 @@ TEST(Issue539892) {
TEST(LogAll) {
SETUP_FLAGS();
i::FLAG_log_all = true;
i::FLAG_turbo_inlining = false;
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
v8::Isolate* isolate = v8::Isolate::New(create_params);
......@@ -583,7 +584,9 @@ TEST(LogAll) {
CHECK(logger.ContainsLine({"api,v8::Script::Run"}));
CHECK(logger.ContainsLine({"code-creation,LazyCompile,", "testAddFn"}));
if (i::FLAG_opt && !i::FLAG_always_opt) {
CHECK(logger.ContainsLine({"code-deopt,", "soft"}));
CHECK(logger.ContainsLine({"code-deopt,", "eager"}));
if (i::FLAG_enable_one_shot_optimization)
CHECK(logger.ContainsLine({"code-deopt,", "soft"}));
CHECK(logger.ContainsLine({"timer-event-start", "V8.DeoptimizeCode"}));
CHECK(logger.ContainsLine({"timer-event-end", "V8.DeoptimizeCode"}));
}
......
......@@ -194,7 +194,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.CallRuntime(Runtime::kIsArray, reg)
.CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, reg_list, pair)
.CallJSRuntime(Context::OBJECT_CREATE, reg_list)
.CallWithSpread(reg, reg_list, 1);
.CallWithSpread(reg, reg_list, 1)
.CallNoFeedback(reg, reg_list);
// Emit binary operator invocations.
builder.BinaryOperation(Token::Value::ADD, reg, 1)
......
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