mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
![Samir Jindel](/assets/img/avatar_default.png)
Change-Id: Ie84529ef3d41d55c29c9a4bf2c84a69e3dbcaa0f Reviewed-on: https://dart-review.googlesource.com/c/93429 Auto-Submit: Samir Jindel <sjindel@google.com> Reviewed-by: Alexander Markov <alexmarkov@google.com> Commit-Queue: Samir Jindel <sjindel@google.com>
203 lines
7.1 KiB
Dart
203 lines
7.1 KiB
Dart
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
// part of "core_patch.dart";
|
|
|
|
// NOTE: When making changes to this class, please also update
|
|
// `VmTarget.instantiateInvocation` and `VmTarget._invocationType` in
|
|
// `pkg/kernel/lib/target/vm.dart`.
|
|
class _InvocationMirror implements Invocation {
|
|
// Constants describing the invocation kind.
|
|
// _FIELD cannot be generated by regular invocation mirrors.
|
|
static const int _METHOD = 0;
|
|
static const int _GETTER = 1;
|
|
static const int _SETTER = 2;
|
|
static const int _FIELD = 3;
|
|
static const int _LOCAL_VAR = 4;
|
|
static const int _KIND_SHIFT = 0;
|
|
static const int _KIND_BITS = 3;
|
|
static const int _KIND_MASK = (1 << _KIND_BITS) - 1;
|
|
|
|
// These values, except _DYNAMIC and _SUPER, are only used when throwing
|
|
// NoSuchMethodError for compile-time resolution failures.
|
|
static const int _DYNAMIC = 0;
|
|
static const int _SUPER = 1;
|
|
static const int _STATIC = 2;
|
|
static const int _CONSTRUCTOR = 3;
|
|
static const int _TOP_LEVEL = 4;
|
|
static const int _LEVEL_SHIFT = _KIND_BITS;
|
|
static const int _LEVEL_BITS = 3;
|
|
static const int _LEVEL_MASK = (1 << _LEVEL_BITS) - 1;
|
|
|
|
// ArgumentsDescriptor layout. Keep in sync with enum in dart_entry.h.
|
|
static const int _TYPE_ARGS_LEN = 0;
|
|
static const int _COUNT = 1;
|
|
static const int _POSITIONAL_COUNT = 2;
|
|
static const int _FIRST_NAMED_ENTRY = 3;
|
|
|
|
// Internal representation of the invocation mirror.
|
|
String _functionName;
|
|
List _argumentsDescriptor;
|
|
List _arguments;
|
|
bool _isSuperInvocation;
|
|
int _delayedTypeArgumentsLen;
|
|
|
|
// External representation of the invocation mirror; populated on demand.
|
|
Symbol _memberName;
|
|
int _type;
|
|
List<Type> _typeArguments;
|
|
List _positionalArguments;
|
|
Map<Symbol, dynamic> _namedArguments;
|
|
|
|
_InvocationMirror._withType(this._memberName, this._type, this._typeArguments,
|
|
this._positionalArguments, this._namedArguments) {
|
|
_typeArguments ??= const <Type>[];
|
|
_positionalArguments ??= const [];
|
|
_namedArguments ??= const {};
|
|
}
|
|
|
|
void _setMemberNameAndType() {
|
|
_type ??= 0;
|
|
if (_functionName.startsWith("get:")) {
|
|
_type |= _GETTER;
|
|
_memberName = new internal.Symbol.unvalidated(_functionName.substring(4));
|
|
} else if (_functionName.startsWith("set:")) {
|
|
_type |= _SETTER;
|
|
_memberName =
|
|
new internal.Symbol.unvalidated(_functionName.substring(4) + "=");
|
|
} else {
|
|
_type |=
|
|
_isSuperInvocation ? (_SUPER << _LEVEL_SHIFT) | _METHOD : _METHOD;
|
|
_memberName = new internal.Symbol.unvalidated(_functionName);
|
|
}
|
|
}
|
|
|
|
Symbol get memberName {
|
|
if (_memberName == null) {
|
|
_setMemberNameAndType();
|
|
}
|
|
return _memberName;
|
|
}
|
|
|
|
int get _typeArgsLen {
|
|
int typeArgsLen = _argumentsDescriptor[_TYPE_ARGS_LEN];
|
|
return typeArgsLen == 0 ? _delayedTypeArgumentsLen : typeArgsLen;
|
|
}
|
|
|
|
List<Type> get typeArguments {
|
|
if (_typeArguments == null) {
|
|
if (_typeArgsLen == 0) {
|
|
return _typeArguments = const <Type>[];
|
|
}
|
|
// A TypeArguments object does not have a corresponding Dart class and
|
|
// cannot be accessed as an array in Dart. Therefore, we need a native
|
|
// call to unpack the individual types into a list.
|
|
_typeArguments = _unpackTypeArguments(_arguments[0], _typeArgsLen);
|
|
}
|
|
return _typeArguments;
|
|
}
|
|
|
|
// Unpack the given TypeArguments object into a new list of individual types.
|
|
static List<Type> _unpackTypeArguments(typeArguments, int numTypeArguments)
|
|
native "InvocationMirror_unpackTypeArguments";
|
|
|
|
List get positionalArguments {
|
|
if (_positionalArguments == null) {
|
|
// The argument descriptor counts the receiver, but not the type arguments
|
|
// as positional arguments.
|
|
int numPositionalArguments = _argumentsDescriptor[_POSITIONAL_COUNT] - 1;
|
|
if (numPositionalArguments == 0) {
|
|
return _positionalArguments = const [];
|
|
}
|
|
// Exclude receiver and type args in the returned list.
|
|
int receiverIndex = _typeArgsLen > 0 ? 1 : 0;
|
|
_positionalArguments = new _ImmutableList._from(
|
|
_arguments, receiverIndex + 1, numPositionalArguments);
|
|
}
|
|
return _positionalArguments;
|
|
}
|
|
|
|
Map<Symbol, dynamic> get namedArguments {
|
|
if (_namedArguments == null) {
|
|
int numArguments = _argumentsDescriptor[_COUNT] - 1; // Exclude receiver.
|
|
int numPositionalArguments = _argumentsDescriptor[_POSITIONAL_COUNT] - 1;
|
|
int numNamedArguments = numArguments - numPositionalArguments;
|
|
if (numNamedArguments == 0) {
|
|
return _namedArguments = const {};
|
|
}
|
|
int receiverIndex = _typeArgsLen > 0 ? 1 : 0;
|
|
_namedArguments = new Map<Symbol, dynamic>();
|
|
for (int i = 0; i < numNamedArguments; i++) {
|
|
int namedEntryIndex = _FIRST_NAMED_ENTRY + 2 * i;
|
|
String arg_name = _argumentsDescriptor[namedEntryIndex];
|
|
var arg_value = _arguments[
|
|
receiverIndex + _argumentsDescriptor[namedEntryIndex + 1]];
|
|
_namedArguments[new internal.Symbol.unvalidated(arg_name)] = arg_value;
|
|
}
|
|
_namedArguments = new Map.unmodifiable(_namedArguments);
|
|
}
|
|
return _namedArguments;
|
|
}
|
|
|
|
bool get isMethod {
|
|
if (_type == null) {
|
|
_setMemberNameAndType();
|
|
}
|
|
return (_type & _KIND_MASK) == _METHOD;
|
|
}
|
|
|
|
bool get isAccessor {
|
|
if (_type == null) {
|
|
_setMemberNameAndType();
|
|
}
|
|
return (_type & _KIND_MASK) != _METHOD;
|
|
}
|
|
|
|
bool get isGetter {
|
|
if (_type == null) {
|
|
_setMemberNameAndType();
|
|
}
|
|
return (_type & _KIND_MASK) == _GETTER;
|
|
}
|
|
|
|
bool get isSetter {
|
|
if (_type == null) {
|
|
_setMemberNameAndType();
|
|
}
|
|
return (_type & _KIND_MASK) == _SETTER;
|
|
}
|
|
|
|
_InvocationMirror(this._functionName, this._argumentsDescriptor,
|
|
this._arguments, this._isSuperInvocation, this._type,
|
|
[this._delayedTypeArgumentsLen = 0]);
|
|
|
|
_InvocationMirror._withoutType(this._functionName, this._typeArguments,
|
|
this._positionalArguments, this._namedArguments, this._isSuperInvocation,
|
|
[this._delayedTypeArgumentsLen = 0]);
|
|
|
|
@pragma("vm:entry-point", "call")
|
|
static _allocateInvocationMirror(String functionName,
|
|
List argumentsDescriptor, List arguments, bool isSuperInvocation,
|
|
[int type = null]) {
|
|
return new _InvocationMirror(
|
|
functionName, argumentsDescriptor, arguments, isSuperInvocation, type);
|
|
}
|
|
|
|
// This factory is used when creating an `Invocation` for a closure call which
|
|
// may have delayed type arguments. In that case, the arguments descriptor will
|
|
// indicate 0 type arguments, but the actual number of type arguments are
|
|
// passed in `delayedTypeArgumentsLen`. If any type arguments are available,
|
|
// the type arguments vector will be the first entry in `arguments`.
|
|
@pragma("vm:entry-point", "call")
|
|
static _allocateInvocationMirrorForClosure(
|
|
String functionName,
|
|
List argumentsDescriptor,
|
|
List arguments,
|
|
int type,
|
|
int delayedTypeArgumentsLen) {
|
|
return new _InvocationMirror(functionName, argumentsDescriptor, arguments,
|
|
false, type, delayedTypeArgumentsLen);
|
|
}
|
|
}
|