[vm] Support new kernel AST invocation nodes in the VM
TEST=Manual testing with new invocation nodes enabled.
Issue: https://github.com/dart-lang/sdk/issues/45340
Change-Id: I7eb5f03b9d9ac16c911812a5dbcd92ad43220278
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/197585
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md
index c891128..e501474 100644
--- a/pkg/kernel/binary.md
+++ b/pkg/kernel/binary.md
@@ -788,7 +788,6 @@
Byte tag = 126;
FileOffset fileOffset;
Expression receiver;
- DartType functionType;
}
type LocalFunctionInvocation extends Expression {
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 123a0a2..2ce3561 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -1131,8 +1131,20 @@
return BuildVariableSet(payload, position);
case kPropertyGet:
return BuildPropertyGet(position);
+ case kInstanceGet:
+ return BuildInstanceGet(position);
+ case kDynamicGet:
+ return BuildDynamicGet(position);
+ case kInstanceTearOff:
+ return BuildInstanceTearOff(position);
+ case kFunctionTearOff:
+ return BuildFunctionTearOff(position);
case kPropertySet:
return BuildPropertySet(position);
+ case kInstanceSet:
+ return BuildInstanceSet(position);
+ case kDynamicSet:
+ return BuildDynamicSet(position);
case kSuperPropertyGet:
return BuildSuperPropertyGet(position);
case kSuperPropertySet:
@@ -1142,7 +1154,17 @@
case kStaticSet:
return BuildStaticSet(position);
case kMethodInvocation:
- return BuildMethodInvocation(position);
+ case kInstanceInvocation:
+ case kDynamicInvocation:
+ return BuildMethodInvocation(position, tag);
+ case kLocalFunctionInvocation:
+ return BuildLocalFunctionInvocation(position);
+ case kFunctionInvocation:
+ return BuildFunctionInvocation(position);
+ case kEqualsCall:
+ return BuildEqualsCall(position);
+ case kEqualsNull:
+ return BuildEqualsNull(position);
case kSuperMethodInvocation:
return BuildSuperMethodInvocation(position);
case kStaticInvocation:
@@ -1218,15 +1240,13 @@
case kConstSetLiteral:
case kConstMapLiteral:
case kSymbolLiteral:
- // Const invocations and const literals are removed by the
- // constant evaluator.
case kListConcatenation:
case kSetConcatenation:
case kMapConcatenation:
case kInstanceCreation:
case kFileUriExpression:
- // Collection concatenation, instance creation operations and
- // in-expression URI changes are internal to the front end and
+ case kStaticTearOff:
+ // These nodes are internal to the front end and
// removed by the constant evaluator.
default:
ReportUnexpectedTag("expression", tag);
@@ -2155,6 +2175,7 @@
return instructions;
}
+
Fragment StreamingFlowGraphBuilder::BuildPropertyGet(TokenPosition* p) {
const intptr_t offset = ReaderOffset() - 1; // Include the tag.
const TokenPosition position = ReadPosition(); // read position.
@@ -2227,6 +2248,212 @@
return instructions;
}
+Fragment StreamingFlowGraphBuilder::BuildInstanceGet(TokenPosition* p) {
+ const intptr_t offset = ReaderOffset() - 1; // Include the tag.
+ ReadByte(); // read kind.
+ const TokenPosition position = ReadPosition(); // read position.
+ if (p != nullptr) *p = position;
+
+ const DirectCallMetadata direct_call =
+ direct_call_metadata_helper_.GetDirectTargetForPropertyGet(offset);
+ const InferredTypeMetadata result_type =
+ inferred_type_metadata_helper_.GetInferredType(offset);
+
+ Fragment instructions = BuildExpression(); // read receiver.
+
+ LocalVariable* receiver = nullptr;
+ if (direct_call.check_receiver_for_null_) {
+ // Duplicate receiver for CheckNull before it is consumed by PushArgument.
+ receiver = MakeTemporary();
+ instructions += LoadLocal(receiver);
+ }
+
+ const String& getter_name = ReadNameAsGetterName(); // read name.
+ SkipDartType(); // read result_type.
+ const NameIndex itarget_name =
+ ReadInterfaceMemberNameReference(); // read interface_target_reference.
+ ASSERT(!H.IsRoot(itarget_name) && H.IsGetter(itarget_name));
+ const auto& interface_target = Function::ZoneHandle(
+ Z, H.LookupMethodByMember(itarget_name, H.DartGetterName(itarget_name)));
+ ASSERT(getter_name.ptr() == interface_target.name());
+
+ if (direct_call.check_receiver_for_null_) {
+ instructions += CheckNull(position, receiver, getter_name);
+ }
+
+ if (!direct_call.target_.IsNull()) {
+ ASSERT(CompilerState::Current().is_aot());
+ instructions +=
+ StaticCall(position, direct_call.target_, 1, Array::null_array(),
+ ICData::kNoRebind, &result_type);
+ } else {
+ const intptr_t kTypeArgsLen = 0;
+ const intptr_t kNumArgsChecked = 1;
+ instructions +=
+ InstanceCall(position, getter_name, Token::kGET, kTypeArgsLen, 1,
+ Array::null_array(), kNumArgsChecked, interface_target,
+ Function::null_function(), &result_type);
+ }
+
+ if (direct_call.check_receiver_for_null_) {
+ instructions += DropTempsPreserveTop(1); // Drop receiver, preserve result.
+ }
+
+ return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildDynamicGet(TokenPosition* p) {
+ const intptr_t offset = ReaderOffset() - 1; // Include the tag.
+ ReadByte(); // read kind.
+ const TokenPosition position = ReadPosition(); // read position.
+ if (p != nullptr) *p = position;
+
+ const DirectCallMetadata direct_call =
+ direct_call_metadata_helper_.GetDirectTargetForPropertyGet(offset);
+ const InferredTypeMetadata result_type =
+ inferred_type_metadata_helper_.GetInferredType(offset);
+
+ Fragment instructions = BuildExpression(); // read receiver.
+
+ LocalVariable* receiver = nullptr;
+ if (direct_call.check_receiver_for_null_) {
+ // Duplicate receiver for CheckNull before it is consumed by PushArgument.
+ receiver = MakeTemporary();
+ instructions += LoadLocal(receiver);
+ }
+
+ const String& getter_name = ReadNameAsGetterName(); // read name.
+
+ if (direct_call.check_receiver_for_null_) {
+ instructions += CheckNull(position, receiver, getter_name);
+ }
+
+ const auto& mangled_name = String::ZoneHandle(
+ Z, Function::CreateDynamicInvocationForwarderName(getter_name));
+ const Function* direct_call_target = &direct_call.target_;
+ if (!direct_call_target->IsNull()) {
+ direct_call_target = &Function::ZoneHandle(
+ direct_call.target_.GetDynamicInvocationForwarder(mangled_name));
+ }
+
+ if (!direct_call_target->IsNull()) {
+ ASSERT(CompilerState::Current().is_aot());
+ instructions +=
+ StaticCall(position, *direct_call_target, 1, Array::null_array(),
+ ICData::kNoRebind, &result_type);
+ } else {
+ const intptr_t kTypeArgsLen = 0;
+ const intptr_t kNumArgsChecked = 1;
+ instructions += InstanceCall(position, mangled_name, Token::kGET,
+ kTypeArgsLen, 1, Array::null_array(),
+ kNumArgsChecked, Function::null_function(),
+ Function::null_function(), &result_type);
+ }
+
+ if (direct_call.check_receiver_for_null_) {
+ instructions += DropTempsPreserveTop(1); // Drop receiver, preserve result.
+ }
+
+ return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildInstanceTearOff(TokenPosition* p) {
+ const intptr_t offset = ReaderOffset() - 1; // Include the tag.
+ ReadByte(); // read kind.
+ const TokenPosition position = ReadPosition(); // read position.
+ if (p != nullptr) *p = position;
+
+ const DirectCallMetadata direct_call =
+ direct_call_metadata_helper_.GetDirectTargetForPropertyGet(offset);
+ const InferredTypeMetadata result_type =
+ inferred_type_metadata_helper_.GetInferredType(offset);
+
+ Fragment instructions = BuildExpression(); // read receiver.
+
+ LocalVariable* receiver = nullptr;
+ if (direct_call.check_receiver_for_null_) {
+ // Duplicate receiver for CheckNull before it is consumed by PushArgument.
+ receiver = MakeTemporary();
+ instructions += LoadLocal(receiver);
+ }
+
+ const String& getter_name = ReadNameAsGetterName(); // read name.
+ SkipDartType(); // read result_type.
+ const NameIndex itarget_name =
+ ReadInterfaceMemberNameReference(); // read interface_target_reference.
+ ASSERT(!H.IsRoot(itarget_name) && H.IsMethod(itarget_name));
+ const auto& tearoff_interface_target = Function::ZoneHandle(
+ Z, H.LookupMethodByMember(itarget_name, H.DartMethodName(itarget_name)));
+
+ if (direct_call.check_receiver_for_null_) {
+ instructions += CheckNull(position, receiver, getter_name);
+ }
+
+ if (!direct_call.target_.IsNull()) {
+ ASSERT(CompilerState::Current().is_aot());
+ instructions +=
+ StaticCall(position, direct_call.target_, 1, Array::null_array(),
+ ICData::kNoRebind, &result_type);
+ } else {
+ const intptr_t kTypeArgsLen = 0;
+ const intptr_t kNumArgsChecked = 1;
+ instructions += InstanceCall(position, getter_name, Token::kGET,
+ kTypeArgsLen, 1, Array::null_array(),
+ kNumArgsChecked, Function::null_function(),
+ tearoff_interface_target, &result_type);
+ }
+
+ if (direct_call.check_receiver_for_null_) {
+ instructions += DropTempsPreserveTop(1); // Drop receiver, preserve result.
+ }
+
+ return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildFunctionTearOff(TokenPosition* p) {
+ const intptr_t offset = ReaderOffset() - 1; // Include the tag.
+ const TokenPosition position = ReadPosition(); // read position.
+ if (p != nullptr) *p = position;
+
+ const DirectCallMetadata direct_call =
+ direct_call_metadata_helper_.GetDirectTargetForPropertyGet(offset);
+ const InferredTypeMetadata result_type =
+ inferred_type_metadata_helper_.GetInferredType(offset);
+
+ Fragment instructions = BuildExpression(); // read receiver.
+
+ LocalVariable* receiver = nullptr;
+ if (direct_call.check_receiver_for_null_) {
+ // Duplicate receiver for CheckNull before it is consumed by PushArgument.
+ receiver = MakeTemporary();
+ instructions += LoadLocal(receiver);
+ }
+
+ if (direct_call.check_receiver_for_null_) {
+ instructions += CheckNull(position, receiver, Symbols::GetCall());
+ }
+
+ if (!direct_call.target_.IsNull()) {
+ ASSERT(CompilerState::Current().is_aot());
+ instructions +=
+ StaticCall(position, direct_call.target_, 1, Array::null_array(),
+ ICData::kNoRebind, &result_type);
+ } else {
+ const intptr_t kTypeArgsLen = 0;
+ const intptr_t kNumArgsChecked = 1;
+ instructions += InstanceCall(position, Symbols::GetCall(), Token::kGET,
+ kTypeArgsLen, 1, Array::null_array(),
+ kNumArgsChecked, Function::null_function(),
+ Function::null_function(), &result_type);
+ }
+
+ if (direct_call.check_receiver_for_null_) {
+ instructions += DropTempsPreserveTop(1); // Drop receiver, preserve result.
+ }
+
+ return instructions;
+}
+
Fragment StreamingFlowGraphBuilder::BuildPropertySet(TokenPosition* p) {
const intptr_t offset = ReaderOffset() - 1; // Include the tag.
@@ -2322,6 +2549,171 @@
return instructions;
}
+Fragment StreamingFlowGraphBuilder::BuildInstanceSet(TokenPosition* p) {
+ const intptr_t offset = ReaderOffset() - 1; // Include the tag.
+ ReadByte(); // read kind.
+
+ const DirectCallMetadata direct_call =
+ direct_call_metadata_helper_.GetDirectTargetForPropertySet(offset);
+ const CallSiteAttributesMetadata call_site_attributes =
+ call_site_attributes_metadata_helper_.GetCallSiteAttributes(offset);
+ const InferredTypeMetadata inferred_type =
+ inferred_type_metadata_helper_.GetInferredType(offset);
+
+ // True if callee can skip argument type checks.
+ bool is_unchecked_call = inferred_type.IsSkipCheck();
+ if (call_site_attributes.receiver_type != nullptr &&
+ call_site_attributes.receiver_type->HasTypeClass() &&
+ !Class::Handle(call_site_attributes.receiver_type->type_class())
+ .IsGeneric()) {
+ is_unchecked_call = true;
+ }
+
+ Fragment instructions(MakeTemp());
+ LocalVariable* variable = MakeTemporary();
+
+ const TokenPosition position = ReadPosition(); // read position.
+ if (p != nullptr) *p = position;
+
+ if (PeekTag() == kThisExpression) {
+ is_unchecked_call = true;
+ }
+ instructions += BuildExpression(); // read receiver.
+
+ LocalVariable* receiver = nullptr;
+ if (direct_call.check_receiver_for_null_) {
+ // Duplicate receiver for CheckNull before it is consumed by PushArgument.
+ receiver = MakeTemporary();
+ instructions += LoadLocal(receiver);
+ }
+
+ const String& setter_name = ReadNameAsSetterName(); // read name.
+
+ instructions += BuildExpression(); // read value.
+ instructions += StoreLocal(TokenPosition::kNoSource, variable);
+
+ const NameIndex itarget_name =
+ ReadInterfaceMemberNameReference(); // read interface_target_reference.
+ ASSERT(!H.IsRoot(itarget_name));
+ const auto& interface_target = Function::ZoneHandle(
+ Z, H.LookupMethodByMember(itarget_name, H.DartSetterName(itarget_name)));
+ ASSERT(setter_name.ptr() == interface_target.name());
+
+ if (direct_call.check_receiver_for_null_) {
+ instructions += CheckNull(position, receiver, setter_name);
+ }
+
+ if (!direct_call.target_.IsNull()) {
+ ASSERT(CompilerState::Current().is_aot());
+ instructions +=
+ StaticCall(position, direct_call.target_, 2, Array::null_array(),
+ ICData::kNoRebind, /*result_type=*/nullptr,
+ /*type_args_count=*/0,
+ /*use_unchecked_entry=*/is_unchecked_call);
+ } else {
+ const intptr_t kTypeArgsLen = 0;
+ const intptr_t kNumArgsChecked = 1;
+
+ instructions += InstanceCall(
+ position, setter_name, Token::kSET, kTypeArgsLen, 2,
+ Array::null_array(), kNumArgsChecked, interface_target,
+ Function::null_function(),
+ /*result_type=*/nullptr,
+ /*use_unchecked_entry=*/is_unchecked_call, &call_site_attributes);
+ }
+
+ instructions += Drop(); // Drop result of the setter invocation.
+
+ if (direct_call.check_receiver_for_null_) {
+ instructions += Drop(); // Drop receiver.
+ }
+
+ return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildDynamicSet(TokenPosition* p) {
+ const intptr_t offset = ReaderOffset() - 1; // Include the tag.
+ ReadByte(); // read kind.
+
+ const DirectCallMetadata direct_call =
+ direct_call_metadata_helper_.GetDirectTargetForPropertySet(offset);
+ const CallSiteAttributesMetadata call_site_attributes =
+ call_site_attributes_metadata_helper_.GetCallSiteAttributes(offset);
+ const InferredTypeMetadata inferred_type =
+ inferred_type_metadata_helper_.GetInferredType(offset);
+
+ // True if callee can skip argument type checks.
+ bool is_unchecked_call = inferred_type.IsSkipCheck();
+ if (call_site_attributes.receiver_type != nullptr &&
+ call_site_attributes.receiver_type->HasTypeClass() &&
+ !Class::Handle(call_site_attributes.receiver_type->type_class())
+ .IsGeneric()) {
+ is_unchecked_call = true;
+ }
+
+ Fragment instructions(MakeTemp());
+ LocalVariable* variable = MakeTemporary();
+
+ const TokenPosition position = ReadPosition(); // read position.
+ if (p != nullptr) *p = position;
+
+ if (PeekTag() == kThisExpression) {
+ is_unchecked_call = true;
+ }
+ instructions += BuildExpression(); // read receiver.
+
+ LocalVariable* receiver = nullptr;
+ if (direct_call.check_receiver_for_null_) {
+ // Duplicate receiver for CheckNull before it is consumed by PushArgument.
+ receiver = MakeTemporary();
+ instructions += LoadLocal(receiver);
+ }
+
+ const String& setter_name = ReadNameAsSetterName(); // read name.
+
+ instructions += BuildExpression(); // read value.
+ instructions += StoreLocal(TokenPosition::kNoSource, variable);
+
+ if (direct_call.check_receiver_for_null_) {
+ instructions += CheckNull(position, receiver, setter_name);
+ }
+
+ const Function* direct_call_target = &direct_call.target_;
+ const auto& mangled_name = String::ZoneHandle(
+ Z, Function::CreateDynamicInvocationForwarderName(setter_name));
+ if (!direct_call_target->IsNull()) {
+ direct_call_target = &Function::ZoneHandle(
+ direct_call.target_.GetDynamicInvocationForwarder(mangled_name));
+ }
+
+ if (!direct_call_target->IsNull()) {
+ ASSERT(CompilerState::Current().is_aot());
+ instructions +=
+ StaticCall(position, *direct_call_target, 2, Array::null_array(),
+ ICData::kNoRebind, /*result_type=*/nullptr,
+ /*type_args_count=*/0,
+ /*use_unchecked_entry=*/is_unchecked_call);
+ } else {
+ const intptr_t kTypeArgsLen = 0;
+ const intptr_t kNumArgsChecked = 1;
+
+ instructions += InstanceCall(
+ position, mangled_name, Token::kSET, kTypeArgsLen, 2,
+ Array::null_array(), kNumArgsChecked, Function::null_function(),
+ Function::null_function(),
+ /*result_type=*/nullptr,
+ /*use_unchecked_entry=*/is_unchecked_call, &call_site_attributes);
+ }
+
+ instructions += Drop(); // Drop result of the setter invocation.
+
+ if (direct_call.check_receiver_for_null_) {
+ instructions += Drop(); // Drop receiver.
+ }
+
+ return instructions;
+}
+
static Function& GetNoSuchMethodOrDie(Thread* thread,
Zone* zone,
const Class& klass) {
@@ -2641,10 +3033,20 @@
}
}
-Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p) {
+Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p,
+ Tag tag) {
+ ASSERT((tag == kMethodInvocation) || (tag == kInstanceInvocation) ||
+ (tag == kDynamicInvocation));
const intptr_t offset = ReaderOffset() - 1; // Include the tag.
- const uint8_t flags = ReadFlags(); // read flags.
+ if ((tag == kInstanceInvocation) || (tag == kDynamicInvocation)) {
+ ReadByte(); // read kind.
+ }
+
+ // read flags.
+ const uint8_t flags =
+ ((tag == kMethodInvocation) || (tag == kInstanceInvocation)) ? ReadFlags()
+ : 0;
const bool is_invariant = (flags & kMethodInvocationFlagInvariant) != 0;
const TokenPosition position = ReadPosition(); // read position.
@@ -2759,9 +3161,15 @@
checked_argument_count = argument_count;
}
+ if (tag == kInstanceInvocation) {
+ SkipDartType(); // read function_type.
+ }
+
const Function* interface_target = &Function::null_function();
const NameIndex itarget_name =
- ReadInterfaceMemberNameReference(); // read interface_target_reference.
+ ((tag == kMethodInvocation) || (tag == kInstanceInvocation))
+ ? ReadInterfaceMemberNameReference()
+ : NameIndex(); // read interface_target_reference.
// TODO(dartbug.com/34497): Once front-end desugars calls via
// fields/getters, filtering of field and getter interface targets here
// can be turned into assertions.
@@ -2846,6 +3254,191 @@
return instructions;
}
+Fragment StreamingFlowGraphBuilder::BuildLocalFunctionInvocation(
+ TokenPosition* p) {
+ const TokenPosition position = ReadPosition();
+ if (p != nullptr) *p = position;
+ // read variable kernel position.
+ const intptr_t variable_kernel_position = ReadUInt();
+ ReadUInt(); // read relative variable index.
+
+ LocalVariable* variable = LookupVariable(variable_kernel_position);
+ ASSERT(!variable->is_late());
+
+ Fragment instructions;
+
+ // Type arguments.
+ intptr_t type_args_len = 0;
+ {
+ AlternativeReadingScope alt(&reader_);
+ ReadUInt(); // read argument count.
+ intptr_t list_length = ReadListLength(); // read types list length.
+ if (list_length > 0) {
+ const TypeArguments& type_arguments =
+ T.BuildTypeArguments(list_length); // read types.
+ instructions += TranslateInstantiatedTypeArguments(type_arguments);
+ }
+ type_args_len = list_length;
+ }
+
+ // Receiver (closure).
+ instructions += LoadLocal(variable);
+
+ intptr_t argument_count;
+ intptr_t positional_argument_count;
+ Array& argument_names = Array::ZoneHandle(Z);
+ instructions +=
+ BuildArguments(&argument_names, &argument_count,
+ &positional_argument_count); // read arguments.
+ ++argument_count; // include receiver
+
+ SkipDartType(); // read function_type.
+
+ // Lookup the function in the closure.
+ instructions += LoadLocal(variable);
+ instructions += LoadNativeField(Slot::Closure_function());
+ if (parsed_function()->function().is_debuggable()) {
+ ASSERT(!parsed_function()->function().is_native());
+ instructions += DebugStepCheck(position);
+ }
+ instructions +=
+ B->ClosureCall(position, type_args_len, argument_count, argument_names,
+ /*use_unchecked_entry=*/true);
+ return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildFunctionInvocation(TokenPosition* p) {
+ const intptr_t offset = ReaderOffset() - 1; // Include the tag.
+ const FunctionAccessKind function_access_kind =
+ static_cast<FunctionAccessKind>(ReadByte()); // read kind.
+ const TokenPosition position = ReadPosition(); // read position.
+ if (p != nullptr) *p = position;
+
+ const InferredTypeMetadata result_type =
+ inferred_type_metadata_helper_.GetInferredType(offset);
+ const CallSiteAttributesMetadata call_site_attributes =
+ call_site_attributes_metadata_helper_.GetCallSiteAttributes(offset);
+
+ const bool is_unchecked_closure_call =
+ (function_access_kind == FunctionAccessKind::kFunctionType);
+ Fragment instructions;
+
+ instructions += BuildExpression(); // read receiver.
+ LocalVariable* receiver_temp = MakeTemporary();
+
+ // Type arguments.
+ intptr_t type_args_len = 0;
+ {
+ AlternativeReadingScope alt(&reader_);
+ ReadUInt(); // read argument count.
+ intptr_t list_length = ReadListLength(); // read types list length.
+ if (list_length > 0) {
+ const TypeArguments& type_arguments =
+ T.BuildTypeArguments(list_length); // read types.
+ instructions += TranslateInstantiatedTypeArguments(type_arguments);
+ }
+ type_args_len = list_length;
+ }
+
+ // Receiver (closure).
+ instructions += LoadLocal(receiver_temp);
+
+ intptr_t argument_count;
+ intptr_t positional_argument_count;
+ Array& argument_names = Array::ZoneHandle(Z);
+ instructions +=
+ BuildArguments(&argument_names, &argument_count,
+ &positional_argument_count); // read arguments.
+ ++argument_count; // include receiver
+
+ SkipDartType(); // read function_type.
+
+ if (is_unchecked_closure_call) {
+ instructions += CheckNull(position, receiver_temp, Symbols::Call(),
+ /*clear_temp=*/false);
+ // Lookup the function in the closure.
+ instructions += LoadLocal(receiver_temp);
+ instructions += LoadNativeField(Slot::Closure_function());
+ if (parsed_function()->function().is_debuggable()) {
+ ASSERT(!parsed_function()->function().is_native());
+ instructions += DebugStepCheck(position);
+ }
+ instructions +=
+ B->ClosureCall(position, type_args_len, argument_count, argument_names,
+ /*use_unchecked_entry=*/true);
+ } else {
+ instructions += InstanceCall(
+ position, Symbols::DynamicCall(), Token::kILLEGAL, type_args_len,
+ argument_count, argument_names, 1, Function::null_function(),
+ Function::null_function(), &result_type,
+ /*use_unchecked_entry=*/false, &call_site_attributes,
+ result_type.ReceiverNotInt());
+ }
+ instructions += DropTempsPreserveTop(1);
+ return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildEqualsCall(TokenPosition* p) {
+ const intptr_t offset = ReaderOffset() - 1; // Include the tag.
+ const TokenPosition position = ReadPosition(); // read position.
+ if (p != nullptr) *p = position;
+
+ const DirectCallMetadata direct_call =
+ direct_call_metadata_helper_.GetDirectTargetForMethodInvocation(offset);
+ ASSERT(!direct_call.check_receiver_for_null_);
+ const InferredTypeMetadata result_type =
+ inferred_type_metadata_helper_.GetInferredType(offset);
+ const CallSiteAttributesMetadata call_site_attributes =
+ call_site_attributes_metadata_helper_.GetCallSiteAttributes(offset);
+
+ Fragment instructions;
+ instructions += BuildExpression(); // read left.
+ instructions += BuildExpression(); // read right.
+ SkipDartType(); // read function_type.
+
+ const NameIndex itarget_name =
+ ReadInterfaceMemberNameReference(); // read interface_target_reference.
+ const auto& interface_target = Function::ZoneHandle(
+ Z,
+ H.LookupMethodByMember(itarget_name, H.DartProcedureName(itarget_name)));
+ ASSERT(interface_target.name() == Symbols::EqualOperator().ptr());
+
+ const intptr_t kTypeArgsLen = 0;
+ const intptr_t kNumArgs = 2;
+ const intptr_t kNumCheckedArgs = 2;
+
+ if (!direct_call.target_.IsNull()) {
+ ASSERT(CompilerState::Current().is_aot());
+ instructions +=
+ StaticCall(position, direct_call.target_, kNumArgs, Array::null_array(),
+ ICData::kNoRebind, &result_type, kTypeArgsLen,
+ /*use_unchecked_entry=*/true);
+ } else {
+ instructions += InstanceCall(
+ position, Symbols::EqualOperator(), Token::kEQ, kTypeArgsLen, kNumArgs,
+ Array::null_array(), kNumCheckedArgs, interface_target,
+ Function::null_function(), &result_type,
+ /*use_unchecked_entry=*/true, &call_site_attributes,
+ result_type.ReceiverNotInt());
+ }
+
+ return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildEqualsNull(TokenPosition* p) {
+ const TokenPosition position = ReadPosition(); // read position.
+ if (p != nullptr) *p = position;
+ Fragment instructions;
+ instructions += BuildExpression(); // read expression.
+ instructions += NullConstant();
+ if (parsed_function()->function().is_debuggable()) {
+ instructions += DebugStepCheck(position);
+ }
+ instructions +=
+ StrictCompare(position, Token::kEQ_STRICT, /*number_check=*/false);
+ return instructions;
+}
+
Fragment StreamingFlowGraphBuilder::BuildSuperMethodInvocation(
TokenPosition* p) {
const intptr_t offset = ReaderOffset() - 1; // Include the tag.
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
index 47f5bca..c11dc7d 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
@@ -274,7 +274,13 @@
Fragment BuildVariableSetImpl(TokenPosition position,
intptr_t variable_kernel_position);
Fragment BuildPropertyGet(TokenPosition* position);
+ Fragment BuildInstanceGet(TokenPosition* position);
+ Fragment BuildDynamicGet(TokenPosition* position);
+ Fragment BuildInstanceTearOff(TokenPosition* position);
+ Fragment BuildFunctionTearOff(TokenPosition* position);
Fragment BuildPropertySet(TokenPosition* position);
+ Fragment BuildInstanceSet(TokenPosition* position);
+ Fragment BuildDynamicSet(TokenPosition* position);
Fragment BuildAllocateInvocationMirrorCall(TokenPosition position,
const String& name,
intptr_t num_type_arguments,
@@ -286,7 +292,11 @@
Fragment BuildSuperPropertySet(TokenPosition* position);
Fragment BuildStaticGet(TokenPosition* position);
Fragment BuildStaticSet(TokenPosition* position);
- Fragment BuildMethodInvocation(TokenPosition* position);
+ Fragment BuildMethodInvocation(TokenPosition* position, Tag tag);
+ Fragment BuildLocalFunctionInvocation(TokenPosition* position);
+ Fragment BuildFunctionInvocation(TokenPosition* position);
+ Fragment BuildEqualsCall(TokenPosition* position);
+ Fragment BuildEqualsNull(TokenPosition* position);
Fragment BuildSuperMethodInvocation(TokenPosition* position);
Fragment BuildStaticInvocation(TokenPosition* position);
Fragment BuildConstructorInvocation(TokenPosition* position);
diff --git a/runtime/vm/compiler/frontend/kernel_fingerprints.cc b/runtime/vm/compiler/frontend/kernel_fingerprints.cc
index 5d5890f..4b0426c 100644
--- a/runtime/vm/compiler/frontend/kernel_fingerprints.cc
+++ b/runtime/vm/compiler/frontend/kernel_fingerprints.cc
@@ -379,6 +379,32 @@
BuildHash(ReadNameAsGetterName().Hash()); // read name.
CalculateGetterNameFingerprint(); // read interface_target_reference.
return;
+ case kInstanceGet:
+ ReadByte(); // read kind.
+ ReadPosition(); // read position.
+ CalculateExpressionFingerprint(); // read receiver.
+ BuildHash(ReadNameAsGetterName().Hash()); // read name.
+ SkipDartType(); // read result_type.
+ CalculateGetterNameFingerprint(); // read interface_target_reference.
+ return;
+ case kDynamicGet:
+ ReadByte(); // read kind.
+ ReadPosition(); // read position.
+ CalculateExpressionFingerprint(); // read receiver.
+ BuildHash(ReadNameAsGetterName().Hash()); // read name.
+ return;
+ case kInstanceTearOff:
+ ReadByte(); // read kind.
+ ReadPosition(); // read position.
+ CalculateExpressionFingerprint(); // read receiver.
+ BuildHash(ReadNameAsGetterName().Hash()); // read name.
+ SkipDartType(); // read result_type.
+ CalculateGetterNameFingerprint(); // read interface_target_reference.
+ return;
+ case kFunctionTearOff:
+ ReadPosition(); // read position.
+ CalculateExpressionFingerprint(); // read receiver.
+ return;
case kPropertySet:
ReadPosition(); // read position.
CalculateExpressionFingerprint(); // read receiver.
@@ -386,6 +412,21 @@
CalculateExpressionFingerprint(); // read value.
CalculateSetterNameFingerprint(); // read interface_target_reference.
return;
+ case kInstanceSet:
+ ReadByte(); // read kind.
+ ReadPosition(); // read position.
+ CalculateExpressionFingerprint(); // read receiver.
+ BuildHash(ReadNameAsSetterName().Hash()); // read name.
+ CalculateExpressionFingerprint(); // read value.
+ CalculateSetterNameFingerprint(); // read interface_target_reference.
+ return;
+ case kDynamicSet:
+ ReadByte(); // read kind.
+ ReadPosition(); // read position.
+ CalculateExpressionFingerprint(); // read receiver.
+ BuildHash(ReadNameAsSetterName().Hash()); // read name.
+ CalculateExpressionFingerprint(); // read value.
+ return;
case kSuperPropertyGet:
ReadPosition(); // read position.
BuildHash(ReadNameAsGetterName().Hash()); // read name.
@@ -414,6 +455,48 @@
CalculateArgumentsFingerprint(); // read arguments.
CalculateMethodNameFingerprint(); // read interface_target_reference.
return;
+ case kInstanceInvocation:
+ ReadByte(); // read kind.
+ ReadFlags(); // read flags.
+ ReadPosition(); // read position.
+ CalculateExpressionFingerprint(); // read receiver.
+ BuildHash(ReadNameAsMethodName().Hash()); // read name.
+ CalculateArgumentsFingerprint(); // read arguments.
+ SkipDartType(); // read function_type.
+ CalculateMethodNameFingerprint(); // read interface_target_reference.
+ return;
+ case kDynamicInvocation:
+ ReadByte(); // read kind.
+ ReadPosition(); // read position.
+ CalculateExpressionFingerprint(); // read receiver.
+ BuildHash(ReadNameAsMethodName().Hash()); // read name.
+ CalculateArgumentsFingerprint(); // read arguments.
+ return;
+ case kLocalFunctionInvocation:
+ ReadPosition(); // read position.
+ ReadUInt(); // read variable kernel position.
+ ReadUInt(); // read relative variable index.
+ CalculateArgumentsFingerprint(); // read arguments.
+ SkipDartType(); // read function_type.
+ return;
+ case kFunctionInvocation:
+ BuildHash(ReadByte()); // read kind.
+ ReadPosition(); // read position.
+ CalculateExpressionFingerprint(); // read receiver.
+ CalculateArgumentsFingerprint(); // read arguments.
+ SkipDartType(); // read function_type.
+ return;
+ case kEqualsCall:
+ ReadPosition(); // read position.
+ CalculateExpressionFingerprint(); // read left.
+ CalculateExpressionFingerprint(); // read right.
+ SkipDartType(); // read function_type.
+ CalculateMethodNameFingerprint(); // read interface_target_reference.
+ return;
+ case kEqualsNull:
+ ReadPosition(); // read position.
+ CalculateExpressionFingerprint(); // read expression.
+ return;
case kSuperMethodInvocation:
ReadPosition(); // read position.
BuildHash(ReadNameAsMethodName().Hash()); // read name.
@@ -558,15 +641,13 @@
case kConstSetLiteral:
case kConstMapLiteral:
case kSymbolLiteral:
- // Const invocations and const literals are removed by the
- // constant evaluator.
case kListConcatenation:
case kSetConcatenation:
case kMapConcatenation:
case kInstanceCreation:
case kFileUriExpression:
- // Collection concatenation, instance creation operations and
- // in-expression URI changes are internal to the front end and
+ case kStaticTearOff:
+ // These nodes are internal to the front end and
// removed by the constant evaluator.
default:
ReportUnexpectedTag("expression", tag);
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index f786a81..8dd8f8a 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -2315,6 +2315,32 @@
SkipName(); // read name.
SkipInterfaceMemberNameReference(); // read interface_target_reference.
return;
+ case kInstanceGet:
+ ReadByte(); // read kind.
+ ReadPosition(); // read position.
+ SkipExpression(); // read receiver.
+ SkipName(); // read name.
+ SkipDartType(); // read result_type.
+ SkipInterfaceMemberNameReference(); // read interface_target_reference.
+ return;
+ case kDynamicGet:
+ ReadByte(); // read kind.
+ ReadPosition(); // read position.
+ SkipExpression(); // read receiver.
+ SkipName(); // read name.
+ return;
+ case kInstanceTearOff:
+ ReadByte(); // read kind.
+ ReadPosition(); // read position.
+ SkipExpression(); // read receiver.
+ SkipName(); // read name.
+ SkipDartType(); // read result_type.
+ SkipInterfaceMemberNameReference(); // read interface_target_reference.
+ return;
+ case kFunctionTearOff:
+ ReadPosition(); // read position.
+ SkipExpression(); // read receiver.
+ return;
case kPropertySet:
ReadPosition(); // read position.
SkipExpression(); // read receiver.
@@ -2322,6 +2348,21 @@
SkipExpression(); // read value.
SkipInterfaceMemberNameReference(); // read interface_target_reference.
return;
+ case kInstanceSet:
+ ReadByte(); // read kind.
+ ReadPosition(); // read position.
+ SkipExpression(); // read receiver.
+ SkipName(); // read name.
+ SkipExpression(); // read value.
+ SkipInterfaceMemberNameReference(); // read interface_target_reference.
+ return;
+ case kDynamicSet:
+ ReadByte(); // read kind.
+ ReadPosition(); // read position.
+ SkipExpression(); // read receiver.
+ SkipName(); // read name.
+ SkipExpression(); // read value.
+ return;
case kSuperPropertyGet:
ReadPosition(); // read position.
SkipName(); // read name.
@@ -2350,6 +2391,48 @@
SkipArguments(); // read arguments.
SkipInterfaceMemberNameReference(); // read interface_target_reference.
return;
+ case kInstanceInvocation:
+ ReadByte(); // read kind.
+ ReadFlags(); // read flags.
+ ReadPosition(); // read position.
+ SkipExpression(); // read receiver.
+ SkipName(); // read name.
+ SkipArguments(); // read arguments.
+ SkipDartType(); // read function_type.
+ SkipInterfaceMemberNameReference(); // read interface_target_reference.
+ return;
+ case kDynamicInvocation:
+ ReadByte(); // read kind.
+ ReadPosition(); // read position.
+ SkipExpression(); // read receiver.
+ SkipName(); // read name.
+ SkipArguments(); // read arguments.
+ return;
+ case kLocalFunctionInvocation:
+ ReadPosition(); // read position.
+ ReadUInt(); // read variable kernel position.
+ ReadUInt(); // read relative variable index.
+ SkipArguments(); // read arguments.
+ SkipDartType(); // read function_type.
+ return;
+ case kFunctionInvocation:
+ ReadByte(); // read kind.
+ ReadPosition(); // read position.
+ SkipExpression(); // read receiver.
+ SkipArguments(); // read arguments.
+ SkipDartType(); // read function_type.
+ return;
+ case kEqualsCall:
+ ReadPosition(); // read position.
+ SkipExpression(); // read left.
+ SkipExpression(); // read right.
+ SkipDartType(); // read function_type.
+ SkipInterfaceMemberNameReference(); // read interface_target_reference.
+ return;
+ case kEqualsNull:
+ ReadPosition(); // read position.
+ SkipExpression(); // read expression.
+ return;
case kSuperMethodInvocation:
ReadPosition(); // read position.
SkipName(); // read name.
@@ -2490,15 +2573,13 @@
case kConstSetLiteral:
case kConstMapLiteral:
case kSymbolLiteral:
- // Const invocations and const literals are removed by the
- // constant evaluator.
case kListConcatenation:
case kSetConcatenation:
case kMapConcatenation:
case kInstanceCreation:
case kFileUriExpression:
- // Collection concatenation, instance creation operations and
- // in-expression URI changes are internal to the front end and
+ case kStaticTearOff:
+ // These nodes are internal to the front end and
// removed by the constant evaluator.
default:
ReportUnexpectedTag("expression", tag);
diff --git a/runtime/vm/compiler/frontend/scope_builder.cc b/runtime/vm/compiler/frontend/scope_builder.cc
index 81730a0..27be5e5 100644
--- a/runtime/vm/compiler/frontend/scope_builder.cc
+++ b/runtime/vm/compiler/frontend/scope_builder.cc
@@ -693,6 +693,34 @@
// read interface_target_reference.
helper_.SkipInterfaceMemberNameReference();
return;
+ case kInstanceGet:
+ helper_.ReadByte(); // read kind.
+ helper_.ReadPosition(); // read position.
+ VisitExpression(); // read receiver.
+ helper_.SkipName(); // read name.
+ helper_.SkipDartType(); // read result_type.
+ // read interface_target_reference.
+ helper_.SkipInterfaceMemberNameReference();
+ return;
+ case kDynamicGet:
+ helper_.ReadByte(); // read kind.
+ helper_.ReadPosition(); // read position.
+ VisitExpression(); // read receiver.
+ helper_.SkipName(); // read name.
+ return;
+ case kInstanceTearOff:
+ helper_.ReadByte(); // read kind.
+ helper_.ReadPosition(); // read position.
+ VisitExpression(); // read receiver.
+ helper_.SkipName(); // read name.
+ helper_.SkipDartType(); // read result_type.
+ // read interface_target_reference.
+ helper_.SkipInterfaceMemberNameReference();
+ return;
+ case kFunctionTearOff:
+ helper_.ReadPosition(); // read position.
+ VisitExpression(); // read receiver.
+ return;
case kPropertySet:
helper_.ReadPosition(); // read position.
VisitExpression(); // read receiver.
@@ -701,6 +729,22 @@
// read interface_target_reference.
helper_.SkipInterfaceMemberNameReference();
return;
+ case kInstanceSet:
+ helper_.ReadByte(); // read kind.
+ helper_.ReadPosition(); // read position.
+ VisitExpression(); // read receiver.
+ helper_.SkipName(); // read name.
+ VisitExpression(); // read value.
+ // read interface_target_reference.
+ helper_.SkipInterfaceMemberNameReference();
+ return;
+ case kDynamicSet:
+ helper_.ReadByte(); // read kind.
+ helper_.ReadPosition(); // read position.
+ VisitExpression(); // read receiver.
+ helper_.SkipName(); // read name.
+ VisitExpression(); // read value.
+ return;
case kSuperPropertyGet:
HandleLoadReceiver();
helper_.ReadPosition(); // read position.
@@ -732,6 +776,53 @@
// read interface_target_reference.
helper_.SkipInterfaceMemberNameReference();
return;
+ case kInstanceInvocation:
+ helper_.ReadByte(); // read kind.
+ helper_.ReadFlags(); // read flags.
+ helper_.ReadPosition(); // read position.
+ VisitExpression(); // read receiver.
+ helper_.SkipName(); // read name.
+ VisitArguments(); // read arguments.
+ helper_.SkipDartType(); // read function_type.
+ // read interface_target_reference.
+ helper_.SkipInterfaceMemberNameReference();
+ return;
+ case kDynamicInvocation:
+ helper_.ReadByte(); // read kind.
+ helper_.ReadPosition(); // read position.
+ VisitExpression(); // read receiver.
+ helper_.SkipName(); // read name.
+ VisitArguments(); // read arguments.
+ return;
+ case kLocalFunctionInvocation: {
+ helper_.ReadPosition(); // read position.
+ intptr_t variable_kernel_offset =
+ helper_.ReadUInt(); // read variable kernel position.
+ helper_.ReadUInt(); // read relative variable index.
+ VisitArguments(); // read arguments.
+ helper_.SkipDartType(); // read function_type.
+ VisitVariableGet(variable_kernel_offset);
+ return;
+ }
+ case kFunctionInvocation:
+ helper_.ReadByte(); // read kind.
+ helper_.ReadPosition(); // read position.
+ VisitExpression(); // read receiver.
+ VisitArguments(); // read arguments.
+ helper_.SkipDartType(); // read function_type.
+ return;
+ case kEqualsCall:
+ helper_.ReadPosition(); // read position.
+ VisitExpression(); // read left.
+ VisitExpression(); // read right.
+ helper_.SkipDartType(); // read function_type.
+ // read interface_target_reference.
+ helper_.SkipInterfaceMemberNameReference();
+ return;
+ case kEqualsNull:
+ helper_.ReadPosition(); // read position.
+ VisitExpression(); // read expression.
+ return;
case kSuperMethodInvocation:
HandleLoadReceiver();
helper_.ReadPosition(); // read position.
@@ -914,15 +1005,13 @@
case kConstSetLiteral:
case kConstMapLiteral:
case kSymbolLiteral:
- // Const invocations and const literals are removed by the
- // constant evaluator.
case kListConcatenation:
case kSetConcatenation:
case kMapConcatenation:
case kInstanceCreation:
case kFileUriExpression:
- // Collection concatenation, instance creation operations and
- // in-expression URI changes are internal to the front end and
+ case kStaticTearOff:
+ // These nodes are internal to the front end and
// removed by the constant evaluator.
default:
ReportUnexpectedTag("expression", tag);
diff --git a/runtime/vm/kernel_binary.h b/runtime/vm/kernel_binary.h
index c7b1fe5..6b6878f 100644
--- a/runtime/vm/kernel_binary.h
+++ b/runtime/vm/kernel_binary.h
@@ -214,6 +214,14 @@
kIsRequired = 1 << 0,
};
+// Keep in sync with package:kernel/lib/ast.dart
+enum class FunctionAccessKind {
+ kFunction,
+ kFunctionType,
+ kInapplicable,
+ kNullable,
+};
+
static const int SpecializedIntLiteralBias = 3;
static const int LibraryCountFieldCountFromEnd = 1;
static const int KernelFormatVersionOffset = 4;