Remove JsInvocationMirror._invokeOn

I believe this was code only used via dart:mirrors

Soon we might want to rename JSInvocationMirror to just JsInvocation (so it's
clear that it is only used for nsm)

Change-Id: I0e0f836b18e6f290311c7173cfafedfcccab5c6f
Reviewed-on: https://dart-review.googlesource.com/69246
Commit-Queue: Sigmund Cherem <sigmund@google.com>
Reviewed-by: Stephen Adams <sra@google.com>
This commit is contained in:
Sigmund Cherem 2018-08-13 18:09:14 +00:00 committed by commit-bot@chromium.org
parent 741f662a60
commit 8a05c944cd
12 changed files with 4 additions and 278 deletions

View file

@ -892,10 +892,6 @@ class CommonElements {
ConstructorEntity get typeVariableConstructor => _typeVariableConstructor ??=
_env.lookupConstructor(typeVariableClass, '');
FunctionEntity _invokeOnMethod;
FunctionEntity get invokeOnMethod => _invokeOnMethod ??= _env
.lookupLocalClassMember(jsInvocationMirrorClass, '_getCachedInvocation');
FunctionEntity _assertTest;
FunctionEntity get assertTest =>
_assertTest ??= _findHelperFunction('assertTest');

View file

@ -1184,21 +1184,9 @@ class DynamicCallSiteTypeInformation<T> extends CallSiteTypeInformation {
inferrer.updateSelectorInMember(
caller, _callType, _call, selector, typeMask);
AbstractValue maskToUse =
closedWorld.extendMaskIfReachesAll(selector, typeMask);
bool canReachAll =
closedWorld.backendUsage.isInvokeOnUsed && (maskToUse != typeMask);
// If this call could potentially reach all methods that satisfy
// the untyped selector (through noSuchMethod's `Invocation`
// and a call to `delegate`), we iterate over all these methods to
// update their parameter types.
_hasClosureCallTargets =
closedWorld.includesClosureCall(selector, maskToUse);
_concreteTargets = closedWorld.locateMembers(selector, maskToUse);
Iterable<MemberEntity> typedTargets = canReachAll
? closedWorld.locateMembers(selector, typeMask)
: _concreteTargets;
closedWorld.includesClosureCall(selector, typeMask);
_concreteTargets = closedWorld.locateMembers(selector, typeMask);
// Update the call graph if the targets could have changed.
if (!identical(_concreteTargets, oldTargets)) {
@ -1237,14 +1225,6 @@ class DynamicCallSiteTypeInformation<T> extends CallSiteTypeInformation {
} else {
result = inferrer.types
.joinTypeMasks(_concreteTargets.map((MemberEntity element) {
// If [canReachAll] is true, then we are iterating over all
// targets that satisfy the untyped selector. We skip the return
// type of the targets that can only be reached through
// `Invocation.delegate`. Note that the `noSuchMethod` targets
// are included in [typedTargets].
if (canReachAll && !typedTargets.contains(element)) {
return abstractValueDomain.emptyType;
}
if (inferrer.returnsListElementType(selector, typeMask)) {
return abstractValueDomain.getContainerElementType(receiver.type);
} else if (inferrer.returnsMapValueType(selector, typeMask)) {

View file

@ -33,9 +33,6 @@ abstract class BackendUsage {
/// `true` if a core-library function requires the preamble file to function.
bool get requiresPreamble;
/// `true` if [CommonElements.invokeOnMethod] is used.
bool get isInvokeOnUsed;
/// `true` of `Object.runtimeType` is used.
bool get isRuntimeTypeUsed;
@ -107,9 +104,6 @@ class BackendUsageBuilderImpl implements BackendUsageBuilder {
/// `true` if a core-library function requires the preamble file to function.
bool requiresPreamble = false;
/// `true` if [CommonElements.invokeOnMethod] is used.
bool isInvokeOnUsed = false;
/// `true` if `Function.apply` is used.
bool isFunctionApplyUsed = false;
@ -227,8 +221,6 @@ class BackendUsageBuilderImpl implements BackendUsageBuilder {
_needToInitializeIsolateAffinityTag = true;
} else if (member == _commonElements.requiresPreambleMarker) {
requiresPreamble = true;
} else if (member == _commonElements.invokeOnMethod) {
isInvokeOnUsed = true;
} else if (_commonElements.isFunctionApplyMethod(member)) {
isFunctionApplyUsed = true;
} else if (member.library == _commonElements.mirrorsLibrary) {
@ -266,7 +258,6 @@ class BackendUsageBuilderImpl implements BackendUsageBuilder {
needToInitializeIsolateAffinityTag: _needToInitializeIsolateAffinityTag,
needToInitializeDispatchProperty: _needToInitializeDispatchProperty,
requiresPreamble: requiresPreamble,
isInvokeOnUsed: isInvokeOnUsed,
runtimeTypeUses: _runtimeTypeUses,
isFunctionApplyUsed: isFunctionApplyUsed,
isMirrorsUsed: isMirrorsUsed,
@ -293,9 +284,6 @@ class BackendUsageImpl implements BackendUsage {
/// `true` if a core-library function requires the preamble file to function.
final bool requiresPreamble;
/// `true` if [CommonElements.invokeOnMethod] is used.
final bool isInvokeOnUsed;
/// `true` if `Function.apply` is used.
final bool isFunctionApplyUsed;
@ -313,7 +301,6 @@ class BackendUsageImpl implements BackendUsage {
this.needToInitializeIsolateAffinityTag,
this.needToInitializeDispatchProperty,
this.requiresPreamble,
this.isInvokeOnUsed,
Set<RuntimeTypeUse> runtimeTypeUses,
this.isFunctionApplyUsed,
this.isMirrorsUsed,

View file

@ -377,10 +377,6 @@ class Emitter extends js_emitter.EmitterBase {
subclassReadGenerator, interceptorsByTagAccess, leafTagsAccess);
}
jsAst.ObjectInitializer generateInterceptedNamesSet() {
return interceptorEmitter.generateInterceptedNamesSet();
}
/// In minified mode we want to keep the name for the most common core types.
bool _isNativeTypeNeedingReflectionName(ClassEntity element) {
return (element == commonElements.intClass ||

View file

@ -93,28 +93,6 @@ class InterceptorEmitter extends CodeEmitterHelper {
return new jsAst.Block(parts);
}
/**
* If [JSInvocationMirror._invokeOn] has been compiled, emit all the
* possible selector names that are intercepted into the
* [interceptedNames] embedded global. The implementation of
* [_invokeOn] will use it to determine whether it should call the
* method with an extra parameter.
*/
jsAst.ObjectInitializer generateInterceptedNamesSet() {
// We could also generate the list of intercepted names at
// runtime, by running through the subclasses of Interceptor
// (which can easily be identified).
if (!closedWorld.backendUsage.isInvokeOnUsed) return null;
Iterable<jsAst.Name> invocationNames = interceptorInvocationNames.toList()
..sort();
;
List<jsAst.Property> properties = invocationNames.map((jsAst.Name name) {
return new jsAst.Property(js.quoteName(name), js.number(1));
}).toList();
return new jsAst.ObjectInitializer(properties, isOneLiner: true);
}
/**
* Emit initializer for `typeToInterceptorMap` data structure used by
* `findInterceptorForType`. See declaration of `typeToInterceptor` in

View file

@ -37,8 +37,6 @@ jsAst.Statement buildSetupProgram(
emitter.generateEmbeddedGlobalAccess(embeddedNames.TYPE_INFORMATION);
jsAst.Expression staticsAccess =
emitter.generateEmbeddedGlobalAccess(embeddedNames.STATICS);
jsAst.Expression interceptedNamesAccess =
emitter.generateEmbeddedGlobalAccess(embeddedNames.INTERCEPTED_NAMES);
jsAst.Expression mangledGlobalNamesAccess =
emitter.generateEmbeddedGlobalAccess(embeddedNames.MANGLED_GLOBAL_NAMES);
jsAst.Expression mangledNamesAccess =
@ -94,9 +92,6 @@ jsAst.Statement buildSetupProgram(
'staticsPropertyName': namer.staticsPropertyName,
'staticsPropertyNameString': js.quoteName(namer.staticsPropertyName),
'typeInformation': typeInformationAccess,
'enabledInvokeOn': closedWorld.backendUsage.isInvokeOnUsed,
'interceptedNames': interceptedNamesAccess,
'interceptedNamesSet': emitter.generateInterceptedNamesSet(),
'notInCspMode': !compiler.options.useContentSecurityPolicy,
'inCspMode': compiler.options.useContentSecurityPolicy,
'deferredAction': namer.deferredAction,
@ -681,10 +676,6 @@ function $setupProgramName(programData, metadataOffset, typesOffset) {
funcs.push(f);
f.\$stubName = getterStubName;
f.\$callName = null;
// Update the interceptedNames map (which only exists if `invokeOn` was
// enabled).
if (#enabledInvokeOn)
if (isIntercepted) #interceptedNames[getterStubName] = 1;
}
if (#usesMangledNames) {
@ -735,8 +726,6 @@ function $setupProgramName(programData, metadataOffset, typesOffset) {
if (!#mangledGlobalNames) #mangledGlobalNames = map();
if (!#statics) #statics = map();
if (!#typeInformation) #typeInformation = map();
if (#enabledInvokeOn)
if (!#interceptedNames) #interceptedNames = #interceptedNamesSet;
var libraries = #libraries;
var mangledNames = #mangledNames;
var mangledGlobalNames = #mangledGlobalNames;

View file

@ -439,7 +439,6 @@ class JsClosedWorldBuilder {
needToInitializeDispatchProperty:
backendUsage.needToInitializeDispatchProperty,
requiresPreamble: backendUsage.requiresPreamble,
isInvokeOnUsed: backendUsage.isInvokeOnUsed,
runtimeTypeUses: runtimeTypeUses,
isFunctionApplyUsed: backendUsage.isFunctionApplyUsed,
isMirrorsUsed: backendUsage.isMirrorsUsed,

View file

@ -40,8 +40,7 @@ import '../universe/feature.dart';
import '../universe/selector.dart';
import '../universe/side_effects.dart' show SideEffects;
import '../universe/target_checks.dart' show TargetChecks;
import '../universe/use.dart'
show ConstantUse, ConstrainedDynamicUse, StaticUse;
import '../universe/use.dart' show ConstantUse, StaticUse;
import '../universe/world_builder.dart' show CodegenWorldBuilder;
import '../world.dart';
import 'graph_builder.dart';
@ -4469,17 +4468,6 @@ class KernelSsaGraphBuilder extends ir.Visitor
_elementMap.getClass(_containingClass(invocation));
FunctionEntity noSuchMethod =
_elementMap.getSuperNoSuchMethod(containingClass);
if (backendUsage.isInvokeOnUsed &&
noSuchMethod.enclosingClass != _commonElements.objectClass) {
// Register the call as dynamic if [noSuchMethod] on the super
// class is _not_ the default implementation from [Object] (it might be
// overridden in the super class, but it might have a different number of
// arguments), in case the [noSuchMethod] implementation calls
// [JSInvocationMirror._invokeOn].
// TODO(johnniwinther): Register this more precisely.
registry
?.registerDynamicUse(new ConstrainedDynamicUse(selector, null, null));
}
ConstantValue nameConstant = constantSystem.createString(publicName);

View file

@ -1849,9 +1849,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
return _abstractValueDomain.createNonNullSubtype(enclosing);
}
}
// If [JSInvocationMirror._invokeOn] is enabled, and this call
// might hit a `noSuchMethod`, we register an untyped selector.
return _closedWorld.extendMaskIfReachesAll(selector, mask);
return mask ?? _abstractValueDomain.dynamicType;
}
void registerMethodInvoke(HInvokeDynamic node) {

View file

@ -161,11 +161,6 @@ abstract class JClosedWorld implements World {
/// Returns `true` if the field [element] is known to be effectively final.
bool fieldNeverChanges(MemberEntity element);
/// Extends the [receiver] type for calling [selector] to take live
/// `noSuchMethod` handlers into account.
AbstractValue extendMaskIfReachesAll(
Selector selector, AbstractValue receiver);
/// Returns `true` if [selector] on [receiver] can hit a `call` method on a
/// subclass of `Closure`.
///
@ -570,16 +565,6 @@ abstract class ClosedWorldBase implements JClosedWorld {
return abstractValueDomain.locateSingleMember(receiver, selector);
}
AbstractValue extendMaskIfReachesAll(
Selector selector, AbstractValue receiver) {
bool canReachAll = true;
if (receiver != null) {
canReachAll = backendUsage.isInvokeOnUsed &&
abstractValueDomain.needsNoSuchMethodHandling(receiver, selector);
}
return canReachAll ? abstractValueDomain.dynamicType : receiver;
}
bool fieldNeverChanges(MemberEntity element) {
if (!element.isField) return false;
if (nativeData.isNativeMember(element)) {

View file

@ -377,171 +377,6 @@ class JSInvocationMirror implements Invocation {
}
return new ConstantMapView<Symbol, dynamic>(map);
}
_getCachedInvocation(Object object) {
var interceptor = getInterceptor(object);
var receiver = object;
var name = _internalName;
var arguments = _arguments;
var interceptedNames = JS_EMBEDDED_GLOBAL('', INTERCEPTED_NAMES);
bool isIntercepted = JS('bool',
'Object.prototype.hasOwnProperty.call(#, #)', interceptedNames, name);
if (isIntercepted) {
receiver = interceptor;
if (JS('bool', '# === #', object, interceptor)) {
interceptor = null;
}
} else {
interceptor = null;
}
bool isCatchAll = false;
var method = JS('var', '#[#]', receiver, name);
if (JS('bool', 'typeof # != "function"', method)) {
String baseName = _symbol_dev.Symbol.getName(memberName);
method = JS('', '#[# + "*"]', receiver, baseName);
if (method == null) {
interceptor = getInterceptor(object);
method = JS('', '#[# + "*"]', interceptor, baseName);
if (method != null) {
isIntercepted = true;
receiver = interceptor;
} else {
interceptor = null;
}
}
isCatchAll = true;
}
if (JS('bool', 'typeof # == "function"', method)) {
if (isCatchAll) {
return new CachedCatchAllInvocation(
name, method, isIntercepted, interceptor);
} else {
return new CachedInvocation(name, method, isIntercepted, interceptor);
}
} else {
// In this case, receiver doesn't implement name. So we should
// invoke noSuchMethod instead (which will often throw a
// NoSuchMethodError).
return new CachedNoSuchMethodInvocation(interceptor);
}
}
/// This method is called by [InstanceMirror.delegate].
static invokeFromMirror(JSInvocationMirror invocation, Object victim) {
var cached = invocation._getCachedInvocation(victim);
if (cached.isNoSuchMethod) {
return cached.invokeOn(victim, invocation);
} else {
return cached.invokeOn(victim, invocation._arguments);
}
}
static getCachedInvocation(JSInvocationMirror invocation, Object victim) {
return invocation._getCachedInvocation(victim);
}
}
class CachedInvocation {
// The mangled name of this invocation.
String mangledName;
/// The JS function to call.
var jsFunction;
/// True if this is an intercepted call.
bool isIntercepted;
/// Non-null interceptor if this is an intercepted call through an
/// [Interceptor].
Interceptor cachedInterceptor;
CachedInvocation(this.mangledName, this.jsFunction, this.isIntercepted,
this.cachedInterceptor);
bool get isNoSuchMethod => false;
bool get isGetterStub => JS('bool', '!!#.\$getterStub', jsFunction);
/// Applies [jsFunction] to [victim] with [arguments].
/// Users of this class must take care to check the arguments first.
invokeOn(Object victim, List arguments) {
var receiver = victim;
if (!isIntercepted) {
if (arguments is! JSArray) arguments = new List.from(arguments);
} else {
arguments = [victim]..addAll(arguments);
if (cachedInterceptor != null) receiver = cachedInterceptor;
}
return JS('var', '#.apply(#, #)', jsFunction, receiver, arguments);
}
}
class CachedCatchAllInvocation extends CachedInvocation {
final ReflectionInfo info;
CachedCatchAllInvocation(String name, jsFunction, bool isIntercepted,
Interceptor cachedInterceptor)
: info = new ReflectionInfo(jsFunction),
super(name, jsFunction, isIntercepted, cachedInterceptor);
bool get isGetterStub => false;
invokeOn(Object victim, List arguments) {
var receiver = victim;
int providedArgumentCount;
int fullParameterCount =
info.requiredParameterCount + info.optionalParameterCount;
if (!isIntercepted) {
if (arguments is JSArray) {
providedArgumentCount = arguments.length;
// If we need to add extra arguments before calling, we have
// to copy the arguments array.
if (providedArgumentCount < fullParameterCount) {
arguments = new List.from(arguments);
}
} else {
arguments = new List.from(arguments);
providedArgumentCount = arguments.length;
}
} else {
arguments = [victim]..addAll(arguments);
if (cachedInterceptor != null) receiver = cachedInterceptor;
providedArgumentCount = arguments.length - 1;
}
if (info.areOptionalParametersNamed &&
(providedArgumentCount > info.requiredParameterCount)) {
throw new UnimplementedNoSuchMethodError(
"Invocation of unstubbed method '${info.reflectionName}'"
" with ${arguments.length} arguments.");
} else if (providedArgumentCount < info.requiredParameterCount) {
throw new UnimplementedNoSuchMethodError(
"Invocation of unstubbed method '${info.reflectionName}'"
" with $providedArgumentCount arguments (too few).");
} else if (providedArgumentCount > fullParameterCount) {
throw new UnimplementedNoSuchMethodError(
"Invocation of unstubbed method '${info.reflectionName}'"
" with $providedArgumentCount arguments (too many).");
}
for (int i = providedArgumentCount; i < fullParameterCount; i++) {
arguments.add(getMetadata(info.defaultValue(i)));
}
return JS('var', '#.apply(#, #)', jsFunction, receiver, arguments);
}
}
class CachedNoSuchMethodInvocation {
/// Non-null interceptor if this is an intercepted call through an
/// [Interceptor].
var interceptor;
CachedNoSuchMethodInvocation(this.interceptor);
bool get isNoSuchMethod => true;
bool get isGetterStub => false;
invokeOn(Object victim, Invocation invocation) {
var receiver = (interceptor == null) ? victim : interceptor;
return receiver.noSuchMethod(invocation);
}
}
class ReflectionInfo {

View file

@ -65,11 +65,6 @@ const TYPES = 'types';
/// runtime-type-information (rti) object.
const GET_TYPE_FROM_NAME = 'getTypeFromName';
/// If [JSInvocationMirror._invokeOn] is being used, this embedded global
/// contains a JavaScript map with the names of methods that are
/// intercepted.
const INTERCEPTED_NAMES = 'interceptedNames';
/// A JS map from mangled global names to their unmangled names.
///
/// If the program does not use reflection, this embedded global may be empty