Files
sdk/runtime/lib/invocation_mirror_patch.dart
T
Samir Jindel 184e2a8b4c [vm] Support partial instantiation of noSuchMethod forwarders in VM.
This is complicated by the fact that the normal factory method for creating
Invocation objects references the arguments descriptor to determine how many
type arguments are passed. This doesn't work for partially instantiated
closures, because the arguments descriptor will say "0" type arguments even when
there may be delayed type arguments attached to the closure from partial
instantiation. The arguments descriptor can't be modified, so we have a new
factory method which takes the number of delayed type arguments directly.

Change-Id: Ic9a35a482b3b7ef80564e674cc6207873e255111
Reviewed-on: https://dart-review.googlesource.com/54245
Commit-Queue: Samir Jindel <sjindel@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
2018-05-14 14:34:58 +00:00

201 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.
final String _functionName;
final List _argumentsDescriptor;
final List _arguments;
final bool _isSuperInvocation;
final 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]);
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`.
static _allocateInvocationMirrorForClosure(
String functionName,
List argumentsDescriptor,
List arguments,
int type,
int delayedTypeArgumentsLen) {
return new _InvocationMirror(functionName, argumentsDescriptor, arguments,
false, type, delayedTypeArgumentsLen);
}
}