| // 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); |
| } |
| } |