Commit c4d770b1 authored by leszeks's avatar leszeks Committed by Commit bot

[ignition] Add a property call bytecode

This is a new bytecode which behaves (for now) exactly like Call,
except that in turbofan graph building we can set the
ConvertReceiverMode to NotNullOrUndefined.

I observe a 1% improvement on Box2D, I'd expect a similar improvement on
other OOP heavy code.

Review-Url: https://codereview.chromium.org/2450243002
Cr-Commit-Position: refs/heads/master@{#40610}
parent 88c5a300
......@@ -1252,9 +1252,10 @@ Node* BytecodeGraphBuilder::ProcessCallArguments(const Operator* call_op,
return value;
}
void BytecodeGraphBuilder::BuildCall(TailCallMode tail_call_mode) {
void BytecodeGraphBuilder::BuildCall(TailCallMode tail_call_mode,
ConvertReceiverMode receiver_hint) {
PrepareEagerCheckpoint();
ConvertReceiverMode receiver_hint = ConvertReceiverMode::kAny;
Node* callee =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
interpreter::Register receiver = bytecode_iterator().GetRegisterOperand(1);
......@@ -1273,14 +1274,20 @@ void BytecodeGraphBuilder::BuildCall(TailCallMode tail_call_mode) {
environment()->BindAccumulator(value, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitCall() { BuildCall(TailCallMode::kDisallow); }
void BytecodeGraphBuilder::VisitCall() {
BuildCall(TailCallMode::kDisallow, ConvertReceiverMode::kAny);
}
void BytecodeGraphBuilder::VisitCallProperty() {
BuildCall(TailCallMode::kDisallow, ConvertReceiverMode::kNotNullOrUndefined);
}
void BytecodeGraphBuilder::VisitTailCall() {
TailCallMode tail_call_mode =
bytecode_array_->GetIsolate()->is_tail_call_elimination_enabled()
? TailCallMode::kAllow
: TailCallMode::kDisallow;
BuildCall(tail_call_mode);
BuildCall(tail_call_mode, ConvertReceiverMode::kAny);
}
void BytecodeGraphBuilder::VisitCallJSRuntime() {
......
......@@ -145,7 +145,8 @@ class BytecodeGraphBuilder {
void BuildLdaLookupContextSlot(TypeofMode typeof_mode);
void BuildLdaLookupGlobalSlot(TypeofMode typeof_mode);
void BuildStaLookupSlot(LanguageMode language_mode);
void BuildCall(TailCallMode tail_call_mode);
void BuildCall(TailCallMode tail_call_mode,
ConvertReceiverMode receiver_hint);
void BuildThrow();
void BuildBinaryOp(const Operator* op);
void BuildBinaryOpWithImmediate(const Operator* op);
......
......@@ -824,9 +824,15 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryEnd(int handler_id) {
BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable,
RegisterList args,
int feedback_slot,
Call::CallType call_type,
TailCallMode tail_call_mode) {
if (tail_call_mode == TailCallMode::kDisallow) {
OutputCall(callable, args, args.register_count(), feedback_slot);
if (call_type == Call::NAMED_PROPERTY_CALL ||
call_type == Call::KEYED_PROPERTY_CALL) {
OutputCallProperty(callable, args, args.register_count(), feedback_slot);
} else {
OutputCall(callable, args, args.register_count(), feedback_slot);
}
} else {
DCHECK(tail_call_mode == TailCallMode::kAllow);
OutputTailCall(callable, args, args.register_count(), feedback_slot);
......
......@@ -187,10 +187,11 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
// Call 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 the type
// feedback vector.
// |args[0]|. The call type of the expression is in |call_type|. Type feedback
// is recorded in the |feedback_slot| in the type feedback vector.
BytecodeArrayBuilder& Call(
Register callable, RegisterList args, int feedback_slot,
Call::CallType call_type,
TailCallMode tail_call_mode = TailCallMode::kDisallow);
// Call the new operator. The accumulator holds the |new_target|.
......
......@@ -2494,7 +2494,8 @@ void BytecodeGenerator::VisitCall(Call* expr) {
builder()->SetExpressionPosition(expr);
int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot());
builder()->Call(callee, args, feedback_slot_index, expr->tail_call_mode());
builder()->Call(callee, args, feedback_slot_index, call_type,
expr->tail_call_mode());
}
void BytecodeGenerator::VisitCallSuper(Call* expr) {
......
......@@ -220,6 +220,7 @@ bool Bytecodes::IsStarLookahead(Bytecode bytecode, OperandScale operand_scale) {
case Bytecode::kDec:
case Bytecode::kTypeOf:
case Bytecode::kCall:
case Bytecode::kCallProperty:
case Bytecode::kNew:
return true;
default:
......
......@@ -145,6 +145,8 @@ namespace interpreter {
/* Call operations */ \
V(Call, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kRegList, \
OperandType::kRegCount, OperandType::kIdx) \
V(CallProperty, AccumulatorUse::kWrite, OperandType::kReg, \
OperandType::kRegList, OperandType::kRegCount, OperandType::kIdx) \
V(TailCall, AccumulatorUse::kWrite, OperandType::kReg, \
OperandType::kRegList, OperandType::kRegCount, OperandType::kIdx) \
V(CallRuntime, AccumulatorUse::kWrite, OperandType::kRuntimeId, \
......@@ -525,8 +527,8 @@ class V8_EXPORT_PRIVATE Bytecodes final {
// Returns true if the bytecode is a call or a constructor call.
static CONSTEXPR bool IsCallOrNew(Bytecode bytecode) {
return bytecode == Bytecode::kCall || bytecode == Bytecode::kTailCall ||
bytecode == Bytecode::kNew;
return bytecode == Bytecode::kCall || bytecode == Bytecode::kCallProperty ||
bytecode == Bytecode::kTailCall || bytecode == Bytecode::kNew;
}
// Returns true if the bytecode is a call to the runtime.
......
......@@ -1626,6 +1626,17 @@ void Interpreter::DoCall(InterpreterAssembler* assembler) {
DoJSCall(assembler, TailCallMode::kDisallow);
}
// CallProperty <callable> <receiver> <arg_count> <feedback_slot_id>
//
// Call a JSfunction or Callable in |callable| with the |receiver| and
// |arg_count| arguments in subsequent registers. Collect type feedback into
// |feedback_slot_id|. The callable is known to be a property of the receiver.
void Interpreter::DoCallProperty(InterpreterAssembler* assembler) {
// TODO(leszeks): Look into making the interpreter use the fact that the
// receiver is non-null.
DoJSCall(assembler, TailCallMode::kDisallow);
}
// TailCall <callable> <receiver> <arg_count> <feedback_slot_id>
//
// Tail call a JSfunction or Callable in |callable| with the |receiver| and
......
......@@ -22,10 +22,10 @@ bytecodes: [
B(Star), R(14),
B(LdaConstant), U8(1),
/* 48 E> */ B(LdrKeyedProperty), R(14), U8(4), R(13),
/* 48 E> */ B(Call), R(13), R(14), U8(1), U8(2),
/* 48 E> */ B(CallProperty), R(13), R(14), U8(1), U8(2),
B(Star), R(2),
/* 45 S> */ B(LdrNamedProperty), R(2), U8(2), U8(8), R(14),
/* 45 E> */ B(Call), R(14), R(2), U8(1), U8(6),
/* 45 E> */ B(CallProperty), R(14), R(2), U8(1), U8(6),
B(Star), R(3),
/* 45 E> */ B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(3), U8(1),
B(ToBooleanLogicalNot),
......@@ -160,10 +160,10 @@ bytecodes: [
B(Mov), R(context), R(13),
/* 68 S> */ B(LdaConstant), U8(1),
/* 68 E> */ B(LdrKeyedProperty), R(0), U8(4), R(14),
/* 68 E> */ B(Call), R(14), R(0), U8(1), U8(2),
/* 68 E> */ B(CallProperty), R(14), R(0), U8(1), U8(2),
B(Star), R(3),
/* 65 S> */ B(LdrNamedProperty), R(3), U8(2), U8(8), R(15),
/* 65 E> */ B(Call), R(15), R(3), U8(1), U8(6),
/* 65 E> */ B(CallProperty), R(15), R(3), U8(1), U8(6),
B(Star), R(4),
/* 65 E> */ B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(4), U8(1),
B(ToBooleanLogicalNot),
......@@ -306,10 +306,10 @@ bytecodes: [
B(Star), R(14),
B(LdaConstant), U8(1),
/* 48 E> */ B(LdrKeyedProperty), R(14), U8(4), R(13),
/* 48 E> */ B(Call), R(13), R(14), U8(1), U8(2),
/* 48 E> */ B(CallProperty), R(13), R(14), U8(1), U8(2),
B(Star), R(2),
/* 45 S> */ B(LdrNamedProperty), R(2), U8(2), U8(8), R(14),
/* 45 E> */ B(Call), R(14), R(2), U8(1), U8(6),
/* 45 E> */ B(CallProperty), R(14), R(2), U8(1), U8(6),
B(Star), R(3),
/* 45 E> */ B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(3), U8(1),
B(ToBooleanLogicalNot),
......@@ -454,10 +454,10 @@ bytecodes: [
B(Star), R(13),
B(LdaConstant), U8(2),
/* 77 E> */ B(LdrKeyedProperty), R(13), U8(4), R(12),
/* 77 E> */ B(Call), R(12), R(13), U8(1), U8(2),
/* 77 E> */ B(CallProperty), R(12), R(13), U8(1), U8(2),
B(Star), R(1),
/* 74 S> */ B(LdrNamedProperty), R(1), U8(3), U8(8), R(13),
/* 74 E> */ B(Call), R(13), R(1), U8(1), U8(6),
/* 74 E> */ B(CallProperty), R(13), R(1), U8(1), U8(6),
B(Star), R(2),
/* 74 E> */ B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(2), U8(1),
B(ToBooleanLogicalNot),
......
......@@ -336,7 +336,7 @@ bytecodes: [
B(Star), R(13),
B(LdaConstant), U8(2),
/* 30 E> */ B(LdrKeyedProperty), R(13), U8(4), R(12),
/* 30 E> */ B(Call), R(12), R(13), U8(1), U8(2),
/* 30 E> */ B(CallProperty), R(12), R(13), U8(1), U8(2),
/* 30 E> */ B(StaContextSlot), R(1), U8(7), U8(0),
B(LdaSmi), U8(-2),
B(TestEqual), R(4), U8(0),
......@@ -349,7 +349,7 @@ bytecodes: [
B(CallRuntime), U16(Runtime::kAbort), R(12), U8(1),
/* 27 S> */ B(LdrContextSlot), R(1), U8(7), U8(0), R(14),
B(LdrNamedProperty), R(14), U8(4), U8(8), R(13),
/* 27 E> */ B(Call), R(13), R(14), U8(1), U8(6),
/* 27 E> */ B(CallProperty), R(13), R(14), U8(1), U8(6),
/* 27 E> */ B(StaContextSlot), R(1), U8(8), U8(0),
B(Star), R(12),
B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(12), U8(1),
......
......@@ -18,7 +18,7 @@ bytecodes: [
/* 10 E> */ B(StackCheck),
/* 16 S> */ B(Nop),
/* 24 E> */ B(LdrNamedProperty), R(arg0), U8(0), U8(4), R(0),
/* 25 E> */ B(Call), R(0), R(arg0), U8(1), U8(2),
/* 25 E> */ B(CallProperty), R(0), R(arg0), U8(1), U8(2),
/* 33 S> */ B(Return),
]
constant pool: [
......@@ -43,7 +43,7 @@ bytecodes: [
B(Mov), R(arg0), R(1),
B(Mov), R(arg1), R(2),
B(Mov), R(arg2), R(3),
/* 31 E> */ B(Call), R(0), R(1), U8(3), U8(2),
/* 31 E> */ B(CallProperty), R(0), R(1), U8(3), U8(2),
/* 43 S> */ B(Return),
]
constant pool: [
......@@ -69,7 +69,7 @@ bytecodes: [
B(Star), R(2),
B(Mov), R(arg0), R(1),
B(Mov), R(arg1), R(3),
/* 28 E> */ B(Call), R(0), R(1), U8(3), U8(2),
/* 28 E> */ B(CallProperty), R(0), R(1), U8(3), U8(2),
/* 44 S> */ B(Return),
]
constant pool: [
......@@ -475,7 +475,7 @@ bytecodes: [
/* 1161 E> */ B(Wide), B(LdaNamedProperty), R16(arg0), U16(0), U16(256),
/* 1169 S> */ B(Nop),
/* 1177 E> */ B(Wide), B(LdrNamedProperty), R16(arg0), U16(0), U16(260), R16(0),
/* 1178 E> */ B(Wide), B(Call), R16(0), R16(arg0), U16(1), U16(258),
/* 1178 E> */ B(Wide), B(CallProperty), R16(0), R16(arg0), U16(1), U16(258),
/* 1186 S> */ B(Return),
]
constant pool: [
......
......@@ -55,7 +55,7 @@ bytecodes: [
/* 47 E> */ B(LdrNamedProperty), R(1), U8(1), U8(4), R(0),
B(LdaConstant), U8(2),
B(Star), R(2),
/* 48 E> */ B(Call), R(0), R(1), U8(2), U8(2),
/* 48 E> */ B(CallProperty), R(0), R(1), U8(2), U8(2),
/* 62 S> */ B(Return),
]
constant pool: [
......
......@@ -1255,7 +1255,7 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
.StoreAccumulatorInRegister(reg)
.MoveRegister(builder.Parameter(0), args[0]);
builder.Call(reg, args, call_slot_index, tail_call_mode);
builder.Call(reg, args, call_slot_index, Call::GLOBAL_CALL, tail_call_mode);
builder.Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
......@@ -1277,7 +1277,7 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
builder.LoadNamedProperty(builder.Parameter(0), name, slot_index)
.StoreAccumulatorInRegister(reg)
.MoveRegister(builder.Parameter(0), args[0]);
builder.Call(reg, args, call_slot_index, tail_call_mode);
builder.Call(reg, args, call_slot_index, Call::GLOBAL_CALL, tail_call_mode);
builder.Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
......@@ -1308,7 +1308,7 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
.LoadLiteral(Smi::FromInt(11))
.StoreAccumulatorInRegister(args[2]);
builder.Call(reg, args, call_slot_index, tail_call_mode);
builder.Call(reg, args, call_slot_index, Call::GLOBAL_CALL, tail_call_mode);
builder.Return();
......@@ -1356,7 +1356,7 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
.LoadLiteral(factory->NewStringFromAsciiChecked("j"))
.StoreAccumulatorInRegister(args[10]);
builder.Call(reg, args, call_slot_index, tail_call_mode);
builder.Call(reg, args, call_slot_index, Call::GLOBAL_CALL, tail_call_mode);
builder.Return();
......
......@@ -125,8 +125,10 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.CreateObjectLiteral(factory->NewFixedArray(1), 0, 0, reg);
// Call operations.
builder.Call(reg, reg_list, 1)
.Call(reg, reg_list, 1, TailCallMode::kAllow)
builder.Call(reg, reg_list, 1, Call::GLOBAL_CALL)
.Call(reg, reg_list, 1, Call::NAMED_PROPERTY_CALL,
TailCallMode::kDisallow)
.Call(reg, reg_list, 1, Call::GLOBAL_CALL, TailCallMode::kAllow)
.CallRuntime(Runtime::kIsArray, reg)
.CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, reg_list, pair)
.CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, reg_list);
......
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