mirror of
https://github.com/dart-lang/sdk
synced 2024-09-19 23:41:50 +00:00
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:
parent
741f662a60
commit
8a05c944cd
|
@ -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');
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 ||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -439,7 +439,6 @@ class JsClosedWorldBuilder {
|
|||
needToInitializeDispatchProperty:
|
||||
backendUsage.needToInitializeDispatchProperty,
|
||||
requiresPreamble: backendUsage.requiresPreamble,
|
||||
isInvokeOnUsed: backendUsage.isInvokeOnUsed,
|
||||
runtimeTypeUses: runtimeTypeUses,
|
||||
isFunctionApplyUsed: backendUsage.isFunctionApplyUsed,
|
||||
isMirrorsUsed: backendUsage.isMirrorsUsed,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue