// 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 _typeArguments; List _positionalArguments; Map _namedArguments; _InvocationMirror._withType(this._memberName, this._type, this._typeArguments, this._positionalArguments, this._namedArguments) { _typeArguments ??= const []; _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 get typeArguments { if (_typeArguments == null) { if (_typeArgsLen == 0) { return _typeArguments = const []; } // 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 _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 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(); 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); } }